@@ -11362,6 +11362,64 @@ static const word16 preferredGroup[] = {
1136211362 ((sizeof(preferredGroup)/sizeof(*preferredGroup)) - 1)
1136311363 /* -1 for the invalid group */
1136411364
11365+ /* WOLFSSL_KEY_SHARE_DEFAULT_GROUP - group used for the speculative key share
11366+ * in ClientHello messages when the application has not selected one via
11367+ * wolfSSL_CTX_set_groups() / wolfSSL_set_groups() or wolfSSL_UseKeyShare().
11368+ *
11369+ * The default is optimized for the likelihood that the server will accept the
11370+ * speculative key share without forcing a HelloRetryRequest. It therefore
11371+ * differs from preferredGroup[] (which is sorted by strength): we pick the
11372+ * most widely deployed group at each tier rather than the strongest.
11373+ *
11374+ * Selection order when not user-defined:
11375+ * 1. A standardized PQ/T hybrid using X25519 or SECP256R1, if available.
11376+ * 2. SECP256R1, then X25519, then SECP384R1.
11377+ * 3. FFDHE 2048 or 3072, for DH-only TLS 1.3 builds.
11378+ * 4. preferredGroup[0] as a final fallback for any other configuration.
11379+ *
11380+ * Users can override the default by defining WOLFSSL_KEY_SHARE_DEFAULT_GROUP
11381+ * in user_settings.h to any of the WOLFSSL_* group identifiers from
11382+ * wolfssl/ssl.h (or the numeric IANA code point). The macro is substituted
11383+ * directly into an assignment, so wrap non-trivial expressions in parentheses.
11384+ */
11385+ #ifndef WOLFSSL_KEY_SHARE_DEFAULT_GROUP
11386+ #if defined(WOLFSSL_TLS13) && defined(WOLFSSL_HAVE_MLKEM) && \
11387+ !defined(WOLFSSL_NO_ML_KEM) && defined(WOLFSSL_PQC_HYBRIDS) && \
11388+ !defined(WOLFSSL_NO_ML_KEM_768) && defined(HAVE_CURVE25519) && \
11389+ ECC_MIN_KEY_SZ <= 256
11390+ #define WOLFSSL_KEY_SHARE_DEFAULT_GROUP WOLFSSL_X25519MLKEM768
11391+ #elif defined(WOLFSSL_TLS13) && defined(WOLFSSL_HAVE_MLKEM) && \
11392+ !defined(WOLFSSL_NO_ML_KEM) && defined(WOLFSSL_PQC_HYBRIDS) && \
11393+ !defined(WOLFSSL_NO_ML_KEM_768) && defined(HAVE_ECC) && \
11394+ (!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) && \
11395+ ECC_MIN_KEY_SZ <= 256
11396+ #define WOLFSSL_KEY_SHARE_DEFAULT_GROUP WOLFSSL_SECP256R1MLKEM768
11397+ #elif defined(WOLFSSL_TLS13) && defined(WOLFSSL_HAVE_MLKEM) && \
11398+ !defined(WOLFSSL_NO_ML_KEM) && defined(WOLFSSL_PQC_HYBRIDS) && \
11399+ !defined(WOLFSSL_NO_ML_KEM_1024) && defined(HAVE_ECC) && \
11400+ (defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)) && \
11401+ ECC_MIN_KEY_SZ <= 384
11402+ #define WOLFSSL_KEY_SHARE_DEFAULT_GROUP WOLFSSL_SECP384R1MLKEM1024
11403+ #elif defined(HAVE_ECC) && (!defined(NO_ECC256) || \
11404+ defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 256 && \
11405+ !defined(NO_ECC_SECP)
11406+ #define WOLFSSL_KEY_SHARE_DEFAULT_GROUP WOLFSSL_ECC_SECP256R1
11407+ #elif !defined(HAVE_FIPS) && defined(HAVE_CURVE25519) && ECC_MIN_KEY_SZ <= 256
11408+ #define WOLFSSL_KEY_SHARE_DEFAULT_GROUP WOLFSSL_ECC_X25519
11409+ #elif defined(HAVE_ECC) && (defined(HAVE_ECC384) || \
11410+ defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 384 && \
11411+ !defined(NO_ECC_SECP)
11412+ #define WOLFSSL_KEY_SHARE_DEFAULT_GROUP WOLFSSL_ECC_SECP384R1
11413+ #elif defined(HAVE_FFDHE_2048)
11414+ #define WOLFSSL_KEY_SHARE_DEFAULT_GROUP WOLFSSL_FFDHE_2048
11415+ #elif defined(HAVE_FFDHE_3072)
11416+ #define WOLFSSL_KEY_SHARE_DEFAULT_GROUP WOLFSSL_FFDHE_3072
11417+ #else
11418+ /* Fall back to whatever preferredGroup[] starts with. */
11419+ #define WOLFSSL_KEY_SHARE_DEFAULT_GROUP (preferredGroup[0])
11420+ #endif
11421+ #endif /* !WOLFSSL_KEY_SHARE_DEFAULT_GROUP */
11422+
1136511423/* Examines the application specified group ranking and returns the rank of the
1136611424 * group.
1136711425 * If no group ranking set then all groups are rank 0 (highest).
@@ -16059,10 +16117,11 @@ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer)
1605916117 int set = 0;
1606016118 int i, j;
1606116119
16062- /* try to find the highest element in ssl->group[]
16063- * that is contained in preferredGroup[].
16064- */
16065- namedGroup = preferredGroup[0];
16120+ /* Find the first element of ssl->group[] that is also
16121+ * present in preferredGroup[]. The user's ranking wins;
16122+ * if nothing intersects, send no key share and let the
16123+ * server drive group selection via HRR. */
16124+ namedGroup = WOLFSSL_NAMED_GROUP_INVALID;
1606616125 for (i = 0; i < ssl->numGroups && !set; i++) {
1606716126 for (j = 0; preferredGroup[j] != WOLFSSL_NAMED_GROUP_INVALID; j++) {
1606816127 if (preferredGroup[j] == ssl->group[i]) {
@@ -16072,12 +16131,10 @@ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer)
1607216131 }
1607316132 }
1607416133 }
16075- if (!set)
16076- namedGroup = WOLFSSL_NAMED_GROUP_INVALID;
1607716134 }
1607816135 else {
1607916136 /* Choose the most preferred group. */
16080- namedGroup = preferredGroup[0] ;
16137+ namedGroup = WOLFSSL_KEY_SHARE_DEFAULT_GROUP ;
1608116138 }
1608216139 }
1608316140 else {
@@ -16088,9 +16145,15 @@ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer)
1608816145 if (namedGroup != WOLFSSL_NAMED_GROUP_INVALID) {
1608916146 ret = TLSX_KeyShare_Use(ssl, namedGroup, 0, NULL, NULL,
1609016147 &ssl->extensions);
16091- if (ret != 0)
16092- return ret;
1609316148 }
16149+ else {
16150+ /* No suitable key share group found, send no key share to
16151+ * trigger a HRR with the server's preferred group. */
16152+ WOLFSSL_MSG("Sending no key share to trigger HRR");
16153+ ret = TLSX_KeyShare_Empty(ssl);
16154+ }
16155+ if (ret != 0)
16156+ return ret;
1609416157 #endif /* HAVE_SUPPORTED_CURVES */
1609516158
1609616159 #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
0 commit comments