Skip to content

Commit 26e2f05

Browse files
authored
Merge pull request #9848 from Frauschi/dtls_hrr_group
Fix for DTLS1.3 HRR group handling
2 parents 5fa18d9 + 7842bf3 commit 26e2f05

3 files changed

Lines changed: 155 additions & 15 deletions

File tree

src/tls.c

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10216,20 +10216,6 @@ int TLSX_KeyShare_Parse_ClientHello(const WOLFSSL* ssl,
1021610216
offset += ret;
1021710217
}
1021810218

10219-
if (ssl->hrr_keyshare_group != 0) {
10220-
/*
10221-
* https://datatracker.ietf.org/doc/html/rfc8446#section-4.2.8
10222-
* when sending the new ClientHello, the client MUST
10223-
* replace the original "key_share" extension with one containing only a
10224-
* new KeyShareEntry for the group indicated in the selected_group field
10225-
* of the triggering HelloRetryRequest
10226-
*/
10227-
if (seenGroupsCnt != 1 || seenGroups[0] != ssl->hrr_keyshare_group) {
10228-
WOLFSSL_ERROR_VERBOSE(BAD_KEY_SHARE_DATA);
10229-
return BAD_KEY_SHARE_DATA;
10230-
}
10231-
}
10232-
1023310219
return 0;
1023410220
}
1023510221

src/tls13.c

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6502,6 +6502,8 @@ static int RestartHandshakeHashWithCookie(WOLFSSL* ssl, Cookie* cookie)
65026502
hrrIdx += 2;
65036503
c16toa(OPAQUE16_LEN, hrr + hrrIdx);
65046504
hrrIdx += 2;
6505+
/* Restore the HRR key share group from the cookie. */
6506+
ato16(cookieData + idx, &ssl->hrr_keyshare_group);
65056507
hrr[hrrIdx++] = cookieData[idx++];
65066508
hrr[hrrIdx++] = cookieData[idx++];
65076509
}
@@ -7015,6 +7017,29 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
70157017
}
70167018
#endif
70177019

7020+
#ifdef HAVE_SUPPORTED_CURVES
7021+
if (ssl->hrr_keyshare_group != 0) {
7022+
/*
7023+
* https://datatracker.ietf.org/doc/html/rfc8446#section-4.2.8
7024+
* when sending the new ClientHello, the client MUST
7025+
* replace the original "key_share" extension with one containing only
7026+
* a new KeyShareEntry for the group indicated in the selected_group
7027+
* field of the triggering HelloRetryRequest.
7028+
*/
7029+
TLSX* extension = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE);
7030+
if (extension != NULL) {
7031+
KeyShareEntry* kse = (KeyShareEntry*)extension->data;
7032+
/* Exactly one KeyShareEntry with the HRR group must be present. */
7033+
if (kse == NULL || kse->next != NULL ||
7034+
kse->group != ssl->hrr_keyshare_group) {
7035+
ERROR_OUT(BAD_KEY_SHARE_DATA, exit_dch);
7036+
}
7037+
}
7038+
else
7039+
ERROR_OUT(BAD_KEY_SHARE_DATA, exit_dch);
7040+
}
7041+
#endif
7042+
70187043
#if defined(HAVE_ECH)
70197044
/* hash clientHelloInner to hsHashesEch independently since it can't include
70207045
* the HRR */
@@ -7509,7 +7534,18 @@ int SendTls13ServerHello(WOLFSSL* ssl, byte extMsgType)
75097534
if (ret != 0)
75107535
return ret;
75117536

7512-
if (extMsgType == hello_retry_request) {
7537+
/* When we send a HRR, we store the selected key share group to later check
7538+
* that the client uses the same group in the second ClientHello.
7539+
*
7540+
* In case of stateless DTLS, we do not store the group, however, as it is
7541+
* already stored in the cookie that is sent to the client. We later recover
7542+
* the group from the cookie to prevent storing a state in a stateless
7543+
* server. */
7544+
if (extMsgType == hello_retry_request
7545+
#if defined(WOLFSSL_DTLS13) && defined(WOLFSSL_SEND_HRR_COOKIE)
7546+
&& (!ssl->options.dtls || ssl->options.dtlsStateful)
7547+
#endif
7548+
) {
75137549
TLSX* ksExt = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE);
75147550
if (ksExt != NULL) {
75157551
KeyShareEntry* kse = (KeyShareEntry*)ksExt->data;

tests/api.c

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24180,6 +24180,12 @@ static word32 test_wolfSSL_dtls_stateless_HashWOLFSSL(const WOLFSSL* ssl)
2418024180
sslCopy.keys.dtls_peer_handshake_number = 0;
2418124181
XMEMSET(&sslCopy.alert_history, 0, sizeof(sslCopy.alert_history));
2418224182
sslCopy.hsHashes = NULL;
24183+
#if !defined(WOLFSSL_NO_CLIENT_AUTH) && \
24184+
((defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3)) || \
24185+
(defined(HAVE_ED25519) && !defined(NO_ED25519_CLIENT_AUTH)) || \
24186+
(defined(HAVE_ED448) && !defined(NO_ED448_CLIENT_AUTH)))
24187+
sslCopy.options.cacheMessages = 0;
24188+
#endif
2418324189
#ifdef WOLFSSL_ASYNC_IO
2418424190
#ifdef WOLFSSL_ASYNC_CRYPT
2418524191
sslCopy.asyncDev = NULL;
@@ -24317,11 +24323,122 @@ static int test_wolfSSL_dtls_stateless(void)
2431724323

2431824324
return TEST_SUCCESS;
2431924325
}
24326+
24327+
/* DTLS stateless API handling multiple CHs with different HRR groups */
24328+
static int test_wolfSSL_dtls_stateless_hrr_group(void)
24329+
{
24330+
EXPECT_DECLS;
24331+
#if defined(WOLFSSL_SEND_HRR_COOKIE)
24332+
size_t i;
24333+
word32 initHash;
24334+
struct {
24335+
method_provider client_meth;
24336+
method_provider server_meth;
24337+
} params[] = {
24338+
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_DTLS13)
24339+
{ wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method },
24340+
#endif
24341+
#if !defined(WOLFSSL_NO_TLS12) && defined(WOLFSSL_DTLS)
24342+
{ wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method },
24343+
#endif
24344+
};
24345+
for (i = 0; i < XELEM_CNT(params) && !EXPECT_FAIL(); i++) {
24346+
WOLFSSL_CTX *ctx_s = NULL, *ctx_c = NULL;
24347+
WOLFSSL *ssl_s = NULL, *ssl_c = NULL, *ssl_c2 = NULL;
24348+
struct test_memio_ctx test_ctx;
24349+
int groups_1[] = {
24350+
WOLFSSL_ECC_SECP256R1,
24351+
WOLFSSL_ECC_SECP384R1,
24352+
WOLFSSL_ECC_SECP521R1
24353+
};
24354+
int groups_2[] = {
24355+
WOLFSSL_ECC_SECP384R1,
24356+
WOLFSSL_ECC_SECP521R1
24357+
};
24358+
char hrrBuf[1000];
24359+
int hrrSz = sizeof(hrrBuf);
24360+
24361+
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
24362+
24363+
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
24364+
params[i].client_meth, params[i].server_meth), 0);
24365+
24366+
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, NULL, &ssl_c2, NULL,
24367+
params[i].client_meth, params[i].server_meth), 0);
24368+
24369+
24370+
wolfSSL_SetLoggingPrefix("server");
24371+
wolfSSL_dtls_set_using_nonblock(ssl_s, 1);
24372+
24373+
initHash = test_wolfSSL_dtls_stateless_HashWOLFSSL(ssl_s);
24374+
24375+
/* Set groups and disable key shares. This ensures that only the given
24376+
* groups are in the SupportedGroups extension and that an empty key
24377+
* share extension is sent in the initial ClientHello of each session.
24378+
* This triggers the server to send a HelloRetryRequest with the first
24379+
* group in the SupportedGroups extension selected. */
24380+
wolfSSL_SetLoggingPrefix("client1");
24381+
ExpectIntEQ(wolfSSL_set_groups(ssl_c, groups_1, 3), WOLFSSL_SUCCESS);
24382+
ExpectIntEQ(wolfSSL_NoKeyShares(ssl_c), WOLFSSL_SUCCESS);
24383+
24384+
wolfSSL_SetLoggingPrefix("client2");
24385+
ExpectIntEQ(wolfSSL_set_groups(ssl_c2, groups_2, 2), WOLFSSL_SUCCESS);
24386+
ExpectIntEQ(wolfSSL_NoKeyShares(ssl_c2), WOLFSSL_SUCCESS);
24387+
24388+
/* Start handshake, send first ClientHello */
24389+
wolfSSL_SetLoggingPrefix("client1");
24390+
ExpectIntEQ(wolfSSL_connect(ssl_c), -1);
24391+
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
24392+
24393+
/* Read first ClientHello, send HRR with WOLFSSL_ECC_SECP256R1 */
24394+
wolfSSL_SetLoggingPrefix("server");
24395+
ExpectIntEQ(wolfDTLS_accept_stateless(ssl_s), 0);
24396+
ExpectIntEQ(test_memio_copy_message(&test_ctx, 1, hrrBuf, &hrrSz, 0), 0);
24397+
ExpectIntGT(hrrSz, 0);
24398+
ExpectIntEQ(initHash, test_wolfSSL_dtls_stateless_HashWOLFSSL(ssl_s));
24399+
test_memio_clear_buffer(&test_ctx, 1);
24400+
24401+
/* Send second ClientHello */
24402+
wolfSSL_SetLoggingPrefix("client2");
24403+
ExpectIntEQ(wolfSSL_connect(ssl_c2), -1);
24404+
ExpectIntEQ(wolfSSL_get_error(ssl_c2, -1), WOLFSSL_ERROR_WANT_READ);
24405+
24406+
/* Read second ClientHello, send HRR now with WOLFSSL_ECC_SECP384R1 */
24407+
wolfSSL_SetLoggingPrefix("server");
24408+
ExpectIntEQ(wolfDTLS_accept_stateless(ssl_s), 0);
24409+
ExpectIntEQ(initHash, test_wolfSSL_dtls_stateless_HashWOLFSSL(ssl_s));
24410+
test_memio_clear_buffer(&test_ctx, 1);
24411+
24412+
/* Complete first handshake with WOLFSSL_ECC_SECP256R1 */
24413+
wolfSSL_SetLoggingPrefix("client1");
24414+
ExpectIntEQ(test_memio_inject_message(&test_ctx, 1, hrrBuf, hrrSz), 0);
24415+
ExpectIntEQ(wolfSSL_connect(ssl_c), -1);
24416+
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
24417+
24418+
wolfSSL_SetLoggingPrefix("server");
24419+
ExpectIntEQ(wolfDTLS_accept_stateless(ssl_s), WOLFSSL_SUCCESS);
24420+
24421+
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
24422+
24423+
wolfSSL_free(ssl_s);
24424+
wolfSSL_free(ssl_c);
24425+
wolfSSL_free(ssl_c2);
24426+
wolfSSL_CTX_free(ctx_s);
24427+
wolfSSL_CTX_free(ctx_c);
24428+
}
24429+
#endif /* WOLFSSL_SEND_HRR_COOKIE */
24430+
return EXPECT_RESULT();
24431+
}
2432024432
#else
2432124433
static int test_wolfSSL_dtls_stateless(void)
2432224434
{
2432324435
return TEST_SKIPPED;
2432424436
}
24437+
24438+
static int test_wolfSSL_dtls_stateless_hrr_group(void)
24439+
{
24440+
return TEST_SKIPPED;
24441+
}
2432524442
#endif /* WOLFSSL_DTLS13 && WOLFSSL_SEND_HRR_COOKIE &&
2432624443
* HAVE_IO_TESTS_DEPENDENCIES && !SINGLE_THREADED */
2432724444

@@ -33186,6 +33303,7 @@ TEST_CASE testCases[] = {
3318633303
TEST_DECL(test_wolfSSL_dtls_bad_record),
3318733304
/* Uses Assert in handshake callback. */
3318833305
TEST_DECL(test_wolfSSL_dtls_stateless),
33306+
TEST_DECL(test_wolfSSL_dtls_stateless_hrr_group),
3318933307
TEST_DECL(test_generate_cookie),
3319033308

3319133309
#ifndef NO_BIO

0 commit comments

Comments
 (0)