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