From a462398387a1003aa66cea9c349468100f086af8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Mon, 19 Jan 2026 18:33:48 +0100 Subject: [PATCH 1/3] Support Brainpool ECC curve TLS 1.3 key exchange When both TLS 1.3 and Brainpool curves are enabled, three new groups can be used for the ECDHE key exchange according to RFC 8734: * WOLFSSL_ECC_BRAINPOOLP256R1TLS13 (31) * WOLFSSL_ECC_BRAINPOOLP384R1TLS13 (32) * WOLFSSL_ECC_BRAINPOOLP512R1TLS13 (33) Also ensure that the existing TLS 1.2 curves are sent properly. The TLS client application is updated to support handshakes via Brainpool curves using the new argument "--bpKs". --- examples/benchmark/tls_bench.c | 3 + examples/client/client.c | 100 ++++++++++++++++++++++--- examples/server/server.c | 3 + src/sniffer.c | 17 +++++ src/ssl.c | 3 + src/tls.c | 126 +++++++++++++++++++++++++++++--- tests/test-ecc-cust-curves.conf | 47 ++++++++++++ wolfssl/ssl.h | 3 + 8 files changed, 279 insertions(+), 23 deletions(-) diff --git a/examples/benchmark/tls_bench.c b/examples/benchmark/tls_bench.c index 29fe81e48..ede7d8fed 100644 --- a/examples/benchmark/tls_bench.c +++ b/examples/benchmark/tls_bench.c @@ -286,6 +286,9 @@ static struct group_info groups[] = { { WOLFSSL_ECC_BRAINPOOLP512R1, "ECC_BRAINPOOLP512R1" }, { WOLFSSL_ECC_X25519, "ECC_X25519" }, { WOLFSSL_ECC_X448, "ECC_X448" }, + { WOLFSSL_ECC_BRAINPOOLP256R1TLS13, "ECC_BRAINPOOLP256R1TLS13" }, + { WOLFSSL_ECC_BRAINPOOLP384R1TLS13, "ECC_BRAINPOOLP384R1TLS13" }, + { WOLFSSL_ECC_BRAINPOOLP512R1TLS13, "ECC_BRAINPOOLP512R1TLS13" }, { WOLFSSL_FFDHE_2048, "FFDHE_2048" }, { WOLFSSL_FFDHE_3072, "FFDHE_3072" }, { WOLFSSL_FFDHE_4096, "FFDHE_4096" }, diff --git a/examples/client/client.c b/examples/client/client.c index c7b1b952f..16ea02075 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -308,7 +308,8 @@ static void ShowVersions(void) #if defined(WOLFSSL_TLS13) && defined(HAVE_SUPPORTED_CURVES) #define MAX_GROUP_NUMBER 4 static void SetKeyShare(WOLFSSL* ssl, int onlyKeyShare, int useX25519, - int useX448, int usePqc, char* pqcAlg, int setGroups) + int useX448, int useBp, int usePqc, char* pqcAlg, + int setGroups) { int ret; int groups[MAX_GROUP_NUMBER] = {0}; @@ -316,6 +317,7 @@ static void SetKeyShare(WOLFSSL* ssl, int onlyKeyShare, int useX25519, (void)useX25519; (void)useX448; + (void)useBp; (void)usePqc; (void)pqcAlg; @@ -349,6 +351,23 @@ static void SetKeyShare(WOLFSSL* ssl, int onlyKeyShare, int useX25519, else err_sys("unable to use curve x448"); } while (ret == WC_NO_ERR_TRACE(WC_PENDING_E)); + #endif + } + else if (useBp) { + #if defined(HAVE_ECC) && defined(HAVE_ECC_BRAINPOOL) + #if (!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 256 + do { + ret = wolfSSL_UseKeyShare(ssl, WOLFSSL_ECC_BRAINPOOLP256R1TLS13); + if (ret == WOLFSSL_SUCCESS) + groups[count++] = WOLFSSL_ECC_BRAINPOOLP256R1TLS13; + #ifdef WOLFSSL_ASYNC_CRYPT + else if (ret == WC_NO_ERR_TRACE(WC_PENDING_E)) + wolfSSL_AsyncPoll(ssl, WOLF_POLL_FLAG_CHECK_HW); + #endif + else + err_sys("unable to use curve brainpoolp256r1"); + } while (ret == WC_NO_ERR_TRACE(WC_PENDING_E)); + #endif #endif } else { @@ -587,7 +606,7 @@ static const char* client_bench_conmsg[][5] = { static int ClientBenchmarkConnections(WOLFSSL_CTX* ctx, char* host, word16 port, int dtlsUDP, int dtlsSCTP, int benchmark, int resumeSession, int useX25519, int useX448, int usePqc, char* pqcAlg, int helloRetry, int onlyKeyShare, - int version, int earlyData) + int version, int earlyData, int useBp) { /* time passed in number of connects give average */ int times = benchmark, skip = (int)((double)times * 0.1); @@ -610,6 +629,7 @@ static int ClientBenchmarkConnections(WOLFSSL_CTX* ctx, char* host, word16 port, (void)onlyKeyShare; (void)version; (void)earlyData; + (void)useBp; while (loops--) { #ifndef NO_SESSION_CACHE @@ -636,7 +656,7 @@ static int ClientBenchmarkConnections(WOLFSSL_CTX* ctx, char* host, word16 port, else if (version >= 4) { if (!helloRetry) SetKeyShare(ssl, onlyKeyShare, useX25519, useX448, - usePqc, pqcAlg, 1); + useBp, usePqc, pqcAlg, 1); else wolfSSL_NoKeyShares(ssl); } @@ -717,7 +737,7 @@ static int ClientBenchmarkConnections(WOLFSSL_CTX* ctx, char* host, word16 port, static int ClientBenchmarkThroughput(WOLFSSL_CTX* ctx, char* host, word16 port, int dtlsUDP, int dtlsSCTP, int block, size_t throughput, int useX25519, int useX448, int usePqc, char* pqcAlg, int exitWithRet, int version, - int onlyKeyShare) + int onlyKeyShare, int useBp) { double start, conn_time = 0, tx_time = 0, rx_time = 0; SOCKET_T sockfd = WOLFSSL_SOCKET_INVALID; @@ -738,11 +758,12 @@ static int ClientBenchmarkThroughput(WOLFSSL_CTX* ctx, char* host, word16 port, (void)useX448; (void)usePqc; (void)pqcAlg; + (void)useBp; (void)version; (void)onlyKeyShare; #if defined(WOLFSSL_TLS13) && defined(HAVE_SUPPORTED_CURVES) if (version >= 4) { - SetKeyShare(ssl, onlyKeyShare, useX25519, useX448, usePqc, + SetKeyShare(ssl, onlyKeyShare, useX25519, useX448, useBp, usePqc, pqcAlg, 1); } #endif @@ -1150,7 +1171,7 @@ static int ClientWriteRead(WOLFSSL* ssl, const char* msg, int msgSz, /* 4. add the same message into Japanese section */ /* (will be translated later) */ /* 5. add printf() into suitable position of Usage() */ -static const char* client_usage_msg[][78] = { +static const char* client_usage_msg[][79] = { /* English */ { " NOTE: All files relative to wolfSSL home dir\n", /* 0 */ @@ -1398,10 +1419,13 @@ static const char* client_usage_msg[][78] = { "--files-are-der Specified files are in DER, not PEM format\n", /* 75 */ #ifdef WOLFSSL_SYS_CRYPTO_POLICY "--crypto-policy \n", /* 76 */ +#endif +#ifdef HAVE_ECC_BRAINPOOL + "--bpKs Use Brainpool ECC group for key share\n", /* 77 */ #endif "\n" "For simpler wolfSSL TLS client examples, visit\n" - "https://github.com/wolfSSL/wolfssl-examples/tree/master/tls\n", /* 77 */ + "https://github.com/wolfSSL/wolfssl-examples/tree/master/tls\n", /* 78 */ NULL, }, #ifndef NO_MULTIBYTE_PRINT @@ -1653,11 +1677,14 @@ static const char* client_usage_msg[][78] = { "--files-are-der Specified files are in DER, not PEM format\n", /* 75 */ #ifdef WOLFSSL_SYS_CRYPTO_POLICY "--crypto-policy \n", /* 76 */ +#endif +#ifdef HAVE_ECC_BRAINPOOL + "--bpKs Use Brainpool ECC group for key share\n", /* 77 */ #endif "\n" "より簡単なwolfSSL TLS クライアントの例については" "下記にアクセスしてください\n" - "https://github.com/wolfSSL/wolfssl-examples/tree/master/tls\n", /* 77 */ + "https://github.com/wolfSSL/wolfssl-examples/tree/master/tls\n", /* 78 */ NULL, }, #endif @@ -1892,6 +1919,9 @@ static void Usage(void) #endif #ifdef HAVE_RPK printf("%s", msg[++msgid]); /* --rpk */ +#endif +#ifdef HAVE_ECC_BRAINPOOL + printf("%s", msg[++msgid]); /* --bpKs */ #endif printf("%s", msg[++msgid]); /* --files-are-der */ printf("%s", msg[++msgid]); /* Documentation Hint */ @@ -2078,6 +2108,9 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) #if defined(WOLFSSL_SYS_CRYPTO_POLICY) { "crypto-policy", 1, 269 }, #endif /* WOLFSSL_SYS_CRYPTO_POLICY */ +#ifdef HAVE_ECC_BRAINPOOL + { "bpKs", 0, 270 }, +#endif { 0, 0, 0 } }; #endif @@ -2187,6 +2220,7 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) #endif int useX25519 = 0; int useX448 = 0; + int useBrainpool = 0; int usePqc = 0; char* pqcAlg = NULL; int exitWithRet = 0; @@ -2311,6 +2345,7 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) (void)earlyData; (void)useX25519; (void)useX448; + (void)useBrainpool; (void)helloRetry; (void)onlyKeyShare; (void)useSupCurve; @@ -2959,6 +2994,15 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) policy = myoptarg; #endif /* WOLFSSL_SYS_CRYPTO_POLICY */ break; +#ifdef HAVE_ECC_BRAINPOOL + case 270: + useBrainpool = 1; + #if defined(HAVE_ECC) && defined(WOLFSSL_TLS13) && \ + defined(HAVE_SUPPORTED_CURVES) + onlyKeyShare = 2; + #endif + break; +#endif default: Usage(); @@ -3680,6 +3724,37 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) } #endif /* HAVE_CURVE448 */ #ifdef HAVE_ECC + #ifdef HAVE_ECC_BRAINPOOL + if (useBrainpool) { + if (version == 4) { + if (wolfSSL_CTX_UseSupportedCurve(ctx, + WOLFSSL_ECC_BRAINPOOLP256R1TLS13) + != WOLFSSL_SUCCESS) { + err_sys("unable to support brainpoolp256r1tls13"); + } + } + else if (version == CLIENT_DOWNGRADE_VERSION) { + if (wolfSSL_CTX_UseSupportedCurve(ctx, + WOLFSSL_ECC_BRAINPOOLP256R1TLS13) + != WOLFSSL_SUCCESS) { + err_sys("unable to support brainpoolp256r1tls13"); + } + if (minVersion <= 3) { + if (wolfSSL_CTX_UseSupportedCurve(ctx, + WOLFSSL_ECC_BRAINPOOLP256R1) + != WOLFSSL_SUCCESS) { + err_sys("unable to support brainpoolp256r1"); + } + } + } + else { + if (wolfSSL_CTX_UseSupportedCurve(ctx, WOLFSSL_ECC_BRAINPOOLP256R1) + != WOLFSSL_SUCCESS) { + err_sys("unable to support brainpoolp256r1"); + } + } + } + #endif /* HAVE_ECC_BRAINPOOL */ if (useSupCurve) { #if !defined(NO_ECC_SECP) && \ (defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)) @@ -3728,7 +3803,8 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) ClientBenchmarkConnections(ctx, host, port, dtlsUDP, dtlsSCTP, benchmark, resumeSession, useX25519, useX448, usePqc, pqcAlg, helloRetry, - onlyKeyShare, version, earlyData); + onlyKeyShare, version, earlyData, + useBrainpool); wolfSSL_CTX_free(ctx); ctx = NULL; XEXIT_T(EXIT_SUCCESS); } @@ -3738,7 +3814,7 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) ClientBenchmarkThroughput(ctx, host, port, dtlsUDP, dtlsSCTP, block, throughput, useX25519, useX448, usePqc, pqcAlg, exitWithRet, version, - onlyKeyShare); + onlyKeyShare, useBrainpool); wolfSSL_CTX_free(ctx); ctx = NULL; if (((func_args*)args)->return_code != EXIT_SUCCESS && !exitWithRet) XEXIT_T(EXIT_SUCCESS); @@ -3872,8 +3948,8 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) #if defined(WOLFSSL_TLS13) && defined(HAVE_SUPPORTED_CURVES) if (!helloRetry && (version >= 4 || version <= -4)) { - SetKeyShare(ssl, onlyKeyShare, useX25519, useX448, usePqc, - pqcAlg, 0); + SetKeyShare(ssl, onlyKeyShare, useX25519, useX448, + useBrainpool, usePqc, pqcAlg, 0); } else { wolfSSL_NoKeyShares(ssl); diff --git a/examples/server/server.c b/examples/server/server.c index 06e0aeb6a..c7c44409d 100644 --- a/examples/server/server.c +++ b/examples/server/server.c @@ -104,6 +104,9 @@ static struct group_info group_id_to_text[] = { { WOLFSSL_ECC_BRAINPOOLP256R1, "BRAINPOOLP256R1" }, { WOLFSSL_ECC_BRAINPOOLP384R1, "BRAINPOOLP384R1" }, { WOLFSSL_ECC_BRAINPOOLP512R1, "BRAINPOOLP512R1" }, + { WOLFSSL_ECC_BRAINPOOLP256R1TLS13, "BRAINPOOLP256R1TLS13" }, + { WOLFSSL_ECC_BRAINPOOLP384R1TLS13, "BRAINPOOLP384R1TLS13" }, + { WOLFSSL_ECC_BRAINPOOLP512R1TLS13, "BRAINPOOLP512R1TLS13" }, { 0, NULL } }; #endif /* CAN_FORCE_CURVE && HAVE_ECC */ diff --git a/src/sniffer.c b/src/sniffer.c index 905e6abc9..0f3e18f1b 100644 --- a/src/sniffer.c +++ b/src/sniffer.c @@ -3364,6 +3364,11 @@ static int ProcessKeyShare(KeyShareInfo* info, const byte* input, int len, info->curve_id = ECC_SM2P256V1; break; #endif /* WOLFSSL_SM2 */ + #ifdef HAVE_ECC_BRAINPOOL + case WOLFSSL_ECC_BRAINPOOLP256R1TLS13: + info->curve_id = ECC_BRAINPOOLP256R1; + break; + #endif /* HAVE_ECC_BRAINPOOL */ #endif #if defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES) #ifndef NO_ECC_SECP @@ -3371,6 +3376,18 @@ static int ProcessKeyShare(KeyShareInfo* info, const byte* input, int len, info->curve_id = ECC_SECP384R1; break; #endif /* !NO_ECC_SECP */ + #ifdef HAVE_ECC_BRAINPOOL + case WOLFSSL_ECC_BRAINPOOLP384R1TLS13: + info->curve_id = ECC_BRAINPOOLP384R1; + break; + #endif /* HAVE_ECC_BRAINPOOL */ + #endif + #if defined(HAVE_ECC512) || defined(HAVE_ALL_CURVES) + #ifdef HAVE_ECC_BRAINPOOL + case WOLFSSL_ECC_BRAINPOOLP512R1TLS13: + info->curve_id = ECC_BRAINPOOLP512R1; + break; + #endif /* HAVE_ECC_BRAINPOOL */ #endif #if defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES) #ifndef NO_ECC_SECP diff --git a/src/ssl.c b/src/ssl.c index dfb408f10..73c44d40f 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -3741,6 +3741,9 @@ static int isValidCurveGroup(word16 name) case WOLFSSL_ECC_SM2P256V1: case WOLFSSL_ECC_X25519: case WOLFSSL_ECC_X448: + case WOLFSSL_ECC_BRAINPOOLP256R1TLS13: + case WOLFSSL_ECC_BRAINPOOLP384R1TLS13: + case WOLFSSL_ECC_BRAINPOOLP512R1TLS13: case WOLFSSL_FFDHE_2048: case WOLFSSL_FFDHE_3072: diff --git a/src/tls.c b/src/tls.c index 8226ba478..e4115c895 100644 --- a/src/tls.c +++ b/src/tls.c @@ -4407,6 +4407,7 @@ static int TLSX_IsGroupSupported(int namedGroup) #endif /* !NO_ECC_SECP */ #ifdef HAVE_ECC_BRAINPOOL case WOLFSSL_ECC_BRAINPOOLP256R1: + case WOLFSSL_ECC_BRAINPOOLP256R1TLS13: break; #endif #ifdef WOLFSSL_SM2 @@ -4429,6 +4430,7 @@ static int TLSX_IsGroupSupported(int namedGroup) #endif /* !NO_ECC_SECP */ #ifdef HAVE_ECC_BRAINPOOL case WOLFSSL_ECC_BRAINPOOLP384R1: + case WOLFSSL_ECC_BRAINPOOLP384R1TLS13: break; #endif #endif @@ -4475,6 +4477,7 @@ static int TLSX_IsGroupSupported(int namedGroup) #if (defined(HAVE_ECC512) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 512 #ifdef HAVE_ECC_BRAINPOOL case WOLFSSL_ECC_BRAINPOOLP512R1: + case WOLFSSL_ECC_BRAINPOOLP512R1TLS13: break; #endif #endif @@ -8154,7 +8157,13 @@ static int TLSX_KeyShare_GenEccKey(WOLFSSL *ssl, KeyShareEntry* kse) curveId = ECC_SM2P256V1; keySize = 32; break; - #endif /* !NO_ECC_SECP */ + #endif /* !WOLFSSL_SM2 */ + #ifdef HAVE_ECC_BRAINPOOL + case WOLFSSL_ECC_BRAINPOOLP256R1TLS13: + curveId = ECC_BRAINPOOLP256R1; + keySize = 32; + break; + #endif /* HAVE_ECC_BRAINPOOL */ #endif #if (defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 384 #ifndef NO_ECC_SECP @@ -8163,6 +8172,20 @@ static int TLSX_KeyShare_GenEccKey(WOLFSSL *ssl, KeyShareEntry* kse) keySize = 48; break; #endif /* !NO_ECC_SECP */ + #ifdef HAVE_ECC_BRAINPOOL + case WOLFSSL_ECC_BRAINPOOLP384R1TLS13: + curveId = ECC_BRAINPOOLP384R1; + keySize = 48; + break; + #endif /* HAVE_ECC_BRAINPOOL */ + #endif + #if (defined(HAVE_ECC512) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 512 + #ifdef HAVE_ECC_BRAINPOOL + case WOLFSSL_ECC_BRAINPOOLP512R1TLS13: + curveId = ECC_BRAINPOOLP512R1; + keySize = 64; + break; + #endif /* HAVE_ECC_BRAINPOOL */ #endif #if (defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 521 #ifndef NO_ECC_SECP @@ -9273,7 +9296,12 @@ static int TLSX_KeyShare_ProcessEcc_ex(WOLFSSL* ssl, case WOLFSSL_ECC_SM2P256V1: curveId = ECC_SM2P256V1; break; - #endif + #endif /* WOLFSSL_SM2 */ + #ifdef HAVE_ECC_BRAINPOOL + case WOLFSSL_ECC_BRAINPOOLP256R1TLS13: + curveId = ECC_BRAINPOOLP256R1; + break; + #endif /* HAVE_ECC_BRAINPOOL */ #endif #if (defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 384 #ifndef NO_ECC_SECP @@ -9281,6 +9309,18 @@ static int TLSX_KeyShare_ProcessEcc_ex(WOLFSSL* ssl, curveId = ECC_SECP384R1; break; #endif /* !NO_ECC_SECP */ + #ifdef HAVE_ECC_BRAINPOOL + case WOLFSSL_ECC_BRAINPOOLP384R1TLS13: + curveId = ECC_BRAINPOOLP384R1; + break; + #endif /* HAVE_ECC_BRAINPOOL */ + #endif + #if (defined(HAVE_ECC512) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 512 + #ifdef HAVE_ECC_BRAINPOOL + case WOLFSSL_ECC_BRAINPOOLP512R1TLS13: + curveId = ECC_BRAINPOOLP512R1; + break; + #endif /* HAVE_ECC_BRAINPOOL */ #endif #if (defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 521 #ifndef NO_ECC_SECP @@ -10631,6 +10671,9 @@ static const word16 preferredGroup[] = { #if !defined(HAVE_FIPS) && defined(WOLFSSL_SM2) WOLFSSL_ECC_SM2P256V1, #endif +#if defined(HAVE_ECC_BRAINPOOL) + WOLFSSL_ECC_BRAINPOOLP256R1TLS13, +#endif #endif #if defined(HAVE_CURVE25519) && ECC_MIN_KEY_SZ <= 256 WOLFSSL_ECC_X25519, @@ -10641,11 +10684,18 @@ static const word16 preferredGroup[] = { #if defined(HAVE_ECC) && (!defined(NO_ECC384) || \ defined(HAVE_ALL_CURVES)) && !defined(NO_ECC_SECP) && ECC_MIN_KEY_SZ <= 384 WOLFSSL_ECC_SECP384R1, +#if defined(HAVE_ECC_BRAINPOOL) + WOLFSSL_ECC_BRAINPOOLP384R1TLS13, +#endif #endif #if defined(HAVE_ECC) && (!defined(NO_ECC521) || \ defined(HAVE_ALL_CURVES)) && !defined(NO_ECC_SECP) && ECC_MIN_KEY_SZ <= 521 WOLFSSL_ECC_SECP521R1, #endif +#if defined(HAVE_ECC) && defined(HAVE_ECC512) && \ + defined(HAVE_ECC_BRAINPOOL) && ECC_MIN_KEY_SZ <= 512 + WOLFSSL_ECC_BRAINPOOLP512R1TLS13, +#endif #if defined(HAVE_FFDHE_2048) WOLFSSL_FFDHE_2048, #endif @@ -14227,9 +14277,27 @@ static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions) #endif #if (defined(HAVE_ECC512) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 512 #ifdef HAVE_ECC_BRAINPOOL - ret = TLSX_UseSupportedCurve(extensions, - WOLFSSL_ECC_BRAINPOOLP512R1, ssl->heap); - if (ret != WOLFSSL_SUCCESS) return ret; + if (IsAtLeastTLSv1_3(ssl->version)) { + /* TLS 1.3 BrainpoolP512 curve */ + ret = TLSX_UseSupportedCurve(extensions, + WOLFSSL_ECC_BRAINPOOLP512R1TLS13, ssl->heap); + if (ret != WOLFSSL_SUCCESS) return ret; + + /* If TLS 1.2 is allowed, also add the TLS 1.2 curve */ + if (ssl->options.downgrade && + (ssl->options.minDowngrade <= TLSv1_2_MINOR || + ssl->options.minDowngrade <= DTLSv1_2_MINOR)) { + ret = TLSX_UseSupportedCurve(extensions, + WOLFSSL_ECC_BRAINPOOLP512R1, ssl->heap); + if (ret != WOLFSSL_SUCCESS) return ret; + } + } + else { + /* TLS 1.2 only */ + ret = TLSX_UseSupportedCurve(extensions, + WOLFSSL_ECC_BRAINPOOLP512R1, ssl->heap); + if (ret != WOLFSSL_SUCCESS) return ret; + } #endif #endif #if (defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 384 @@ -14239,9 +14307,27 @@ static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions) if (ret != WOLFSSL_SUCCESS) return ret; #endif #ifdef HAVE_ECC_BRAINPOOL - ret = TLSX_UseSupportedCurve(extensions, - WOLFSSL_ECC_BRAINPOOLP384R1, ssl->heap); - if (ret != WOLFSSL_SUCCESS) return ret; + if (IsAtLeastTLSv1_3(ssl->version)) { + /* TLS 1.3 BrainpoolP384 curve */ + ret = TLSX_UseSupportedCurve(extensions, + WOLFSSL_ECC_BRAINPOOLP384R1TLS13, ssl->heap); + if (ret != WOLFSSL_SUCCESS) return ret; + + /* If TLS 1.2 is allowed, also add the TLS 1.2 curve */ + if (ssl->options.downgrade && + (ssl->options.minDowngrade <= TLSv1_2_MINOR || + ssl->options.minDowngrade <= DTLSv1_2_MINOR)) { + ret = TLSX_UseSupportedCurve(extensions, + WOLFSSL_ECC_BRAINPOOLP384R1, ssl->heap); + if (ret != WOLFSSL_SUCCESS) return ret; + } + } + else { + /* TLS 1.2 only */ + ret = TLSX_UseSupportedCurve(extensions, + WOLFSSL_ECC_BRAINPOOLP384R1, ssl->heap); + if (ret != WOLFSSL_SUCCESS) return ret; + } #endif #endif #endif /* HAVE_ECC */ @@ -14267,9 +14353,27 @@ static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions) if (ret != WOLFSSL_SUCCESS) return ret; #endif #ifdef HAVE_ECC_BRAINPOOL - ret = TLSX_UseSupportedCurve(extensions, - WOLFSSL_ECC_BRAINPOOLP256R1, ssl->heap); - if (ret != WOLFSSL_SUCCESS) return ret; + if (IsAtLeastTLSv1_3(ssl->version)) { + /* TLS 1.3 BrainpoolP256 curve */ + ret = TLSX_UseSupportedCurve(extensions, + WOLFSSL_ECC_BRAINPOOLP256R1TLS13, ssl->heap); + if (ret != WOLFSSL_SUCCESS) return ret; + + /* If TLS 1.2 is allowed, also add the TLS 1.2 curve */ + if (ssl->options.downgrade && + (ssl->options.minDowngrade <= TLSv1_2_MINOR || + ssl->options.minDowngrade <= DTLSv1_2_MINOR)) { + ret = TLSX_UseSupportedCurve(extensions, + WOLFSSL_ECC_BRAINPOOLP256R1, ssl->heap); + if (ret != WOLFSSL_SUCCESS) return ret; + } + } + else { + /* TLS 1.2 only */ + ret = TLSX_UseSupportedCurve(extensions, + WOLFSSL_ECC_BRAINPOOLP256R1, ssl->heap); + if (ret != WOLFSSL_SUCCESS) return ret; + } #endif #ifdef WOLFSSL_SM2 ret = TLSX_UseSupportedCurve(extensions, diff --git a/tests/test-ecc-cust-curves.conf b/tests/test-ecc-cust-curves.conf index 6f24783e8..7ad1d7891 100644 --- a/tests/test-ecc-cust-curves.conf +++ b/tests/test-ecc-cust-curves.conf @@ -180,6 +180,53 @@ -A ./certs/ecc/server-bp256r1-cert.pem -C +# server TLSv1.3 TLS13-AES128-GCM-SHA256 +-v 4 +-l TLS13-AES128-GCM-SHA256 +-c ./certs/ecc/server-bp256r1-cert.pem +-k ./certs/ecc/bp256r1-key.pem +-d + +# client TLSv1.3 TLS13-AES128-GCM-SHA256 (brainpool key share) +-v 4 +-l TLS13-AES128-GCM-SHA256 +-A ./certs/ecc/server-bp256r1-cert.pem +-x +-C +--bpKs + +# server TLSv1.3 TLS13-AES128-GCM-SHA256 +-v 4 +-l "TLS13-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256" +-c ./certs/ecc/server-bp256r1-cert.pem +-k ./certs/ecc/bp256r1-key.pem +-d + +# client TLSv1.3 TLS13-AES128-GCM-SHA256 (brainpool key share; downgrade) +-v d +-l "TLS13-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256" +-A ./certs/ecc/server-bp256r1-cert.pem +-x +-C +--bpKs +-7 3 + + +# server TLSv1.2 ECDHE-ECDSA-AES128-GCM-SHA256 +-v 3 +-l ECDHE-ECDSA-AES128-GCM-SHA256 +-c ./certs/ecc/server-bp256r1-cert.pem +-k ./certs/ecc/bp256r1-key.pem +-d + +# client TLSv1.2 ECDHE-ECDSA-AES128-GCM-SHA256 (brainpool key share) +-v 3 +-l ECDHE-ECDSA-AES128-GCM-SHA256 +-A ./certs/ecc/server-bp256r1-cert.pem +-x +-C +--bpKs + # -- SECP256K1 without OID inside PKCS#8 -- # server TLSv1.2 ECDHE-ECDSA-AES128-GCM-SHA256 -v 3 diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index a1c7bedf4..ff6af35d0 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -4619,6 +4619,9 @@ enum { WOLFSSL_ECC_BRAINPOOLP512R1 = 28, WOLFSSL_ECC_X25519 = 29, WOLFSSL_ECC_X448 = 30, + WOLFSSL_ECC_BRAINPOOLP256R1TLS13 = 31, + WOLFSSL_ECC_BRAINPOOLP384R1TLS13 = 32, + WOLFSSL_ECC_BRAINPOOLP512R1TLS13 = 33, WOLFSSL_ECC_SM2P256V1 = 41, WOLFSSL_ECC_MAX = 41, WOLFSSL_ECC_MAX_AVAIL = 46, From eb8ba6124e420ad4acdfc656df9d21267f74ae52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Mon, 19 Jan 2026 18:42:17 +0100 Subject: [PATCH 2/3] Support TLS 1.3 ECC Brainpool authentication This also fixes TLS 1.2 authentication to only succeed in case the brainpool curve was present in the supported_groups extension. --- src/internal.c | 121 +++++++++++++++++++++++++++++--- src/ssl.c | 2 + src/tls.c | 25 +++++++ src/tls13.c | 49 +++++++++---- tests/api.c | 12 +++- tests/test-ecc-cust-curves.conf | 17 +++-- wolfssl/internal.h | 10 ++- 7 files changed, 196 insertions(+), 40 deletions(-) diff --git a/src/internal.c b/src/internal.c index 86c20fd15..e3aece713 100644 --- a/src/internal.c +++ b/src/internal.c @@ -3312,6 +3312,23 @@ static WC_INLINE void AddSuiteHashSigAlgo(byte* hashSigAlgo, byte macAlgo, #endif } else +#endif +#ifdef HAVE_ECC_BRAINPOOL + if (sigAlgo == ecc_brainpool_sa_algo) { + if (macAlgo == sha512_mac) { + ADD_HASH_SIG_ALGO(hashSigAlgo, inOutIdx, NEW_SA_MAJOR, + ECDSA_BRAINPOOLP512R1TLS13_SHA512_MINOR); + } + else if (macAlgo == sha384_mac) { + ADD_HASH_SIG_ALGO(hashSigAlgo, inOutIdx, NEW_SA_MAJOR, + ECDSA_BRAINPOOLP384R1TLS13_SHA384_MINOR); + } + else if (macAlgo == sha256_mac) { + ADD_HASH_SIG_ALGO(hashSigAlgo, inOutIdx, NEW_SA_MAJOR, + ECDSA_BRAINPOOLP256R1TLS13_SHA256_MINOR); + } + } + else #endif { ADD_HASH_SIG_ALGO(hashSigAlgo, inOutIdx, macAlgo, sigAlgo); @@ -3320,11 +3337,12 @@ static WC_INLINE void AddSuiteHashSigAlgo(byte* hashSigAlgo, byte macAlgo, } void InitSuitesHashSigAlgo(byte* hashSigAlgo, int haveSig, int tls1_2, - int keySz, word16* len) + int tls1_3, int keySz, word16* len) { word16 idx = 0; (void)tls1_2; + (void)tls1_3; (void)keySz; #if defined(HAVE_ECC) || defined(HAVE_ED25519) || defined(HAVE_ED448) @@ -3333,14 +3351,32 @@ void InitSuitesHashSigAlgo(byte* hashSigAlgo, int haveSig, int tls1_2, #ifdef WOLFSSL_SHA512 AddSuiteHashSigAlgo(hashSigAlgo, sha512_mac, ecc_dsa_sa_algo, keySz, &idx); + #ifdef HAVE_ECC_BRAINPOOL + if (tls1_3) { + AddSuiteHashSigAlgo(hashSigAlgo, sha512_mac, ecc_brainpool_sa_algo, + keySz, &idx); + } + #endif #endif #ifdef WOLFSSL_SHA384 AddSuiteHashSigAlgo(hashSigAlgo, sha384_mac, ecc_dsa_sa_algo, keySz, &idx); + #ifdef HAVE_ECC_BRAINPOOL + if (tls1_3) { + AddSuiteHashSigAlgo(hashSigAlgo, sha384_mac, ecc_brainpool_sa_algo, + keySz, &idx); + } + #endif #endif #ifndef NO_SHA256 AddSuiteHashSigAlgo(hashSigAlgo, sha256_mac, ecc_dsa_sa_algo, keySz, &idx); + #ifdef HAVE_ECC_BRAINPOOL + if (tls1_3) { + AddSuiteHashSigAlgo(hashSigAlgo, sha256_mac, ecc_brainpool_sa_algo, + keySz, &idx); + } + #endif #endif #if !defined(NO_SHA) && (!defined(NO_OLD_TLS) || \ defined(WOLFSSL_ALLOW_TLS_SHA1)) @@ -3465,9 +3501,7 @@ void InitSuites(Suites* suites, ProtocolVersion pv, int keySz, word16 haveRSA, word16 idx = 0; int tls = pv.major == SSLv3_MAJOR && pv.minor >= TLSv1_MINOR; int tls1_2 = pv.major == SSLv3_MAJOR && pv.minor >= TLSv1_2_MINOR; -#ifdef WOLFSSL_TLS13 int tls1_3 = IsAtLeastTLSv1_3(pv); -#endif int dtls = 0; int haveRSAsig = 1; @@ -3484,6 +3518,7 @@ void InitSuites(Suites* suites, ProtocolVersion pv, int keySz, word16 haveRSA, (void)tls; /* shut up compiler */ (void)tls1_2; + (void)tls1_3; (void)dtls; (void)haveDH; (void)havePSK; @@ -4511,8 +4546,8 @@ void InitSuites(Suites* suites, ProtocolVersion pv, int keySz, word16 haveRSA, suites->suiteSz = idx; if (suites->hashSigAlgoSz == 0) { - InitSuitesHashSigAlgo(suites->hashSigAlgo, SIG_ALL, tls1_2, keySz, - &suites->hashSigAlgoSz); + InitSuitesHashSigAlgo(suites->hashSigAlgo, SIG_ALL, tls1_2, tls1_3, + keySz, &suites->hashSigAlgoSz); } /* Moved to the end as we set some of the vars but never use them */ @@ -4571,6 +4606,22 @@ void DecodeSigAlg(const byte* input, byte* hashAlgo, byte* hsType) *hashAlgo = PSS_PSS_HASH_TO_MAC(input[1]); } else + #endif + #ifdef HAVE_ECC_BRAINPOOL + /* RFC 8734 TLS 1.3 Brainpool curves */ + if (input[1] == ECDSA_BRAINPOOLP256R1TLS13_SHA256_MINOR) { + *hsType = ecc_brainpool_sa_algo; + *hashAlgo = sha256_mac; + } + else if (input[1] == ECDSA_BRAINPOOLP384R1TLS13_SHA384_MINOR) { + *hsType = ecc_brainpool_sa_algo; + *hashAlgo = sha384_mac; + } + else if (input[1] == ECDSA_BRAINPOOLP512R1TLS13_SHA512_MINOR) { + *hsType = ecc_brainpool_sa_algo; + *hashAlgo = sha512_mac; + } + else #endif { *hsType = input[0]; @@ -28273,6 +28324,7 @@ static int ParseCipherList(Suites* suites, word16 haveSHA1 = 1; /* allowed by default if compiled in */ word16 haveRC4 = 1; /* allowed by default if compiled in */ #endif + int tls1_3 = 0; const int suiteSz = GetCipherNamesSize(); const char* next = list; @@ -28598,6 +28650,7 @@ static int ParseCipherList(Suites* suites, (cipher_names[i].cipherSuite0 == ECC_BYTE && (cipher_names[i].cipherSuite == TLS_SHA256_SHA256 || cipher_names[i].cipherSuite == TLS_SHA384_SHA384))) { + tls1_3 = 1; #ifndef NO_RSA haveSig |= SIG_RSA; #endif @@ -28701,8 +28754,8 @@ static int ParseCipherList(Suites* suites, #endif { suites->suiteSz = (word16)idx; - InitSuitesHashSigAlgo(suites->hashSigAlgo, haveSig, 1, keySz, - &suites->hashSigAlgoSz); + InitSuitesHashSigAlgo(suites->hashSigAlgo, haveSig, 1, tls1_3, + keySz, &suites->hashSigAlgoSz); } #ifdef HAVE_RENEGOTIATION_INDICATION @@ -28775,6 +28828,7 @@ int SetCipherListFromBytes(WOLFSSL_CTX* ctx, Suites* suites, const byte* list, int haveFalconSig = 0; int haveDilithiumSig = 0; int haveAnon = 0; + int tls1_3 = 0; if (suites == NULL || list == NULL) { WOLFSSL_MSG("SetCipherListFromBytes parameter error"); @@ -28834,6 +28888,7 @@ int SetCipherListFromBytes(WOLFSSL_CTX* ctx, Suites* suites, const byte* list, secondByte == TLS_SHA384_SHA384)) || (firstByte == CIPHER_BYTE && (secondByte == TLS_SM4_GCM_SM3 || secondByte == TLS_SM4_CCM_SM3))) { + tls1_3 = 1; #ifndef NO_RSA haveRSAsig = 1; #endif @@ -28885,8 +28940,8 @@ int SetCipherListFromBytes(WOLFSSL_CTX* ctx, Suites* suites, const byte* list, haveSig |= haveFalconSig ? SIG_FALCON : 0; haveSig |= haveDilithiumSig ? SIG_DILITHIUM : 0; haveSig |= haveAnon ? SIG_ANON : 0; - InitSuitesHashSigAlgo(suites->hashSigAlgo, haveSig, 1, keySz, - &suites->hashSigAlgoSz); + InitSuitesHashSigAlgo(suites->hashSigAlgo, haveSig, 1, tls1_3, + keySz, &suites->hashSigAlgoSz); #ifdef HAVE_RENEGOTIATION_INDICATION if (ctx->method->side == WOLFSSL_CLIENT_END) { if (suites->suiteSz > WOLFSSL_MAX_SUITE_SZ - 2) { @@ -29067,7 +29122,7 @@ int SetSuitesHashSigAlgo(Suites* suites, const char* list) #endif /* OPENSSL_EXTRA */ -#if !defined(NO_WOLFSSL_SERVER) || !defined(NO_CERTS) +#if !defined(NO_TLS) && (!defined(NO_WOLFSSL_SERVER) || !defined(NO_CERTS)) static int MatchSigAlgo(WOLFSSL* ssl, int sigAlgo) { #ifdef HAVE_ED25519 @@ -29134,6 +29189,41 @@ static int MatchSigAlgo(WOLFSSL* ssl, int sigAlgo) if (sigAlgo == rsa_pss_sa_algo) return 1; } +#endif +#ifdef HAVE_ECC_BRAINPOOL + if ((ssl->pkCurveOID == ECC_BRAINPOOLP256R1_OID) || + (ssl->pkCurveOID == ECC_BRAINPOOLP384R1_OID) || + (ssl->pkCurveOID == ECC_BRAINPOOLP512R1_OID)) { + if (IsAtLeastTLSv1_3(ssl->version)) { + /* Certificate has an ECC Brainpool key, only match with the + * specified ECDSA brainpool signature algorithms for TLS 1.3 */ + return sigAlgo == ecc_brainpool_sa_algo; + } + else { + /* Certificate has an ECC Brainpool key, match with ECDSA in TLS 1.2 + * case, but only when the related Brainpool curve is present in + * the supported_groups extension. */ + if (ssl->pkCurveOID == ECC_BRAINPOOLP256R1_OID && + TLSX_SupportedCurve_IsSupported(ssl, + WOLFSSL_ECC_BRAINPOOLP256R1)) { + return sigAlgo == ecc_dsa_sa_algo; + } + else if (ssl->pkCurveOID == ECC_BRAINPOOLP384R1_OID && + TLSX_SupportedCurve_IsSupported(ssl, + WOLFSSL_ECC_BRAINPOOLP384R1)) { + return sigAlgo == ecc_dsa_sa_algo; + } + else if (ssl->pkCurveOID == ECC_BRAINPOOLP512R1_OID && + TLSX_SupportedCurve_IsSupported(ssl, + WOLFSSL_ECC_BRAINPOOLP512R1)) { + return sigAlgo == ecc_dsa_sa_algo; + } + else { + /* Curve not supported in supported_groups extension. */ + return 0; + } + } + } #endif /* Signature algorithm matches certificate. */ return sigAlgo == ssl->options.sigAlgo; @@ -29299,6 +29389,15 @@ int PickHashSigAlgo(WOLFSSL* ssl, const byte* hashSigAlgo, word32 hashSigAlgoSz, break; } #endif /* HAVE_DILITHIUM */ + #if defined(HAVE_ECC_BRAINPOOL) + if (ssl->pkCurveOID == ECC_BRAINPOOLP256R1_OID || + ssl->pkCurveOID == ECC_BRAINPOOLP384R1_OID || + ssl->pkCurveOID == ECC_BRAINPOOLP512R1_OID) { + /* Matched ECC Brainpool. Set sigAlgo to "normal" ECDSA here + * for compatibility with TLS 1.2. */ + sigAlgo = ecc_dsa_sa_algo; + } + #endif #if defined(WOLFSSL_ECDSA_MATCH_HASH) && defined(USE_ECDSA_KEYSZ_HASH_ALGO) #error "WOLFSSL_ECDSA_MATCH_HASH and USE_ECDSA_KEYSZ_HASH_ALGO cannot " @@ -29439,7 +29538,7 @@ int PickHashSigAlgo(WOLFSSL* ssl, const byte* hashSigAlgo, word32 hashSigAlgoSz, return ret; } -#endif /* !defined(NO_WOLFSSL_SERVER) || !defined(NO_CERTS) */ +#endif /* !NO_TLS && (!defined(NO_WOLFSSL_SERVER) || !defined(NO_CERTS)) */ #if defined(WOLFSSL_CALLBACKS) || defined(OPENSSL_EXTRA) diff --git a/src/ssl.c b/src/ssl.c index 73c44d40f..6aef8e925 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -12442,6 +12442,7 @@ int wolfSSL_set_compression(WOLFSSL* ssl) *sigAlgo = DSAk; break; case ecc_dsa_sa_algo: + case ecc_brainpool_sa_algo: *sigAlgo = ECDSAk; break; case rsa_pss_sa_algo: @@ -18367,6 +18368,7 @@ static int SaToNid(byte sa, int* nid) *nid = WC_NID_dsa; break; case ecc_dsa_sa_algo: + case ecc_brainpool_sa_algo: *nid = WC_NID_X9_62_id_ecPublicKey; break; case rsa_pss_sa_algo: diff --git a/src/tls.c b/src/tls.c index e4115c895..b7ba5f2ea 100644 --- a/src/tls.c +++ b/src/tls.c @@ -5332,6 +5332,31 @@ int TLSX_SupportedFFDHE_Set(WOLFSSL* ssl) } #endif /* HAVE_FFDHE && !WOLFSSL_NO_TLS12 */ +/* Check if the given curve is present in the supported groups extension. + * + * ssl SSL/TLS object. + * name The curve name to check. + * returns 1 if present, 0 otherwise. + */ +int TLSX_SupportedCurve_IsSupported(WOLFSSL* ssl, word16 name) +{ + TLSX* extension; + SupportedCurve* curve; + + extension = TLSX_Find(ssl->extensions, TLSX_SUPPORTED_GROUPS); + if (extension == NULL) + return 0; + + curve = (SupportedCurve*)extension->data; + while (curve != NULL) { + if (curve->name == name) + return 1; + curve = curve->next; + } + + return 0; +} + #endif /* !NO_WOLFSSL_SERVER */ #if defined(WOLFSSL_TLS13) && !defined(WOLFSSL_NO_SERVER_GROUPS_EXT) diff --git a/src/tls13.c b/src/tls13.c index 9b4d829b1..6c4eeb4c4 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -7786,12 +7786,12 @@ static int SendTls13CertificateRequest(WOLFSSL* ssl, byte* reqCtx, return SIDE_ERROR; /* Get the length of the hashSigAlgo buffer */ - InitSuitesHashSigAlgo(NULL, SIG_ALL, 1, ssl->buffers.keySz, + InitSuitesHashSigAlgo(NULL, SIG_ALL, 1, 1, ssl->buffers.keySz, &hashSigAlgoSz); sa = TLSX_SignatureAlgorithms_New(ssl, hashSigAlgoSz, ssl->heap); if (sa == NULL) return MEMORY_ERROR; - InitSuitesHashSigAlgo(sa->hashSigAlgo, SIG_ALL, 1, ssl->buffers.keySz, + InitSuitesHashSigAlgo(sa->hashSigAlgo, SIG_ALL, 1, 1, ssl->buffers.keySz, &hashSigAlgoSz); ret = TLSX_Push(&ssl->extensions, TLSX_SIGNATURE_ALGORITHMS, sa, ssl->heap); if (ret != 0) { @@ -7898,8 +7898,22 @@ static WC_INLINE void EncodeSigAlg(const WOLFSSL * ssl, byte hashAlgo, byte hsTy switch (hsType) { #ifdef HAVE_ECC case ecc_dsa_sa_algo: - output[0] = hashAlgo; - output[1] = ecc_dsa_sa_algo; + if (ssl->pkCurveOID == ECC_BRAINPOOLP256R1_OID) { + output[0] = NEW_SA_MAJOR; + output[1] = ECDSA_BRAINPOOLP256R1TLS13_SHA256_MINOR; + } + else if (ssl->pkCurveOID == ECC_BRAINPOOLP384R1_OID) { + output[0] = NEW_SA_MAJOR; + output[1] = ECDSA_BRAINPOOLP384R1TLS13_SHA384_MINOR; + } + else if (ssl->pkCurveOID == ECC_BRAINPOOLP512R1_OID) { + output[0] = NEW_SA_MAJOR; + output[1] = ECDSA_BRAINPOOLP512R1TLS13_SHA512_MINOR; + } + else { + output[0] = hashAlgo; + output[1] = ecc_dsa_sa_algo; + } break; #endif #if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3) @@ -8068,16 +8082,19 @@ static enum wc_MACAlgorithm GetNewSAHashAlgo(int typeIn) switch (typeIn) { case RSA_PSS_RSAE_SHA256_MINOR: case RSA_PSS_PSS_SHA256_MINOR: + case ECDSA_BRAINPOOLP256R1TLS13_SHA256_MINOR: return sha256_mac; case RSA_PSS_RSAE_SHA384_MINOR: case RSA_PSS_PSS_SHA384_MINOR: + case ECDSA_BRAINPOOLP384R1TLS13_SHA384_MINOR: return sha384_mac; case RSA_PSS_RSAE_SHA512_MINOR: case RSA_PSS_PSS_SHA512_MINOR: case ED25519_SA_MINOR: case ED448_SA_MINOR: + case ECDSA_BRAINPOOLP512R1TLS13_SHA512_MINOR: return sha512_mac; default: return no_mac; @@ -8133,6 +8150,13 @@ static WC_INLINE int DecodeTls13SigAlg(byte* input, byte* hashAlgo, *hsType = ed448_sa_algo; /* Hash performed as part of sign/verify operation. */ } + #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)) { + *hsType = ecc_dsa_sa_algo; + } #endif else ret = INVALID_PARAMETER; @@ -10564,17 +10588,12 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, #ifdef HAVE_ECC if ((ssl->options.peerSigAlgo == ecc_dsa_sa_algo) && (ssl->peerEccDsaKeyPresent)) { - #if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3) - if (ssl->options.peerSigAlgo != sm2_sa_algo) - #endif - { - ret = CreateECCEncodedSig(args->sigData, - args->sigDataSz, ssl->options.peerHashAlgo); - if (ret < 0) - goto exit_dcv; - args->sigDataSz = (word16)ret; - ret = 0; - } + ret = CreateECCEncodedSig(args->sigData, + args->sigDataSz, ssl->options.peerHashAlgo); + if (ret < 0) + goto exit_dcv; + args->sigDataSz = (word16)ret; + ret = 0; } #ifdef WOLFSSL_DUAL_ALG_CERTS diff --git a/tests/api.c b/tests/api.c index f2e3401e0..b55751f97 100644 --- a/tests/api.c +++ b/tests/api.c @@ -16091,7 +16091,7 @@ static int test_wolfSSL_sigalg_info(void) word16 idx = 0; int allSigAlgs = SIG_ECDSA | SIG_RSA | SIG_SM2 | SIG_FALCON | SIG_DILITHIUM; - InitSuitesHashSigAlgo(hashSigAlgo, allSigAlgs, 1, 0xFFFFFFFF, &len); + InitSuitesHashSigAlgo(hashSigAlgo, allSigAlgs, 1, 1, 0xFFFFFFFF, &len); for (idx = 0; idx < len; idx += 2) { int hashAlgo = 0; int sigAlgo = 0; @@ -16103,7 +16103,7 @@ static int test_wolfSSL_sigalg_info(void) ExpectIntNE(sigAlgo, 0); } - InitSuitesHashSigAlgo(hashSigAlgo, allSigAlgs | SIG_ANON, 1, + InitSuitesHashSigAlgo(hashSigAlgo, allSigAlgs | SIG_ANON, 1, 1, 0xFFFFFFFF, &len); for (idx = 0; idx < len; idx += 2) { int hashAlgo = 0; @@ -29192,7 +29192,13 @@ static int test_certreq_sighash_algos(void) 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] == 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); diff --git a/tests/test-ecc-cust-curves.conf b/tests/test-ecc-cust-curves.conf index 7ad1d7891..42f8b3561 100644 --- a/tests/test-ecc-cust-curves.conf +++ b/tests/test-ecc-cust-curves.conf @@ -49,7 +49,7 @@ -A ./certs/ecc/client-secp256k1-cert.pem -V -# client TLSv1.2 ECDHE-ECDSA-AES128-GCM-SHA256 (mutal auth) +# client TLSv1.2 ECDHE-ECDSA-AES128-GCM-SHA256 (mutual auth) -v 3 -l ECDHE-ECDSA-AES128-GCM-SHA256 -c ./certs/ecc/client-secp256k1-cert.pem @@ -65,7 +65,7 @@ -A ./certs/ecc/client-secp256k1-cert.pem -V -# client TLSv1.2 ECDH-ECDSA-AES128-GCM-SHA256 (static - mutal auth) +# client TLSv1.2 ECDH-ECDSA-AES128-GCM-SHA256 (static - mutual auth) -v 3 -l ECDH-ECDSA-AES128-GCM-SHA256 -c ./certs/ecc/client-secp256k1-cert.pem @@ -73,7 +73,7 @@ -A ./certs/ecc/server-secp256k1-cert.pem -C -# server TLSv1.3 TLS13-AES128-GCM-SHA256 (mutal auth) +# server TLSv1.3 TLS13-AES128-GCM-SHA256 (mutual auth) -v 4 -l TLS13-AES128-GCM-SHA256 -c ./certs/ecc/server-secp256k1-cert.pem @@ -81,7 +81,7 @@ -A ./certs/ecc/client-secp256k1-cert.pem -V -# client TLSv1.3 TLS13-AES128-GCM-SHA256 (mutal auth) +# client TLSv1.3 TLS13-AES128-GCM-SHA256 (mutual auth) -v 4 -l TLS13-AES128-GCM-SHA256 -c ./certs/ecc/client-secp256k1-cert.pem @@ -140,7 +140,7 @@ -A ./certs/ecc/client-bp256r1-cert.pem -V -# client TLSv1.2 ECDHE-ECDSA-AES128-GCM-SHA256 (mutal auth) +# client TLSv1.2 ECDHE-ECDSA-AES128-GCM-SHA256 (mutual auth) -v 3 -l ECDHE-ECDSA-AES128-GCM-SHA256 -c ./certs/ecc/client-bp256r1-cert.pem @@ -156,7 +156,7 @@ -A ./certs/ecc/client-bp256r1-cert.pem -V -# client TLSv1.2 ECDH-ECDSA-AES128-GCM-SHA256 (static - mutal auth) +# client TLSv1.2 ECDH-ECDSA-AES128-GCM-SHA256 (static - mutual auth) -v 3 -l ECDH-ECDSA-AES128-GCM-SHA256 -c ./certs/ecc/client-bp256r1-cert.pem @@ -164,7 +164,7 @@ -A ./certs/ecc/server-bp256r1-cert.pem -C -# server TLSv1.3 TLS13-AES128-GCM-SHA256 (mutal auth) +# server TLSv1.3 TLS13-AES128-GCM-SHA256 (mutual auth) -v 4 -l TLS13-AES128-GCM-SHA256 -c ./certs/ecc/server-bp256r1-cert.pem @@ -172,7 +172,7 @@ -A ./certs/ecc/client-bp256r1-cert.pem -V -# client TLSv1.3 TLS13-AES128-GCM-SHA256 (mutal auth) +# client TLSv1.3 TLS13-AES128-GCM-SHA256 (mutual auth) -v 4 -l TLS13-AES128-GCM-SHA256 -c ./certs/ecc/client-bp256r1-cert.pem @@ -211,7 +211,6 @@ --bpKs -7 3 - # server TLSv1.2 ECDHE-ECDSA-AES128-GCM-SHA256 -v 3 -l ECDHE-ECDSA-AES128-GCM-SHA256 diff --git a/wolfssl/internal.h b/wolfssl/internal.h index ac11ce992..d5ed774e9 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -1761,6 +1761,9 @@ enum Misc { RSA_PSS_PSS_SHA256_MINOR = 0x09, RSA_PSS_PSS_SHA384_MINOR = 0x0A, RSA_PSS_PSS_SHA512_MINOR = 0x0B, + ECDSA_BRAINPOOLP256R1TLS13_SHA256_MINOR = 0x1A, + ECDSA_BRAINPOOLP384R1TLS13_SHA384_MINOR = 0x1B, + ECDSA_BRAINPOOLP512R1TLS13_SHA512_MINOR = 0x1C, ED25519_SA_MAJOR = 8, /* Most significant byte for ED25519 */ ED25519_SA_MINOR = 7, /* Least significant byte for ED25519 */ @@ -1884,7 +1887,7 @@ WOLFSSL_LOCAL int NamedGroupIsPqcHybrid(int group); */ #define WOLFSSL_MAX_SIGALGO 128 #else - #define WOLFSSL_MAX_SIGALGO 38 + #define WOLFSSL_MAX_SIGALGO 44 #endif #endif @@ -2378,7 +2381,8 @@ typedef struct CipherSuite { #define InitSuitesHashSigAlgo wolfSSL_InitSuitesHashSigAlgo #endif WOLFSSL_TEST_VIS void InitSuitesHashSigAlgo(byte* hashSigAlgo, int have, - int tls1_2, int keySz, word16* len); + int tls1_2, int tls1_3, int keySz, + word16* len); WOLFSSL_LOCAL int AllocateCtxSuites(WOLFSSL_CTX* ctx); WOLFSSL_LOCAL int AllocateSuites(WOLFSSL* ssl); WOLFSSL_LOCAL void InitSuites(Suites* suites, ProtocolVersion pv, int keySz, @@ -3399,6 +3403,7 @@ WOLFSSL_LOCAL int TLSX_ValidateSupportedCurves(const WOLFSSL* ssl, byte first, byte second, word32* ecdhCurveOID); WOLFSSL_LOCAL int TLSX_SupportedCurve_CheckPriority(WOLFSSL* ssl); WOLFSSL_LOCAL int TLSX_SupportedFFDHE_Set(WOLFSSL* ssl); +WOLFSSL_LOCAL int TLSX_SupportedCurve_IsSupported(WOLFSSL* ssl, word16 name); #endif WOLFSSL_LOCAL int TLSX_SupportedCurve_Preferred(WOLFSSL* ssl, int checkSupported); @@ -4316,6 +4321,7 @@ enum SignatureAlgorithm { dilithium_level5_sa_algo = 16, sm2_sa_algo = 17, any_sa_algo = 18, + ecc_brainpool_sa_algo = 19, invalid_sa_algo = 255 }; From bde1bf6ce78f435fd15f70113ddba6d135b3b5e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Thu, 22 Jan 2026 13:40:33 +0100 Subject: [PATCH 3/3] Fix user_settings ASM multiple define --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 788b29a81..d276b7fc7 100644 --- a/configure.ac +++ b/configure.ac @@ -10855,7 +10855,7 @@ then # Replace all options and just use WOLFSSL_USER_SETTINGS and # WOLFSSL_USER_SETTINGS_ASM. AM_CFLAGS="-DWOLFSSL_USER_SETTINGS -DWOLFSSL_USER_SETTINGS_ASM" - AM_CCASFLAGS="$AM_CCASFLAGS -DWOLFSSL_USER_SETTINGS -DWOLFSSL_USER_SETTINGS_ASM" + AM_CCASFLAGS="-DWOLFSSL_USER_SETTINGS -DWOLFSSL_USER_SETTINGS_ASM" # Generate assembly-safe user_settings_asm.h (just preprocessor directives # from user_settings.h).