]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Advertise FFDHE groups also with TLS 1.2-only
authorViktor Dukhovni <openssl-users@dukhovni.org>
Tue, 16 Dec 2025 16:48:06 +0000 (03:48 +1100)
committerAlexandr Nedvedicky <sashan@openssl.org>
Thu, 5 Feb 2026 09:09:18 +0000 (10:09 +0100)
When the TLS max version is TLS 1.2, include supported RFC7919 FFDHE
groups in the supported_groups extension, provided we support at least
one DHE key exchange ciphersuite.

Also skip the EC point formats extension when the minimum (D)TLS version
is greater than 1.2.  That extension is obsolete as of (D)TLS 1.3.

Finally, folded some extant long lines from the previous RFC7919 commits.

Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Saša Nedvědický <sashan@openssl.org>
MergeDate: Thu Feb  5 09:09:43 2026
(Merged from https://github.com/openssl/openssl/pull/24551)

15 files changed:
ssl/ssl_local.h
ssl/statem/extensions_clnt.c
ssl/statem/extensions_srvr.c
ssl/statem/statem_srvr.c
ssl/t1_lib.c
test/recipes/70-test_sslmessages.t
test/recipes/70-test_tls13kexmodes.t
test/recipes/70-test_tls13messages.t
test/recipes/75-test_quicapi_data/ssltraceref-zlib.txt
test/recipes/75-test_quicapi_data/ssltraceref.txt
test/recipes/80-test_ssl_old.t
test/recipes/90-test_sslapi_data/ssltraceref-zlib.txt
test/recipes/90-test_sslapi_data/ssltraceref.txt
test/ssl_old_test.c
test/sslapitest.c

index a50ee6e1dc71b037aa77b89af8ab6b6642486561..0f6402b2b7da91429869f5e232a1d900ab1a0bc1 100644 (file)
@@ -2801,7 +2801,7 @@ __owur int tls1_set_groups_list(SSL_CTX *ctx,
     const char *str);
 __owur EVP_PKEY *ssl_generate_pkey_group(SSL_CONNECTION *s, uint16_t id);
 __owur int tls_valid_group(SSL_CONNECTION *s, uint16_t group_id, int minversion,
-    int maxversion, int isec, int *okfortls13);
+    int maxversion, int *okfortls13, const TLS_GROUP_INFO **giptr);
 __owur EVP_PKEY *ssl_generate_param_group(SSL_CONNECTION *s, uint16_t id);
 void tls1_get_formatlist(SSL_CONNECTION *s, const unsigned char **pformats,
     size_t *num_formats);
index e91b7400ea41b70bd47d608cf449bb5794845a6f..6453b84fd7f8957560cd9cd675befb5f66cb4884 100644 (file)
 #include "../ssl_local.h"
 #include "internal/cryptlib.h"
 #include "internal/ssl_unwrap.h"
+#include "internal/tlsgroups.h"
 #include "statem_local.h"
 
+/* Used in the negotiate_dhe function */
+typedef enum {
+    ffdhe_check,
+    ecdhe_check,
+    ptfmt_check
+} dhe_check_t;
+
 EXT_RETURN tls_construct_ctos_renegotiate(SSL_CONNECTION *s, WPACKET *pkt,
     unsigned int context, X509 *x,
     size_t chainidx)
@@ -136,43 +144,78 @@ EXT_RETURN tls_construct_ctos_srp(SSL_CONNECTION *s, WPACKET *pkt,
 }
 #endif
 
-static int use_ecc(SSL_CONNECTION *s, int min_version, int max_version)
+/*
+ * With (D)TLS < 1.3 the only negotiated supported key exchange groups are
+ * FFDHE (RFC7919) and ECDHE/ECX (RFC8422 + legacy).  With (D)TLS 1.3, we add
+ * KEMs, and the supported groups are no longer cipher-dependent.
+ *
+ * This function serves two purposes:
+ *
+ * - To determine whether to send the supported point formats extension.
+ *   This is no longer applicable with (D)TLS >= 1.3.
+ * - To determine whether to send the supported groups extension.
+ *
+ * In the former case, we only care about whether both ECC ciphers and EC/ECX
+ * supported groups are configured, and the (D)TLS min version is at most 1.2.
+ *
+ * In the latter case, we also admit DHE ciphers with FFDHE groups, or any TLS
+ * 1.3 cipher, since the extension is effectively mandatory for (D)TLS 1.3,
+ * with the sole exception of psk-ke resumption, provided the client is sure
+ * that the server will not want elect a full handshake. The check type then
+ * indicates whether ECDHE or FFDHE negotiation should be performed.
+ */
+static int negotiate_dhe(SSL_CONNECTION *s, dhe_check_t check_type,
+    int min_version, int max_version)
 {
     int i, end, ret = 0;
-    unsigned long alg_k, alg_a;
     STACK_OF(SSL_CIPHER) *cipher_stack = NULL;
     const uint16_t *pgroups = NULL;
     size_t num_groups, j;
     SSL *ssl = SSL_CONNECTION_GET_SSL(s);
+    int dtls = SSL_CONNECTION_IS_DTLS(s);
 
+    /* See if we support any EC or FFDHE ciphersuites */
     cipher_stack = SSL_get1_supported_ciphers(ssl);
     end = sk_SSL_CIPHER_num(cipher_stack);
     for (i = 0; i < end; i++) {
         const SSL_CIPHER *c = sk_SSL_CIPHER_value(cipher_stack, i);
-
-        alg_k = c->algorithm_mkey;
-        alg_a = c->algorithm_auth;
-        if ((alg_k & (SSL_kECDHE | SSL_kECDHEPSK))
-            || (alg_a & SSL_aECDSA)
-            || c->min_tls >= TLS1_3_VERSION) {
+        unsigned long alg_k = c->algorithm_mkey;
+        unsigned long alg_a = c->algorithm_auth;
+
+        int is_ffdhe_ciphersuite = (alg_k & (SSL_kDHE | SSL_kDHEPSK));
+        int is_ec_ciphersuite = ((alg_k & (SSL_kECDHE | SSL_kECDHEPSK))
+            || (alg_a & SSL_aECDSA));
+        int is_tls13 = (dtls ? DTLS_VERSION_GT(c->min_dtls, DTLS1_2_VERSION)
+                             : (c->min_tls > TLS1_2_VERSION));
+
+        if ((check_type == ffdhe_check && (is_ffdhe_ciphersuite || is_tls13))
+            || (check_type == ecdhe_check && (is_ec_ciphersuite || is_tls13))
+            || (check_type == ptfmt_check && is_ec_ciphersuite)) {
             ret = 1;
             break;
         }
     }
     sk_SSL_CIPHER_free(cipher_stack);
-    if (!ret)
+    if (ret == 0)
         return 0;
 
-    /* Check we have at least one EC supported group */
+    /* Check we have at least one EC or FFDHE supported group */
     tls1_get_supported_groups(s, &pgroups, &num_groups);
     for (j = 0; j < num_groups; j++) {
         uint16_t ctmp = pgroups[j];
+        const TLS_GROUP_INFO *ginfo = NULL;
+
+        if (!tls_valid_group(s, ctmp, min_version, max_version, NULL, &ginfo))
+            continue;
 
-        if (tls_valid_group(s, ctmp, min_version, max_version, 1, NULL)
+        if (check_type == ffdhe_check && is_ffdhe_group(ginfo->group_id)
             && tls_group_allowed(s, ctmp, SSL_SECOP_CURVE_SUPPORTED))
             return 1;
-    }
 
+        if (check_type != ffdhe_check && is_ecdhe_group(ginfo->group_id)
+            && tls_group_allowed(s, ctmp, SSL_SECOP_CURVE_SUPPORTED))
+            return 1;
+    }
     return 0;
 }
 
@@ -189,12 +232,14 @@ EXT_RETURN tls_construct_ctos_ec_pt_formats(SSL_CONNECTION *s, WPACKET *pkt,
         SSLfatal(s, SSL_AD_INTERNAL_ERROR, reason);
         return EXT_RETURN_FAIL;
     }
-    if (!use_ecc(s, min_version, max_version))
+    if (!negotiate_dhe(s, ptfmt_check, min_version, max_version))
         return EXT_RETURN_NOT_SENT;
 
-    /* Add TLS extension ECPointFormats to the ClientHello message */
     tls1_get_formatlist(s, &pformats, &num_formats);
+    if (num_formats == 0)
+        return EXT_RETURN_NOT_SENT;
 
+    /* Add TLS extension ECPointFormats to the ClientHello message */
     if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_ec_point_formats)
         /* Sub-packet for formats extension */
         || !WPACKET_start_sub_packet_u16(pkt)
@@ -214,6 +259,8 @@ EXT_RETURN tls_construct_ctos_supported_groups(SSL_CONNECTION *s, WPACKET *pkt,
     const uint16_t *pgroups = NULL;
     size_t num_groups = 0, i, tls13added = 0, added = 0;
     int min_version, max_version, reason;
+    int dtls = SSL_CONNECTION_IS_DTLS(s);
+    int use_ecdhe, use_ffdhe;
 
     reason = ssl_get_min_max_version(s, &min_version, &max_version, NULL);
     if (reason != 0) {
@@ -222,11 +269,13 @@ EXT_RETURN tls_construct_ctos_supported_groups(SSL_CONNECTION *s, WPACKET *pkt,
     }
 
     /*
-     * We only support EC groups in TLSv1.2 or below, and in DTLS. Therefore
-     * if we don't have EC support then we don't send this extension.
+     * If we don't support suitable groups, don't send the extension
      */
-    if (!use_ecc(s, min_version, max_version)
-        && (SSL_CONNECTION_IS_DTLS(s) || max_version < TLS1_3_VERSION))
+    use_ecdhe = negotiate_dhe(s, ecdhe_check, min_version, max_version);
+    use_ffdhe = negotiate_dhe(s, ffdhe_check, min_version, max_version);
+    if (!use_ecdhe && !use_ffdhe
+        && (dtls ? DTLS_VERSION_LE(max_version, DTLS1_2_VERSION)
+                 : (max_version <= TLS1_2_VERSION)))
         return EXT_RETURN_NOT_SENT;
 
     /*
@@ -244,19 +293,25 @@ EXT_RETURN tls_construct_ctos_supported_groups(SSL_CONNECTION *s, WPACKET *pkt,
     }
     /* Copy group ID if supported */
     for (i = 0; i < num_groups; i++) {
+        const TLS_GROUP_INFO *ginfo = NULL;
         uint16_t ctmp = pgroups[i];
         int okfortls13;
 
-        if (tls_valid_group(s, ctmp, min_version, max_version, 0, &okfortls13)
-            && tls_group_allowed(s, ctmp, SSL_SECOP_CURVE_SUPPORTED)) {
-            if (!WPACKET_put_bytes_u16(pkt, ctmp)) {
-                SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
-                return EXT_RETURN_FAIL;
-            }
-            if (okfortls13 && max_version == TLS1_3_VERSION)
-                tls13added++;
-            added++;
+        if (!tls_valid_group(s, ctmp, min_version, max_version, &okfortls13,
+                &ginfo)
+            || (!use_ecdhe && is_ecdhe_group(ginfo->group_id))
+            || (!use_ffdhe && is_ffdhe_group(ginfo->group_id))
+            /* Note: SSL_SECOP_CURVE_SUPPORTED covers all key exchange groups */
+            || !tls_group_allowed(s, ctmp, SSL_SECOP_CURVE_SUPPORTED))
+            continue;
+
+        if (!WPACKET_put_bytes_u16(pkt, ctmp)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+            return EXT_RETURN_FAIL;
         }
+        if (okfortls13 && max_version == TLS1_3_VERSION)
+            tls13added++;
+        added++;
     }
     if (!WPACKET_close(pkt) || !WPACKET_close(pkt)) {
         if (added == 0)
@@ -746,7 +801,7 @@ EXT_RETURN tls_construct_ctos_key_share(SSL_CONNECTION *s, WPACKET *pkt,
             if (!tls_group_allowed(s, pgroups[i], SSL_SECOP_CURVE_SUPPORTED))
                 continue;
             if (!tls_valid_group(s, pgroups[i], TLS1_3_VERSION, TLS1_3_VERSION,
-                    0, NULL))
+                    NULL, NULL))
                 continue;
 
             group_id = pgroups[i];
@@ -1912,7 +1967,7 @@ int tls_parse_stoc_key_share(SSL_CONNECTION *s, PACKET *pkt,
         if (i >= num_groups
             || !tls_group_allowed(s, group_id, SSL_SECOP_CURVE_SUPPORTED)
             || !tls_valid_group(s, group_id, TLS1_3_VERSION, TLS1_3_VERSION,
-                0, NULL)) {
+                NULL, NULL)) {
             SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_BAD_KEY_SHARE);
             return 0;
         }
index f24186174049f51562830c3e001560caa57b0710..a0ac7653f157a29cdfdc1d03a9ebedff9fd77bea 100644 (file)
@@ -731,7 +731,7 @@ static KS_EXTRACTION_RESULT extract_keyshares(SSL_CONNECTION *s, PACKET *key_sha
         if (!check_in_list(s, group_id, srvrgroups, srvr_num_groups, 1, NULL)
             || !tls_group_allowed(s, group_id, SSL_SECOP_CURVE_SUPPORTED)
             || !tls_valid_group(s, group_id, TLS1_3_VERSION, TLS1_3_VERSION,
-                0, NULL)) {
+                NULL, NULL)) {
             /* Share not suitable or not supported, check next share */
             continue;
         }
@@ -807,7 +807,7 @@ static void check_overlap(SSL_CONNECTION *s,
             || !tls_group_allowed(s, candidate_groups[current_group],
                 SSL_SECOP_CURVE_SUPPORTED)
             || !tls_valid_group(s, candidate_groups[current_group], TLS1_3_VERSION,
-                TLS1_3_VERSION, 0, NULL))
+                TLS1_3_VERSION, NULL, NULL))
             /* No overlap or group not suitable, check next group */
             continue;
 
@@ -1692,7 +1692,7 @@ EXT_RETURN tls_construct_stoc_supported_groups(SSL_CONNECTION *s, WPACKET *pkt,
     for (i = 0; i < numgroups; i++) {
         uint16_t group = groups[i];
 
-        if (tls_valid_group(s, group, version, version, 0, NULL)
+        if (tls_valid_group(s, group, version, version, NULL, NULL)
             && tls_group_allowed(s, group, SSL_SECOP_CURVE_SUPPORTED)) {
             if (first) {
                 /*
index ea011c71a79a433517c93d611ed33fa337193a24..2f6cef3343b29f12c9f82f012432920775ecd1c7 100644 (file)
@@ -2629,8 +2629,8 @@ CON_FUNC_RETURN tls_construct_server_key_exchange(SSL_CONNECTION *s,
                 }
 #if !defined(OPENSSL_NO_DEPRECATED_3_0)
                 if ((pkdhp == NULL) && (s->cert->dh_tmp_cb != NULL)) {
-                    pkdh = ssl_dh_to_pkey(s->cert->dh_tmp_cb(SSL_CONNECTION_GET_USER_SSL(s),
-                        0, 1024));
+                    pkdh = ssl_dh_to_pkey(
+                        s->cert->dh_tmp_cb(SSL_CONNECTION_GET_USER_SSL(s), 0, 1024));
                     if (pkdh == NULL) {
                         SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
                         goto err;
index b0bfc92e32282545c9420aa1435a1070588e412d..aca0bc6398df1c16c066c019ab112bbad6191ede 100644 (file)
@@ -857,25 +857,25 @@ void tls1_get_group_tuples(SSL_CONNECTION *s, const size_t **ptuples,
 }
 
 int tls_valid_group(SSL_CONNECTION *s, uint16_t group_id,
-    int minversion, int maxversion,
-    int isec, int *okfortls13)
+    int minversion, int maxversion, int *okfortls13,
+    const TLS_GROUP_INFO **giptr)
 {
     const TLS_GROUP_INFO *ginfo = tls1_group_id_lookup(SSL_CONNECTION_GET_CTX(s),
         group_id);
-    int ret;
+    int ret = 0;
     int group_minversion, group_maxversion;
 
     if (okfortls13 != NULL)
         *okfortls13 = 0;
 
     if (ginfo == NULL)
-        return 0;
+        goto end;
 
     group_minversion = SSL_CONNECTION_IS_DTLS(s) ? ginfo->mindtls : ginfo->mintls;
     group_maxversion = SSL_CONNECTION_IS_DTLS(s) ? ginfo->maxdtls : ginfo->maxtls;
 
     if (group_minversion < 0 || group_maxversion < 0)
-        return 0;
+        goto end;
     if (group_maxversion == 0)
         ret = 1;
     else
@@ -888,11 +888,9 @@ int tls_valid_group(SSL_CONNECTION *s, uint16_t group_id,
             *okfortls13 = (group_maxversion == 0)
                 || (group_maxversion >= TLS1_3_VERSION);
     }
-    ret &= !isec
-        || strcmp(ginfo->algorithm, "EC") == 0
-        || strcmp(ginfo->algorithm, "X25519") == 0
-        || strcmp(ginfo->algorithm, "X448") == 0;
-
+end:
+    if (giptr != NULL)
+        *giptr = ginfo;
     return ret;
 }
 
index bb1789710c4114bcd10688fcd230548c2e19e9db..7871e349cdee4d696a6c9dd5a1bbdc5e14e7d911 100644 (file)
@@ -100,7 +100,7 @@ my $proxy = TLSProxy::Proxy->new(
     [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_STATUS_REQUEST,
         TLSProxy::Message::CLIENT,
         checkhandshake::STATUS_REQUEST_CLI_EXTENSION],
-    (disabled("ec") ? () :
+    ((disabled("ec") && disabled("dh")) ? () :
                       [TLSProxy::Message::MT_CLIENT_HELLO,
                        TLSProxy::Message::EXT_SUPPORTED_GROUPS,
                        TLSProxy::Message::CLIENT,
index cd71a313b858d41fa8d0d66a99cfdc2de6705db2..aba24ec93a41b8f7337fbf8fae4198dafbec2e3a 100644 (file)
@@ -70,9 +70,10 @@ plan skip_all => "$test_name needs EC enabled"
     [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SUPPORTED_GROUPS,
         TLSProxy::Message::CLIENT,
         checkhandshake::DEFAULT_EXTENSIONS],
-    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_EC_POINT_FORMATS,
-        TLSProxy::Message::CLIENT,
-        checkhandshake::DEFAULT_EXTENSIONS],
+    (disabled("tls1_2") ? () :
+        [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_EC_POINT_FORMATS,
+            TLSProxy::Message::CLIENT,
+            checkhandshake::DEFAULT_EXTENSIONS]),
     [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SIG_ALGS,
         TLSProxy::Message::CLIENT,
         checkhandshake::DEFAULT_EXTENSIONS],
@@ -123,9 +124,10 @@ plan skip_all => "$test_name needs EC enabled"
     [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SUPPORTED_GROUPS,
         TLSProxy::Message::CLIENT,
         checkhandshake::DEFAULT_EXTENSIONS],
-    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_EC_POINT_FORMATS,
-        TLSProxy::Message::CLIENT,
-        checkhandshake::DEFAULT_EXTENSIONS],
+    (disabled("tls1_2") ? () :
+        [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_EC_POINT_FORMATS,
+            TLSProxy::Message::CLIENT,
+            checkhandshake::DEFAULT_EXTENSIONS]),
     [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SIG_ALGS,
         TLSProxy::Message::CLIENT,
         checkhandshake::DEFAULT_EXTENSIONS],
index 3a04cca334add0600c446dba7e872eba3160c567..af223b56a812570398dc2093c1e5b307668ac264 100644 (file)
@@ -70,9 +70,10 @@ plan skip_all => "$test_name needs EC enabled"
     [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SUPPORTED_GROUPS,
         TLSProxy::Message::CLIENT,
         checkhandshake::DEFAULT_EXTENSIONS],
-    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_EC_POINT_FORMATS,
-        TLSProxy::Message::CLIENT,
-        checkhandshake::DEFAULT_EXTENSIONS],
+    (disabled("tls1_2") ? () :
+        [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_EC_POINT_FORMATS,
+            TLSProxy::Message::CLIENT,
+            checkhandshake::DEFAULT_EXTENSIONS]),
     [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SIG_ALGS,
         TLSProxy::Message::CLIENT,
         checkhandshake::DEFAULT_EXTENSIONS],
@@ -126,9 +127,10 @@ plan skip_all => "$test_name needs EC enabled"
     [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SUPPORTED_GROUPS,
         TLSProxy::Message::CLIENT,
         checkhandshake::DEFAULT_EXTENSIONS],
-    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_EC_POINT_FORMATS,
-        TLSProxy::Message::CLIENT,
-        checkhandshake::DEFAULT_EXTENSIONS],
+    (disabled("tls1_2") ? () :
+        [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_EC_POINT_FORMATS,
+            TLSProxy::Message::CLIENT,
+            checkhandshake::DEFAULT_EXTENSIONS]),
     [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SIG_ALGS,
         TLSProxy::Message::CLIENT,
         checkhandshake::DEFAULT_EXTENSIONS],
index 535b37b2bd958ad58de6cad03a264937fe8e738b..f797cac12825569f3aad44904b9260ece6c304f9 100644 (file)
@@ -19,8 +19,6 @@ Header:
           000f - 01 02 04 04 80 0c 00 00-05 04 80 08 00 00 06   ...............
           001e - 04 80 08 00 00 07 04 80-08 00 00 08 02 40 64   .............@d
           002d - 09 02 40 64                                    ..@d
-        extension_type=ec_point_formats(11), length=2
-          uncompressed (0)
         extension_type=supported_groups(10), length=18
           X25519MLKEM768 (4588)
           ecdh_x25519 (29)
index c5502b68a722466bf59c0644b61d1bbb5a07dfd8..fe5a32bea33c8690bd5a8070794a7a7dfd32d768 100644 (file)
@@ -19,8 +19,6 @@ Header:
           000f - 01 02 04 04 80 0c 00 00-05 04 80 08 00 00 06   ...............
           001e - 04 80 08 00 00 07 04 80-08 00 00 08 02 40 64   .............@d
           002d - 09 02 40 64                                    ..@d
-        extension_type=ec_point_formats(11), length=2
-          uncompressed (0)
         extension_type=supported_groups(10), length=18
           X25519MLKEM768 (4588)
           ecdh_x25519 (29)
index 0039fe2172512075ca907361bd17496823e05f94..a0653ef2169566008a59cf013984716ddedde9e4 100644 (file)
@@ -566,11 +566,16 @@ sub testssl {
 
           SKIP: {
               skip "skipping dhe512 test", 1
-                  if ($no_dh);
+                  if ($no_dh || $no_ec);
 
+              # Need some explicit EC groups to suppress default support of
+              # ffdhe2048 and ffdhe3072 in the client hello, which then
+              # overrides the server's DH temp parameters from "-dh512".
+              #
               is(run(test([@ssltest,
                            "-s_cipher", "EDH",
                            "-c_cipher", 'EDH:@SECLEVEL=1',
+                           "-groups", "?P-256:?X25519:?MLKEM512",
                            "-dhe512",
                            $protocol])), 0,
                  "testing connection with weak DH, expecting failure");
index 4c58d23db577e0bdcf5e56e11af1eb68f9c9464f..a9a503345f04fec7943a503af2bb2fa0af4e03bc 100644 (file)
@@ -14,10 +14,6 @@ Header:
       compression_methods (len=1)
         No Compression (0x00)
       extensions, length = ?
-        extension_type=ec_point_formats(11), length=4
-          uncompressed (0)
-          ansiX962_compressed_prime (1)
-          ansiX962_compressed_char2 (2)
         extension_type=supported_groups(10), length=20
           MLKEM512 (512)
           MLKEM768 (513)
index 451c98284ba06c2aa08d17f6dc65ac6e05f3d220..273fd35c1101a2540302f7b3558ea8a0eb9a0ddf 100644 (file)
@@ -14,10 +14,6 @@ Header:
       compression_methods (len=1)
         No Compression (0x00)
       extensions, length = ?
-        extension_type=ec_point_formats(11), length=4
-          uncompressed (0)
-          ansiX962_compressed_prime (1)
-          ansiX962_compressed_char2 (2)
         extension_type=supported_groups(10), length=20
           MLKEM512 (512)
           MLKEM768 (513)
index ea3c204026facd32da123e8229abd72b600b97b1..49e5a954d280db50605bbe3cc28c5c54164c81f7 100644 (file)
@@ -648,6 +648,9 @@ static void sv_usage(void)
     fprintf(stderr,
         " -dhe4096      - use 4096 bit key (safe prime) for DHE\n");
 #endif
+    fprintf(
+        stderr,
+        " -groups <list> - override the default client supported groups list\n");
     fprintf(stderr, " -no_dhe       - disable DHE\n");
 #ifndef OPENSSL_NO_EC
     fprintf(stderr, " -no_ecdhe     - disable ECDHE\n");
@@ -910,9 +913,10 @@ int main(int argc, char *argv[])
     long bytes = 256L;
 #ifndef OPENSSL_NO_DH
     EVP_PKEY *dhpkey;
-    int dhe512 = 0, dhe1024dsa = 0, dhe4096 = 0;
+    int dhe512 = 0, dhe1024dsa = 0, dhe2048 = 0, dhe4096 = 0;
     int no_dhe = 0;
 #endif
+    const char *groups = NULL;
     int no_psk = 0;
     int print_time = 0;
     clock_t s_time = 0, c_time = 0;
@@ -1001,6 +1005,8 @@ int main(int argc, char *argv[])
             dhe512 = 1;
         else if (strcmp(*argv, "-dhe1024dsa") == 0)
             dhe1024dsa = 1;
+        else if (strcmp(*argv, "-dhe2048") == 0)
+            dhe2048 = 1;
         else if (strcmp(*argv, "-dhe4096") == 0)
             dhe4096 = 1;
 #endif
@@ -1018,6 +1024,10 @@ int main(int argc, char *argv[])
 #else
             no_psk = 1;
 #endif
+        } else if (strcmp(*argv, "-groups") == 0) {
+            if (--argc < 1)
+                goto bad;
+            groups = *(++argv);
         } else if (strcmp(*argv, "-tls1_2") == 0) {
             tls1_2 = 1;
         } else if (strcmp(*argv, "-tls1_1") == 0) {
@@ -1502,6 +1512,8 @@ int main(int argc, char *argv[])
             dhpkey = get_dh1024dsa(libctx);
         else if (dhe512)
             dhpkey = get_dh512(libctx);
+        else if (dhe2048)
+            dhpkey = get_dh2048(libctx);
         else if (dhe4096)
             dhpkey = get_dh4096(libctx);
         else
@@ -1519,6 +1531,12 @@ int main(int argc, char *argv[])
             EVP_PKEY_free(dhpkey);
     }
 #endif
+    if (groups != NULL && !SSL_CTX_set1_groups_list(c_ctx, groups)) {
+        BIO_printf(bio_err, "error setting client supported groups to: %s\n",
+            groups);
+        ERR_print_errors(bio_err);
+        goto end;
+    }
 
     if (!(SSL_CTX_load_verify_file(s_ctx, CAfile)
             || SSL_CTX_load_verify_dir(s_ctx, CApath))
index 5e2ac8daecc7f509c3a78cb766d43686c427abf8..eb57864979259f4acd84f040ccc337a85adfc452 100644 (file)
@@ -5389,6 +5389,7 @@ static int test_key_exchange(int idx)
     char *kexch_name0 = NULL;
     const char *kexch_names = NULL;
     int shared_group0;
+    const char *client_group_name = NULL;
 
     switch (idx) {
 #ifndef OPENSSL_NO_EC
@@ -5433,7 +5434,6 @@ static int test_key_exchange(int idx)
 #ifndef OPENSSL_NO_TLS1_2
     case 20:
         max_version = TLS1_2_VERSION;
-        kexch_name0 = "ffdhe2048";
 #endif
         /* Fall through */
     case 6:
@@ -5466,17 +5466,21 @@ static int test_key_exchange(int idx)
 #if !defined(OPENSSL_NO_TLS1_2)
     case 19:
         max_version = TLS1_2_VERSION;
+        kexch_groups = NULL;
 #if !defined(OPENSSL_NO_EC)
         /* Set at least one EC group so the handshake completes */
         kexch_names = "MLKEM512:MLKEM768:MLKEM1024:secp256r1";
+        kexch_name0 = "secp256r1";
+        break;
 #elif !defined(OPENSSL_NO_DH)
-        kexch_names = "MLKEM512:MLKEM768:MLKEM1024";
+        kexch_names = "MLKEM512:MLKEM768:MLKEM1024:ffdhe2048";
+        kexch_name0 = "ffdhe2048";
+        break;
 #else
         /* With neither EC nor DH TLS 1.2 can't happen */
         return 1;
 #endif
 #endif
-        /* Fall through */
     case 12:
         kexch_groups = NULL;
         if (kexch_names == NULL)
@@ -5573,42 +5577,28 @@ static int test_key_exchange(int idx)
     if (!TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE)))
         goto end;
 
+    shared_group0 = SSL_get_shared_group(serverssl, 0);
+    if (kexch_groups != NULL
+        && !TEST_int_eq(shared_group0, kexch_groups[0]))
+        goto end;
+    if (!TEST_str_eq(SSL_group_to_name(serverssl, shared_group0),
+            kexch_name0))
+        goto end;
     /*
-     * If the handshake succeeds the negotiated kexch alg should be the first
-     * one in configured, except in the case of "all" FFDHE and "all" ML-KEM
-     * groups (idx == 19, 20), which are TLSv1.3 only so we expect no shared
-     * group to exist.
+     * With TLS <= 1.2, the client will not infer an FFDHE group name from
+     * the server's DH parameters, so we allow NULL client names in that
+     * case.
      */
-    shared_group0 = SSL_get_shared_group(serverssl, 0);
-    switch (idx) {
-    case 19:
-#if !defined(OPENSSL_NO_EC)
-        /* MLKEM + TLS 1.2 and no DH => "secp526r1" */
-        if (!TEST_int_eq(shared_group0, NID_X9_62_prime256v1))
-            goto end;
-        break;
-#endif
-        /* Fall through */
-    case 20:
-        if (!TEST_int_eq(shared_group0, 0))
-            goto end;
-        break;
-    default:
-        if (kexch_groups != NULL
-            && !TEST_int_eq(shared_group0, kexch_groups[0]))
-            goto end;
-        if (!TEST_str_eq(SSL_group_to_name(serverssl, shared_group0),
-                kexch_name0))
-            goto end;
-        if (!TEST_str_eq(SSL_get0_group_name(serverssl), kexch_name0)
-            || !TEST_str_eq(SSL_get0_group_name(clientssl), kexch_name0))
-            goto end;
-        if (!TEST_int_eq(SSL_get_negotiated_group(serverssl), shared_group0))
-            goto end;
-        if (!TEST_int_eq(SSL_get_negotiated_group(clientssl), shared_group0))
-            goto end;
-        break;
-    }
+    client_group_name = SSL_get0_group_name(clientssl);
+    if (!TEST_str_eq(SSL_get0_group_name(serverssl), kexch_name0)
+        || ((max_version >= TLS1_3_VERSION || client_group_name != NULL)
+            && !TEST_str_eq(client_group_name, kexch_name0)))
+        goto end;
+    if (!TEST_int_eq(SSL_get_negotiated_group(serverssl), shared_group0))
+        goto end;
+    if (client_group_name != NULL
+        && !TEST_int_eq(SSL_get_negotiated_group(clientssl), shared_group0))
+        goto end;
 
     testresult = 1;
 end:
@@ -5713,11 +5703,7 @@ static int test_negotiated_group(int idx)
         kexch_alg = ecdhe_kexch_groups[idx];
     else
         kexch_alg = ffdhe_kexch_groups[idx];
-    /* We expect nothing for the unimplemented TLS 1.2 FFDHE named groups */
-    if (!istls13 && !isecdhe)
-        expectednid = NID_undef;
-    else
-        expectednid = kexch_alg;
+    expectednid = kexch_alg;
 
     if (is_fips && (kexch_alg == NID_X25519 || kexch_alg == NID_X448))
         return TEST_skip("X25519 and X448 might not be available in fips provider.");
@@ -5754,9 +5740,13 @@ static int test_negotiated_group(int idx)
     if (!TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE)))
         goto end;
 
-    /* Initial handshake; always the configured one */
-    if (!TEST_uint_eq(SSL_get_negotiated_group(clientssl), expectednid)
-        || !TEST_uint_eq(SSL_get_negotiated_group(serverssl), expectednid))
+    /*
+     * Initial handshake; always the configured one.  With TLS <= 1.2 and FFDHE
+     * the client does not infer a negotiated group id.
+     */
+    if (!TEST_uint_eq(SSL_get_negotiated_group(serverssl), expectednid)
+        || ((istls13 || isecdhe)
+            && !TEST_uint_eq(SSL_get_negotiated_group(clientssl), expectednid)))
         goto end;
 
     if (!TEST_ptr((origsess = SSL_get1_session(clientssl))))
@@ -5781,8 +5771,9 @@ static int test_negotiated_group(int idx)
         goto end;
 
     /* Still had better agree, since nothing changed... */
-    if (!TEST_uint_eq(SSL_get_negotiated_group(clientssl), expectednid)
-        || !TEST_uint_eq(SSL_get_negotiated_group(serverssl), expectednid))
+    if (!TEST_uint_eq(SSL_get_negotiated_group(serverssl), expectednid)
+        || ((istls13 || isecdhe)
+            && !TEST_uint_eq(SSL_get_negotiated_group(clientssl), expectednid)))
         goto end;
 
     SSL_shutdown(clientssl);
@@ -5809,11 +5800,7 @@ static int test_negotiated_group(int idx)
         if (!TEST_int_ne(expectednid, kexch_alg))
             goto end;
     } else {
-        /* TLS 1.2 only supports named groups for ECDHE. */
-        if (isecdhe)
-            expectednid = kexch_alg;
-        else
-            expectednid = 0;
+        expectednid = kexch_alg;
     }
     if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl,
             NULL, NULL))
@@ -5827,8 +5814,9 @@ static int test_negotiated_group(int idx)
         goto end;
 
     /* Check that we get what we expected */
-    if (!TEST_uint_eq(SSL_get_negotiated_group(clientssl), expectednid)
-        || !TEST_uint_eq(SSL_get_negotiated_group(serverssl), expectednid))
+    if (!TEST_uint_eq(SSL_get_negotiated_group(serverssl), expectednid)
+        || ((istls13 || isecdhe)
+            && !TEST_uint_eq(SSL_get_negotiated_group(clientssl), expectednid)))
         goto end;
 
     testresult = 1;
@@ -11447,7 +11435,6 @@ end:
     return testresult;
 }
 
-#ifndef OPENSSL_NO_TLS1_3
 /*
  * Test the server will reject FFDHE ciphersuites if no supported FFDHE group is
  * advertised by the client.
@@ -11667,7 +11654,6 @@ end:
 
     return testresult;
 }
-#endif /* OPENSSL_NO_TLS1_3 */
 
 #endif /* OPENSSL_NO_DH */
 #endif /* OPENSSL_NO_TLS1_2 */
@@ -14495,12 +14481,10 @@ int setup_tests(void)
 #ifndef OPENSSL_NO_DH
     ADD_ALL_TESTS(test_set_tmp_dh, 11);
     ADD_ALL_TESTS(test_dh_auto, 7);
-#ifndef OPENSSL_NO_TLS1_3
     ADD_ALL_TESTS(test_no_shared_ffdhe_group, 10);
     ADD_ALL_TESTS(test_shared_ffdhe_group, 5);
 #endif
 #endif
-#endif
 #ifndef OSSL_NO_USABLE_TLS1_3
     ADD_TEST(test_sni_tls13);
     ADD_ALL_TESTS(test_ticket_lifetime, 2);