diff --git a/src/tls.c b/src/tls.c index 94bda4772..743fbf3e9 100644 --- a/src/tls.c +++ b/src/tls.c @@ -9979,6 +9979,20 @@ int TLSX_KeyShare_Parse_ClientHello(const WOLFSSL* ssl, offset += ret; } + if (ssl->hrr_keyshare_group != 0) { + /* + * https://datatracker.ietf.org/doc/html/rfc8446#section-4.2.8 + * when sending the new ClientHello, the client MUST + * replace the original "key_share" extension with one containing only a + * new KeyShareEntry for the group indicated in the selected_group field + * of the triggering HelloRetryRequest + */ + if (seenGroupsCnt != 1 || seenGroups[0] != ssl->hrr_keyshare_group) { + WOLFSSL_ERROR_VERBOSE(BAD_KEY_SHARE_DATA); + return BAD_KEY_SHARE_DATA; + } + } + return 0; } diff --git a/src/tls13.c b/src/tls13.c index 6eeabb4ee..e4026c852 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -7475,6 +7475,15 @@ int SendTls13ServerHello(WOLFSSL* ssl, byte extMsgType) if (ret != 0) return ret; + if (extMsgType == hello_retry_request) { + TLSX* ksExt = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE); + if (ksExt != NULL) { + KeyShareEntry* kse = (KeyShareEntry*)ksExt->data; + if (kse != NULL) + ssl->hrr_keyshare_group = kse->group; + } + } + #ifdef WOLFSSL_SEND_HRR_COOKIE if (ssl->options.sendCookie && extMsgType == hello_retry_request) { /* Reset the hashes from here. We will be able to restart the hashes diff --git a/tests/api.c b/tests/api.c index 631675c24..59ee2f423 100644 --- a/tests/api.c +++ b/tests/api.c @@ -268,7 +268,7 @@ #endif #ifdef WOLFSSL_DUMP_MEMIO_STREAM -const char* currentTestName; +const char* currentTestName = NULL; char tmpDirName[16]; int tmpDirNameSet = 0; #endif diff --git a/tests/api/test_tls13.c b/tests/api/test_tls13.c index e79e11466..abf0e1e02 100644 --- a/tests/api/test_tls13.c +++ b/tests/api/test_tls13.c @@ -2572,3 +2572,83 @@ int test_tls13_duplicate_extension(void) } + +int test_key_share_mismatch(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_TLS13) && \ + defined(HAVE_SUPPORTED_CURVES) && defined(HAVE_ECC) && \ + defined(BUILD_TLS_AES_128_GCM_SHA256) + /* Taken from payload in https://github.com/wolfSSL/wolfssl/issues/9362 */ + const byte ch1_bin[] = { + 0x16, 0x03, 0x03, 0x00, 0x96, 0x01, 0x00, 0x00, 0x92, 0x03, 0x03, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x20, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x00, 0x02, 0x13, 0x01, 0x01, 0x00, 0x00, 0x47, + 0x00, 0x0a, 0x00, 0x08, 0x00, 0x06, 0x00, 0x18, 0x00, 0x17, 0x00, 0x1d, + 0x00, 0x0d, 0x00, 0x06, 0x00, 0x04, 0x04, 0x01, 0x08, 0x04, 0x00, 0x33, + 0x00, 0x26, 0x00, 0x24, 0x00, 0x1d, 0x00, 0x20, 0x07, 0xaa, 0xff, 0x3e, + 0x9f, 0xc1, 0x67, 0x27, 0x55, 0x44, 0xf4, 0xc3, 0xa6, 0xa1, 0x7c, 0xd8, + 0x37, 0xf2, 0xec, 0x6e, 0x78, 0xcd, 0x8a, 0x57, 0xb1, 0xe3, 0xdf, 0xb3, + 0xcc, 0x03, 0x5a, 0x76, 0x00, 0x2b, 0x00, 0x03, 0x02, 0x03, 0x04 + }; + const byte ch2_bin[] = { + 0x16, 0x03, 0x03, 0x00, 0xb7, 0x01, 0x00, 0x00, 0xb3, 0x03, 0x03, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x20, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x00, 0x02, 0x13, 0x01, 0x01, 0x00, 0x00, 0x68, + 0x00, 0x0a, 0x00, 0x08, 0x00, 0x06, 0x00, 0x18, 0x00, 0x17, 0x00, 0x1d, + 0x00, 0x0d, 0x00, 0x06, 0x00, 0x04, 0x04, 0x01, 0x08, 0x04, 0x00, 0x33, + 0x00, 0x47, 0x00, 0x45, 0x00, 0x17, 0x00, 0x41, 0x04, 0x0c, 0x90, 0x1d, + 0x42, 0x3c, 0x83, 0x1c, 0xa8, 0x5e, 0x27, 0xc7, 0x3c, 0x26, 0x3b, 0xa1, + 0x32, 0x72, 0x1b, 0xb9, 0xd7, 0xa8, 0x4c, 0x4f, 0x03, 0x80, 0xb2, 0xa6, + 0x75, 0x6f, 0xd6, 0x01, 0x33, 0x1c, 0x88, 0x70, 0x23, 0x4d, 0xec, 0x87, + 0x85, 0x04, 0xc1, 0x74, 0x14, 0x4f, 0xa4, 0xb1, 0x4b, 0x66, 0xa6, 0x51, + 0x69, 0x16, 0x06, 0xd8, 0x17, 0x3e, 0x55, 0xbd, 0x37, 0xe3, 0x81, 0x56, + 0x9e, 0x00, 0x2b, 0x00, 0x03, 0x02, 0x03, 0x04 + }; + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + int client_group[] = {WOLFSSL_ECC_SECP521R1}; + int server_group[] = {WOLFSSL_ECC_SECP384R1, WOLFSSL_ECC_SECP256R1}; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0); + ExpectIntEQ(wolfSSL_set_groups(ssl_c, + client_group, XELEM_CNT(client_group)), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set_groups(ssl_s, + server_group, XELEM_CNT(server_group)), WOLFSSL_SUCCESS); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), BAD_KEY_SHARE_DATA); + + wolfSSL_free(ssl_s); + ssl_s = NULL; + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, NULL, &ctx_s, NULL, &ssl_s, + NULL, wolfTLSv1_3_server_method), 0); + ExpectIntEQ(wolfSSL_set_groups(ssl_s, + server_group, XELEM_CNT(server_group)), WOLFSSL_SUCCESS); + ExpectIntEQ(test_memio_inject_message(&test_ctx, 0, (const char*)ch1_bin, + sizeof(ch1_bin)), 0); + ExpectIntEQ(wolfSSL_accept(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + ExpectIntEQ(test_memio_inject_message(&test_ctx, 0, (const char*)ch2_bin, + sizeof(ch2_bin)), 0); + ExpectIntEQ(wolfSSL_accept(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), BAD_KEY_SHARE_DATA); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); +#endif + return EXPECT_RESULT(); +} diff --git a/tests/api/test_tls13.h b/tests/api/test_tls13.h index 5364e53eb..85669d818 100644 --- a/tests/api/test_tls13.h +++ b/tests/api/test_tls13.h @@ -31,6 +31,7 @@ int test_tls13_rpk_handshake(void); int test_tls13_pq_groups(void); int test_tls13_early_data(void); int test_tls13_same_ch(void); +int test_key_share_mismatch(void); int test_tls13_hrr_different_cs(void); int test_tls13_sg_missing(void); int test_tls13_ks_missing(void); @@ -47,6 +48,7 @@ int test_tls13_duplicate_extension(void); TEST_DECL_GROUP("tls13", test_tls13_hrr_different_cs), \ TEST_DECL_GROUP("tls13", test_tls13_sg_missing), \ TEST_DECL_GROUP("tls13", test_tls13_ks_missing), \ - TEST_DECL_GROUP("tls13", test_tls13_duplicate_extension) + TEST_DECL_GROUP("tls13", test_tls13_duplicate_extension), \ + TEST_DECL_GROUP("tls13", test_key_share_mismatch) #endif /* WOLFCRYPT_TEST_TLS13_H */ diff --git a/tests/utils.h b/tests/utils.h index 34ba47d34..ecc800f82 100644 --- a/tests/utils.h +++ b/tests/utils.h @@ -27,6 +27,11 @@ #ifndef TESTS_UTILS_H #define TESTS_UTILS_H +#ifdef WOLFSSL_DUMP_MEMIO_STREAM +extern char tmpDirName[16]; +extern const char* currentTestName; +#endif + #if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && \ (!defined(NO_RSA) || defined(HAVE_RPK)) && \ !defined(NO_WOLFSSL_SERVER) && !defined(NO_WOLFSSL_CLIENT) && \ diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 79182b9ea..c975865ca 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -6150,6 +6150,7 @@ struct WOLFSSL { void* session_ticket_ctx; byte expect_session_ticket; #endif + word16 hrr_keyshare_group; #endif /* HAVE_TLS_EXTENSIONS */ #ifdef HAVE_OCSP void* ocspIOCtx;