-
Notifications
You must be signed in to change notification settings - Fork 746
Add PQ KeyExchange Required TLS Policy #5358
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
base: main
Are you sure you want to change the base?
Changes from all commits
bc25c34
e5594e2
e3e1055
182980a
7a28eb5
b76cb2b
35f251e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| name: AWS-CRT-SDK-TLSv1.3-2025-PQ-KX-Required | ||
| min version: TLS1.3 | ||
| rules: | ||
| - Perfect Forward Secrecy: yes | ||
| - FIPS 140-3 (2019): no | ||
| cipher suites: | ||
| - TLS_AES_128_GCM_SHA256 | ||
| - TLS_AES_256_GCM_SHA384 | ||
| - TLS_CHACHA20_POLY1305_SHA256 | ||
| signature schemes: | ||
| - mldsa44 | ||
| - mldsa65 | ||
| - mldsa87 | ||
| - ecdsa_sha256 | ||
| - ecdsa_sha384 | ||
| - ecdsa_sha512 | ||
| - rsa_pss_pss_sha256 | ||
| - rsa_pss_pss_sha384 | ||
| - rsa_pss_pss_sha512 | ||
| - rsa_pss_rsae_sha256 | ||
| - rsa_pss_rsae_sha384 | ||
| - rsa_pss_rsae_sha512 | ||
| - rsa_pkcs1_sha256 | ||
| - rsa_pkcs1_sha384 | ||
| - rsa_pkcs1_sha512 | ||
| curves: | ||
| pq: | ||
| - revision: 5 | ||
| - kems: | ||
| - kem groups: | ||
| -- X25519MLKEM768 | ||
| -- SecP256r1MLKEM768 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -108,12 +108,37 @@ const struct s2n_ecc_named_curve *s2n_get_predicted_negotiated_ecdhe_curve(const | |
| return NULL; | ||
| } | ||
|
|
||
| int s2n_test_tls13_pq_handshake_cleanup(struct s2n_stuffer *client_to_server, struct s2n_stuffer *server_to_client, | ||
| struct s2n_connection *client_conn, struct s2n_connection *server_conn, struct s2n_cert_chain_and_key *chain_and_key, | ||
| struct s2n_config *client_config, struct s2n_config *server_config) | ||
| { | ||
| POSIX_GUARD(s2n_stuffer_free(client_to_server)); | ||
| POSIX_GUARD(s2n_stuffer_free(server_to_client)); | ||
|
|
||
| POSIX_GUARD(s2n_connection_free(client_conn)); | ||
| POSIX_GUARD(s2n_connection_free(server_conn)); | ||
|
|
||
| POSIX_GUARD(s2n_cert_chain_and_key_free(chain_and_key)); | ||
| POSIX_GUARD(s2n_config_free(server_config)); | ||
| POSIX_GUARD(s2n_config_free(client_config)); | ||
|
|
||
| return S2N_SUCCESS; | ||
| } | ||
|
|
||
| int s2n_test_tls13_pq_handshake(const struct s2n_security_policy *client_sec_policy, | ||
| const struct s2n_security_policy *server_sec_policy, const struct s2n_kem_group *expected_kem_group, | ||
| const struct s2n_ecc_named_curve *expected_curve, bool hrr_expected, bool len_prefix_expected) | ||
| const struct s2n_security_policy *server_sec_policy, const bool expected_handshake_success, const int expected_s2nerrno, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It feels like the number of arguments in this method is reaching a bit of a tipping point with the number of arguments. I think we have some more general methods for "handshake two connections" and I wonder if that might be neater?
I'm not sure that's the best solution, but ideally we'd find something a bit neater? |
||
| const struct s2n_kem_group *expected_kem_group, const struct s2n_ecc_named_curve *expected_curve, bool hrr_expected, bool len_prefix_expected) | ||
| { | ||
| /* XOR check: can expect to negotiate either a KEM group, or a classic EC curve, but not both/neither */ | ||
| POSIX_ENSURE((expected_kem_group == NULL) != (expected_curve == NULL), S2N_ERR_SAFETY); | ||
| if (expected_handshake_success) { | ||
| POSIX_ENSURE((expected_kem_group == NULL) != (expected_curve == NULL), S2N_ERR_SAFETY); | ||
| } else { | ||
| /* If we expect the handshake to fail, then none of the expected success values should be set */ | ||
| POSIX_ENSURE_EQ(expected_kem_group, NULL); | ||
| POSIX_ENSURE_EQ(expected_curve, NULL); | ||
| POSIX_ENSURE_EQ(hrr_expected, false); | ||
| POSIX_ENSURE_EQ(len_prefix_expected, false); | ||
| } | ||
|
|
||
| /* Set up connections */ | ||
| struct s2n_connection *client_conn = NULL, *server_conn = NULL; | ||
|
|
@@ -156,9 +181,13 @@ int s2n_test_tls13_pq_handshake(const struct s2n_security_policy *client_sec_pol | |
|
|
||
| /* Server reads ClientHello */ | ||
| POSIX_ENSURE_EQ(s2n_conn_get_current_message_type(server_conn), CLIENT_HELLO); | ||
| POSIX_GUARD(s2n_handshake_read_io(server_conn)); | ||
| POSIX_ENSURE_EQ((expected_handshake_success ? S2N_SUCCESS : S2N_FAILURE), s2n_handshake_read_io(server_conn)); | ||
|
|
||
| POSIX_ENSURE_EQ(server_conn->actual_protocol_version, S2N_TLS13); /* Server is now on TLS13 */ | ||
| if (expected_handshake_success) { | ||
| POSIX_ENSURE_EQ(server_conn->actual_protocol_version, S2N_TLS13); /* Server is now on TLS13 */ | ||
| } else { | ||
| POSIX_ENSURE_EQ(expected_s2nerrno, s2n_errno); | ||
| } | ||
|
|
||
| /* Assert that the server chose the correct group */ | ||
| if (expected_kem_group) { | ||
|
|
@@ -180,12 +209,14 @@ int s2n_test_tls13_pq_handshake(const struct s2n_security_policy *client_sec_pol | |
|
|
||
| /* Server sends ServerHello or HRR */ | ||
| POSIX_GUARD(s2n_conn_set_handshake_type(server_conn)); | ||
| POSIX_ENSURE_EQ(hrr_expected, s2n_handshake_type_check_tls13_flag(server_conn, HELLO_RETRY_REQUEST)); | ||
| POSIX_GUARD(s2n_handshake_write_io(server_conn)); | ||
|
|
||
| /* Server sends CCS */ | ||
| POSIX_ENSURE_EQ(s2n_conn_get_current_message_type(server_conn), SERVER_CHANGE_CIPHER_SPEC); | ||
| POSIX_GUARD(s2n_handshake_write_io(server_conn)); | ||
| if (expected_handshake_success) { | ||
| POSIX_ENSURE_EQ(hrr_expected, s2n_handshake_type_check_tls13_flag(server_conn, HELLO_RETRY_REQUEST)); | ||
| POSIX_ENSURE_EQ(s2n_conn_get_current_message_type(server_conn), SERVER_CHANGE_CIPHER_SPEC); | ||
| POSIX_GUARD(s2n_handshake_write_io(server_conn)); | ||
| } | ||
|
|
||
| if (hrr_expected) { | ||
| /* Client reads HRR */ | ||
|
|
@@ -219,11 +250,28 @@ int s2n_test_tls13_pq_handshake(const struct s2n_security_policy *client_sec_pol | |
|
|
||
| /* Client reads ServerHello */ | ||
| POSIX_ENSURE_EQ(s2n_conn_get_current_message_type(client_conn), SERVER_HELLO); | ||
| POSIX_GUARD(s2n_handshake_read_io(client_conn)); | ||
| POSIX_ENSURE_EQ((expected_handshake_success ? S2N_SUCCESS : S2N_FAILURE), s2n_handshake_read_io(client_conn)); | ||
|
|
||
| /* We've gotten far enough in the handshake that both client and server should have | ||
| * derived the shared secrets, so we don't send/receive any more messages. */ | ||
|
|
||
| if (!expected_handshake_success) { | ||
| POSIX_ENSURE_EQ(NULL, client_conn->kex_params.server_kem_group_params.kem_group); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not entirely following what these asserts actually mean beyond the |
||
| POSIX_ENSURE_EQ(NULL, client_conn->kex_params.server_kem_group_params.kem_params.kem); | ||
| POSIX_ENSURE_EQ(NULL, client_conn->kex_params.server_kem_group_params.ecc_params.negotiated_curve); | ||
| POSIX_ENSURE_EQ(NULL, client_conn->kex_params.server_ecc_evp_params.negotiated_curve); | ||
|
|
||
| POSIX_ENSURE_EQ(NULL, server_conn->kex_params.server_kem_group_params.kem_group); | ||
| POSIX_ENSURE_EQ(NULL, server_conn->kex_params.server_kem_group_params.kem_params.kem); | ||
| POSIX_ENSURE_EQ(NULL, server_conn->kex_params.server_kem_group_params.ecc_params.negotiated_curve); | ||
| POSIX_ENSURE_EQ(NULL, server_conn->kex_params.server_ecc_evp_params.negotiated_curve); | ||
|
|
||
| POSIX_GUARD(s2n_test_tls13_pq_handshake_cleanup(&client_to_server, &server_to_client, client_conn, server_conn, | ||
| chain_and_key, client_config, server_config)); | ||
|
|
||
| return S2N_SUCCESS; | ||
| } | ||
|
|
||
| /* Assert that the correct group was negotiated (we re-check the server group to assert that | ||
| * nothing unexpected changed between then and now while e.g. processing HRR) */ | ||
| if (expected_kem_group) { | ||
|
|
@@ -314,15 +362,8 @@ int s2n_test_tls13_pq_handshake(const struct s2n_security_policy *client_sec_pol | |
| POSIX_ENSURE_EQ(0, memcmp(server_secrets->server_handshake_secret, client_secrets->server_handshake_secret, size)); | ||
|
|
||
| /* Clean up */ | ||
| POSIX_GUARD(s2n_stuffer_free(&client_to_server)); | ||
| POSIX_GUARD(s2n_stuffer_free(&server_to_client)); | ||
|
|
||
| POSIX_GUARD(s2n_connection_free(client_conn)); | ||
| POSIX_GUARD(s2n_connection_free(server_conn)); | ||
|
|
||
| POSIX_GUARD(s2n_cert_chain_and_key_free(chain_and_key)); | ||
| POSIX_GUARD(s2n_config_free(server_config)); | ||
| POSIX_GUARD(s2n_config_free(client_config)); | ||
| POSIX_GUARD(s2n_test_tls13_pq_handshake_cleanup(&client_to_server, &server_to_client, client_conn, server_conn, | ||
| chain_and_key, client_config, server_config)); | ||
|
|
||
| return S2N_SUCCESS; | ||
| } | ||
|
|
@@ -472,6 +513,8 @@ int main() | |
| /* Self talk test with each TLS 1.3 KemGroup we support */ | ||
| for (size_t i = 0; i < S2N_KEM_GROUPS_COUNT; i++) { | ||
| const struct s2n_kem_group *kem_group = ALL_SUPPORTED_KEM_GROUPS[i]; | ||
| bool expected_handshake_success = true; | ||
| int expected_err_code = S2N_SUCCESS; | ||
|
|
||
| if (kem_group == NULL || !s2n_kem_group_is_available(kem_group)) { | ||
| continue; | ||
|
|
@@ -502,7 +545,7 @@ int main() | |
| .len_prefix_expected = false, | ||
| }; | ||
|
|
||
| EXPECT_SUCCESS(s2n_test_tls13_pq_handshake(test_vec.client_policy, test_vec.server_policy, | ||
| EXPECT_SUCCESS(s2n_test_tls13_pq_handshake(test_vec.client_policy, test_vec.server_policy, expected_handshake_success, expected_err_code, | ||
| test_vec.expected_kem_group, test_vec.expected_curve, test_vec.hrr_expected, test_vec.len_prefix_expected)); | ||
| } | ||
|
|
||
|
|
@@ -519,6 +562,16 @@ int main() | |
| * If PQ is disabled, the expected negotiation outcome is overridden below | ||
| * before performing the handshake test. */ | ||
| const struct pq_handshake_test_vector test_vectors[] = { | ||
| #if defined(S2N_LIBCRYPTO_SUPPORTS_MLKEM) | ||
| { | ||
| .client_policy = &security_policy_aws_crt_sdk_tls_13_06_25_pq_kx_required, | ||
| .server_policy = &security_policy_aws_crt_sdk_tls_13_06_25_pq_kx_required, | ||
| .expected_kem_group = &s2n_x25519_mlkem_768, | ||
| .expected_curve = NULL, | ||
| .hrr_expected = false, | ||
| .len_prefix_expected = false, | ||
| }, | ||
| #endif | ||
| { | ||
| .client_policy = &security_policy_pq_tls_1_3_2023_06_01, | ||
| .server_policy = &security_policy_pq_tls_1_0_2021_05_24, | ||
|
|
@@ -744,13 +797,14 @@ int main() | |
| const struct pq_handshake_test_vector *vector = &test_vectors[i]; | ||
| const struct s2n_security_policy *client_policy = vector->client_policy; | ||
| const struct s2n_security_policy *server_policy = vector->server_policy; | ||
| bool expected_handshake_success = true; | ||
| int expected_err_code = S2N_SUCCESS; | ||
| const struct s2n_kem_group *kem_group = vector->expected_kem_group; | ||
| const struct s2n_ecc_named_curve *curve = vector->expected_curve; | ||
| bool hrr_expected = vector->hrr_expected; | ||
| bool len_prefix_expected = vector->len_prefix_expected; | ||
|
|
||
| if (!s2n_pq_is_enabled()) { | ||
| EXPECT_TRUE(client_policy->ecc_preferences->count > 0); | ||
| if (!s2n_pq_is_enabled() && (client_policy->ecc_preferences->count > 0)) { | ||
| const struct s2n_ecc_named_curve *client_default = client_policy->ecc_preferences->ecc_curves[0]; | ||
| const struct s2n_ecc_named_curve *predicted_curve = s2n_get_predicted_negotiated_ecdhe_curve(client_policy, server_policy); | ||
|
|
||
|
|
@@ -787,7 +841,50 @@ int main() | |
| POSIX_ENSURE_EQ(kem_group->iana_id, predicted_kem_group->iana_id); | ||
| } | ||
|
|
||
| EXPECT_SUCCESS(s2n_test_tls13_pq_handshake(client_policy, server_policy, kem_group, curve, hrr_expected, len_prefix_expected)); | ||
| EXPECT_SUCCESS(s2n_test_tls13_pq_handshake(client_policy, server_policy, expected_handshake_success, expected_err_code, kem_group, curve, hrr_expected, len_prefix_expected)); | ||
| } | ||
|
|
||
| const struct pq_handshake_test_vector expected_failures[] = { | ||
| #if !defined(S2N_LIBCRYPTO_SUPPORTS_MLKEM) | ||
| { | ||
| .client_policy = &security_policy_aws_crt_sdk_tls_13_06_25_pq_kx_required, | ||
| .server_policy = &security_policy_aws_crt_sdk_tls_13_06_25_pq_kx_required, | ||
| .expected_kem_group = NULL, | ||
| .expected_curve = NULL, | ||
| .hrr_expected = false, | ||
| .len_prefix_expected = false, | ||
| }, | ||
| #endif | ||
| { | ||
| .client_policy = &security_policy_aws_crt_sdk_tls_13_06_25_pq_kx_required, | ||
| .server_policy = &security_policy_aws_crt_sdk_tls_12_06_23, | ||
| .expected_kem_group = NULL, | ||
| .expected_curve = NULL, | ||
| .hrr_expected = false, | ||
| .len_prefix_expected = false, | ||
| }, | ||
| { | ||
| .client_policy = &security_policy_aws_crt_sdk_tls_12_06_23, | ||
| .server_policy = &security_policy_aws_crt_sdk_tls_13_06_25_pq_kx_required, | ||
| .expected_kem_group = NULL, | ||
| .expected_curve = NULL, | ||
| .hrr_expected = false, | ||
| .len_prefix_expected = false, | ||
| }, | ||
| }; | ||
|
|
||
| for (size_t i = 0; i < s2n_array_len(expected_failures); i++) { | ||
| const struct pq_handshake_test_vector *vector = &expected_failures[i]; | ||
| const struct s2n_security_policy *client_policy = vector->client_policy; | ||
| const struct s2n_security_policy *server_policy = vector->server_policy; | ||
| bool expected_handshake_success = false; | ||
| int expected_err_code = S2N_ERR_ECDHE_UNSUPPORTED_CURVE; | ||
| const struct s2n_kem_group *kem_group = vector->expected_kem_group; | ||
| const struct s2n_ecc_named_curve *curve = vector->expected_curve; | ||
| bool hrr_expected = vector->hrr_expected; | ||
| bool len_prefix_expected = vector->len_prefix_expected; | ||
|
|
||
| EXPECT_SUCCESS(s2n_test_tls13_pq_handshake(client_policy, server_policy, expected_handshake_success, expected_err_code, kem_group, curve, hrr_expected, len_prefix_expected)); | ||
| } | ||
|
|
||
| END_TEST(); | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.