From 3151993ec0fb707b4b4fd62fbd29b4a0485b12d2 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Thu, 28 May 2026 14:05:19 +0000 Subject: [PATCH] Allow RSA client certs on ECDHE-ECDSA mutual auth The TLS 1.2 server derived the single advertised ClientCertificateType and the signature_algorithms list in its CertificateRequest from the negotiated cipher suite's own signature algorithm. On an ECDHE-ECDSA suite only ecdsa_sign was offered (and only ECDSA sig algs), so RSA clients could not authenticate even though the server could happily verify an RSA certificate. The same was true in reverse for an RSA server: the CertificateRequest only advertised rsa_sign. Refactor SendCertificateRequest to advertise certificate_types and signature_algorithms covering both sig families when both are compiled in. Three static helpers in internal.c keep the logic in one place without mutating ssl->suites: GetServerCertReqCertTypes - certificate_types to emit GetServerCertReqHashSigAlgo - signature_algorithms to emit InServerCertReqHashSigAlgo - membership check used for verification The advertised lists are written to stack buffers in the caller. To keep DoCertificateVerify in agreement with what we actually sent, the SupportedHashSigAlgo call site there is replaced with InServerCertReqHashSigAlgo, which rebuilds the same list locally and looks up the client's chosen algo. Replace the magic certTypes buffer size with a new MAX_CERT_REQ_CERT_TYPE_CNT constant declared next to ClientCertificateType. Add two end-to-end mutual-auth tests covering both directions: test_tls12_ecdhe_ecdsa_rsa_client_cert - ECDSA server, RSA client test_tls12_ecdhe_rsa_ecdsa_client_cert - RSA server, ECDSA client Update test_certreq_sighash_algos to permit RSA / RSA-PSS sig algs in the ECDHE-ECDSA CertificateRequest; the previous assertion locked in the ECDSA-only behaviour that this change corrects. TLS 1.3 is unaffected: RFC 8446 removed certificate_types from CertificateRequest, and TLS 1.3 cipher suites do not bind a signature algorithm, so the server's hashSigAlgo already covers both sig families when either has been compiled in. --- src/internal.c | 200 +++++++++++++++++++++++++++++++++--------- tests/api.c | 34 ++++--- tests/api/test_tls.c | 108 +++++++++++++++++++++++ tests/api/test_tls.h | 4 + tests/test-fails.conf | 18 ---- wolfssl/internal.h | 4 + 6 files changed, 297 insertions(+), 71 deletions(-) diff --git a/src/internal.c b/src/internal.c index 75c007c657..854c0c9894 100644 --- a/src/internal.c +++ b/src/internal.c @@ -25818,6 +25818,145 @@ int SendCertificate(WOLFSSL* ssl) #if !defined(NO_TLS) +/* Returns the certificate_types this server advertises in its + * CertificateRequest. The list is broader than the negotiated cipher suite's + * own signature algorithm so a client may authenticate with a certificate of + * a different type (e.g. an RSA client on an ECDHE-ECDSA suite). */ +static int GetServerCertReqCertTypes(const WOLFSSL* ssl, byte* certTypes) +{ + int n = 0; +#ifdef HAVE_ECC + if ((ssl->options.cipherSuite0 == ECC_BYTE || + ssl->options.cipherSuite0 == CHACHA_BYTE) && + ssl->specs.sig_algo == ecc_dsa_sa_algo) { + certTypes[n++] = ecdsa_sign; + #ifndef NO_RSA + certTypes[n++] = rsa_sign; + #endif + } + else +#if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3) && \ + (defined(WOLFSSL_SM4_CBC) || defined(WOLFSSL_SM4_GCM) || \ + defined(WOLFSSL_SM4_CCM)) + if (ssl->options.cipherSuite0 == SM_BYTE && (0 + #ifdef BUILD_TLS_ECDHE_ECDSA_WITH_SM4_CBC_SM3 + || ssl->options.cipherSuite == TLS_ECDHE_ECDSA_WITH_SM4_CBC_SM3 + #endif + #ifdef BUILD_TLS_ECDHE_ECDSA_WITH_SM4_GCM_SM3 + || ssl->options.cipherSuite == TLS_ECDHE_ECDSA_WITH_SM4_GCM_SM3 + #endif + #ifdef BUILD_TLS_ECDHE_ECDSA_WITH_SM4_CCM_SM3 + || ssl->options.cipherSuite == TLS_ECDHE_ECDSA_WITH_SM4_CCM_SM3 + #endif + )) { + certTypes[n++] = ecdsa_sign; + } + else +#endif +#endif /* HAVE_ECC */ + { +#ifndef NO_RSA + certTypes[n++] = rsa_sign; +#endif +#ifdef HAVE_ECC + certTypes[n++] = ecdsa_sign; +#endif + } + return n; +} + +/* Returns the set of sig families covered by the given hash/sig algorithm + * list, as a bitmask of SIG_* values. Uses DecodeSigAlg so the NEW_SA_MAJOR + * encoding (ED25519/ED448/RSA-PSS-PSS/brainpool) is classified correctly. */ +static int HashSigAlgoCoverage(const byte* hashSigAlgo, word16 hashSigAlgoSz) +{ + int coverage = 0; + word16 j; + byte hashAlgo; + byte sigAlgo; + for (j = 0; (j + 1) < hashSigAlgoSz; j += HELLO_EXT_SIGALGO_SZ) { + DecodeSigAlg(&hashSigAlgo[j], &hashAlgo, &sigAlgo); + (void)hashAlgo; + switch (sigAlgo) { + case rsa_sa_algo: + #ifdef WC_RSA_PSS + case rsa_pss_sa_algo: + case rsa_pss_pss_algo: + #endif + coverage |= SIG_RSA; + break; + #ifdef HAVE_ECC + case ecc_dsa_sa_algo: + #ifdef HAVE_ECC_BRAINPOOL + case ecc_brainpool_sa_algo: + #endif + coverage |= SIG_ECDSA; + break; + #endif + default: + break; + } + } + return coverage; +} + +/* Builds the signature_algorithms this server advertises in its + * CertificateRequest. Respects a user-configured suites->hashSigAlgo (e.g. + * via wolfSSL_set1_sigalgs_list) and only broadens the list when one of the + * advertised certificate_types has no matching signature algorithm in the + * configured list. The result is written to the caller's buffer; no SSL + * state is modified. */ +static void GetServerCertReqHashSigAlgo(const WOLFSSL* ssl, + byte* hashSigAlgo, word16* hashSigAlgoSz) +{ + const Suites* suites = WOLFSSL_SUITES(ssl); + byte certTypes[MAX_CERT_REQ_CERT_TYPE_CNT]; + int typeTotal; + int need = 0; + int have; + int j; + word16 localSz = 0; + + typeTotal = GetServerCertReqCertTypes(ssl, certTypes); + for (j = 0; j < typeTotal; j++) { + if (certTypes[j] == rsa_sign) + need |= SIG_RSA; + else if (certTypes[j] == ecdsa_sign) + need |= SIG_ECDSA; + } + have = HashSigAlgoCoverage(suites->hashSigAlgo, suites->hashSigAlgoSz); + + if ((need & ~have) != 0) { + /* The configured list is missing signature algorithms for at least + * one of the advertised certificate_types. Build a broader list + * locally that covers every advertised type. */ + InitSuitesHashSigAlgo(hashSigAlgo, need | have, 1, 0, + ssl->buffers.keySz, &localSz); + *hashSigAlgoSz = localSz; + return; + } + + XMEMCPY(hashSigAlgo, suites->hashSigAlgo, suites->hashSigAlgoSz); + *hashSigAlgoSz = suites->hashSigAlgoSz; +} + +/* Returns 1 if algo (2 bytes) is in the server's CertificateRequest + * signature_algorithms list, 0 otherwise. Used to validate the client's + * CertificateVerify against what we actually advertised. */ +static int InServerCertReqHashSigAlgo(const WOLFSSL* ssl, const byte* algo) +{ + byte list[WOLFSSL_MAX_SIGALGO]; + word16 listSz = 0; + word16 j; + + GetServerCertReqHashSigAlgo(ssl, list, &listSz); + for (j = 0; (j + 1) < listSz; j += HELLO_EXT_SIGALGO_SZ) { + if (XMEMCMP(&list[j], algo, HELLO_EXT_SIGALGO_SZ) == 0) + return 1; + } + return 0; +} + /* handle generation of certificate_request (13) */ int SendCertificateRequest(WOLFSSL* ssl) { @@ -25829,16 +25968,24 @@ int SendCertificateRequest(WOLFSSL* ssl) #ifndef WOLFSSL_NO_CA_NAMES WOLF_STACK_OF(WOLFSSL_X509_NAME)* names; #endif - const Suites* suites = WOLFSSL_SUITES(ssl); - - int typeTotal = 1; /* only 1 for now */ - int reqSz = ENUM_LEN + typeTotal + REQ_HEADER_SZ; /* add auth later */ + byte certTypes[MAX_CERT_REQ_CERT_TYPE_CNT]; + int typeTotal; + int t; + byte localHashSigAlgo[WOLFSSL_MAX_SIGALGO]; + word16 localHashSigAlgoSz = 0; + int reqSz; WOLFSSL_START(WC_FUNC_CERTIFICATE_REQUEST_SEND); WOLFSSL_ENTER("SendCertificateRequest"); + typeTotal = GetServerCertReqCertTypes(ssl, certTypes); + if (IsAtLeastTLSv1_2(ssl)) + GetServerCertReqHashSigAlgo(ssl, localHashSigAlgo, &localHashSigAlgoSz); + + reqSz = ENUM_LEN + typeTotal + REQ_HEADER_SZ; /* add auth later */ + if (IsAtLeastTLSv1_2(ssl)) - reqSz += LENGTH_SZ + suites->hashSigAlgoSz; + reqSz += LENGTH_SZ + localHashSigAlgoSz; #ifndef WOLFSSL_NO_CA_NAMES /* Certificate Authorities */ @@ -25891,43 +26038,16 @@ int SendCertificateRequest(WOLFSSL* ssl) /* write to output */ output[i++] = (byte)typeTotal; /* # of types */ -#ifdef HAVE_ECC - if ((ssl->options.cipherSuite0 == ECC_BYTE || - ssl->options.cipherSuite0 == CHACHA_BYTE) && - ssl->specs.sig_algo == ecc_dsa_sa_algo) { - output[i++] = ecdsa_sign; - } - else -#if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3) && \ - (defined(WOLFSSL_SM4_CBC) || defined(WOLFSSL_SM4_GCM) || \ - defined(WOLFSSL_SM4_CCM)) - if (ssl->options.cipherSuite0 == SM_BYTE && (0 - #ifdef BUILD_TLS_ECDHE_ECDSA_WITH_SM4_CBC_SM3 - || ssl->options.cipherSuite == TLS_ECDHE_ECDSA_WITH_SM4_CBC_SM3 - #endif - #ifdef BUILD_TLS_ECDHE_ECDSA_WITH_SM4_GCM_SM3 - || ssl->options.cipherSuite == TLS_ECDHE_ECDSA_WITH_SM4_GCM_SM3 - #endif - #ifdef BUILD_TLS_ECDHE_ECDSA_WITH_SM4_CCM_SM3 - || ssl->options.cipherSuite == TLS_ECDHE_ECDSA_WITH_SM4_CCM_SM3 - #endif - )) { - output[i++] = ecdsa_sign; - } - else -#endif -#endif /* HAVE_ECC */ - { - output[i++] = rsa_sign; - } + for (t = 0; t < typeTotal; t++) + output[i++] = certTypes[t]; /* supported hash/sig */ if (IsAtLeastTLSv1_2(ssl)) { - c16toa(suites->hashSigAlgoSz, &output[i]); + c16toa(localHashSigAlgoSz, &output[i]); i += OPAQUE16_LEN; - XMEMCPY(&output[i], suites->hashSigAlgo, suites->hashSigAlgoSz); - i += suites->hashSigAlgoSz; + XMEMCPY(&output[i], localHashSigAlgo, localHashSigAlgoSz); + i += localHashSigAlgoSz; } /* Certificate Authorities */ @@ -38949,9 +39069,9 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl) ERROR_OUT(BUFFER_ERROR, exit_dcv); } - /* Check if hashSigAlgo in CertificateVerify is supported - * in our ssl->suites or ssl->ctx->suites. */ - if (!SupportedHashSigAlgo(ssl, &input[args->idx])) { + /* Check the algorithm in CertificateVerify against the + * list we actually advertised in our CertificateRequest. */ + if (!InServerCertReqHashSigAlgo(ssl, &input[args->idx])) { WOLFSSL_MSG("Signature algorithm was not in " "CertificateRequest"); ERROR_OUT(INVALID_PARAMETER, exit_dcv); diff --git a/tests/api.c b/tests/api.c index fe92bdee85..02282e1884 100644 --- a/tests/api.c +++ b/tests/api.c @@ -35648,8 +35648,9 @@ static int test_dtls_seq_num_downgrade(void) } /** - * Make sure we don't send RSA Signature Hash Algorithms in the - * CertificateRequest when we don't have any such ciphers set. + * Make sure the CertificateRequest advertises ECDSA signature hash algorithms + * for an ECDHE-ECDSA server, and also includes RSA algorithms so that RSA + * clients can authenticate (the certificate_type advertised covers both). * @return EXPECT_RESULT() */ static int test_certreq_sighash_algos(void) @@ -35710,17 +35711,24 @@ static int test_certreq_sighash_algos(void) idx += OPAQUE16_LEN; maxIdx = idx + (int)len; for (; idx < maxIdx && EXPECT_SUCCESS(); idx += OPAQUE16_LEN) { - if (test_ctx.c_buff[idx+1] == ED25519_SA_MINOR || - test_ctx.c_buff[idx+1] == ED448_SA_MINOR || - test_ctx.c_buff[idx+1] == - ECDSA_BRAINPOOLP256R1TLS13_SHA256_MINOR || - test_ctx.c_buff[idx+1] == - ECDSA_BRAINPOOLP384R1TLS13_SHA384_MINOR || - test_ctx.c_buff[idx+1] == - ECDSA_BRAINPOOLP512R1TLS13_SHA512_MINOR) - ExpectIntEQ(test_ctx.c_buff[idx], NEW_SA_MAJOR); - else - ExpectIntEQ(test_ctx.c_buff[idx+1], ecc_dsa_sa_algo); + byte first = test_ctx.c_buff[idx]; + byte second = test_ctx.c_buff[idx+1]; + if (second == ED25519_SA_MINOR || + second == ED448_SA_MINOR || + second == ECDSA_BRAINPOOLP256R1TLS13_SHA256_MINOR || + second == ECDSA_BRAINPOOLP384R1TLS13_SHA384_MINOR || + second == ECDSA_BRAINPOOLP512R1TLS13_SHA512_MINOR) { + ExpectIntEQ(first, NEW_SA_MAJOR); + } + else { + /* ECDHE-ECDSA suites advertise ECDSA so the negotiated + * cipher can be used, and also RSA / RSA-PSS so RSA + * clients can authenticate via mutual auth. Note that + * RSA-PSS is encoded with sigAlgo first then mac. */ + ExpectTrue(second == ecc_dsa_sa_algo || + second == rsa_sa_algo || + first == rsa_pss_sa_algo); + } } break; } diff --git a/tests/api/test_tls.c b/tests/api/test_tls.c index ee2e112bfa..5fb8d814da 100644 --- a/tests/api/test_tls.c +++ b/tests/api/test_tls.c @@ -1219,3 +1219,111 @@ int test_wolfSSL_alert_desc_string(void) #endif return EXPECT_RESULT(); } + +/* TLS 1.2 mutual auth: an ECDHE-ECDSA server (ECDSA certificate) accepting an + * RSA client certificate. */ +int test_tls12_ecdhe_ecdsa_rsa_client_cert(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && !defined(WOLFSSL_NO_TLS12) \ + && defined(HAVE_ECC) && !defined(NO_RSA) && !defined(NO_SHA256) \ + && defined(HAVE_AESGCM) && defined(KEEP_PEER_CERT) \ + && !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) \ + && !defined(NO_FILESYSTEM) && !defined(NO_CERTS) + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + WOLFSSL_X509* peer = NULL; + const char* cipher = "ECDHE-ECDSA-AES128-GCM-SHA256"; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0); + + /* Server: ECDSA certificate (=> ECDHE-ECDSA suite), require client + * authentication, and trust the (self-signed) RSA client certificate. */ + ExpectIntEQ(wolfSSL_use_certificate_file(ssl_s, eccCertFile, + WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_use_PrivateKey_file(ssl_s, eccKeyFile, + WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx_s, cliCertFile, NULL), + WOLFSSL_SUCCESS); + wolfSSL_set_verify(ssl_s, WOLFSSL_VERIFY_PEER | + WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); + ExpectIntEQ(wolfSSL_set_cipher_list(ssl_s, cipher), WOLFSSL_SUCCESS); + + /* Client: RSA certificate/key, and trust the ECC CA that signed the + * server's ECDSA certificate. */ + ExpectIntEQ(wolfSSL_use_certificate_file(ssl_c, cliCertFile, + WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_use_PrivateKey_file(ssl_c, cliKeyFile, + WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx_c, caEccCertFile, NULL), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set_cipher_list(ssl_c, cipher), WOLFSSL_SUCCESS); + + /* Mutual authentication completes and the server obtains the client's + * RSA certificate even though the negotiated suite is ECDHE-ECDSA. */ + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectStrEQ(wolfSSL_get_cipher_name(ssl_c), cipher); + ExpectNotNull(peer = wolfSSL_get_peer_certificate(ssl_s)); + wolfSSL_X509_free(peer); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); +#endif + return EXPECT_RESULT(); +} + +/* TLS 1.2 mutual auth: an ECDHE-RSA server (RSA certificate) accepting an + * ECDSA client certificate. */ +int test_tls12_ecdhe_rsa_ecdsa_client_cert(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && !defined(WOLFSSL_NO_TLS12) \ + && defined(HAVE_ECC) && !defined(NO_RSA) && !defined(NO_SHA256) \ + && defined(HAVE_AESGCM) && defined(KEEP_PEER_CERT) \ + && !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) \ + && !defined(NO_FILESYSTEM) && !defined(NO_CERTS) + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + WOLFSSL_X509* peer = NULL; + const char* cipher = "ECDHE-RSA-AES128-GCM-SHA256"; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0); + + /* Server: default RSA certificate (=> ECDHE-RSA), require client + * authentication, and trust the (self-signed) ECDSA client certificate. */ + ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx_s, cliEccCertFile, NULL), + WOLFSSL_SUCCESS); + wolfSSL_set_verify(ssl_s, WOLFSSL_VERIFY_PEER | + WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); + ExpectIntEQ(wolfSSL_set_cipher_list(ssl_s, cipher), WOLFSSL_SUCCESS); + + /* Client: ECDSA certificate/key. The default client CTX already trusts + * the RSA CA that signed the server's certificate. */ + ExpectIntEQ(wolfSSL_use_certificate_file(ssl_c, cliEccCertFile, + WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_use_PrivateKey_file(ssl_c, cliEccKeyFile, + WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set_cipher_list(ssl_c, cipher), WOLFSSL_SUCCESS); + + /* Mutual authentication completes and the server obtains the client's + * ECDSA certificate even though the negotiated suite is ECDHE-RSA. */ + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectStrEQ(wolfSSL_get_cipher_name(ssl_c), cipher); + ExpectNotNull(peer = wolfSSL_get_peer_certificate(ssl_s)); + wolfSSL_X509_free(peer); + + 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_tls.h b/tests/api/test_tls.h index fb796244d7..48f200ce8b 100644 --- a/tests/api/test_tls.h +++ b/tests/api/test_tls.h @@ -36,6 +36,8 @@ int test_tls_set_session_min_downgrade(void); int test_tls_set_curves_list_ecc_fallback(void); int test_tls12_corrupted_finished(void); int test_tls12_peerauth_failsafe(void); +int test_tls12_ecdhe_ecdsa_rsa_client_cert(void); +int test_tls12_ecdhe_rsa_ecdsa_client_cert(void); int test_wolfSSL_alert_type_string(void); int test_wolfSSL_alert_desc_string(void); @@ -54,6 +56,8 @@ int test_wolfSSL_alert_desc_string(void); TEST_DECL_GROUP("tls", test_tls_set_curves_list_ecc_fallback), \ TEST_DECL_GROUP("tls", test_tls12_corrupted_finished), \ TEST_DECL_GROUP("tls", test_tls12_peerauth_failsafe), \ + TEST_DECL_GROUP("tls", test_tls12_ecdhe_ecdsa_rsa_client_cert), \ + TEST_DECL_GROUP("tls", test_tls12_ecdhe_rsa_ecdsa_client_cert), \ TEST_DECL_GROUP("tls", test_wolfSSL_alert_type_string), \ TEST_DECL_GROUP("tls", test_wolfSSL_alert_desc_string) diff --git a/tests/test-fails.conf b/tests/test-fails.conf index 74530e3e0e..e8f2772276 100644 --- a/tests/test-fails.conf +++ b/tests/test-fails.conf @@ -161,24 +161,6 @@ -l ECDHE-ECDSA-AES128-GCM-SHA256 -H verifyFail -# Client is using RSA certificate with ECDSA cipher suite. Server will fail. -# server --v 3 --l ECDHE-ECDSA-AES128-GCM-SHA256 --c ./certs/server-ecc.pem --k ./certs/ecc-key.pem --A ./certs/client-cert.pem --H verifyFail --H exitWithRet - -# client --v 3 --l ECDHE-ECDSA-AES128-GCM-SHA256 --c ./certs/client-cert.pem --k ./certs/client-key.pem --A ./certs/ca-ecc-cert.pem --H exitWithRet - # server send alert on no mutual authentication -v 3 -F diff --git a/wolfssl/internal.h b/wolfssl/internal.h index fc918fbc77..59d4686572 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -4525,6 +4525,10 @@ enum ClientCertificateType { mldsa_sign = 68, }; +/* Maximum number of ClientCertificateType bytes the server emits in a + * CertificateRequest. Currently rsa_sign and ecdsa_sign. */ +#define MAX_CERT_REQ_CERT_TYPE_CNT 2 + #ifndef WOLFSSL_AEAD_ONLY enum CipherType { stream, block, aead };