From 3f1d6eebd5c61881954ba89f232a9f7b71bfd190 Mon Sep 17 00:00:00 2001 From: Kareem Date: Thu, 17 Sep 2026 15:55:21 -0700 Subject: [PATCH 1/4] Ensure the ECDSA signature scheme is bound to the certificate curve. --- src/internal.c | 2 +- src/tls13.c | 23 +++++- tests/api/test_tls13.c | 160 +++++++++++++++++++++++++++++++++++++ tests/api/test_tls13.c.rej | 11 +++ tests/api/test_tls13.h | 4 +- wolfssl/internal.h | 5 ++ 6 files changed, 201 insertions(+), 4 deletions(-) create mode 100644 tests/api/test_tls13.c.rej diff --git a/src/internal.c b/src/internal.c index 5507c325982..e6a71dc300e 100644 --- a/src/internal.c +++ b/src/internal.c @@ -33224,7 +33224,7 @@ static int MatchSigAlgo(WOLFSSL* ssl, int hashAlgo, int sigAlgo) #if defined(HAVE_ECC) && \ ((defined(WOLFSSL_TLS13) && !defined(NO_CERTS)) || \ defined(USE_ECDSA_KEYSZ_HASH_ALGO)) -static int CmpEccStrength(int hashAlgo, int curveSz) +int CmpEccStrength(int hashAlgo, int curveSz) { int dgstSz = GetMacDigestSize((byte)hashAlgo); if (dgstSz <= 0) diff --git a/src/tls13.c b/src/tls13.c index 7ca1e3e0458..501eed632cd 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -12420,6 +12420,20 @@ static void FreeDcv13Args(WOLFSSL* ssl, void* pArgs) (void)ssl; } +#ifdef HAVE_ECC +/* An ECDSA SignatureScheme names a curve as well as a hash, so the peer key + * has to be on the curve the announced scheme names (RFC 8446 4.4.3). + * + * returns 1 when the peer key's group agrees with the announced hash. */ +static int EccPeerCurveMatchesSigAlgo(WOLFSSL* ssl) +{ + if ((ssl->peerEccDsaKey == NULL) || (ssl->peerEccDsaKey->dp == NULL)) + return 0; + return CmpEccStrength(ssl->options.peerHashAlgo, + ssl->peerEccDsaKey->dp->size) == 0; +} +#endif /* HAVE_ECC */ + #ifdef WOLFSSL_DUAL_ALG_CERTS #ifndef NO_RSA /* ssl->peerCert->sapkiDer is the alternative public key. Hopefully it is a @@ -12828,14 +12842,16 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, if (ssl->options.peerSigAlgo == ecc_dsa_sa_algo) { WOLFSSL_MSG("Peer sent ECC sig"); validSigAlgo = (ssl->peerEccDsaKey != NULL) && - ssl->peerEccDsaKeyPresent; + ssl->peerEccDsaKeyPresent && + EccPeerCurveMatchesSigAlgo(ssl); } #endif #if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3) if (ssl->options.peerSigAlgo == sm2_sa_algo) { WOLFSSL_MSG("Peer sent SM2 sig"); validSigAlgo = (ssl->peerEccDsaKey != NULL) && - ssl->peerEccDsaKeyPresent; + ssl->peerEccDsaKeyPresent && + EccPeerCurveMatchesSigAlgo(ssl); } #endif #ifdef HAVE_FALCON @@ -13260,6 +13276,9 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, if ((args->altSigAlgo == ecc_dsa_sa_algo) && (ssl->peerEccDsaKeyPresent)) { WOLFSSL_MSG("Doing ECC peer cert alt verify"); + if (!EccPeerCurveMatchesSigAlgo(ssl)) { + ERROR_OUT(SIG_VERIFY_E, exit_dcv); + } ret = EccVerify(ssl, sig, args->altSignatureSz, args->altSigData, args->altSigDataSz, ssl->peerEccDsaKey, diff --git a/tests/api/test_tls13.c b/tests/api/test_tls13.c index 23247f69fde..b47ba9344e6 100644 --- a/tests/api/test_tls13.c +++ b/tests/api/test_tls13.c @@ -13979,3 +13979,163 @@ int test_tls13_psk_key_zeroized(void) #endif return EXPECT_RESULT(); } + +/* A TLS 1.3 ECDSA SignatureScheme names a curve as well as a hash + * (RFC 8446 4.4.3), so the receiver must check the peer key's curve against + * the announced scheme. Both directions are covered: the server's + * CertificateVerify and, under mutual TLS, the client's. */ +int test_tls13_ecdsa_scheme_curve_binding(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_TLS13) && defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \ + defined(HAVE_ECC) && !defined(NO_ECC256) && !defined(NO_SHA256) && \ + (defined(HAVE_ALL_CURVES) || defined(HAVE_ECC521)) && \ + defined(WOLFSSL_SHA512) && defined(OPENSSL_EXTRA) && \ + defined(WOLFSSL_PEM_TO_DER) && \ + !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \ + !defined(NO_CERTS) && !defined(NO_FILESYSTEM) + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + const char* p521Cert = "./certs/p521/server-p521.pem"; + const char* p521Key = "./certs/p521/server-p521-priv.pem"; + const char* p521Ca = "./certs/p521/ca-p521.pem"; + + /* Sanity: the P-256 server certificate authenticates under the scheme that + * names its own curve, ecdsa_secp256r1_sha256. */ + 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_CTX_load_verify_locations(ctx_c, caEccCertFile, NULL), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_use_certificate_file(ssl_s, eccCertFile, CERT_FILETYPE), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_use_PrivateKey_file(ssl_s, eccKeyFile, CERT_FILETYPE), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set1_sigalgs_list(ssl_c, "ECDSA+SHA256"), + WOLFSSL_SUCCESS); + ExpectIntEQ(ssl_c->suites->hashSigAlgoSz, 2); + ExpectIntEQ(ssl_c->suites->hashSigAlgo[0], sha256_mac); + ExpectIntEQ(ssl_c->suites->hashSigAlgo[1], ecc_dsa_sa_algo); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectIntEQ(ssl_c->options.peerSigAlgo, ecc_dsa_sa_algo); + ExpectIntEQ(ssl_c->options.peerHashAlgo, sha256_mac); + ExpectIntEQ(ssl_c->options.peerAuthGood, 1); + + wolfSSL_free(ssl_c); ssl_c = NULL; + wolfSSL_free(ssl_s); ssl_s = NULL; + wolfSSL_CTX_free(ctx_c); ctx_c = NULL; + wolfSSL_CTX_free(ctx_s); ctx_s = NULL; + + /* Sanity: a P-521 certificate authenticates under ecdsa_secp521r1_sha512, + * the only scheme this client offers. */ + 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_CTX_load_verify_locations(ctx_c, p521Ca, NULL), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_use_certificate_file(ssl_s, p521Cert, + WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_use_PrivateKey_file(ssl_s, p521Key, + WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set1_sigalgs_list(ssl_c, "ECDSA+SHA512"), + WOLFSSL_SUCCESS); + ExpectIntEQ(ssl_c->suites->hashSigAlgoSz, 2); + ExpectIntEQ(ssl_c->suites->hashSigAlgo[0], sha512_mac); + ExpectIntEQ(ssl_c->suites->hashSigAlgo[1], ecc_dsa_sa_algo); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectIntEQ(ssl_c->options.peerSigAlgo, ecc_dsa_sa_algo); + ExpectIntEQ(ssl_c->options.peerHashAlgo, sha512_mac); + ExpectIntEQ(ssl_c->options.peerAuthGood, 1); + + wolfSSL_free(ssl_c); ssl_c = NULL; + wolfSSL_free(ssl_s); ssl_s = NULL; + wolfSSL_CTX_free(ctx_c); ctx_c = NULL; + wolfSSL_CTX_free(ctx_s); ctx_s = NULL; + + /* Control: the same client policy against the P-256 certificate. The + * server finds no scheme it can use for that key, so the handshake never + * reaches CertificateVerify. */ + 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_CTX_load_verify_locations(ctx_c, caEccCertFile, NULL), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_use_certificate_file(ssl_s, eccCertFile, CERT_FILETYPE), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_use_PrivateKey_file(ssl_s, eccKeyFile, CERT_FILETYPE), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set1_sigalgs_list(ssl_c, "ECDSA+SHA512"), + WOLFSSL_SUCCESS); + ExpectIntNE(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectIntEQ(ssl_s->error, WC_NO_ERR_TRACE(MATCH_SUITE_ERROR)); + + wolfSSL_free(ssl_c); ssl_c = NULL; + wolfSSL_free(ssl_s); ssl_s = NULL; + wolfSSL_CTX_free(ctx_c); ctx_c = NULL; + wolfSSL_CTX_free(ctx_s); ctx_s = NULL; + + /* Server CertificateVerify. Overriding the key size the sender pairs its + * digest against makes it announce ecdsa_secp521r1_sha512 over a P-256 + * key. The certificate, the chain and the signature are all internally + * consistent, so only the curve check can reject it. */ + 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_CTX_load_verify_locations(ctx_c, caEccCertFile, NULL), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_use_certificate_file(ssl_s, eccCertFile, CERT_FILETYPE), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_use_PrivateKey_file(ssl_s, eccKeyFile, CERT_FILETYPE), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set1_sigalgs_list(ssl_c, "ECDSA+SHA512"), + WOLFSSL_SUCCESS); + if (EXPECT_SUCCESS()) + ssl_s->buffers.keySz = 66; + ExpectIntNE(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectIntEQ(ssl_c->error, WC_NO_ERR_TRACE(SIG_VERIFY_E)); + ExpectIntEQ(ssl_c->options.peerAuthGood, 0); + + wolfSSL_free(ssl_c); ssl_c = NULL; + wolfSSL_free(ssl_s); ssl_s = NULL; + wolfSSL_CTX_free(ctx_c); ctx_c = NULL; + wolfSSL_CTX_free(ctx_s); ctx_s = NULL; + + /* Client CertificateVerify under mutual TLS. The server holds a P-521 + * certificate and restricts its CertificateRequest to + * ecdsa_secp521r1_sha512; the client answers with a P-256 certificate + * under that label. */ + 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_CTX_load_verify_locations(ctx_c, p521Ca, NULL), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_use_certificate_file(ssl_s, p521Cert, + WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_use_PrivateKey_file(ssl_s, p521Key, + WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx_s, cliEccCertFile, NULL), + WOLFSSL_SUCCESS); + if (EXPECT_SUCCESS()) { + wolfSSL_set_verify(ssl_s, + WOLFSSL_VERIFY_PEER | WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); + } + ExpectIntEQ(wolfSSL_set1_sigalgs_list(ssl_s, "ECDSA+SHA512"), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_use_certificate_file(ssl_c, cliEccCertFile, + CERT_FILETYPE), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_use_PrivateKey_file(ssl_c, cliEccKeyFile, + CERT_FILETYPE), WOLFSSL_SUCCESS); + if (EXPECT_SUCCESS()) + ssl_c->buffers.keySz = 66; + ExpectIntNE(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectIntEQ(ssl_s->error, WC_NO_ERR_TRACE(SIG_VERIFY_E)); + ExpectIntEQ(ssl_s->options.peerAuthGood, 0); + + wolfSSL_free(ssl_c); ssl_c = NULL; + wolfSSL_free(ssl_s); ssl_s = NULL; + wolfSSL_CTX_free(ctx_c); ctx_c = NULL; + wolfSSL_CTX_free(ctx_s); ctx_s = NULL; +#endif + return EXPECT_RESULT(); +} diff --git a/tests/api/test_tls13.c.rej b/tests/api/test_tls13.c.rej new file mode 100644 index 00000000000..e4fa14cf9f4 --- /dev/null +++ b/tests/api/test_tls13.c.rej @@ -0,0 +1,11 @@ +--- tests/api/test_tls13.c ++++ tests/api/test_tls13.c +@@ -13685,7 +13685,7 @@ static void test_tls13_cks_free_cb(void* ptr) + int test_tls13_cks_hrr_reparse(void) + { + EXPECT_DECLS; +-#ifdef TEST_TLS13_CKS_REPARSE ++#if defined(TEST_TLS13_CKS_REPARSE) && defined(USE_WOLFSSL_MEMORY) + WOLFSSL_CTX *ctx_c = NULL; + WOLFSSL_CTX *ctx_s = NULL; + WOLFSSL *ssl_c = NULL; diff --git a/tests/api/test_tls13.h b/tests/api/test_tls13.h index e81a98c2268..8126f4882c3 100644 --- a/tests/api/test_tls13.h +++ b/tests/api/test_tls13.h @@ -154,6 +154,7 @@ int test_tls13_cryptocb_async(void); int test_tls13_ticket_psk_modes(void); int test_tls13_psk_mode_mismatch_falls_back(void); int test_tls13_ticket_psk_modes_uses_policy(void); +int test_tls13_ecdsa_scheme_curve_binding(void); int test_tls13_send_session_ticket_psk_modes(void); int test_tls13_new_session_ticket_ext_framing(void); int test_tls13_new_session_ticket_keeps_ems(void); @@ -302,6 +303,7 @@ int test_tls13_psk_key_zeroized(void); TEST_DECL_GROUP("tls13", test_tls13_hs_secret_zeroized_psk_ke), \ TEST_DECL_GROUP("tls13", test_tls13_hs_secret_zeroized_sha384), \ TEST_DECL_GROUP("tls13", test_tls13_early_secret_zeroized), \ - TEST_DECL_GROUP("tls13", test_tls13_psk_key_zeroized) + TEST_DECL_GROUP("tls13", test_tls13_psk_key_zeroized), \ + TEST_DECL_GROUP("tls13", test_tls13_ecdsa_scheme_curve_binding) #endif /* WOLFCRYPT_TEST_TLS13_H */ diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 1ffeac00b5c..fe8840bbbad 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -2574,6 +2574,11 @@ WOLFSSL_TEST_VIS void InitSuitesHashSigAlgo(byte* hashSigAlgo, int have, WOLFSSL_LOCAL int AllocateCtxSuites(WOLFSSL_CTX* ctx); WOLFSSL_LOCAL int InitCtxSuitesWithMutex(WOLFSSL_CTX* ctx); WOLFSSL_LOCAL int AllocateSuites(WOLFSSL* ssl); +#if defined(HAVE_ECC) && \ + ((defined(WOLFSSL_TLS13) && !defined(NO_CERTS)) || \ + defined(USE_ECDSA_KEYSZ_HASH_ALGO)) +WOLFSSL_LOCAL int CmpEccStrength(int hashAlgo, int curveSz); +#endif WOLFSSL_LOCAL void InitSuites(Suites* suites, ProtocolVersion pv, int keySz, word16 haveRSA, word16 havePSK, word16 haveDH, word16 haveECDSAsig, word16 haveECC, From 2e8dd860d8e77e6faeeb442a04983f0bf75f3ff3 Mon Sep 17 00:00:00 2001 From: Kareem Date: Thu, 17 Sep 2026 16:04:45 -0700 Subject: [PATCH 2/4] Ensure MFL is always validated in TLS 1.3, even with WOLFSSL_OLD_UNSUPPORTED_EXTENSION defined. Fixes F-11837. --- src/tls.c | 5 ++-- tests/api/test_tls_parse.c | 55 +++++++++++++++++++++++++++++++++++--- 2 files changed, 55 insertions(+), 5 deletions(-) diff --git a/src/tls.c b/src/tls.c index 2dec929827f..13447e4ceb3 100644 --- a/src/tls.c +++ b/src/tls.c @@ -3321,9 +3321,11 @@ static int TLSX_MFL_Parse(WOLFSSL* ssl, const byte* input, word16 length, return BUFFER_ERROR; #ifdef WOLFSSL_OLD_UNSUPPORTED_EXTENSION - (void) isRequest; + /* Legacy lenient handling applies to TLS 1.2 and earlier only. */ + if (!isRequest && IsAtLeastTLSv1_3(ssl->version)) { #else if (!isRequest) { +#endif TLSX* extension; if (TLSX_CheckUnsupportedExtension(ssl, TLSX_MAX_FRAGMENT_LENGTH)) @@ -3344,7 +3346,6 @@ static int TLSX_MFL_Parse(WOLFSSL* ssl, const byte* input, word16 length, return UNKNOWN_MAX_FRAG_LEN_E; } } -#endif switch (*input) { case WOLFSSL_MFL_2_8 : ssl->max_fragment = 256; break; diff --git a/tests/api/test_tls_parse.c b/tests/api/test_tls_parse.c index e8291b978bd..7099927cb1a 100644 --- a/tests/api/test_tls_parse.c +++ b/tests/api/test_tls_parse.c @@ -696,14 +696,16 @@ int test_TLSX_EncryptThenMac_parse(void) int test_TLSX_MFL_parse(void) { EXPECT_DECLS; -#if defined(HAVE_MAX_FRAGMENT) && !defined(WOLFSSL_OLD_UNSUPPORTED_EXTENSION) && !defined(NO_TLS) && !defined(NO_WOLFSSL_CLIENT) && \ - defined(HAVE_TLS_EXTENSIONS) && \ - !defined(WOLFSSL_NO_TLS12) +#if defined(HAVE_MAX_FRAGMENT) && !defined(NO_TLS) && \ + !defined(NO_WOLFSSL_CLIENT) && defined(HAVE_TLS_EXTENSIONS) && \ + ((!defined(WOLFSSL_OLD_UNSUPPORTED_EXTENSION) && \ + !defined(WOLFSSL_NO_TLS12)) || defined(WOLFSSL_TLS13)) WOLFSSL_CTX* ctx = NULL; WOLFSSL* ssl = NULL; byte ext[8]; word16 extLen; +#if !defined(WOLFSSL_OLD_UNSUPPORTED_EXTENSION) && !defined(WOLFSSL_NO_TLS12) /* Client did not request MFL: any server_hello response is flagged as * an unrequested extension before the value is even looked at. */ ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method())); @@ -740,6 +742,53 @@ int test_TLSX_MFL_parse(void) } wolfSSL_free(ssl); wolfSSL_CTX_free(ctx); +#endif /* !WOLFSSL_OLD_UNSUPPORTED_EXTENSION && !WOLFSSL_NO_TLS12 */ + +#ifdef WOLFSSL_TLS13 + /* TLS 1.3 (RFC 8446 Section 4.2): a response the client did not request + * is rejected in encrypted_extensions, also when the legacy TLS 1.2 + * handling is compiled in. */ + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + if (ssl != NULL) { + const byte resp[] = { WOLFSSL_MFL_2_9 }; + extLen = test_tls_parse_build_ext(ext, sizeof(ext), + TLSXT_MAX_FRAGMENT_LENGTH, resp, (word16)sizeof(resp)); + ExpectIntEQ(TLSX_Parse(ssl, ext, extLen, encrypted_extensions, NULL), + WC_NO_ERR_TRACE(UNSUPPORTED_EXTENSION)); + ExpectIntEQ(ssl->max_fragment, MAX_RECORD_SIZE); + } + wolfSSL_free(ssl); + ssl = NULL; + wolfSSL_CTX_free(ctx); + ctx = NULL; + + /* Client requested MFL_2_9: a mismatching response is rejected and + * leaves the fragment size alone, the same value is applied. */ + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + if (ssl != NULL) { + const byte mismatch[] = { WOLFSSL_MFL_2_10 }; + const byte match[] = { WOLFSSL_MFL_2_9 }; + + ExpectIntEQ(wolfSSL_UseMaxFragment(ssl, WOLFSSL_MFL_2_9), + WOLFSSL_SUCCESS); + + extLen = test_tls_parse_build_ext(ext, sizeof(ext), + TLSXT_MAX_FRAGMENT_LENGTH, mismatch, (word16)sizeof(mismatch)); + ExpectIntEQ(TLSX_Parse(ssl, ext, extLen, encrypted_extensions, NULL), + WC_NO_ERR_TRACE(UNKNOWN_MAX_FRAG_LEN_E)); + ExpectIntEQ(ssl->max_fragment, MAX_RECORD_SIZE); + + extLen = test_tls_parse_build_ext(ext, sizeof(ext), + TLSXT_MAX_FRAGMENT_LENGTH, match, (word16)sizeof(match)); + ExpectIntEQ(TLSX_Parse(ssl, ext, extLen, encrypted_extensions, NULL), + 0); + ExpectIntEQ(ssl->max_fragment, 512); + } + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif /* WOLFSSL_TLS13 */ #endif return EXPECT_RESULT(); } From 6206b86cbae2bc15550637b77a4725ddcf69bd8a Mon Sep 17 00:00:00 2001 From: Kareem Date: Thu, 17 Sep 2026 20:17:53 -0700 Subject: [PATCH 3/4] Improve ECDSA curve check. --- src/tls13.c | 122 ++++++++++++++++++++++++++++++++++++----- tests/api/test_tls13.c | 51 +++++++++++++++++ 2 files changed, 158 insertions(+), 15 deletions(-) diff --git a/src/tls13.c b/src/tls13.c index 501eed632cd..29c4ce96173 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -9591,27 +9591,59 @@ static enum wc_MACAlgorithm GetNewSAHashAlgo(int typeIn) } } +#ifdef HAVE_ECC +/* Curve the ECDSA signature schemes pair with each hash (RFC 8446 4.2.3). */ +static WC_INLINE int EccCurveFromHashAlgo(byte hashAlgo) +{ + switch (hashAlgo) { +#ifndef NO_SHA256 + case sha256_mac: + return ECC_SECP256R1; +#endif +#ifdef WOLFSSL_SHA384 + case sha384_mac: + return ECC_SECP384R1; +#endif +#ifdef WOLFSSL_SHA512 + case sha512_mac: + return ECC_SECP521R1; +#endif + default: + return ECC_CURVE_INVALID; + } +} +#endif /* HAVE_ECC */ + /* Decode the signature algorithm. * * input The encoded signature algorithm. * hashalgo The hash algorithm. * hsType The signature type. + * eccCurve Curve the scheme names, ECC_CURVE_INVALID if it names none. * returns INVALID_PARAMETER if not recognized and 0 otherwise. */ static WC_INLINE int DecodeTls13SigAlg(byte* input, byte* hashAlgo, - byte* hsType) + byte* hsType, int* eccCurve) { int ret = 0; #if defined(WOLFSSL_HAVE_SLHDSA) byte slhType; #endif +#ifdef HAVE_ECC + /* Set by the arms whose scheme names a curve. */ + *eccCurve = ECC_CURVE_INVALID; +#else + (void)eccCurve; +#endif + switch (input[0]) { #if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3) case SM2_SA_MAJOR: if (input[1] == SM2_SA_MINOR) { *hsType = sm2_sa_algo; *hashAlgo = sm3_mac; + *eccCurve = ECC_SM2P256V1; } else ret = INVALID_PARAMETER; @@ -9648,10 +9680,18 @@ static WC_INLINE int DecodeTls13SigAlg(byte* input, byte* hashAlgo, } #endif #ifdef HAVE_ECC_BRAINPOOL - else if ((input[1] == ECDSA_BRAINPOOLP256R1TLS13_SHA256_MINOR) || - (input[1] == ECDSA_BRAINPOOLP384R1TLS13_SHA384_MINOR) || - (input[1] == ECDSA_BRAINPOOLP512R1TLS13_SHA512_MINOR)) { + /* RFC 8734 3: each of these names its own curve. */ + else if (input[1] == ECDSA_BRAINPOOLP256R1TLS13_SHA256_MINOR) { *hsType = ecc_dsa_sa_algo; + *eccCurve = ECC_BRAINPOOLP256R1; + } + else if (input[1] == ECDSA_BRAINPOOLP384R1TLS13_SHA384_MINOR) { + *hsType = ecc_dsa_sa_algo; + *eccCurve = ECC_BRAINPOOLP384R1; + } + else if (input[1] == ECDSA_BRAINPOOLP512R1TLS13_SHA512_MINOR) { + *hsType = ecc_dsa_sa_algo; + *eccCurve = ECC_BRAINPOOLP512R1; } #endif else @@ -9709,6 +9749,12 @@ static WC_INLINE int DecodeTls13SigAlg(byte* input, byte* hashAlgo, default: *hashAlgo = input[0]; *hsType = input[1]; +#ifdef HAVE_ECC + /* RFC 8446 4.2.3: each ECDSA scheme pairs one curve with one + * hash. The hybrid schemes below name these same curves. */ + if (*hsType == ecc_dsa_sa_algo) + *eccCurve = EccCurveFromHashAlgo(*hashAlgo); +#endif break; } @@ -9724,7 +9770,8 @@ static WC_INLINE int DecodeTls13SigAlg(byte* input, byte* hashAlgo, * returns INVALID_PARAMETER if not recognized and 0 otherwise. */ static WC_INLINE int DecodeTls13HybridSigAlg(byte* input, byte* hashAlg, - byte *sigAlg, byte *altSigAlg) + byte *sigAlg, byte *altSigAlg, + int* eccCurve) { if (input[0] != HYBRID_SA_MAJOR) { @@ -9805,6 +9852,14 @@ static WC_INLINE int DecodeTls13HybridSigAlg(byte* input, byte* hashAlg, return INVALID_PARAMETER; } +#ifdef HAVE_ECC + /* Every hybrid scheme naming an ECDSA curve pairs it with the same hash + * the ECDSA schemes do. */ + *eccCurve = EccCurveFromHashAlgo(*hashAlg); +#else + (void)eccCurve; +#endif + return 0; } #endif /* WOLFSSL_DUAL_ALG_CERTS */ @@ -12421,16 +12476,46 @@ static void FreeDcv13Args(WOLFSSL* ssl, void* pArgs) } #ifdef HAVE_ECC +/* Whether some signature scheme names this curve. EncodeSigAlg only has a + * scheme of its own for these; a key on any other curve is sent under the + * plain ECDSA scheme matching its size. */ +static int EccCurveHasSigAlgo(int curveId) +{ + switch (curveId) { + case ECC_SECP256R1: + case ECC_SECP384R1: + case ECC_SECP521R1: +#ifdef HAVE_ECC_BRAINPOOL + case ECC_BRAINPOOLP256R1: + case ECC_BRAINPOOLP384R1: + case ECC_BRAINPOOLP512R1: +#endif +#if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3) + case ECC_SM2P256V1: +#endif + return 1; + default: + return 0; + } +} + /* An ECDSA SignatureScheme names a curve as well as a hash, so the peer key * has to be on the curve the announced scheme names (RFC 8446 4.4.3). + * expCurve is that curve, as reported by the signature algorithm decoder. * - * returns 1 when the peer key's group agrees with the announced hash. */ -static int EccPeerCurveMatchesSigAlgo(WOLFSSL* ssl) + * A curve no scheme names is only ever sent under the plain ECDSA scheme for + * its size, so those are held to the size alone. + * + * returns 1 when the peer key's curve agrees with the announced scheme. */ +static int EccPeerCurveMatchesSigAlgo(WOLFSSL* ssl, int expCurve) { - if ((ssl->peerEccDsaKey == NULL) || (ssl->peerEccDsaKey->dp == NULL)) + ecc_key* key = ssl->peerEccDsaKey; + + if ((key == NULL) || (key->dp == NULL)) return 0; - return CmpEccStrength(ssl->options.peerHashAlgo, - ssl->peerEccDsaKey->dp->size) == 0; + if (EccCurveHasSigAlgo(key->dp->id)) + return key->dp->id == expCurve; + return CmpEccStrength(ssl->options.peerHashAlgo, key->dp->size) == 0; } #endif /* HAVE_ECC */ @@ -12639,6 +12724,10 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, int validSigAlgo; const Suites* suites = WOLFSSL_SUITES(ssl); word16 i; + /* Curve the announced scheme names; ECC_CURVE_INVALID (-1) when + * it names none. Declared even without ECC built, as the decoders + * take its address. */ + int expEccCurve = -1; /* Signature algorithm. */ if ((args->idx - args->begin) + ENUM_LEN + ENUM_LEN > totalSz) { @@ -12674,14 +12763,15 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, } ret = DecodeTls13SigAlg(input + args->idx, - &ssl->options.peerHashAlgo, &ssl->options.peerSigAlgo); + &ssl->options.peerHashAlgo, &ssl->options.peerSigAlgo, + &expEccCurve); #ifdef WOLFSSL_DUAL_ALG_CERTS } else { ret = DecodeTls13HybridSigAlg(input + args->idx, &ssl->options.peerHashAlgo, &ssl->options.peerSigAlgo, - &args->altSigAlgo); + &args->altSigAlgo, &expEccCurve); } #endif /* WOLFSSL_DUAL_ALG_CERTS */ @@ -12843,7 +12933,7 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, WOLFSSL_MSG("Peer sent ECC sig"); validSigAlgo = (ssl->peerEccDsaKey != NULL) && ssl->peerEccDsaKeyPresent && - EccPeerCurveMatchesSigAlgo(ssl); + EccPeerCurveMatchesSigAlgo(ssl, expEccCurve); } #endif #if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3) @@ -12851,7 +12941,7 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, WOLFSSL_MSG("Peer sent SM2 sig"); validSigAlgo = (ssl->peerEccDsaKey != NULL) && ssl->peerEccDsaKeyPresent && - EccPeerCurveMatchesSigAlgo(ssl); + EccPeerCurveMatchesSigAlgo(ssl, expEccCurve); } #endif #ifdef HAVE_FALCON @@ -13276,7 +13366,9 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, if ((args->altSigAlgo == ecc_dsa_sa_algo) && (ssl->peerEccDsaKeyPresent)) { WOLFSSL_MSG("Doing ECC peer cert alt verify"); - if (!EccPeerCurveMatchesSigAlgo(ssl)) { + if (!EccPeerCurveMatchesSigAlgo(ssl, + EccCurveFromHashAlgo( + ssl->options.peerHashAlgo))) { ERROR_OUT(SIG_VERIFY_E, exit_dcv); } ret = EccVerify(ssl, sig, args->altSignatureSz, diff --git a/tests/api/test_tls13.c b/tests/api/test_tls13.c index b47ba9344e6..16852c64ea3 100644 --- a/tests/api/test_tls13.c +++ b/tests/api/test_tls13.c @@ -14000,6 +14000,10 @@ int test_tls13_ecdsa_scheme_curve_binding(void) const char* p521Cert = "./certs/p521/server-p521.pem"; const char* p521Key = "./certs/p521/server-p521-priv.pem"; const char* p521Ca = "./certs/p521/ca-p521.pem"; +#ifdef HAVE_ECC_BRAINPOOL + const char* bpCert = "./certs/ecc/server-bp256r1-cert.pem"; + const char* bpKey = "./certs/ecc/bp256r1-key.pem"; +#endif /* Sanity: the P-256 server certificate authenticates under the scheme that * names its own curve, ecdsa_secp256r1_sha256. */ @@ -14136,6 +14140,53 @@ int test_tls13_ecdsa_scheme_curve_binding(void) wolfSSL_free(ssl_s); ssl_s = NULL; wolfSSL_CTX_free(ctx_c); ctx_c = NULL; wolfSSL_CTX_free(ctx_s); ctx_s = NULL; + +#ifdef HAVE_ECC_BRAINPOOL + /* Same-size curves are not interchangeable: brainpoolP256r1 has schemes of + * its own (RFC 8734), so it must not be accepted under + * ecdsa_secp256r1_sha256. Overriding the curve the sender reports for its + * own key is what makes it use the plain ECDSA scheme. The digest length + * matches the group here, so only the curve check can reject it. */ + 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_CTX_load_verify_locations(ctx_c, bpCert, NULL), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_use_certificate_file(ssl_s, bpCert, + WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_use_PrivateKey_file(ssl_s, bpKey, + WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set1_sigalgs_list(ssl_c, "ECDSA+SHA256"), + WOLFSSL_SUCCESS); + if (EXPECT_SUCCESS()) + ssl_s->pkCurveOID = ECC_SECP256R1_OID; + ExpectIntNE(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectIntEQ(ssl_c->error, WC_NO_ERR_TRACE(SIG_VERIFY_E)); + ExpectIntEQ(ssl_c->options.peerAuthGood, 0); + + wolfSSL_free(ssl_c); ssl_c = NULL; + wolfSSL_free(ssl_s); ssl_s = NULL; + wolfSSL_CTX_free(ctx_c); ctx_c = NULL; + wolfSSL_CTX_free(ctx_s); ctx_s = NULL; + + /* Control: the same certificate under its own scheme is accepted. */ + 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_CTX_load_verify_locations(ctx_c, bpCert, NULL), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_use_certificate_file(ssl_s, bpCert, + WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_use_PrivateKey_file(ssl_s, bpKey, + WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectIntEQ(ssl_c->options.peerAuthGood, 1); + + wolfSSL_free(ssl_c); ssl_c = NULL; + wolfSSL_free(ssl_s); ssl_s = NULL; + wolfSSL_CTX_free(ctx_c); ctx_c = NULL; + wolfSSL_CTX_free(ctx_s); ctx_s = NULL; +#endif /* HAVE_ECC_BRAINPOOL */ #endif return EXPECT_RESULT(); } From 8102a6adfb7dca53cee71b2029aa38fa92e30616 Mon Sep 17 00:00:00 2001 From: Kareem Date: Wed, 30 Sep 2026 16:36:35 -0700 Subject: [PATCH 4/4] Refactor code, use OID sum rather than ID to compare. Ensure sigalg matches expected sigalg for the OID sum. --- src/tls13.c | 147 ++++++++++++++++------------------------------------ 1 file changed, 44 insertions(+), 103 deletions(-) diff --git a/src/tls13.c b/src/tls13.c index 29c4ce96173..e51f3e277a6 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -9591,59 +9591,27 @@ static enum wc_MACAlgorithm GetNewSAHashAlgo(int typeIn) } } -#ifdef HAVE_ECC -/* Curve the ECDSA signature schemes pair with each hash (RFC 8446 4.2.3). */ -static WC_INLINE int EccCurveFromHashAlgo(byte hashAlgo) -{ - switch (hashAlgo) { -#ifndef NO_SHA256 - case sha256_mac: - return ECC_SECP256R1; -#endif -#ifdef WOLFSSL_SHA384 - case sha384_mac: - return ECC_SECP384R1; -#endif -#ifdef WOLFSSL_SHA512 - case sha512_mac: - return ECC_SECP521R1; -#endif - default: - return ECC_CURVE_INVALID; - } -} -#endif /* HAVE_ECC */ - /* Decode the signature algorithm. * * input The encoded signature algorithm. * hashalgo The hash algorithm. * hsType The signature type. - * eccCurve Curve the scheme names, ECC_CURVE_INVALID if it names none. * returns INVALID_PARAMETER if not recognized and 0 otherwise. */ static WC_INLINE int DecodeTls13SigAlg(byte* input, byte* hashAlgo, - byte* hsType, int* eccCurve) + byte* hsType) { int ret = 0; #if defined(WOLFSSL_HAVE_SLHDSA) byte slhType; #endif -#ifdef HAVE_ECC - /* Set by the arms whose scheme names a curve. */ - *eccCurve = ECC_CURVE_INVALID; -#else - (void)eccCurve; -#endif - switch (input[0]) { #if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3) case SM2_SA_MAJOR: if (input[1] == SM2_SA_MINOR) { *hsType = sm2_sa_algo; *hashAlgo = sm3_mac; - *eccCurve = ECC_SM2P256V1; } else ret = INVALID_PARAMETER; @@ -9680,18 +9648,10 @@ static WC_INLINE int DecodeTls13SigAlg(byte* input, byte* hashAlgo, } #endif #ifdef HAVE_ECC_BRAINPOOL - /* RFC 8734 3: each of these names its own curve. */ - else if (input[1] == ECDSA_BRAINPOOLP256R1TLS13_SHA256_MINOR) { - *hsType = ecc_dsa_sa_algo; - *eccCurve = ECC_BRAINPOOLP256R1; - } - else if (input[1] == ECDSA_BRAINPOOLP384R1TLS13_SHA384_MINOR) { - *hsType = ecc_dsa_sa_algo; - *eccCurve = ECC_BRAINPOOLP384R1; - } - else if (input[1] == ECDSA_BRAINPOOLP512R1TLS13_SHA512_MINOR) { + else if ((input[1] == ECDSA_BRAINPOOLP256R1TLS13_SHA256_MINOR) || + (input[1] == ECDSA_BRAINPOOLP384R1TLS13_SHA384_MINOR) || + (input[1] == ECDSA_BRAINPOOLP512R1TLS13_SHA512_MINOR)) { *hsType = ecc_dsa_sa_algo; - *eccCurve = ECC_BRAINPOOLP512R1; } #endif else @@ -9749,12 +9709,6 @@ static WC_INLINE int DecodeTls13SigAlg(byte* input, byte* hashAlgo, default: *hashAlgo = input[0]; *hsType = input[1]; -#ifdef HAVE_ECC - /* RFC 8446 4.2.3: each ECDSA scheme pairs one curve with one - * hash. The hybrid schemes below name these same curves. */ - if (*hsType == ecc_dsa_sa_algo) - *eccCurve = EccCurveFromHashAlgo(*hashAlgo); -#endif break; } @@ -9770,8 +9724,7 @@ static WC_INLINE int DecodeTls13SigAlg(byte* input, byte* hashAlgo, * returns INVALID_PARAMETER if not recognized and 0 otherwise. */ static WC_INLINE int DecodeTls13HybridSigAlg(byte* input, byte* hashAlg, - byte *sigAlg, byte *altSigAlg, - int* eccCurve) + byte *sigAlg, byte *altSigAlg) { if (input[0] != HYBRID_SA_MAJOR) { @@ -9852,14 +9805,6 @@ static WC_INLINE int DecodeTls13HybridSigAlg(byte* input, byte* hashAlg, return INVALID_PARAMETER; } -#ifdef HAVE_ECC - /* Every hybrid scheme naming an ECDSA curve pairs it with the same hash - * the ECDSA schemes do. */ - *eccCurve = EccCurveFromHashAlgo(*hashAlg); -#else - (void)eccCurve; -#endif - return 0; } #endif /* WOLFSSL_DUAL_ALG_CERTS */ @@ -12476,46 +12421,41 @@ static void FreeDcv13Args(WOLFSSL* ssl, void* pArgs) } #ifdef HAVE_ECC -/* Whether some signature scheme names this curve. EncodeSigAlg only has a - * scheme of its own for these; a key on any other curve is sent under the - * plain ECDSA scheme matching its size. */ -static int EccCurveHasSigAlgo(int curveId) -{ - switch (curveId) { - case ECC_SECP256R1: - case ECC_SECP384R1: - case ECC_SECP521R1: -#ifdef HAVE_ECC_BRAINPOOL - case ECC_BRAINPOOLP256R1: - case ECC_BRAINPOOLP384R1: - case ECC_BRAINPOOLP512R1: -#endif -#if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3) - case ECC_SM2P256V1: -#endif - return 1; - default: - return 0; - } -} - /* An ECDSA SignatureScheme names a curve as well as a hash, so the peer key * has to be on the curve the announced scheme names (RFC 8446 4.4.3). - * expCurve is that curve, as reported by the signature algorithm decoder. - * - * A curve no scheme names is only ever sent under the plain ECDSA scheme for - * its size, so those are held to the size alone. * - * returns 1 when the peer key's curve agrees with the announced scheme. */ -static int EccPeerCurveMatchesSigAlgo(WOLFSSL* ssl, int expCurve) + * returns 1 when the peer key's group agrees with the announced hash. */ +static int EccPeerCurveMatchesSigAlgo(WOLFSSL* ssl, byte hashAlgo, + byte sigAlgo) { ecc_key* key = ssl->peerEccDsaKey; if ((key == NULL) || (key->dp == NULL)) return 0; - if (EccCurveHasSigAlgo(key->dp->id)) - return key->dp->id == expCurve; - return CmpEccStrength(ssl->options.peerHashAlgo, key->dp->size) == 0; + + /* A curve with a scheme of its own has to be used with it, or a same + * sized curve would satisfy any of them. */ +#ifdef HAVE_ECC_BRAINPOOL + if ((key->dp->oidSum == ECC_BRAINPOOLP256R1_OID) || + (key->dp->oidSum == ECC_BRAINPOOLP384R1_OID) || + (key->dp->oidSum == ECC_BRAINPOOLP512R1_OID)) { + if (sigAlgo != ecc_brainpool_sa_algo) + return 0; + } + else +#endif +#if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3) + if (key->dp->oidSum == ECC_SM2P256V1_OID) { + if (sigAlgo != sm2_sa_algo) + return 0; + } + else +#endif + if (sigAlgo != ecc_dsa_sa_algo) { + return 0; + } + + return CmpEccStrength(hashAlgo, key->dp->size) == 0; } #endif /* HAVE_ECC */ @@ -12724,10 +12664,6 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, int validSigAlgo; const Suites* suites = WOLFSSL_SUITES(ssl); word16 i; - /* Curve the announced scheme names; ECC_CURVE_INVALID (-1) when - * it names none. Declared even without ECC built, as the decoders - * take its address. */ - int expEccCurve = -1; /* Signature algorithm. */ if ((args->idx - args->begin) + ENUM_LEN + ENUM_LEN > totalSz) { @@ -12763,15 +12699,14 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, } ret = DecodeTls13SigAlg(input + args->idx, - &ssl->options.peerHashAlgo, &ssl->options.peerSigAlgo, - &expEccCurve); + &ssl->options.peerHashAlgo, &ssl->options.peerSigAlgo); #ifdef WOLFSSL_DUAL_ALG_CERTS } else { ret = DecodeTls13HybridSigAlg(input + args->idx, &ssl->options.peerHashAlgo, &ssl->options.peerSigAlgo, - &args->altSigAlgo, &expEccCurve); + &args->altSigAlgo); } #endif /* WOLFSSL_DUAL_ALG_CERTS */ @@ -12930,10 +12865,15 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, #endif #ifdef HAVE_ECC if (ssl->options.peerSigAlgo == ecc_dsa_sa_algo) { + byte curveHash = 0, curveSig = 0; WOLFSSL_MSG("Peer sent ECC sig"); + /* DecodeTls13SigAlg folds the brainpool schemes onto + * ecc_dsa_sa_algo; DecodeSigAlg keeps them apart. */ + DecodeSigAlg(input + args->begin, &curveHash, &curveSig); validSigAlgo = (ssl->peerEccDsaKey != NULL) && ssl->peerEccDsaKeyPresent && - EccPeerCurveMatchesSigAlgo(ssl, expEccCurve); + EccPeerCurveMatchesSigAlgo(ssl, curveHash, + curveSig); } #endif #if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3) @@ -12941,7 +12881,9 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, WOLFSSL_MSG("Peer sent SM2 sig"); validSigAlgo = (ssl->peerEccDsaKey != NULL) && ssl->peerEccDsaKeyPresent && - EccPeerCurveMatchesSigAlgo(ssl, expEccCurve); + EccPeerCurveMatchesSigAlgo(ssl, + ssl->options.peerHashAlgo, + ssl->options.peerSigAlgo); } #endif #ifdef HAVE_FALCON @@ -13367,8 +13309,7 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, (ssl->peerEccDsaKeyPresent)) { WOLFSSL_MSG("Doing ECC peer cert alt verify"); if (!EccPeerCurveMatchesSigAlgo(ssl, - EccCurveFromHashAlgo( - ssl->options.peerHashAlgo))) { + ssl->options.peerHashAlgo, ecc_dsa_sa_algo)) { ERROR_OUT(SIG_VERIFY_E, exit_dcv); } ret = EccVerify(ssl, sig, args->altSignatureSz,