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

Add new MLKEM TLS Policies #4830

Merged
merged 3 commits into from
Oct 17, 2024
Merged
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
186 changes: 186 additions & 0 deletions tests/unit/s2n_pq_mlkem_policies_test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
/*
* 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_pq.h"
#include "s2n_test.h"
#include "testlib/s2n_testlib.h"
#include "tls/s2n_kem.h"
#include "tls/s2n_security_policies.h"
#include "tls/s2n_tls.h"

static S2N_RESULT s2n_policy_has_cipher(const struct s2n_security_policy *security_policy, const struct s2n_cipher_suite *needle, bool *val)
{
RESULT_ENSURE_REF(security_policy);
RESULT_ENSURE_REF(security_policy->cipher_preferences);
RESULT_ENSURE_REF(security_policy->cipher_preferences->suites);

for (size_t i = 0; i < security_policy->cipher_preferences->count; i++) {
const struct s2n_cipher_suite *hay = security_policy->cipher_preferences->suites[i];
if (hay == needle) {
*val = true;
return S2N_RESULT_OK;
}
}

*val = false;
return S2N_RESULT_OK;
}

static S2N_RESULT s2n_policy_has_kem(const struct s2n_security_policy *security_policy, const struct s2n_kem **kem_list, size_t kem_list_count, bool *val)
{
RESULT_ENSURE_REF(security_policy);
RESULT_ENSURE_REF(security_policy->kem_preferences);

if (security_policy->kem_preferences->tls13_kem_groups == NULL || security_policy->kem_preferences->tls13_kem_group_count == 0) {
*val = false;
return S2N_RESULT_OK;
}

for (size_t i = 0; i < security_policy->kem_preferences->tls13_kem_group_count; i++) {
const struct s2n_kem_group *supported_kem_group = security_policy->kem_preferences->tls13_kem_groups[i];
RESULT_ENSURE_REF(supported_kem_group);
for (int j = 0; j < kem_list_count; j++) {
const struct s2n_kem *banned_kem = kem_list[j];
RESULT_ENSURE_REF(banned_kem);
if (supported_kem_group->kem == banned_kem) {
*val = true;
return S2N_RESULT_OK;
}
}
}

*val = false;
return S2N_RESULT_OK;
}

static S2N_RESULT s2n_policy_in_list(const char *policy_name, const char **exception_list, size_t list_count, bool *val)
{
RESULT_ENSURE_REF(policy_name);

for (size_t i = 0; i < list_count; i++) {
const char *exception = exception_list[i];
RESULT_ENSURE_REF(exception);

if (strlen(policy_name) != strlen(exception)) {
continue;
}

if (memcmp(policy_name, exception, strlen(policy_name)) == 0) {
*val = true;
return S2N_RESULT_OK;
}
}

*val = false;
return S2N_RESULT_OK;
}

/* List of all ML-KEM Parameter sizes */
const struct s2n_kem *mlkem_list[] = {
&s2n_mlkem_768
};

/* Ciphers that should not be present in TLS Policies that have ML-KEM */
const struct s2n_cipher_suite *legacy_cipher_suites[] = {
&s2n_ecdhe_kyber_rsa_with_aes_256_gcm_sha384, /* Draft cipher for negotiating Kyber in TLS 1.2. */
&s2n_rsa_with_3des_ede_cbc_sha,
&s2n_dhe_rsa_with_3des_ede_cbc_sha,
&s2n_ecdhe_rsa_with_3des_ede_cbc_sha,
&s2n_ecdhe_rsa_with_rc4_128_sha,
&s2n_rsa_with_rc4_128_sha,
&s2n_rsa_with_rc4_128_md5,
&s2n_null_cipher_suite,
};

/* List of s2n TLS Security Policies that are allowed to have legacy TLS Ciphers and support ML-KEM */
const char *cipher_exceptions[] = {
"test_all",
};

/* List of s2n TLS Security Policies that are allowed to have a minimum TLS Version below TLS 1.2 and support ML-KEM */
const char *tls_version_exceptions[] = {
"test_all",
};

const size_t mlkem_list_size = s2n_array_len(mlkem_list);
const size_t cipher_exceptions_size = s2n_array_len(cipher_exceptions);
const size_t tls_version_exceptions_size = s2n_array_len(tls_version_exceptions);

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

/* Enforce minimum requirements on all security policies that support ML-KEM */
for (size_t policy_index = 0; security_policy_selection[policy_index].version != NULL; policy_index++) {
const struct s2n_security_policy_selection selection = security_policy_selection[policy_index];
const char *policy_name = selection.version;
const struct s2n_security_policy *security_policy = selection.security_policy;
POSIX_ENSURE_REF(security_policy);

bool has_mlkem = false;
EXPECT_OK(s2n_policy_has_kem(security_policy, mlkem_list, mlkem_list_size, &has_mlkem));

if (!has_mlkem) {
continue;
}

/* ML-KEM requires TLS 1.3 in order to be negotiated. Ensure that Policies with ML-KEM also support TLS 1.3 */
bool has_tls_13_cipher = false;
for (size_t i = 0; i < security_policy->cipher_preferences->count; i++) {
if (security_policy->cipher_preferences->suites[i]->minimum_required_tls_version == S2N_TLS13) {
has_tls_13_cipher = true;
break;
}
}
EXPECT_TRUE(has_tls_13_cipher);

/* Ensure all security policies that have ML-KEM support do not use previous draft wire-format
* for Hybrid KeyShares with length prefixing. */
const struct s2n_kem_preferences *kem_preferences = security_policy->kem_preferences;
POSIX_ENSURE_REF(kem_preferences);
EXPECT_FALSE(s2n_tls13_client_must_use_hybrid_kem_length_prefix(kem_preferences));

/* All security policies that have ML-KEM should have TLS 1.2 as their minimum supported TLS Version */
if (security_policy->minimum_protocol_version < S2N_TLS12) {
bool has_exception = false;
EXPECT_OK(s2n_policy_in_list(policy_name, tls_version_exceptions, tls_version_exceptions_size, &has_exception));

if (!has_exception) {
fprintf(stdout, "Security Policy: %s has ML-KEM and uses a legacy TLS Version: %d\n",
policy_name, security_policy->minimum_protocol_version);
FAIL_MSG("ML-KEM policies should not contain legacy TLS Versions.");
}
}

/* Policies that have ML-KEM should not have 3DES, RC4, or (abandoned/deprecated) draft TLS 1.2 Kyber support */
for (int j = 0; j < s2n_array_len(legacy_cipher_suites); j++) {
bool has_cipher = false;
EXPECT_OK(s2n_policy_has_cipher(security_policy, legacy_cipher_suites[j], &has_cipher));

if (has_cipher) {
bool has_exception = false;
EXPECT_OK(s2n_policy_in_list(policy_name, cipher_exceptions, cipher_exceptions_size, &has_exception));

if (!has_exception) {
fprintf(stdout, "Security Policy: %s has ML-KEM and legacy cipher: %s\n",
policy_name, legacy_cipher_suites[j]->name);
FAIL_MSG("ML-KEM policies should not contain legacy ciphers.");
}
}
}
}

END_TEST();
}
120 changes: 120 additions & 0 deletions tls/s2n_cipher_preferences.c
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,96 @@ const struct s2n_cipher_preferences cipher_preferences_20210825_gcm = {
.allow_chacha20_boosting = false,
};

/* Same as cipher_suites_20210825, but with 3DES removed */
struct s2n_cipher_suite *cipher_suites_20241008[] = {
S2N_TLS13_CLOUDFRONT_CIPHER_SUITES_20200716,
&s2n_ecdhe_ecdsa_with_aes_128_cbc_sha,
&s2n_ecdhe_rsa_with_aes_128_cbc_sha,
&s2n_ecdhe_ecdsa_with_aes_128_gcm_sha256,
&s2n_ecdhe_rsa_with_aes_128_gcm_sha256,
&s2n_ecdhe_ecdsa_with_aes_256_gcm_sha384,
&s2n_ecdhe_rsa_with_aes_256_gcm_sha384,
&s2n_ecdhe_ecdsa_with_aes_128_cbc_sha256,
&s2n_ecdhe_rsa_with_aes_128_cbc_sha256,
&s2n_ecdhe_ecdsa_with_aes_256_cbc_sha,
&s2n_ecdhe_rsa_with_aes_256_cbc_sha,
&s2n_ecdhe_ecdsa_with_aes_256_cbc_sha384,
&s2n_ecdhe_rsa_with_aes_256_cbc_sha384,
&s2n_rsa_with_aes_128_cbc_sha,
&s2n_rsa_with_aes_128_gcm_sha256,
&s2n_rsa_with_aes_256_gcm_sha384,
&s2n_rsa_with_aes_128_cbc_sha256,
&s2n_rsa_with_aes_256_cbc_sha,
&s2n_rsa_with_aes_256_cbc_sha256,
&s2n_dhe_rsa_with_aes_128_cbc_sha,
&s2n_dhe_rsa_with_aes_128_gcm_sha256,
&s2n_dhe_rsa_with_aes_256_gcm_sha384,
&s2n_dhe_rsa_with_aes_128_cbc_sha256,
&s2n_dhe_rsa_with_aes_256_cbc_sha,
&s2n_dhe_rsa_with_aes_256_cbc_sha256,
};

const struct s2n_cipher_preferences cipher_preferences_20241008 = {
.count = s2n_array_len(cipher_suites_20241008),
.suites = cipher_suites_20241008,
.allow_chacha20_boosting = false,
};

/* Same as cipher_suites_20210825_gcm and cipher_suites_pq_tls_1_0_2021_05_26, but with 3DES and Kyber (for TLS 1.2) removed */
struct s2n_cipher_suite *cipher_suites_20241008_gcm[] = {
S2N_TLS13_CLOUDFRONT_CIPHER_SUITES_20200716,
&s2n_ecdhe_ecdsa_with_aes_128_gcm_sha256,
&s2n_ecdhe_rsa_with_aes_128_gcm_sha256,
&s2n_ecdhe_ecdsa_with_aes_256_gcm_sha384,
&s2n_ecdhe_rsa_with_aes_256_gcm_sha384,
&s2n_ecdhe_ecdsa_with_aes_128_cbc_sha,
&s2n_ecdhe_rsa_with_aes_128_cbc_sha,
&s2n_ecdhe_ecdsa_with_aes_128_cbc_sha256,
&s2n_ecdhe_rsa_with_aes_128_cbc_sha256,
&s2n_ecdhe_ecdsa_with_aes_256_cbc_sha,
&s2n_ecdhe_rsa_with_aes_256_cbc_sha,
&s2n_ecdhe_ecdsa_with_aes_256_cbc_sha384,
&s2n_ecdhe_rsa_with_aes_256_cbc_sha384,
&s2n_rsa_with_aes_128_gcm_sha256,
&s2n_rsa_with_aes_256_gcm_sha384,
&s2n_rsa_with_aes_128_cbc_sha,
&s2n_rsa_with_aes_128_cbc_sha256,
&s2n_rsa_with_aes_256_cbc_sha,
&s2n_rsa_with_aes_256_cbc_sha256,
&s2n_dhe_rsa_with_aes_128_gcm_sha256,
&s2n_dhe_rsa_with_aes_256_gcm_sha384,
&s2n_dhe_rsa_with_aes_128_cbc_sha,
&s2n_dhe_rsa_with_aes_128_cbc_sha256,
&s2n_dhe_rsa_with_aes_256_cbc_sha,
&s2n_dhe_rsa_with_aes_256_cbc_sha256,
};

const struct s2n_cipher_preferences cipher_preferences_20241008_gcm = {
.count = s2n_array_len(cipher_suites_20241008_gcm),
.suites = cipher_suites_20241008_gcm,
.allow_chacha20_boosting = false,
};

/* Same as cipher_preferences_pq_tls_1_0_2021_05_24, but with 3DES and Kyber (for TLS 1.2) removed */
struct s2n_cipher_suite *cipher_suites_20241009[] = {
S2N_TLS13_CIPHER_SUITES_20190801,
&s2n_ecdhe_rsa_with_aes_256_gcm_sha384,
&s2n_ecdhe_rsa_with_aes_128_gcm_sha256,
&s2n_ecdhe_rsa_with_aes_256_cbc_sha384,
&s2n_ecdhe_rsa_with_aes_256_cbc_sha,
&s2n_ecdhe_rsa_with_aes_128_cbc_sha256,
&s2n_dhe_rsa_with_aes_256_cbc_sha256,
&s2n_dhe_rsa_with_aes_128_cbc_sha256,
&s2n_dhe_rsa_with_aes_256_cbc_sha,
&s2n_dhe_rsa_with_aes_128_cbc_sha,
};

const struct s2n_cipher_preferences cipher_preferences_20241009 = {
.count = s2n_array_len(cipher_suites_20241009),
.suites = cipher_suites_20241009,
.allow_chacha20_boosting = false,
};

struct s2n_cipher_suite *cipher_suites_null[] = {
&s2n_null_cipher_suite
};
Expand Down Expand Up @@ -906,6 +996,36 @@ const struct s2n_cipher_preferences elb_security_policy_fs_1_2_Res_2019_08 = {
.allow_chacha20_boosting = false,
};

/*
* S2N_TLS13_CLOUDFRONT_CIPHER_SUITES_20200716 on top of cipher_suites_elb_security_policy_tls_1_2_ext_2018_06
*/
struct s2n_cipher_suite *cipher_suites_elb_security_policy_tls13_1_2_Ext2_2021_06[] = {
S2N_TLS13_CLOUDFRONT_CIPHER_SUITES_20200716,
&s2n_ecdhe_ecdsa_with_aes_128_gcm_sha256,
&s2n_ecdhe_rsa_with_aes_128_gcm_sha256,
&s2n_ecdhe_ecdsa_with_aes_128_cbc_sha256,
&s2n_ecdhe_rsa_with_aes_128_cbc_sha256,
&s2n_ecdhe_ecdsa_with_aes_128_cbc_sha,
&s2n_ecdhe_rsa_with_aes_128_cbc_sha,
&s2n_ecdhe_ecdsa_with_aes_256_gcm_sha384,
&s2n_ecdhe_rsa_with_aes_256_gcm_sha384,
&s2n_ecdhe_ecdsa_with_aes_256_cbc_sha384,
&s2n_ecdhe_rsa_with_aes_256_cbc_sha384,
&s2n_ecdhe_rsa_with_aes_256_cbc_sha,
&s2n_ecdhe_ecdsa_with_aes_256_cbc_sha,
&s2n_rsa_with_aes_128_gcm_sha256,
&s2n_rsa_with_aes_128_cbc_sha256,
&s2n_rsa_with_aes_128_cbc_sha,
&s2n_rsa_with_aes_256_gcm_sha384,
&s2n_rsa_with_aes_256_cbc_sha256,
&s2n_rsa_with_aes_256_cbc_sha,
};

const struct s2n_cipher_preferences elb_security_policy_tls13_1_2_Ext2_2021_06 = {
.count = s2n_array_len(cipher_suites_elb_security_policy_tls13_1_2_Ext2_2021_06),
.suites = cipher_suites_elb_security_policy_tls13_1_2_Ext2_2021_06,
};

struct s2n_cipher_suite *cipher_suites_cloudfront_upstream[] = {
&s2n_ecdhe_ecdsa_with_aes_256_gcm_sha384,
&s2n_ecdhe_rsa_with_aes_256_gcm_sha384,
Expand Down
4 changes: 4 additions & 0 deletions tls/s2n_cipher_preferences.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ extern const struct s2n_cipher_preferences cipher_preferences_20210831;
extern const struct s2n_cipher_preferences cipher_preferences_20231213;
extern const struct s2n_cipher_preferences cipher_preferences_20231214;
extern const struct s2n_cipher_preferences cipher_preferences_20240603;
extern const struct s2n_cipher_preferences cipher_preferences_20241008;
extern const struct s2n_cipher_preferences cipher_preferences_20241008_gcm;
extern const struct s2n_cipher_preferences cipher_preferences_20241009;

extern const struct s2n_cipher_preferences cipher_preferences_default_fips;

Expand All @@ -83,6 +86,7 @@ extern const struct s2n_cipher_preferences elb_security_policy_fs_2018_06;
extern const struct s2n_cipher_preferences elb_security_policy_fs_1_2_2019_08;
extern const struct s2n_cipher_preferences elb_security_policy_fs_1_1_2019_08;
extern const struct s2n_cipher_preferences elb_security_policy_fs_1_2_Res_2019_08;
extern const struct s2n_cipher_preferences elb_security_policy_tls13_1_2_Ext2_2021_06;

/* CloudFront upstream */
extern const struct s2n_cipher_preferences cipher_preferences_cloudfront_upstream;
Expand Down
34 changes: 34 additions & 0 deletions tls/s2n_kem_preferences.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,24 @@ const struct s2n_kem_group *pq_kem_groups_r3_2023_12[] = {
&s2n_secp256r1_kyber_512_r3,
};

/* Includes only IETF standard KEM Groups. */
const struct s2n_kem_group *pq_kem_groups_ietf_2024_10[] = {
&s2n_x25519_mlkem_768,
&s2n_secp256r1_mlkem_768,
};

/* Includes both IETF standard KEM Groups, and earlier draft standards with Kyber. */
const struct s2n_kem_group *pq_kem_groups_mixed_2024_10[] = {
&s2n_x25519_mlkem_768,
&s2n_secp256r1_mlkem_768,
&s2n_secp256r1_kyber_768_r3,
&s2n_x25519_kyber_768_r3,
&s2n_secp384r1_kyber_768_r3,
&s2n_secp521r1_kyber_1024_r3,
&s2n_secp256r1_kyber_512_r3,
&s2n_x25519_kyber_512_r3,
};

const struct s2n_kem_preferences kem_preferences_pq_tls_1_0_2021_05 = {
.kem_count = s2n_array_len(pq_kems_r3_2021_05),
.kems = pq_kems_r3_2021_05,
Expand Down Expand Up @@ -77,6 +95,22 @@ const struct s2n_kem_preferences kem_preferences_pq_tls_1_3_2023_12 = {
.tls13_pq_hybrid_draft_revision = 5
};

const struct s2n_kem_preferences kem_preferences_pq_tls_1_3_ietf_2024_10 = {
.kem_count = 0,
.kems = NULL,
.tls13_kem_group_count = s2n_array_len(pq_kem_groups_ietf_2024_10),
.tls13_kem_groups = pq_kem_groups_ietf_2024_10,
.tls13_pq_hybrid_draft_revision = 5
};

const struct s2n_kem_preferences kem_preferences_pq_tls_1_3_mixed_2024_10 = {
.kem_count = 0,
.kems = NULL,
.tls13_kem_group_count = s2n_array_len(pq_kem_groups_mixed_2024_10),
.tls13_kem_groups = pq_kem_groups_mixed_2024_10,
.tls13_pq_hybrid_draft_revision = 5
};

const struct s2n_kem_preferences kem_preferences_all = {
.kem_count = s2n_array_len(pq_kems_r3_2021_05),
.kems = pq_kems_r3_2021_05,
Expand Down
2 changes: 2 additions & 0 deletions tls/s2n_kem_preferences.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ extern const struct s2n_kem_preferences kem_preferences_pq_tls_1_0_2021_05;
extern const struct s2n_kem_preferences kem_preferences_pq_tls_1_0_2023_01;
extern const struct s2n_kem_preferences kem_preferences_pq_tls_1_3_2023_06;
extern const struct s2n_kem_preferences kem_preferences_pq_tls_1_3_2023_12;
extern const struct s2n_kem_preferences kem_preferences_pq_tls_1_3_ietf_2024_10;
extern const struct s2n_kem_preferences kem_preferences_pq_tls_1_3_mixed_2024_10;
extern const struct s2n_kem_preferences kem_preferences_all;
extern const struct s2n_kem_preferences kem_preferences_null;

Expand Down
Loading
Loading