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 <tjh@openssl.org>
Reviewed-by: Saša Nedvědický <sashan@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/26801)
This commit is contained in:
Viktor Dukhovni 2025-02-18 02:41:51 +11:00 committed by Tomas Mraz
parent 96075a6a40
commit 63a70d63e2
7 changed files with 66 additions and 111 deletions

View File

@ -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);

View File

@ -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.)

View File

@ -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}
};

View File

@ -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

View File

@ -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: {

View File

@ -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);

View File

@ -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));