From: Viktor Dukhovni Date: Mon, 17 Feb 2025 15:41:51 +0000 (+1100) Subject: Add hybrid ML-KEM based groups to default TLS groups X-Git-Tag: openssl-3.5.0-alpha1~84 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=63a70d63e273cb419eb875ea30c2ac1864737c28;p=thirdparty%2Fopenssl.git Add hybrid ML-KEM based groups to default TLS groups - send two key shares by default - trim down the list of default groups The default TLS group list setting is now: ?*X25519MLKEM768 / ?*X25519:?secp256r1 / ?X448:?secp384r1:?secp521r1 / ?ffdhe2048:?ffdhe3072 Reviewed-by: Tim Hudson Reviewed-by: Saša Nedvědický Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/26801) --- diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 74246c71b3d..3f5abaa48c4 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -4383,7 +4383,6 @@ void SSL_CTX_free(SSL_CTX *a) OPENSSL_free(a->ext.supportedgroups); OPENSSL_free(a->ext.keyshares); OPENSSL_free(a->ext.tuples); - OPENSSL_free(a->ext.supported_groups_default); OPENSSL_free(a->ext.alpn); OPENSSL_secure_free(a->ext.secure); diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h index fad69d8d468..3cebc1c5069 100644 --- a/ssl/ssl_local.h +++ b/ssl/ssl_local.h @@ -1037,8 +1037,6 @@ struct ssl_ctx_st { size_t tuples_len; /* Number of group tuples */ size_t *tuples; /* Number of groups in each group tuple */ - uint16_t *supported_groups_default; - size_t supported_groups_default_len; /* * ALPN information (we are in the process of transitioning from NPN to * ALPN.) diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index 83047349a52..04c0c99160e 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c @@ -198,30 +198,12 @@ static const unsigned char ecformats_default[] = { TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2 }; -/* The default curves */ -static const uint16_t supported_groups_default[] = { - OSSL_TLS_GROUP_ID_x25519, /* X25519 (29) */ - OSSL_TLS_GROUP_ID_secp256r1, /* secp256r1 (23) */ - OSSL_TLS_GROUP_ID_x448, /* X448 (30) */ - OSSL_TLS_GROUP_ID_secp521r1, /* secp521r1 (25) */ - OSSL_TLS_GROUP_ID_secp384r1, /* secp384r1 (24) */ - OSSL_TLS_GROUP_ID_gc256A, /* GC256A (34) */ - OSSL_TLS_GROUP_ID_gc256B, /* GC256B (35) */ - OSSL_TLS_GROUP_ID_gc256C, /* GC256C (36) */ - OSSL_TLS_GROUP_ID_gc256D, /* GC256D (37) */ - OSSL_TLS_GROUP_ID_gc512A, /* GC512A (38) */ - OSSL_TLS_GROUP_ID_gc512B, /* GC512B (39) */ - OSSL_TLS_GROUP_ID_gc512C, /* GC512C (40) */ - OSSL_TLS_GROUP_ID_ffdhe2048, /* ffdhe2048 (0x100) */ - OSSL_TLS_GROUP_ID_ffdhe3072, /* ffdhe3072 (0x101) */ - OSSL_TLS_GROUP_ID_ffdhe4096, /* ffdhe4096 (0x102) */ - OSSL_TLS_GROUP_ID_ffdhe6144, /* ffdhe6144 (0x103) */ - OSSL_TLS_GROUP_ID_ffdhe8192, /* ffdhe8192 (0x104) */ -}; - /* Group list string of the built-in pseudo group DEFAULT */ #define DEFAULT_GROUP_NAME "DEFAULT" -#define DEFAULT_GROUP_LIST "X25519:secp256r1:X448:secp521r1:secp384r1:GC256A:GC256B:GC256C:GC256D:GC512A:GC512B:GC512C:ffdhe2048:ffdhe3072:ffdhe4096:ffdhe6144:ffdhe8192", +#define TLS_DEFAULT_GROUP_LIST \ + "?*X25519MLKEM768 / ?*X25519:?secp256r1 / ?X448:?secp384r1:?secp521r1 / ?ffdhe2048:?ffdhe3072" +#define QUIC_DEFAULT_GROUP_LIST \ + "X25519:secp256r1:X448:secp521r1:secp384r1:ffdhe2048:ffdhe3072:ffdhe4096:ffdhe6144:ffdhe8192" static const uint16_t suiteb_curves[] = { OSSL_TLS_GROUP_ID_secp256r1, @@ -380,55 +362,12 @@ static int discover_provider_groups(OSSL_PROVIDER *provider, void *vctx) int ssl_load_groups(SSL_CTX *ctx) { - size_t i, j, num_deflt_grps = 0; - uint16_t tmp_supp_groups[OSSL_NELEM(supported_groups_default)]; - if (!OSSL_PROVIDER_do_all(ctx->libctx, discover_provider_groups, ctx)) return 0; - for (i = 0; i < OSSL_NELEM(supported_groups_default); i++) { - for (j = 0; j < ctx->group_list_len; j++) { - if (ctx->group_list[j].group_id == supported_groups_default[i]) { - tmp_supp_groups[num_deflt_grps++] = ctx->group_list[j].group_id; - break; - } - } - } - - if (num_deflt_grps == 0) - return 1; - - ctx->ext.supported_groups_default - = OPENSSL_malloc(sizeof(uint16_t) * num_deflt_grps); - - if (ctx->ext.supported_groups_default == NULL) - return 0; - - memcpy(ctx->ext.supported_groups_default, - tmp_supp_groups, - num_deflt_grps * sizeof(tmp_supp_groups[0])); - ctx->ext.supported_groups_default_len = num_deflt_grps; - - /* - * Default groups have no explicit key share nor a tuple, - * hence we'll generate a key share for the first group and - * define one big tuple consisting of all default groups - */ - if (ctx->ext.keyshares == NULL) - ctx->ext.keyshares = OPENSSL_malloc(sizeof(*ctx->ext.keyshares)); - if (ctx->ext.keyshares == NULL) - return 0; - ctx->ext.keyshares_len = 1; - ctx->ext.keyshares[0] = 0; - - if (ctx->ext.tuples == NULL) - ctx->ext.tuples = OPENSSL_malloc(sizeof(*ctx->ext.tuples)); - if (ctx->ext.tuples == NULL) - return 0; - ctx->ext.tuples_len = 1; - ctx->ext.tuples[0] = ctx->ext.supported_groups_default_len; - - return 1; + if (!IS_QUIC_CTX(ctx)) + return SSL_CTX_set1_groups_list(ctx, TLS_DEFAULT_GROUP_LIST); + return SSL_CTX_set1_groups_list(ctx, QUIC_DEFAULT_GROUP_LIST); } #define TLS_SIGALG_LIST_MALLOC_BLOCK_SIZE 10 @@ -846,8 +785,8 @@ void tls1_get_supported_groups(SSL_CONNECTION *s, const uint16_t **pgroups, default: if (s->ext.supportedgroups == NULL) { - *pgroups = sctx->ext.supported_groups_default; - *pgroupslen = sctx->ext.supported_groups_default_len; + *pgroups = sctx->ext.supportedgroups; + *pgroupslen = sctx->ext.supportedgroups_len; } else { *pgroups = s->ext.supportedgroups; *pgroupslen = s->ext.supportedgroups_len; @@ -875,8 +814,8 @@ void tls1_get_requested_keyshare_groups(SSL_CONNECTION *s, const uint16_t **pgro SSL_CTX *sctx = SSL_CONNECTION_GET_CTX(s); if (s->ext.supportedgroups == NULL) { - *pgroups = sctx->ext.supported_groups_default; - *pgroupslen = sctx->ext.supported_groups_default_len; + *pgroups = sctx->ext.supportedgroups; + *pgroupslen = sctx->ext.supportedgroups_len; } else { *pgroups = s->ext.keyshares; *pgroupslen = s->ext.keyshares_len; @@ -1192,7 +1131,7 @@ static const char *DEFAULT_GROUPNAME_FIRST_CHARACTER = "D"; /* The list of all built-in pseudo-group-name structures */ static const default_group_string_st default_group_strings[] = { - {DEFAULT_GROUP_NAME, DEFAULT_GROUP_LIST}, + {DEFAULT_GROUP_NAME, TLS_DEFAULT_GROUP_LIST}, {SUITE_B_GROUP_NAME, SUITE_B_GROUP_LIST} }; diff --git a/test/clienthellotest.c b/test/clienthellotest.c index b4f2c20bdb9..c922586415a 100644 --- a/test/clienthellotest.c +++ b/test/clienthellotest.c @@ -98,6 +98,10 @@ static int test_client_hello(int currtest) SSL_CTX_set_options(ctx, SSL_OP_TLSEXT_PADDING); /* Make sure we get a consistent size across TLS versions */ SSL_CTX_clear_options(ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); + /* Avoid large keyshares */ + if (!TEST_true(SSL_CTX_set1_groups_list(ctx, + "?X25519:?secp256r1:?ffdhe2048:?ffdhe3072"))) + goto end; /* * Add some dummy ALPN protocols so that the ClientHello is at least * F5_WORKAROUND_MIN_MSG_LEN bytes long - meaning padding will be diff --git a/test/recipes/70-test_tls13cookie.t b/test/recipes/70-test_tls13cookie.t index 4be31c52e7f..bcc29b88f32 100644 --- a/test/recipes/70-test_tls13cookie.t +++ b/test/recipes/70-test_tls13cookie.t @@ -44,7 +44,8 @@ my $testtype; #Test 1: Inserting a cookie into an HRR should see it echoed in the ClientHello $testtype = COOKIE_ONLY; $proxy->filter(\&cookie_filter); -$proxy->serverflags("-curves X25519") if !disabled("ecx"); +$proxy->serverflags("-curves X25519"); +$proxy->clientflags("-curves X25519:secp256r1"); $proxy->start() or plan skip_all => "Unable to start up Proxy for tests"; plan tests => 2; SKIP: { diff --git a/test/sslapitest.c b/test/sslapitest.c index 1d4fbab5817..8c1b2073b87 100644 --- a/test/sslapitest.c +++ b/test/sslapitest.c @@ -9873,44 +9873,38 @@ static int test_unknown_sigalgs_groups(void) return ret; } +#if (!defined(OPENSSL_NO_EC) || !defined(OPENSSL_NO_DH)) || !defined(OPENSSL_NO_ML_KEM) static int test_configuration_of_groups(void) { int ret = 0; SSL_CTX *ctx = NULL; -#if (!defined(OPENSSL_NO_EC) || !defined(OPENSSL_NO_DH)) - size_t default_groups_len; -#endif + size_t groups_len; if (!TEST_ptr(ctx = SSL_CTX_new_ex(libctx, NULL, TLS_server_method()))) goto end; + groups_len = ctx->ext.supportedgroups_len; -#if (!defined(OPENSSL_NO_EC) || !defined(OPENSSL_NO_DH)) - default_groups_len = ctx->ext.supported_groups_default_len; - - if (!TEST_size_t_gt(default_groups_len, 0) + if (!TEST_size_t_gt(groups_len, 0) || !TEST_int_gt(SSL_CTX_set1_groups_list(ctx, "DEFAULT"), 0) - || !TEST_size_t_eq(ctx->ext.supportedgroups_len, default_groups_len)) + || !TEST_size_t_eq(ctx->ext.supportedgroups_len, groups_len)) goto end; -#endif -#if (!defined(OPENSSL_NO_EC) || !defined(OPENSSL_NO_DH)) if (!TEST_int_gt(SSL_CTX_set1_groups_list(ctx, "DEFAULT:-?P-256"), 0) # if !defined(OPENSSL_NO_EC) - || !TEST_size_t_eq(ctx->ext.supportedgroups_len, default_groups_len - 1) + || !TEST_size_t_eq(ctx->ext.supportedgroups_len, groups_len - 1) # else - || !TEST_size_t_eq(ctx->ext.supportedgroups_len, default_groups_len) + || !TEST_size_t_eq(ctx->ext.supportedgroups_len, groups_len) # endif ) goto end; -#endif -#if !defined(OPENSSL_NO_EC) +# if !defined(OPENSSL_NO_EC) if (!TEST_int_gt(SSL_CTX_set1_groups_list(ctx, "?P-256:?P-521:-?P-256"), 0) || !TEST_size_t_eq(ctx->ext.supportedgroups_len, 1) || !TEST_int_eq(ctx->ext.supportedgroups[0], OSSL_TLS_GROUP_ID_secp521r1) ) goto end; -#endif +# endif ret = 1; @@ -9918,6 +9912,7 @@ end: SSL_CTX_free(ctx); return ret; } +#endif #if !defined(OPENSSL_NO_EC) \ && (!defined(OSSL_NO_USABLE_TLS1_3) || !defined(OPENSSL_NO_TLS1_2)) @@ -9988,6 +9983,13 @@ static int test_sigalgs_available(int idx) if (!TEST_ptr(cctx) || !TEST_ptr(sctx)) goto end; + /* Avoid MLKEM groups that depend on possibly filtered-out digests */ + if (!TEST_true(SSL_CTX_set1_groups_list(cctx, + "?X25519:?secp256r1:?ffdhe2048:?ffdhe3072")) + || !TEST_true(SSL_CTX_set1_groups_list(sctx, + "?X25519:?secp256r1:?ffdhe2048:?ffdhe3072"))) + goto end; + if (idx != 5) { /* RSA first server key */ if (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(), @@ -13212,7 +13214,9 @@ int setup_tests(void) #endif ADD_ALL_TESTS(test_servername, 10); ADD_TEST(test_unknown_sigalgs_groups); +#if (!defined(OPENSSL_NO_EC) || !defined(OPENSSL_NO_DH)) || !defined(OPENSSL_NO_ML_KEM) ADD_TEST(test_configuration_of_groups); +#endif #if !defined(OPENSSL_NO_EC) \ && (!defined(OSSL_NO_USABLE_TLS1_3) || !defined(OPENSSL_NO_TLS1_2)) ADD_ALL_TESTS(test_sigalgs_available, 6); diff --git a/test/tls13groupselection_test.c b/test/tls13groupselection_test.c index e3a25dba134..fcebc1e43e6 100644 --- a/test/tls13groupselection_test.c +++ b/test/tls13groupselection_test.c @@ -81,7 +81,7 @@ static const struct tls13groupselection_test_st tls13groupselection_tests[] = { "secp521r1:secp384r1:X25519:prime256v1:X448", /* test 3 */ "X25519:secp384r1:prime256v1", SERVER_PREFERENCE, - "X25519", HRR + "x25519", HRR }, /* @@ -94,12 +94,12 @@ static const struct tls13groupselection_test_st tls13groupselection_tests[] = { "secp521r1:secp384r1:*X25519/*prime256v1:X448", /* test 4 */ "secp521r1:*prime256v1:X25519:X448", CLIENT_PREFERENCE, - "X25519", SH + "x25519", SH }, { "secp521r1:secp384r1:*X25519/*prime256v1:X448", /* test 5 */ "secp521r1:*prime256v1:X25519:X448", SERVER_PREFERENCE, - "prime256v1", SH + "secp256r1", SH }, /* @@ -126,24 +126,24 @@ static const struct tls13groupselection_test_st tls13groupselection_tests[] = { "*X25519:prime256v1:*X448", /* test 8 */ "secp521r1:secp384r1/X448:X25519", CLIENT_PREFERENCE, - "X25519", SH + "x25519", SH }, { "*X25519:prime256v1:*X448", /* test 9 */ "secp521r1:secp384r1/X448:X25519", SERVER_PREFERENCE, - "X448", SH + "x448", SH }, /* (F) Check that '?' will ignore unknown group but use known group */ { "*X25519:?unknown_group_123:prime256v1:*X448", /* test 10 */ "secp521r1:secp384r1/X448:?unknown_group_456:?X25519", CLIENT_PREFERENCE, - "X25519", SH + "x25519", SH }, { "*X25519:prime256v1:*X448:?*unknown_group_789", /* test 11 */ "secp521r1:secp384r1/?X448:?unknown_group_456:X25519", SERVER_PREFERENCE, - "X448", SH + "x448", SH }, /* @@ -152,12 +152,20 @@ static const struct tls13groupselection_test_st tls13groupselection_tests[] = { NULL, /* test 12 */ NULL, CLIENT_PREFERENCE, - "X25519", SH +#ifndef OPENSSL_NO_ML_KEM + "X25519MLKEM768", SH +#else + "x25519", SH +#endif }, { NULL, /* test 13 */ NULL, SERVER_PREFERENCE, - "X25519", SH +#ifndef OPENSSL_NO_ML_KEM + "X25519MLKEM768", SH +#else + "x25519", SH +#endif }, /* @@ -166,35 +174,35 @@ static const struct tls13groupselection_test_st tls13groupselection_tests[] = { "*X25519:*X448", /* test 14 */ "secp521r1:X25519:prime256v1:-X25519:secp384r1/X448", CLIENT_PREFERENCE, - "X448", SH + "x448", SH }, { "*X25519:*X448", /* test 15 */ "secp521r1:X25519:prime256v1:-X25519:secp384r1/X448", SERVER_PREFERENCE, - "X448", SH + "x448", SH }, { "*X25519:prime256v1:*X448", /* test 16 */ "X25519:prime256v1/X448:-X25519", CLIENT_PREFERENCE, - "prime256v1", HRR + "secp256r1", HRR }, { "*X25519:prime256v1:*X448", /* test 17 */ "X25519:prime256v1/X448:-X25519", SERVER_PREFERENCE, - "prime256v1", HRR + "secp256r1", HRR }, /* * (I) Check handling of the "DEFAULT" 'pseudo group name' */ { "*X25519:DEFAULT:-prime256v1:-X448", /* test 18 */ - "DEFAULT:-X25519", + "DEFAULT:-X25519:-?X25519MLKEM768", CLIENT_PREFERENCE, - "secp521r1", HRR + "secp384r1", HRR }, { "*X25519:DEFAULT:-prime256v1:-X448", /* test 19 */ - "DEFAULT:-X25519", + "DEFAULT:-X25519:-?X25519MLKEM768", SERVER_PREFERENCE, - "secp521r1", HRR + "secp384r1", HRR }, /* * (J) Deduplication check @@ -215,7 +223,7 @@ static const struct tls13groupselection_test_st tls13groupselection_tests[] = { "*X25519:*prime256v1:-X25519", /* test 22 */ "X25519:prime256v1", CLIENT_PREFERENCE, - "prime256v1", SH + "secp256r1", SH }, /* * (L) Syntax errors @@ -408,6 +416,7 @@ static int test_groupnegotiation(const struct tls13groupselection_test_st *curre int ok = 0; int negotiated_group_client = 0; int negotiated_group_server = 0; + const char *group_name_client; SSL_CTX *client_ctx = NULL, *server_ctx = NULL; SSL *clientssl = NULL, *serverssl = NULL; enum SERVER_RESPONSE server_response; @@ -471,11 +480,12 @@ static int test_groupnegotiation(const struct tls13groupselection_test_st *curre */ negotiated_group_client = SSL_get_negotiated_group(clientssl); negotiated_group_server = SSL_get_negotiated_group(serverssl); + group_name_client = SSL_group_to_name(clientssl, negotiated_group_client); if (!TEST_int_eq(negotiated_group_client, negotiated_group_server)) goto end; if (!TEST_int_eq((int)current_test_vector->expected_server_response, (int)server_response)) goto end; - if (TEST_int_eq(negotiated_group_client, OBJ_sn2nid(current_test_vector->expected_group))) + if (TEST_str_eq(group_name_client, current_test_vector->expected_group)) ok = 1; } else { TEST_false_or_end(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE));