Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: TLS1.2 support for RSA-PSS certificates #4927

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions tests/integrationv2/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,16 @@ def __init__(self, name, prefix, location=TEST_CERT_DIRECTORY):
self.algorithm = 'RSAPSS'

def compatible_with_cipher(self, cipher):
return (self.algorithm == cipher.algorithm) or (cipher.algorithm == 'ANY')
if self.algorithm == cipher.algorithm:
return True
if cipher.algorithm == 'ANY':
return True
if self.algorithm == 'RSAPSS':
if cipher.algorithm != 'RSA':
return False
if 'ECDHE' in cipher.name:
return True
return False

def compatible_with_curve(self, curve):
if self.algorithm != 'EC':
Expand Down Expand Up @@ -442,7 +451,7 @@ class Signatures(object):

RSA_PSS_PSS_SHA256 = Signature(
'rsa_pss_pss_sha256',
min_protocol=Protocols.TLS13,
min_protocol=Protocols.TLS12,
sig_type='RSA-PSS-PSS',
sig_digest='SHA256')

Expand Down
5 changes: 2 additions & 3 deletions tests/integrationv2/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,8 @@ def invalid_test_parameters(*args, **kwargs):
# Always consider S2N
providers.append(S2N)

# Only TLS1.3 supports RSA-PSS-PSS certificates
# (Earlier versions support RSA-PSS signatures, just via RSA-PSS-RSAE)
if protocol and protocol is not Protocols.TLS13:
# Older versions do not support RSA-PSS-PSS certificates
if protocol and protocol < Protocols.TLS12:
if client_certificate and client_certificate.algorithm == 'RSAPSS':
return True
if certificate and certificate.algorithm == 'RSAPSS':
Expand Down
6 changes: 3 additions & 3 deletions tests/unit/s2n_security_policies_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ int main(int argc, char **argv)
int max = security_policy->signature_preferences->signature_schemes[i]->maximum_protocol_version;
s2n_signature_algorithm sig_alg = security_policy->signature_preferences->signature_schemes[i]->sig_alg;

if (min == S2N_TLS13 || max >= S2N_TLS13) {
if (min <= S2N_TLS13 || max >= S2N_TLS13) {
has_tls_13_sig_alg = true;
}

Expand Down Expand Up @@ -825,8 +825,8 @@ int main(int argc, char **argv)
}
}

/* If scheme will be used for pre-tls1.3 */
if (min_version < S2N_TLS13) {
/* If scheme will be used for legacy versions */
if (min_version < S2N_TLS12) {
EXPECT_NOT_EQUAL(scheme->sig_alg, S2N_SIGNATURE_RSA_PSS_PSS);
}
}
Expand Down
142 changes: 142 additions & 0 deletions tests/unit/s2n_self_talk_certificates_test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

#include "crypto/s2n_rsa_pss.h"
#include "s2n_test.h"
#include "testlib/s2n_testlib.h"
#include "tls/s2n_tls.h"

static uint8_t s2n_noop_verify_host_fn(const char *name, size_t len, void *data)
{
return 1;
}

static S2N_RESULT s2n_test_load_certificate(struct s2n_cert_chain_and_key **chain_out,
char *chain_pem_out, const char *chain_pem_path, const char *key_pem_path)
{
RESULT_ENSURE_REF(chain_out);

char key_pem[S2N_MAX_TEST_PEM_SIZE] = { 0 };
RESULT_GUARD_POSIX(s2n_read_test_pem(chain_pem_path, chain_pem_out, S2N_MAX_TEST_PEM_SIZE));
RESULT_GUARD_POSIX(s2n_read_test_pem(key_pem_path, key_pem, S2N_MAX_TEST_PEM_SIZE));

*chain_out = s2n_cert_chain_and_key_new();
RESULT_ENSURE_REF(*chain_out);
RESULT_GUARD_POSIX(s2n_cert_chain_and_key_load_pem(*chain_out, chain_pem_out, key_pem));

return S2N_RESULT_OK;
}

static bool s2n_test_is_valid(struct s2n_cert_chain_and_key *chain, uint8_t version)
{
const s2n_pkey_type cert_type = s2n_cert_chain_and_key_get_pkey_type(chain);
if (cert_type == S2N_PKEY_TYPE_RSA_PSS) {
/* RSA-PSS certificates were introduced in TLS1.3, but must also be
* supported in TLS1.2. They are not supported for earlier versions.
*
*= https://www.rfc-editor.org/rfc/rfc8446#section-4.2.3
*= type=test
*# - Implementations that advertise support for RSASSA-PSS (which is
*# mandatory in TLS 1.3) MUST be prepared to accept a signature using
*# that scheme even when TLS 1.2 is negotiated. In TLS 1.2,
*# RSASSA-PSS is used with RSA cipher suites.
*/
return (version >= S2N_TLS12);
}
return true;
}

int main(int argc, char **argv)
{
BEGIN_TEST();

if (!s2n_is_rsa_pss_certs_supported() || !s2n_is_tls13_fully_supported()) {
END_TEST();
}

const uint8_t test_versions[] = { S2N_TLS13, S2N_TLS12, S2N_TLS11, S2N_TLS10 };
const char *test_certs[][2] = {
{ S2N_RSA_2048_PKCS1_SHA256_CERT_CHAIN, S2N_RSA_2048_PKCS1_SHA256_CERT_KEY },
{ S2N_ECDSA_P384_PKCS1_CERT_CHAIN, S2N_ECDSA_P384_PKCS1_KEY },
{ S2N_ECDSA_P512_CERT_CHAIN, S2N_ECDSA_P512_KEY },
{ S2N_RSA_PSS_2048_SHA256_LEAF_CERT, S2N_RSA_PSS_2048_SHA256_LEAF_KEY },
};

for (size_t cert_i = 0; cert_i < s2n_array_len(test_certs); cert_i++) {
DEFER_CLEANUP(struct s2n_cert_chain_and_key *chain = NULL,
s2n_cert_chain_and_key_ptr_free);
char pem[S2N_MAX_TEST_PEM_SIZE] = { 0 };
EXPECT_OK(s2n_test_load_certificate(&chain, pem,
test_certs[cert_i][0], test_certs[cert_i][1]));

for (size_t version_i = 0; version_i < s2n_array_len(test_versions); version_i++) {
uint8_t version = test_versions[version_i];

/* We intentionally use the default policies.
* The default policies should support all certificate types.
*/
const char *security_policy = "default";
if (version >= S2N_TLS13) {
security_policy = "default_tls13";
} else if (version < S2N_TLS12) {
/* The default policies don't support legacy versions */
security_policy = "test_all";
}

DEFER_CLEANUP(struct s2n_config *config = s2n_config_new(), s2n_config_ptr_free);
EXPECT_NOT_NULL(config);
EXPECT_SUCCESS(s2n_config_add_cert_chain_and_key_to_store(config, chain));
EXPECT_SUCCESS(s2n_config_add_pem_to_trust_store(config, pem));
EXPECT_SUCCESS(s2n_config_set_verify_host_callback(config, s2n_noop_verify_host_fn, NULL));
EXPECT_SUCCESS(s2n_config_set_max_blinding_delay(config, 0));
EXPECT_SUCCESS(s2n_config_set_cipher_preferences(config, security_policy));

DEFER_CLEANUP(struct s2n_connection *server = s2n_connection_new(S2N_SERVER),
s2n_connection_ptr_free);
EXPECT_NOT_NULL(server);
EXPECT_SUCCESS(s2n_connection_set_config(server, config));
server->server_protocol_version = version;

DEFER_CLEANUP(struct s2n_connection *client = s2n_connection_new(S2N_CLIENT),
s2n_connection_ptr_free);
EXPECT_NOT_NULL(client);
EXPECT_SUCCESS(s2n_connection_set_config(client, config));
client->client_protocol_version = version;

DEFER_CLEANUP(struct s2n_test_io_pair io_pair = { 0 }, s2n_io_pair_close);
EXPECT_SUCCESS(s2n_io_pair_init_non_blocking(&io_pair));
EXPECT_SUCCESS(s2n_connections_set_io_pair(client, server, &io_pair));

bool handshake_success =
(s2n_negotiate_test_server_and_client(server, client) == S2N_SUCCESS);
if (handshake_success) {
EXPECT_EQUAL(server->actual_protocol_version, version);
EXPECT_EQUAL(client->actual_protocol_version, version);
}

const char *error_message = "Handshake failed";
if (!s2n_test_is_valid(chain, version)) {
error_message = "Handshake unexpectedly succeeded";
}
if (handshake_success != s2n_test_is_valid(chain, version)) {
fprintf(stderr, "%s version=%i cert=%s\n",
error_message, version, test_certs[cert_i][0]);
FAIL_MSG(error_message);
}
}
}

END_TEST();
}
2 changes: 0 additions & 2 deletions tls/s2n_signature_algorithms.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,6 @@ static S2N_RESULT s2n_signature_scheme_validate_for_recv(struct s2n_connection *
if (conn->actual_protocol_version >= S2N_TLS13) {
RESULT_ENSURE_NE(scheme->hash_alg, S2N_HASH_SHA1);
RESULT_ENSURE_NE(scheme->sig_alg, S2N_SIGNATURE_RSA);
} else {
RESULT_ENSURE_NE(scheme->sig_alg, S2N_SIGNATURE_RSA_PSS_PSS);
}

return S2N_RESULT_OK;
Expand Down
6 changes: 3 additions & 3 deletions tls/s2n_signature_scheme.c
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ const struct s2n_signature_scheme s2n_rsa_pss_pss_sha256 = {
.sig_alg = S2N_SIGNATURE_RSA_PSS_PSS,
.libcrypto_nid = NID_rsassaPss,
.signature_curve = NULL, /* Elliptic Curve not needed for RSA */
.minimum_protocol_version = S2N_TLS13,
.minimum_protocol_version = S2N_TLS12,
};

const struct s2n_signature_scheme s2n_rsa_pss_pss_sha384 = {
Expand All @@ -191,7 +191,7 @@ const struct s2n_signature_scheme s2n_rsa_pss_pss_sha384 = {
.sig_alg = S2N_SIGNATURE_RSA_PSS_PSS,
.libcrypto_nid = NID_rsassaPss,
.signature_curve = NULL, /* Elliptic Curve not needed for RSA */
.minimum_protocol_version = S2N_TLS13,
.minimum_protocol_version = S2N_TLS12,
};

const struct s2n_signature_scheme s2n_rsa_pss_pss_sha512 = {
Expand All @@ -201,7 +201,7 @@ const struct s2n_signature_scheme s2n_rsa_pss_pss_sha512 = {
.sig_alg = S2N_SIGNATURE_RSA_PSS_PSS,
.libcrypto_nid = NID_rsassaPss,
.signature_curve = NULL, /* Elliptic Curve not needed for RSA */
.minimum_protocol_version = S2N_TLS13,
.minimum_protocol_version = S2N_TLS12,
};

/* Chosen based on AWS server recommendations as of 05/24.
Expand Down
Loading