Skip to content

Commit 5ccc512

Browse files
committed
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.
1 parent 27fe8a7 commit 5ccc512

7 files changed

Lines changed: 192 additions & 35 deletions

File tree

src/internal.c

Lines changed: 107 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3312,6 +3312,23 @@ static WC_INLINE void AddSuiteHashSigAlgo(byte* hashSigAlgo, byte macAlgo,
33123312
#endif
33133313
}
33143314
else
3315+
#endif
3316+
#ifdef HAVE_ECC_BRAINPOOL
3317+
if (sigAlgo == ecc_brainpool_sa_algo) {
3318+
if (macAlgo == sha512_mac) {
3319+
ADD_HASH_SIG_ALGO(hashSigAlgo, inOutIdx, NEW_SA_MAJOR,
3320+
ECDSA_BRAINPOOLP512R1TLS13_SHA512_MINOR);
3321+
}
3322+
else if (macAlgo == sha384_mac) {
3323+
ADD_HASH_SIG_ALGO(hashSigAlgo, inOutIdx, NEW_SA_MAJOR,
3324+
ECDSA_BRAINPOOLP384R1TLS13_SHA384_MINOR);
3325+
}
3326+
else if (macAlgo == sha256_mac) {
3327+
ADD_HASH_SIG_ALGO(hashSigAlgo, inOutIdx, NEW_SA_MAJOR,
3328+
ECDSA_BRAINPOOLP256R1TLS13_SHA256_MINOR);
3329+
}
3330+
}
3331+
else
33153332
#endif
33163333
{
33173334
ADD_HASH_SIG_ALGO(hashSigAlgo, inOutIdx, macAlgo, sigAlgo);
@@ -3320,11 +3337,12 @@ static WC_INLINE void AddSuiteHashSigAlgo(byte* hashSigAlgo, byte macAlgo,
33203337
}
33213338

33223339
void InitSuitesHashSigAlgo(byte* hashSigAlgo, int haveSig, int tls1_2,
3323-
int keySz, word16* len)
3340+
int tls1_3, int keySz, word16* len)
33243341
{
33253342
word16 idx = 0;
33263343

33273344
(void)tls1_2;
3345+
(void)tls1_3;
33283346
(void)keySz;
33293347

33303348
#if defined(HAVE_ECC) || defined(HAVE_ED25519) || defined(HAVE_ED448)
@@ -3333,14 +3351,32 @@ void InitSuitesHashSigAlgo(byte* hashSigAlgo, int haveSig, int tls1_2,
33333351
#ifdef WOLFSSL_SHA512
33343352
AddSuiteHashSigAlgo(hashSigAlgo, sha512_mac, ecc_dsa_sa_algo, keySz,
33353353
&idx);
3354+
#ifdef HAVE_ECC_BRAINPOOL
3355+
if (tls1_3) {
3356+
AddSuiteHashSigAlgo(hashSigAlgo, sha512_mac, ecc_brainpool_sa_algo,
3357+
keySz, &idx);
3358+
}
3359+
#endif
33363360
#endif
33373361
#ifdef WOLFSSL_SHA384
33383362
AddSuiteHashSigAlgo(hashSigAlgo, sha384_mac, ecc_dsa_sa_algo, keySz,
33393363
&idx);
3364+
#ifdef HAVE_ECC_BRAINPOOL
3365+
if (tls1_3) {
3366+
AddSuiteHashSigAlgo(hashSigAlgo, sha384_mac, ecc_brainpool_sa_algo,
3367+
keySz, &idx);
3368+
}
3369+
#endif
33403370
#endif
33413371
#ifndef NO_SHA256
33423372
AddSuiteHashSigAlgo(hashSigAlgo, sha256_mac, ecc_dsa_sa_algo, keySz,
33433373
&idx);
3374+
#ifdef HAVE_ECC_BRAINPOOL
3375+
if (tls1_3) {
3376+
AddSuiteHashSigAlgo(hashSigAlgo, sha256_mac, ecc_brainpool_sa_algo,
3377+
keySz, &idx);
3378+
}
3379+
#endif
33443380
#endif
33453381
#if !defined(NO_SHA) && (!defined(NO_OLD_TLS) || \
33463382
defined(WOLFSSL_ALLOW_TLS_SHA1))
@@ -4511,8 +4547,8 @@ void InitSuites(Suites* suites, ProtocolVersion pv, int keySz, word16 haveRSA,
45114547
suites->suiteSz = idx;
45124548

45134549
if (suites->hashSigAlgoSz == 0) {
4514-
InitSuitesHashSigAlgo(suites->hashSigAlgo, SIG_ALL, tls1_2, keySz,
4515-
&suites->hashSigAlgoSz);
4550+
InitSuitesHashSigAlgo(suites->hashSigAlgo, SIG_ALL, tls1_2, tls1_3,
4551+
keySz, &suites->hashSigAlgoSz);
45164552
}
45174553

45184554
/* Moved to the end as we set some of the vars but never use them */
@@ -4571,6 +4607,22 @@ void DecodeSigAlg(const byte* input, byte* hashAlgo, byte* hsType)
45714607
*hashAlgo = PSS_PSS_HASH_TO_MAC(input[1]);
45724608
}
45734609
else
4610+
#endif
4611+
#ifdef HAVE_ECC_BRAINPOOL
4612+
/* RFC 8734 TLS 1.3 Brainpool curves */
4613+
if (input[1] == ECDSA_BRAINPOOLP256R1TLS13_SHA256_MINOR) {
4614+
*hsType = ecc_brainpool_sa_algo;
4615+
*hashAlgo = sha256_mac;
4616+
}
4617+
else if (input[1] == ECDSA_BRAINPOOLP384R1TLS13_SHA384_MINOR) {
4618+
*hsType = ecc_brainpool_sa_algo;
4619+
*hashAlgo = sha384_mac;
4620+
}
4621+
else if (input[1] == ECDSA_BRAINPOOLP512R1TLS13_SHA512_MINOR) {
4622+
*hsType = ecc_brainpool_sa_algo;
4623+
*hashAlgo = sha512_mac;
4624+
}
4625+
else
45744626
#endif
45754627
{
45764628
*hsType = input[0];
@@ -28273,6 +28325,7 @@ static int ParseCipherList(Suites* suites,
2827328325
word16 haveSHA1 = 1; /* allowed by default if compiled in */
2827428326
word16 haveRC4 = 1; /* allowed by default if compiled in */
2827528327
#endif
28328+
int tls1_3 = 0;
2827628329
const int suiteSz = GetCipherNamesSize();
2827728330
const char* next = list;
2827828331

@@ -28598,6 +28651,7 @@ static int ParseCipherList(Suites* suites,
2859828651
(cipher_names[i].cipherSuite0 == ECC_BYTE &&
2859928652
(cipher_names[i].cipherSuite == TLS_SHA256_SHA256 ||
2860028653
cipher_names[i].cipherSuite == TLS_SHA384_SHA384))) {
28654+
tls1_3 = 1;
2860128655
#ifndef NO_RSA
2860228656
haveSig |= SIG_RSA;
2860328657
#endif
@@ -28701,8 +28755,8 @@ static int ParseCipherList(Suites* suites,
2870128755
#endif
2870228756
{
2870328757
suites->suiteSz = (word16)idx;
28704-
InitSuitesHashSigAlgo(suites->hashSigAlgo, haveSig, 1, keySz,
28705-
&suites->hashSigAlgoSz);
28758+
InitSuitesHashSigAlgo(suites->hashSigAlgo, haveSig, 1, tls1_3,
28759+
keySz, &suites->hashSigAlgoSz);
2870628760
}
2870728761

2870828762
#ifdef HAVE_RENEGOTIATION_INDICATION
@@ -28775,6 +28829,7 @@ int SetCipherListFromBytes(WOLFSSL_CTX* ctx, Suites* suites, const byte* list,
2877528829
int haveFalconSig = 0;
2877628830
int haveDilithiumSig = 0;
2877728831
int haveAnon = 0;
28832+
int tls1_3 = 0;
2877828833

2877928834
if (suites == NULL || list == NULL) {
2878028835
WOLFSSL_MSG("SetCipherListFromBytes parameter error");
@@ -28834,6 +28889,7 @@ int SetCipherListFromBytes(WOLFSSL_CTX* ctx, Suites* suites, const byte* list,
2883428889
secondByte == TLS_SHA384_SHA384)) ||
2883528890
(firstByte == CIPHER_BYTE && (secondByte == TLS_SM4_GCM_SM3 ||
2883628891
secondByte == TLS_SM4_CCM_SM3))) {
28892+
tls1_3 = 1;
2883728893
#ifndef NO_RSA
2883828894
haveRSAsig = 1;
2883928895
#endif
@@ -28885,8 +28941,8 @@ int SetCipherListFromBytes(WOLFSSL_CTX* ctx, Suites* suites, const byte* list,
2888528941
haveSig |= haveFalconSig ? SIG_FALCON : 0;
2888628942
haveSig |= haveDilithiumSig ? SIG_DILITHIUM : 0;
2888728943
haveSig |= haveAnon ? SIG_ANON : 0;
28888-
InitSuitesHashSigAlgo(suites->hashSigAlgo, haveSig, 1, keySz,
28889-
&suites->hashSigAlgoSz);
28944+
InitSuitesHashSigAlgo(suites->hashSigAlgo, haveSig, 1, tls1_3,
28945+
keySz, &suites->hashSigAlgoSz);
2889028946
#ifdef HAVE_RENEGOTIATION_INDICATION
2889128947
if (ctx->method->side == WOLFSSL_CLIENT_END) {
2889228948
if (suites->suiteSz > WOLFSSL_MAX_SUITE_SZ - 2) {
@@ -29134,6 +29190,41 @@ static int MatchSigAlgo(WOLFSSL* ssl, int sigAlgo)
2913429190
if (sigAlgo == rsa_pss_sa_algo)
2913529191
return 1;
2913629192
}
29193+
#endif
29194+
#ifdef HAVE_ECC_BRAINPOOL
29195+
if ((ssl->pkCurveOID == ECC_BRAINPOOLP256R1_OID) ||
29196+
(ssl->pkCurveOID == ECC_BRAINPOOLP384R1_OID) ||
29197+
(ssl->pkCurveOID == ECC_BRAINPOOLP512R1_OID)) {
29198+
if (IsAtLeastTLSv1_3(ssl->version)) {
29199+
/* Certificate has an ECC Brainpool key, only match with the
29200+
* specified ECDSA brainpool signature algorithms for TLS 1.3 */
29201+
return sigAlgo == ecc_brainpool_sa_algo;
29202+
}
29203+
else {
29204+
/* Certificate has an ECC Brainpool key, match with ECDSA in TLS 1.2
29205+
* case, but only when the related Brainpool curve is present in
29206+
* the supported_groups extension. */
29207+
if (ssl->pkCurveOID == ECC_BRAINPOOLP256R1_OID &&
29208+
TLSX_SupportedCurve_IsSupported(ssl,
29209+
WOLFSSL_ECC_BRAINPOOLP256R1)) {
29210+
return sigAlgo == ecc_dsa_sa_algo;
29211+
}
29212+
else if (ssl->pkCurveOID == ECC_BRAINPOOLP384R1_OID &&
29213+
TLSX_SupportedCurve_IsSupported(ssl,
29214+
WOLFSSL_ECC_BRAINPOOLP384R1)) {
29215+
return sigAlgo == ecc_dsa_sa_algo;
29216+
}
29217+
else if (ssl->pkCurveOID == ECC_BRAINPOOLP512R1_OID &&
29218+
TLSX_SupportedCurve_IsSupported(ssl,
29219+
WOLFSSL_ECC_BRAINPOOLP512R1)) {
29220+
return sigAlgo == ecc_dsa_sa_algo;
29221+
}
29222+
else {
29223+
/* Curve not supported in supported_groups extension. */
29224+
return 0;
29225+
}
29226+
}
29227+
}
2913729228
#endif
2913829229
/* Signature algorithm matches certificate. */
2913929230
return sigAlgo == ssl->options.sigAlgo;
@@ -29299,6 +29390,15 @@ int PickHashSigAlgo(WOLFSSL* ssl, const byte* hashSigAlgo, word32 hashSigAlgoSz,
2929929390
break;
2930029391
}
2930129392
#endif /* HAVE_DILITHIUM */
29393+
#if defined(HAVE_ECC_BRAINPOOL)
29394+
if (ssl->pkCurveOID == ECC_BRAINPOOLP256R1_OID ||
29395+
ssl->pkCurveOID == ECC_BRAINPOOLP384R1_OID ||
29396+
ssl->pkCurveOID == ECC_BRAINPOOLP512R1_OID) {
29397+
/* Matched ECC Brainpool. Set sigAlgo to "normal" ECDSA here
29398+
* for compatibilty with TLS 1.2. */
29399+
sigAlgo = ecc_dsa_sa_algo;
29400+
}
29401+
#endif
2930229402

2930329403
#if defined(WOLFSSL_ECDSA_MATCH_HASH) && defined(USE_ECDSA_KEYSZ_HASH_ALGO)
2930429404
#error "WOLFSSL_ECDSA_MATCH_HASH and USE_ECDSA_KEYSZ_HASH_ALGO cannot "

src/ssl.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12442,6 +12442,7 @@ int wolfSSL_set_compression(WOLFSSL* ssl)
1244212442
*sigAlgo = DSAk;
1244312443
break;
1244412444
case ecc_dsa_sa_algo:
12445+
case ecc_brainpool_sa_algo:
1244512446
*sigAlgo = ECDSAk;
1244612447
break;
1244712448
case rsa_pss_sa_algo:
@@ -18367,6 +18368,7 @@ static int SaToNid(byte sa, int* nid)
1836718368
*nid = WC_NID_dsa;
1836818369
break;
1836918370
case ecc_dsa_sa_algo:
18371+
case ecc_brainpool_sa_algo:
1837018372
*nid = WC_NID_X9_62_id_ecPublicKey;
1837118373
break;
1837218374
case rsa_pss_sa_algo:

src/tls.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5332,6 +5332,31 @@ int TLSX_SupportedFFDHE_Set(WOLFSSL* ssl)
53325332
}
53335333
#endif /* HAVE_FFDHE && !WOLFSSL_NO_TLS12 */
53345334

5335+
/* Check if the given curve is present in the supported groups extension.
5336+
*
5337+
* ssl SSL/TLS object.
5338+
* name The curve name to check.
5339+
* returns 1 if present, 0 otherwise.
5340+
*/
5341+
int TLSX_SupportedCurve_IsSupported(WOLFSSL* ssl, word16 name)
5342+
{
5343+
TLSX* extension;
5344+
SupportedCurve* curve;
5345+
5346+
extension = TLSX_Find(ssl->extensions, TLSX_SUPPORTED_GROUPS);
5347+
if (extension == NULL)
5348+
return 0;
5349+
5350+
curve = (SupportedCurve*)extension->data;
5351+
while (curve != NULL) {
5352+
if (curve->name == name)
5353+
return 1;
5354+
curve = curve->next;
5355+
}
5356+
5357+
return 0;
5358+
}
5359+
53355360
#endif /* !NO_WOLFSSL_SERVER */
53365361

53375362
#if defined(WOLFSSL_TLS13) && !defined(WOLFSSL_NO_SERVER_GROUPS_EXT)

src/tls13.c

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7786,12 +7786,12 @@ static int SendTls13CertificateRequest(WOLFSSL* ssl, byte* reqCtx,
77867786
return SIDE_ERROR;
77877787

77887788
/* Get the length of the hashSigAlgo buffer */
7789-
InitSuitesHashSigAlgo(NULL, SIG_ALL, 1, ssl->buffers.keySz,
7789+
InitSuitesHashSigAlgo(NULL, SIG_ALL, 1, 1, ssl->buffers.keySz,
77907790
&hashSigAlgoSz);
77917791
sa = TLSX_SignatureAlgorithms_New(ssl, hashSigAlgoSz, ssl->heap);
77927792
if (sa == NULL)
77937793
return MEMORY_ERROR;
7794-
InitSuitesHashSigAlgo(sa->hashSigAlgo, SIG_ALL, 1, ssl->buffers.keySz,
7794+
InitSuitesHashSigAlgo(sa->hashSigAlgo, SIG_ALL, 1, 1, ssl->buffers.keySz,
77957795
&hashSigAlgoSz);
77967796
ret = TLSX_Push(&ssl->extensions, TLSX_SIGNATURE_ALGORITHMS, sa, ssl->heap);
77977797
if (ret != 0) {
@@ -7898,8 +7898,22 @@ static WC_INLINE void EncodeSigAlg(const WOLFSSL * ssl, byte hashAlgo, byte hsTy
78987898
switch (hsType) {
78997899
#ifdef HAVE_ECC
79007900
case ecc_dsa_sa_algo:
7901-
output[0] = hashAlgo;
7902-
output[1] = ecc_dsa_sa_algo;
7901+
if (ssl->pkCurveOID == ECC_BRAINPOOLP256R1_OID) {
7902+
output[0] = NEW_SA_MAJOR;
7903+
output[1] = ECDSA_BRAINPOOLP256R1TLS13_SHA256_MINOR;
7904+
}
7905+
else if (ssl->pkCurveOID == ECC_BRAINPOOLP384R1_OID) {
7906+
output[0] = NEW_SA_MAJOR;
7907+
output[1] = ECDSA_BRAINPOOLP384R1TLS13_SHA384_MINOR;
7908+
}
7909+
else if (ssl->pkCurveOID == ECC_BRAINPOOLP512R1_OID) {
7910+
output[0] = NEW_SA_MAJOR;
7911+
output[1] = ECDSA_BRAINPOOLP512R1TLS13_SHA512_MINOR;
7912+
}
7913+
else {
7914+
output[0] = hashAlgo;
7915+
output[1] = ecc_dsa_sa_algo;
7916+
}
79037917
break;
79047918
#endif
79057919
#if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3)
@@ -8068,16 +8082,19 @@ static enum wc_MACAlgorithm GetNewSAHashAlgo(int typeIn)
80688082
switch (typeIn) {
80698083
case RSA_PSS_RSAE_SHA256_MINOR:
80708084
case RSA_PSS_PSS_SHA256_MINOR:
8085+
case ECDSA_BRAINPOOLP256R1TLS13_SHA256_MINOR:
80718086
return sha256_mac;
80728087

80738088
case RSA_PSS_RSAE_SHA384_MINOR:
80748089
case RSA_PSS_PSS_SHA384_MINOR:
8090+
case ECDSA_BRAINPOOLP384R1TLS13_SHA384_MINOR:
80758091
return sha384_mac;
80768092

80778093
case RSA_PSS_RSAE_SHA512_MINOR:
80788094
case RSA_PSS_PSS_SHA512_MINOR:
80798095
case ED25519_SA_MINOR:
80808096
case ED448_SA_MINOR:
8097+
case ECDSA_BRAINPOOLP512R1TLS13_SHA512_MINOR:
80818098
return sha512_mac;
80828099
default:
80838100
return no_mac;
@@ -8133,6 +8150,13 @@ static WC_INLINE int DecodeTls13SigAlg(byte* input, byte* hashAlgo,
81338150
*hsType = ed448_sa_algo;
81348151
/* Hash performed as part of sign/verify operation. */
81358152
}
8153+
#endif
8154+
#ifdef HAVE_ECC_BRAINPOOL
8155+
else if ((input[1] == ECDSA_BRAINPOOLP256R1TLS13_SHA256_MINOR) ||
8156+
(input[1] == ECDSA_BRAINPOOLP384R1TLS13_SHA384_MINOR) ||
8157+
(input[1] == ECDSA_BRAINPOOLP512R1TLS13_SHA512_MINOR)) {
8158+
*hsType = ecc_dsa_sa_algo;
8159+
}
81368160
#endif
81378161
else
81388162
ret = INVALID_PARAMETER;
@@ -10564,17 +10588,12 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input,
1056410588
#ifdef HAVE_ECC
1056510589
if ((ssl->options.peerSigAlgo == ecc_dsa_sa_algo) &&
1056610590
(ssl->peerEccDsaKeyPresent)) {
10567-
#if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3)
10568-
if (ssl->options.peerSigAlgo != sm2_sa_algo)
10569-
#endif
10570-
{
10571-
ret = CreateECCEncodedSig(args->sigData,
10572-
args->sigDataSz, ssl->options.peerHashAlgo);
10573-
if (ret < 0)
10574-
goto exit_dcv;
10575-
args->sigDataSz = (word16)ret;
10576-
ret = 0;
10577-
}
10591+
ret = CreateECCEncodedSig(args->sigData,
10592+
args->sigDataSz, ssl->options.peerHashAlgo);
10593+
if (ret < 0)
10594+
goto exit_dcv;
10595+
args->sigDataSz = (word16)ret;
10596+
ret = 0;
1057810597
}
1057910598

1058010599
#ifdef WOLFSSL_DUAL_ALG_CERTS

tests/api.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16091,7 +16091,7 @@ static int test_wolfSSL_sigalg_info(void)
1609116091
word16 idx = 0;
1609216092
int allSigAlgs = SIG_ECDSA | SIG_RSA | SIG_SM2 | SIG_FALCON | SIG_DILITHIUM;
1609316093

16094-
InitSuitesHashSigAlgo(hashSigAlgo, allSigAlgs, 1, 0xFFFFFFFF, &len);
16094+
InitSuitesHashSigAlgo(hashSigAlgo, allSigAlgs, 1, 1, 0xFFFFFFFF, &len);
1609516095
for (idx = 0; idx < len; idx += 2) {
1609616096
int hashAlgo = 0;
1609716097
int sigAlgo = 0;
@@ -16103,7 +16103,7 @@ static int test_wolfSSL_sigalg_info(void)
1610316103
ExpectIntNE(sigAlgo, 0);
1610416104
}
1610516105

16106-
InitSuitesHashSigAlgo(hashSigAlgo, allSigAlgs | SIG_ANON, 1,
16106+
InitSuitesHashSigAlgo(hashSigAlgo, allSigAlgs | SIG_ANON, 1, 1,
1610716107
0xFFFFFFFF, &len);
1610816108
for (idx = 0; idx < len; idx += 2) {
1610916109
int hashAlgo = 0;
@@ -29192,7 +29192,13 @@ static int test_certreq_sighash_algos(void)
2919229192
maxIdx = idx + (int)len;
2919329193
for (; idx < maxIdx && EXPECT_SUCCESS(); idx += OPAQUE16_LEN) {
2919429194
if (test_ctx.c_buff[idx+1] == ED25519_SA_MINOR ||
29195-
test_ctx.c_buff[idx+1] == ED448_SA_MINOR)
29195+
test_ctx.c_buff[idx+1] == ED448_SA_MINOR ||
29196+
test_ctx.c_buff[idx+1] ==
29197+
ECDSA_BRAINPOOLP256R1TLS13_SHA256_MINOR ||
29198+
test_ctx.c_buff[idx+1] ==
29199+
ECDSA_BRAINPOOLP384R1TLS13_SHA384_MINOR ||
29200+
test_ctx.c_buff[idx+1] ==
29201+
ECDSA_BRAINPOOLP512R1TLS13_SHA512_MINOR)
2919629202
ExpectIntEQ(test_ctx.c_buff[idx], NEW_SA_MAJOR);
2919729203
else
2919829204
ExpectIntEQ(test_ctx.c_buff[idx+1], ecc_dsa_sa_algo);

0 commit comments

Comments
 (0)