diff options
Diffstat (limited to 'extra/wolfssl/wolfssl/src/tls13.c')
-rw-r--r-- | extra/wolfssl/wolfssl/src/tls13.c | 934 |
1 files changed, 777 insertions, 157 deletions
diff --git a/extra/wolfssl/wolfssl/src/tls13.c b/extra/wolfssl/wolfssl/src/tls13.c index d16a5761..9a2e240c 100644 --- a/extra/wolfssl/wolfssl/src/tls13.c +++ b/extra/wolfssl/wolfssl/src/tls13.c @@ -117,6 +117,7 @@ #include <wolfssl/wolfcrypt/asn.h> #include <wolfssl/wolfcrypt/dh.h> #include <wolfssl/wolfcrypt/kdf.h> +#include <wolfssl/wolfcrypt/signature.h> #ifdef NO_INLINE #include <wolfssl/wolfcrypt/misc.h> #else @@ -135,6 +136,15 @@ #define FALSE 0 #endif +#ifndef HAVE_AEAD + #ifndef _MSC_VER + #error "The build option HAVE_AEAD is required for TLS 1.3" + #else + #pragma \ + message("error: The build option HAVE_AEAD is required for TLS 1.3") + #endif +#endif + #ifndef HAVE_HKDF #ifndef _MSC_VER #error "The build option HAVE_HKDF is required for TLS 1.3" @@ -187,21 +197,7 @@ static WC_INLINE int GetMsgHash(WOLFSSL* ssl, byte* hash); #endif /* Expand data using HMAC, salt and label and info. - * TLS v1.3 defines this function. Use callback if available. - * - * ssl The SSL/TLS object. - * okm The generated pseudorandom key - output key material. - * okmLen The length of generated pseudorandom key - - * output key material. - * prk The salt - pseudo-random key. - * prkLen The length of the salt - pseudo-random key. - * protocol The TLS protocol label. - * protocolLen The length of the TLS protocol label. - * info The information to expand. - * infoLen The length of the information. - * digest The type of digest to use. - * returns 0 on success, otherwise failure. - */ + * TLS v1.3 defines this function. Use callback if available. */ static int Tls13HKDFExpandLabel(WOLFSSL* ssl, byte* okm, word32 okmLen, const byte* prk, word32 prkLen, const byte* protocol, word32 protocolLen, @@ -225,18 +221,24 @@ static int Tls13HKDFExpandLabel(WOLFSSL* ssl, byte* okm, word32 okmLen, #endif (void)ssl; PRIVATE_KEY_UNLOCK(); +#if !defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3)) + ret = wc_Tls13_HKDF_Expand_Label_ex(okm, okmLen, prk, prkLen, + protocol, protocolLen, + label, labelLen, + info, infoLen, digest, + ssl->heap, ssl->devId); +#else ret = wc_Tls13_HKDF_Expand_Label(okm, okmLen, prk, prkLen, protocol, protocolLen, label, labelLen, info, infoLen, digest); +#endif PRIVATE_KEY_LOCK(); return ret; } -#if !defined(HAVE_FIPS) || !defined(wc_Tls13_HKDF_Expand_Label) -/* Same as above, but pass in the side we are expanding for. - * - * side The side (WOLFSSL_CLIENT_END or WOLFSSL_SERVER_END). +/* Same as above, but pass in the side we are expanding for: + * side: either WOLFSSL_CLIENT_END or WOLFSSL_SERVER_END. */ static int Tls13HKDFExpandKeyLabel(WOLFSSL* ssl, byte* okm, word32 okmLen, const byte* prk, word32 prkLen, @@ -245,8 +247,9 @@ static int Tls13HKDFExpandKeyLabel(WOLFSSL* ssl, byte* okm, word32 okmLen, const byte* info, word32 infoLen, int digest, int side) { + int ret; #if defined(HAVE_PK_CALLBACKS) - int ret = NOT_COMPILED_IN; + ret = NOT_COMPILED_IN; if (ssl->ctx && ssl->ctx->HKDFExpandLabelCb) { ret = ssl->ctx->HKDFExpandLabelCb(okm, okmLen, prk, prkLen, protocol, protocolLen, @@ -254,25 +257,33 @@ static int Tls13HKDFExpandKeyLabel(WOLFSSL* ssl, byte* okm, word32 okmLen, info, infoLen, digest, side); } - if (ret != NOT_COMPILED_IN) return ret; #endif -/* hash buffer may not be fully initialized, but the sending length won't - * extend beyond the initialized span. - */ -PRAGMA_GCC_DIAG_PUSH -PRAGMA_GCC("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") - (void)ssl; - (void)side; - return wc_Tls13_HKDF_Expand_Label(okm, okmLen, prk, prkLen, +#if !defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3)) + ret = wc_Tls13_HKDF_Expand_Label_ex(okm, okmLen, prk, prkLen, + protocol, protocolLen, + label, labelLen, + info, infoLen, digest, + ssl->heap, ssl->devId); + +#elif defined(HAVE_FIPS) && defined(wc_Tls13_HKDF_Expand_Label) + ret = wc_Tls13_HKDF_Expand_Label_fips(okm, okmLen, prk, prkLen, + protocol, protocolLen, + label, labelLen, + info, infoLen, digest); +#else + ret = wc_Tls13_HKDF_Expand_Label(okm, okmLen, prk, prkLen, protocol, protocolLen, label, labelLen, info, infoLen, digest); -PRAGMA_GCC_DIAG_POP +#endif + (void)ssl; + (void)side; + return ret; } -#endif /* !HAVE_FIPS || !wc_Tls13_HKDF_Expand_Label */ + /* Derive a key from a message. * @@ -302,7 +313,7 @@ static int DeriveKeyMsg(WOLFSSL* ssl, byte* output, int outputLen, switch (hashAlgo) { #ifndef NO_WOLFSSL_SHA256 case sha256_mac: - ret = wc_InitSha256_ex(&digest.sha256, ssl->heap, INVALID_DEVID); + ret = wc_InitSha256_ex(&digest.sha256, ssl->heap, ssl->devId); if (ret == 0) { ret = wc_Sha256Update(&digest.sha256, msg, msgLen); if (ret == 0) @@ -315,7 +326,7 @@ static int DeriveKeyMsg(WOLFSSL* ssl, byte* output, int outputLen, #endif #ifdef WOLFSSL_SHA384 case sha384_mac: - ret = wc_InitSha384_ex(&digest.sha384, ssl->heap, INVALID_DEVID); + ret = wc_InitSha384_ex(&digest.sha384, ssl->heap, ssl->devId); if (ret == 0) { ret = wc_Sha384Update(&digest.sha384, msg, msgLen); if (ret == 0) @@ -328,7 +339,7 @@ static int DeriveKeyMsg(WOLFSSL* ssl, byte* output, int outputLen, #endif #ifdef WOLFSSL_TLS13_SHA512 case sha512_mac: - ret = wc_InitSha512_ex(&digest.sha512, ssl->heap, INVALID_DEVID); + ret = wc_InitSha512_ex(&digest.sha512, ssl->heap, ssl->devId); if (ret == 0) { ret = wc_Sha512Update(&digest.sha512, msg, msgLen); if (ret == 0) @@ -341,7 +352,7 @@ static int DeriveKeyMsg(WOLFSSL* ssl, byte* output, int outputLen, #endif #ifdef WOLFSSL_SM3 case sm3_mac: - ret = wc_InitSm3(&digest.sm3, ssl->heap, INVALID_DEVID); + ret = wc_InitSm3(&digest.sm3, ssl->heap, ssl->devId); if (ret == 0) { ret = wc_Sm3Update(&digest.sm3, msg, msgLen); if (ret == 0) @@ -469,34 +480,31 @@ int Tls13DeriveKey(WOLFSSL* ssl, byte* output, int outputLen, } #endif /* WOLFSSL_DTLS13 */ - if (outputLen == -1) + if (outputLen == -1) { outputLen = hashSz; - if (includeMsgs) + } + if (includeMsgs) { hashOutSz = hashSz; + } + else { + /* Appease static analyzers by making sure hash is cleared, since it is + * passed into expand key label where older wc_Tls13_HKDF_Expand_Label + * will unconditionally try to call a memcpy on it, however length will + * always be 0. */ + XMEMSET(hash, 0, sizeof(hash)); + hashOutSz = 0; + } - /* hash buffer may not be fully initialized, but the sending length won't - * extend beyond the initialized span. - */ - PRAGMA_GCC_DIAG_PUSH - PRAGMA_GCC("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") PRIVATE_KEY_UNLOCK(); - #if defined(HAVE_FIPS) && defined(wc_Tls13_HKDF_Expand_Label) - (void)side; - ret = wc_Tls13_HKDF_Expand_Label_fips(output, outputLen, secret, hashSz, - protocol, protocolLen, label, labelLen, - hash, hashOutSz, digestAlg); - #else ret = Tls13HKDFExpandKeyLabel(ssl, output, outputLen, secret, hashSz, protocol, protocolLen, label, labelLen, hash, hashOutSz, digestAlg, side); - #endif PRIVATE_KEY_LOCK(); #ifdef WOLFSSL_CHECK_MEM_ZERO wc_MemZero_Add("TLS 1.3 derived key", output, outputLen); #endif return ret; - PRAGMA_GCC_DIAG_POP } /* Convert TLS mac ID to a hash algorithm ID @@ -1108,8 +1116,8 @@ static int DeriveTrafficSecret(WOLFSSL* ssl, byte* secret, int side) } -static int Tls13_HKDF_Extract(WOLFSSL *ssl, byte* prk, const byte* salt, int saltLen, - byte* ikm, int ikmLen, int digest) +static int Tls13_HKDF_Extract(WOLFSSL *ssl, byte* prk, const byte* salt, + int saltLen, byte* ikm, int ikmLen, int digest) { int ret; #ifdef HAVE_PK_CALLBACKS @@ -1120,9 +1128,21 @@ static int Tls13_HKDF_Extract(WOLFSSL *ssl, byte* prk, const byte* salt, int sal } else #endif +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + if ((int)ssl->arrays->psk_keySz < 0) { + ret = PSK_KEY_ERROR; + } + else +#endif { - (void)ssl; + #if !defined(HAVE_FIPS) || \ + (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3)) + ret = wc_Tls13_HKDF_Extract_ex(prk, salt, saltLen, ikm, ikmLen, digest, + ssl->heap, ssl->devId); + #else ret = wc_Tls13_HKDF_Extract(prk, salt, saltLen, ikm, ikmLen, digest); + (void)ssl; + #endif } return ret; } @@ -3541,6 +3561,12 @@ int CreateCookieExt(const WOLFSSL* ssl, byte* hash, word16 hashSz, return BAD_FUNC_ARG; } + if (ssl->buffers.tls13CookieSecret.buffer == NULL || + ssl->buffers.tls13CookieSecret.length == 0) { + WOLFSSL_MSG("Missing DTLS 1.3 cookie secret"); + return COOKIE_ERROR; + } + /* Cookie Data = Hash Len | Hash | CS | KeyShare Group */ cookie[cookieSz++] = (byte)hashSz; XMEMCPY(cookie + cookieSz, hash, hashSz); @@ -3923,7 +3949,8 @@ static int SetupPskKey(WOLFSSL* ssl, PreSharedKey* psk, int clientHello) ssl->options.cipherSuite = WOLFSSL_DEF_PSK_CIPHER; } if (ssl->arrays->psk_keySz == 0 || - ssl->arrays->psk_keySz > MAX_PSK_KEY_LEN) { + (ssl->arrays->psk_keySz > MAX_PSK_KEY_LEN && + (int)ssl->arrays->psk_keySz != USE_HW_PSK)) { WOLFSSL_ERROR_VERBOSE(PSK_KEY_ERROR); return PSK_KEY_ERROR; } @@ -3936,7 +3963,7 @@ static int SetupPskKey(WOLFSSL* ssl, PreSharedKey* psk, int clientHello) #endif /* !WOLFSSL_PSK_ONE_ID */ if (!clientHello && (psk->cipherSuite0 != suite[0] || - psk->cipherSuite != suite[1])) { + psk->cipherSuite != suite[1])) { WOLFSSL_ERROR_VERBOSE(PSK_KEY_ERROR); return PSK_KEY_ERROR; } @@ -4688,7 +4715,7 @@ int SendTls13ClientHello(WOLFSSL* ssl) } #if defined(WOLFSSL_DTLS13) && !defined(WOLFSSL_NO_CLIENT) -static int Dtls13DoDowngrade(WOLFSSL* ssl) +static int Dtls13ClientDoDowngrade(WOLFSSL* ssl) { int ret; if (ssl->dtls13ClientHello == NULL) @@ -4719,8 +4746,8 @@ static int EchCheckAcceptance(WOLFSSL* ssl, const byte* input, int serverRandomOffset, int helloSz) { int ret = 0; - int digestType; - int digestSize; + int digestType = 0; + int digestSize = 0; HS_Hashes* tmpHashes; HS_Hashes* acceptHashes; byte zeros[WC_MAX_DIGEST_SIZE]; @@ -4786,17 +4813,30 @@ static int EchCheckAcceptance(WOLFSSL* ssl, const byte* input, } } /* extract clientRandomInner with a key of all zeros */ - if (ret == 0) + if (ret == 0) { + PRIVATE_KEY_UNLOCK(); + #if !defined(HAVE_FIPS) || \ + (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3)) + ret = wc_HKDF_Extract_ex(digestType, zeros, digestSize, + ssl->arrays->clientRandomInner, RAN_LEN, expandLabelPrk, + ssl->heap, ssl->devId); + #else ret = wc_HKDF_Extract(digestType, zeros, digestSize, ssl->arrays->clientRandomInner, RAN_LEN, expandLabelPrk); + #endif + PRIVATE_KEY_LOCK(); + } /* tls expand with the confirmation label */ - if (ret == 0) - ret = wc_Tls13_HKDF_Expand_Label(acceptConfirmation, - ECH_ACCEPT_CONFIRMATION_SZ, - expandLabelPrk, digestSize, tls13ProtocolLabel, - TLS13_PROTOCOL_LABEL_SZ, echAcceptConfirmationLabel, - ECH_ACCEPT_CONFIRMATION_LABEL_SZ, transcriptEchConf, digestSize, - digestType); + if (ret == 0) { + PRIVATE_KEY_UNLOCK(); + ret = Tls13HKDFExpandKeyLabel(ssl, + acceptConfirmation, ECH_ACCEPT_CONFIRMATION_SZ, + expandLabelPrk, digestSize, + tls13ProtocolLabel, TLS13_PROTOCOL_LABEL_SZ, + echAcceptConfirmationLabel, ECH_ACCEPT_CONFIRMATION_LABEL_SZ, + transcriptEchConf, digestSize, digestType, WOLFSSL_SERVER_END); + PRIVATE_KEY_LOCK(); + } if (ret == 0) { /* last 8 bytes should match our expand output */ ret = XMEMCMP(acceptConfirmation, @@ -4839,10 +4879,10 @@ static int EchWriteAcceptance(WOLFSSL* ssl, byte* output, int serverRandomOffset, int helloSz) { int ret = 0; - int digestType; - int digestSize; - HS_Hashes* tmpHashes; - HS_Hashes* acceptHashes; + int digestType = 0; + int digestSize = 0; + HS_Hashes* tmpHashes = NULL; + HS_Hashes* acceptHashes = NULL; byte zeros[WC_MAX_DIGEST_SIZE]; byte transcriptEchConf[WC_MAX_DIGEST_SIZE]; byte expandLabelPrk[WC_MAX_DIGEST_SIZE]; @@ -4913,21 +4953,28 @@ static int EchWriteAcceptance(WOLFSSL* ssl, byte* output, /* extract clientRandom with a key of all zeros */ if (ret == 0) { PRIVATE_KEY_UNLOCK(); + #if !defined(HAVE_FIPS) || \ + (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3)) + ret = wc_HKDF_Extract_ex(digestType, zeros, digestSize, + ssl->arrays->clientRandom, RAN_LEN, expandLabelPrk, + ssl->heap, ssl->devId); + #else ret = wc_HKDF_Extract(digestType, zeros, digestSize, ssl->arrays->clientRandom, RAN_LEN, expandLabelPrk); + #endif PRIVATE_KEY_LOCK(); } /* tls expand with the confirmation label */ if (ret == 0) { PRIVATE_KEY_UNLOCK(); - ret = wc_Tls13_HKDF_Expand_Label( + ret = Tls13HKDFExpandKeyLabel(ssl, output + serverRandomOffset + RAN_LEN - ECH_ACCEPT_CONFIRMATION_SZ, - ECH_ACCEPT_CONFIRMATION_SZ, - expandLabelPrk, digestSize, tls13ProtocolLabel, - TLS13_PROTOCOL_LABEL_SZ, echAcceptConfirmationLabel, - ECH_ACCEPT_CONFIRMATION_LABEL_SZ, transcriptEchConf, digestSize, - digestType); + ECH_ACCEPT_CONFIRMATION_SZ, + expandLabelPrk, digestSize, + tls13ProtocolLabel, TLS13_PROTOCOL_LABEL_SZ, + echAcceptConfirmationLabel, ECH_ACCEPT_CONFIRMATION_LABEL_SZ, + transcriptEchConf, digestSize, digestType, WOLFSSL_SERVER_END); PRIVATE_KEY_LOCK(); } @@ -5074,7 +5121,7 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, if (ssl->options.dtls) { ssl->chVersion.minor = DTLSv1_2_MINOR; ssl->version.minor = DTLSv1_2_MINOR; - ret = Dtls13DoDowngrade(ssl); + ret = Dtls13ClientDoDowngrade(ssl); if (ret != 0) return ret; } @@ -5168,7 +5215,7 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, if (ssl->options.dtls) { ssl->chVersion.minor = DTLSv1_2_MINOR; ssl->version.minor = DTLSv1_2_MINOR; - ret = Dtls13DoDowngrade(ssl); + ret = Dtls13ClientDoDowngrade(ssl); if (ret != 0) return ret; } @@ -5241,7 +5288,7 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, #ifdef WOLFSSL_DTLS13 if (ssl->options.dtls) { - ret = Dtls13DoDowngrade(ssl); + ret = Dtls13ClientDoDowngrade(ssl); if (ret != 0) return ret; } @@ -5799,7 +5846,8 @@ int FindPskSuite(const WOLFSSL* ssl, PreSharedKey* psk, byte* psk_key, *found = (*psk_keySz != 0); } if (*found) { - if (*psk_keySz > MAX_PSK_KEY_LEN) { + if (*psk_keySz > MAX_PSK_KEY_LEN && + *((int*)psk_keySz) != USE_HW_PSK) { WOLFSSL_MSG("Key len too long in FindPsk()"); ret = PSK_KEY_ERROR; WOLFSSL_ERROR_VERBOSE(ret); @@ -5854,29 +5902,27 @@ static int FindPsk(WOLFSSL* ssl, PreSharedKey* psk, const byte* suite, int* err) ret = FindPskSuite(ssl, psk, ssl->arrays->psk_key, &ssl->arrays->psk_keySz, suite, &found, foundSuite); if (ret == 0 && found) { - if ((ret == 0) && found) { - /* Default to ciphersuite if cb doesn't specify. */ - ssl->options.resuming = 0; - /* Don't send certificate request when using PSK. */ - ssl->options.verifyPeer = 0; + /* Default to ciphersuite if cb doesn't specify. */ + ssl->options.resuming = 0; + /* Don't send certificate request when using PSK. */ + ssl->options.verifyPeer = 0; - /* PSK age is always zero. */ - if (psk->ticketAge != 0) { - ret = PSK_KEY_ERROR; - WOLFSSL_ERROR_VERBOSE(ret); - } + /* PSK age is always zero. */ + if (psk->ticketAge != 0) { + ret = PSK_KEY_ERROR; + WOLFSSL_ERROR_VERBOSE(ret); } - if ((ret == 0) && found) { + if (ret == 0) { /* Set PSK ciphersuite into SSL. */ ssl->options.cipherSuite0 = foundSuite[0]; ssl->options.cipherSuite = foundSuite[1]; ret = SetCipherSpecs(ssl); } - if ((ret == 0) && found) { + if (ret == 0) { /* Derive the early secret using the PSK. */ ret = DeriveEarlySecret(ssl); } - if ((ret == 0) && found) { + if (ret == 0) { /* PSK negotiation has succeeded */ ssl->options.isPSK = 1; /* SERVER: using PSK for peer authentication. */ @@ -6296,6 +6342,12 @@ int TlsCheckCookie(const WOLFSSL* ssl, const byte* cookie, word16 cookieSz) byte cookieType = 0; byte macSz = 0; + if (ssl->buffers.tls13CookieSecret.buffer == NULL || + ssl->buffers.tls13CookieSecret.length == 0) { + WOLFSSL_MSG("Missing DTLS 1.3 cookie secret"); + return COOKIE_ERROR; + } + #if !defined(NO_SHA) && defined(NO_SHA256) cookieType = SHA; macSz = WC_SHA_DIGEST_SIZE; @@ -6670,6 +6722,7 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, * wolfSSL_accept_TLSv13 when changing this one. */ if (IsDtlsNotSctpMode(ssl) && ssl->options.sendCookie && !ssl->options.dtlsStateful) { + DtlsSetSeqNumForReply(ssl); ret = DoClientHelloStateless(ssl, input + *inOutIdx, helloSz, 0, NULL); if (ret != 0 || !ssl->options.dtlsStateful) { *inOutIdx += helloSz; @@ -7088,6 +7141,7 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, #ifdef HAVE_SESSION_TICKET if (ssl->options.resuming) { ssl->options.resuming = 0; + ssl->arrays->psk_keySz = 0; XMEMSET(ssl->arrays->psk_key, 0, ssl->specs.hash_size); } #endif @@ -7760,6 +7814,54 @@ static WC_INLINE void EncodeSigAlg(byte hashAlgo, byte hsType, byte* output) } } +#ifdef WOLFSSL_DUAL_ALG_CERTS +/* These match up with what the OQS team has defined. */ +#define HYBRID_SA_MAJOR 0xFE +#define HYBRID_P256_DILITHIUM_LEVEL2_SA_MINOR 0xA1 +#define HYBRID_RSA3072_DILITHIUM_LEVEL2_SA_MINOR 0xA2 +#define HYBRID_P384_DILITHIUM_LEVEL3_SA_MINOR 0xA4 +#define HYBRID_P521_DILITHIUM_LEVEL5_SA_MINOR 0xA6 +#define HYBRID_P256_FALCON_LEVEL1_SA_MINOR 0x0C +#define HYBRID_RSA3072_FALCON_LEVEL1_SA_MINOR 0x0D +#define HYBRID_P521_FALCON_LEVEL5_SA_MINOR 0x0F + +static void EncodeDualSigAlg(byte sigAlg, byte altSigAlg, byte* output) +{ + /* Initialize output to error indicator. */ + output[0] = 0x0; + output[1] = 0x0; + + if (sigAlg == ecc_dsa_sa_algo && altSigAlg == dilithium_level2_sa_algo) { + output[1] = HYBRID_P256_DILITHIUM_LEVEL2_SA_MINOR; + } + else if (sigAlg == rsa_pss_sa_algo && + altSigAlg == dilithium_level2_sa_algo) { + output[1] = HYBRID_RSA3072_DILITHIUM_LEVEL2_SA_MINOR; + } + else if (sigAlg == ecc_dsa_sa_algo && + altSigAlg == dilithium_level3_sa_algo) { + output[1] = HYBRID_P384_DILITHIUM_LEVEL3_SA_MINOR; + } + else if (sigAlg == ecc_dsa_sa_algo && + altSigAlg == dilithium_level5_sa_algo) { + output[1] = HYBRID_P521_DILITHIUM_LEVEL5_SA_MINOR; + } + else if (sigAlg == ecc_dsa_sa_algo && altSigAlg == falcon_level1_sa_algo) { + output[1] = HYBRID_P256_FALCON_LEVEL1_SA_MINOR; + } + else if (sigAlg == rsa_pss_sa_algo && altSigAlg == falcon_level1_sa_algo) { + output[1] = HYBRID_RSA3072_FALCON_LEVEL1_SA_MINOR; + } + else if (sigAlg == ecc_dsa_sa_algo && altSigAlg == falcon_level5_sa_algo) { + output[1] = HYBRID_P521_FALCON_LEVEL5_SA_MINOR; + } + + if (output[1] != 0x0) { + output[0] = HYBRID_SA_MAJOR; + } +} +#endif /* WOLFSSL_DUAL_ALG_CERTS */ + /* Decode the signature algorithm. * * input The encoded signature algorithm. @@ -7852,6 +7954,65 @@ static WC_INLINE int DecodeTls13SigAlg(byte* input, byte* hashAlgo, return ret; } +#ifdef WOLFSSL_DUAL_ALG_CERTS +/* Decode the hybrid signature algorithm. + * + * input The encoded signature algorithm. + * hashalgo The hash algorithm. + * hsType The signature type. + * returns INVALID_PARAMETER if not recognized and 0 otherwise. + */ +static WC_INLINE int DecodeTls13HybridSigAlg(byte* input, byte* hashAlg, + byte *sigAlg, byte *altSigAlg) +{ + + if (input[0] != HYBRID_SA_MAJOR) { + return INVALID_PARAMETER; + } + + if (input[1] == HYBRID_P256_DILITHIUM_LEVEL2_SA_MINOR) { + *sigAlg = ecc_dsa_sa_algo; + *hashAlg = 4; /* WC_HASH_TYPE_SHA? Reviewer? */ + *altSigAlg = dilithium_level2_sa_algo; + } + else if (input[1] == HYBRID_RSA3072_DILITHIUM_LEVEL2_SA_MINOR) { + *sigAlg = rsa_pss_sa_algo; + *hashAlg = 4; + *altSigAlg = dilithium_level2_sa_algo; + } + else if (input[1] == HYBRID_P384_DILITHIUM_LEVEL3_SA_MINOR) { + *sigAlg = ecc_dsa_sa_algo; + *hashAlg = 5; + *altSigAlg = dilithium_level3_sa_algo; + } + else if (input[1] == HYBRID_P521_DILITHIUM_LEVEL5_SA_MINOR) { + *sigAlg = ecc_dsa_sa_algo; + *hashAlg = 6; + *altSigAlg = dilithium_level5_sa_algo; + } + else if (input[1] == HYBRID_P256_FALCON_LEVEL1_SA_MINOR) { + *sigAlg = ecc_dsa_sa_algo; + *hashAlg = 4; + *altSigAlg = falcon_level1_sa_algo; + } + else if (input[1] == HYBRID_RSA3072_FALCON_LEVEL1_SA_MINOR) { + *sigAlg = rsa_pss_sa_algo; + *hashAlg = 4; + *altSigAlg = falcon_level1_sa_algo; + } + else if (input[1] == HYBRID_P521_FALCON_LEVEL5_SA_MINOR) { + *sigAlg = ecc_dsa_sa_algo; + *hashAlg = 6; + *altSigAlg = falcon_level5_sa_algo; + } + else { + return INVALID_PARAMETER; + } + + return 0; +} +#endif /* WOLFSSL_DUAL_ALG_CERTS */ + /* Get the hash of the messages so far. * * ssl The SSL/TLS object. @@ -8505,6 +8666,10 @@ typedef struct Scv13Args { byte sigAlgo; byte* sigData; word16 sigDataSz; +#ifdef WOLFSSL_DUAL_ALG_CERTS + byte altSigAlgo; + word16 altSigLen; /* Only used in the case of both native and alt. */ +#endif } Scv13Args; static void FreeScv13Args(WOLFSSL* ssl, void* pArgs) @@ -8647,6 +8812,29 @@ static int SendTls13CertificateVerify(WOLFSSL* ssl) ERROR_OUT(NO_PRIVATE_KEY, exit_scv); } else { +#ifdef WOLFSSL_DUAL_ALG_CERTS + if (wolfSSL_is_server(ssl) && + ssl->sigSpec != NULL && + *ssl->sigSpec == WOLFSSL_CKS_SIGSPEC_ALTERNATIVE) { + /* In the case of alternative, we swap in the alt. */ + if (ssl->ctx->altPrivateKey == NULL) { + ERROR_OUT(NO_PRIVATE_KEY, exit_scv); + } + ssl->buffers.keyType = ssl->buffers.altKeyType; + ssl->buffers.keySz = ssl->buffers.altKeySz; + /* If we own it, free key before overriding it. */ + if (ssl->buffers.weOwnKey) { + FreeDer(&ssl->buffers.key); + } + + /* Transfer ownership. ssl->ctx always owns the alt private + * key. */ + ssl->buffers.key = ssl->ctx->altPrivateKey; + ssl->ctx->altPrivateKey = NULL; + ssl->buffers.weOwnKey = 1; + ssl->buffers.weOwnAltKey = 0; + } +#endif /* WOLFSSL_DUAL_ALG_CERTS */ ret = DecodePrivateKey(ssl, &args->length); if (ret != 0) goto exit_scv; @@ -8728,7 +8916,51 @@ static int SendTls13CertificateVerify(WOLFSSL* ssl) else { ERROR_OUT(ALGO_ID_E, exit_scv); } - EncodeSigAlg(ssl->options.hashAlgo, args->sigAlgo, args->verify); + +#ifdef WOLFSSL_DUAL_ALG_CERTS + if (ssl->peerSigSpec == NULL) { + /* The peer did not respond. We didn't send CKS or they don't + * support it. Either way, we do not need to handle dual + * key/sig case. */ + ssl->sigSpec = NULL; + ssl->sigSpecSz = 0; + } + + if (wolfSSL_is_server(ssl) && + ssl->sigSpec != NULL && + *ssl->sigSpec == WOLFSSL_CKS_SIGSPEC_BOTH) { + /* The native was already decoded. Now we need to do the + * alternative. Note that no swap was done because this case is + * both native and alternative, not just alternative. */ + if (ssl->ctx->altPrivateKey == NULL) { + ERROR_OUT(NO_PRIVATE_KEY, exit_scv); + } + + if (ssl->buffers.altKeyType == falcon_level1_sa_algo || + ssl->buffers.altKeyType == falcon_level5_sa_algo || + ssl->buffers.altKeyType == dilithium_level2_sa_algo || + ssl->buffers.altKeyType == dilithium_level3_sa_algo || + ssl->buffers.altKeyType == dilithium_level5_sa_algo) { + args->altSigAlgo = ssl->buffers.altKeyType; + } + else { + ERROR_OUT(ALGO_ID_E, exit_scv); + } + /* After this call, args->altSigLen has the length we need for + * the alternative signature. */ + ret = DecodeAltPrivateKey(ssl, &args->altSigLen); + if (ret != 0) + goto exit_scv; + + EncodeDualSigAlg(args->sigAlgo, args->altSigAlgo, args->verify); + if (args->verify[0] == 0) { + ERROR_OUT(ALGO_ID_E, exit_scv); + } + } + else +#endif /* WOLFSSL_DUAL_ALG_CERTS */ + EncodeSigAlg(ssl->options.hashAlgo, args->sigAlgo, + args->verify); if (args->sigData == NULL) { if (ssl->hsType == DYNAMIC_TYPE_RSA) { @@ -8807,6 +9039,7 @@ static int SendTls13CertificateVerify(WOLFSSL* ssl) } sig->length = ED448_SIG_SIZE; } + #endif /* HAVE_ED448 */ #if defined(HAVE_PQC) #if defined(HAVE_FALCON) @@ -8850,6 +9083,32 @@ static int SendTls13CertificateVerify(WOLFSSL* ssl) #endif ); } + +#ifdef WOLFSSL_DUAL_ALG_CERTS + if (wolfSSL_is_server(ssl) && + ssl->sigSpec != NULL && + *ssl->sigSpec == WOLFSSL_CKS_SIGSPEC_BOTH) { + if (ssl->hsAltType == DYNAMIC_TYPE_DILITHIUM) { + /* note the + sig->length; we are appending. */ + ret = wc_dilithium_sign_msg( + args->sigData, args->sigDataSz, + args->verify + HASH_SIG_SIZE + + VERIFY_HEADER + sig->length, + (word32*)&args->altSigLen, + (dilithium_key*)ssl->hsAltKey, ssl->rng); + + } + else if (ssl->hsAltType == DYNAMIC_TYPE_FALCON) { + /* note the sig->length; we are appending. */ + ret = wc_falcon_sign_msg(args->sigData, args->sigDataSz, + args->verify + HASH_SIG_SIZE + + VERIFY_HEADER + sig->length, + (word32*)&args->altSigLen, + (falcon_key*)ssl->hsAltKey, + ssl->rng); + } + } +#endif /* WOLFSSL_DUAL_ALG_CERTS */ args->length = (word16)sig->length; } #endif /* HAVE_ECC */ @@ -8887,7 +9146,7 @@ static int SendTls13CertificateVerify(WOLFSSL* ssl) ret = wc_falcon_sign_msg(args->sigData, args->sigDataSz, args->verify + HASH_SIG_SIZE + VERIFY_HEADER, (word32*)&sig->length, - (falcon_key*)ssl->hsKey); + (falcon_key*)ssl->hsKey, ssl->rng); args->length = (word16)sig->length; } #endif @@ -8896,7 +9155,7 @@ static int SendTls13CertificateVerify(WOLFSSL* ssl) ret = wc_dilithium_sign_msg(args->sigData, args->sigDataSz, args->verify + HASH_SIG_SIZE + VERIFY_HEADER, (word32*)&sig->length, - (dilithium_key*)ssl->hsKey); + (dilithium_key*)ssl->hsKey, ssl->rng); args->length = (word16)sig->length; } #endif @@ -8909,6 +9168,36 @@ static int SendTls13CertificateVerify(WOLFSSL* ssl) (RsaKey*)ssl->hsKey, ssl->buffers.key ); + +#ifdef WOLFSSL_DUAL_ALG_CERTS + /* In the case of RSA, we need to do the CKS both case here + * BEFORE args->sigData is overwritten!! We keep the sig + * separate and then append later so we don't interfere with the + * checks below. */ + if (wolfSSL_is_server(ssl) && + ssl->sigSpec != NULL && + *ssl->sigSpec == WOLFSSL_CKS_SIGSPEC_BOTH) { + if (ssl->hsAltType == DYNAMIC_TYPE_DILITHIUM) { + /* note the + args->sigLen; we are appending. */ + ret = wc_dilithium_sign_msg(args->sigData, + args->sigDataSz, + args->verify + HASH_SIG_SIZE + VERIFY_HEADER + + args->sigLen, + (word32*)&args->altSigLen, + (dilithium_key*)ssl->hsAltKey, ssl->rng); + } + else if (ssl->hsAltType == DYNAMIC_TYPE_FALCON) { + /* note the + args->sigLen; we are appending. */ + ret = wc_falcon_sign_msg(args->sigData, args->sigDataSz, + args->verify + HASH_SIG_SIZE + + VERIFY_HEADER + args->sigLen, + (word32*)&args->altSigLen, + (falcon_key*)ssl->hsAltKey, + ssl->rng); + } + } +#endif /* WOLFSSL_DUAL_ALG_CERTS */ + if (ret == 0) { args->length = (word16)args->sigLen; @@ -8924,6 +9213,11 @@ static int SendTls13CertificateVerify(WOLFSSL* ssl) goto exit_scv; } +#ifdef WOLFSSL_DUAL_ALG_CERTS + /* Add in length of the alt sig which will be appended to the sig */ + args->length += args->altSigLen; +#endif /* WOLFSSL_DUAL_ALG_CERTS */ + /* Add signature length. */ c16toa(args->length, args->verify + HASH_SIG_SIZE); @@ -9142,11 +9436,16 @@ typedef struct Dcv13Args { word32 sigSz; word32 idx; word32 begin; - byte hashAlgo; - byte sigAlgo; byte* sigData; word16 sigDataSz; +#ifdef WOLFSSL_DUAL_ALG_CERTS + byte altSigAlgo; + byte* altSigData; + word16 altSigDataSz; + word16 altSignatureSz; + byte altPeerAuthGood; +#endif } Dcv13Args; static void FreeDcv13Args(WOLFSSL* ssl, void* pArgs) @@ -9157,10 +9456,82 @@ static void FreeDcv13Args(WOLFSSL* ssl, void* pArgs) XFREE(args->sigData, ssl->heap, DYNAMIC_TYPE_SIGNATURE); args->sigData = NULL; } - +#ifdef WOLFSSL_DUAL_ALG_CERTS + if (args && args->altSigData != NULL) { + XFREE(args->altSigData, ssl->heap, DYNAMIC_TYPE_SIGNATURE); + args->altSigData = NULL; + } +#endif (void)ssl; } +#ifdef WOLFSSL_DUAL_ALG_CERTS +/* ssl->peerCert->sapkiDer is the alternative public key. Hopefully it is a + * dilithium public key. Convert it into a usable public key. */ +static int decodeDilithiumKey(WOLFSSL* ssl, int level) +{ + int keyRet; + word32 tmpIdx = 0; + + if (ssl->peerDilithiumKeyPresent) + return INVALID_PARAMETER; + + keyRet = AllocKey(ssl, DYNAMIC_TYPE_DILITHIUM, + (void**)&ssl->peerDilithiumKey); + if (keyRet != 0) + return PEER_KEY_ERROR; + + ssl->peerDilithiumKeyPresent = 1; + keyRet = wc_dilithium_init(ssl->peerDilithiumKey); + if (keyRet != 0) + return PEER_KEY_ERROR; + + keyRet = wc_dilithium_set_level(ssl->peerDilithiumKey, level); + if (keyRet != 0) + return PEER_KEY_ERROR; + + keyRet = wc_Dilithium_PublicKeyDecode(ssl->peerCert.sapkiDer, &tmpIdx, + ssl->peerDilithiumKey, + ssl->peerCert.sapkiLen); + if (keyRet != 0) + return PEER_KEY_ERROR; + + return 0; +} + +/* ssl->peerCert->sapkiDer is the alternative public key. Hopefully it is a + * falcon public key. Convert it into a usable public key. */ +static int decodeFalconKey(WOLFSSL* ssl, int level) +{ + int keyRet; + word32 tmpIdx = 0; + + if (ssl->peerFalconKeyPresent) + return INVALID_PARAMETER; + + keyRet = AllocKey(ssl, DYNAMIC_TYPE_FALCON, (void**)&ssl->peerFalconKey); + if (keyRet != 0) + return PEER_KEY_ERROR; + + ssl->peerFalconKeyPresent = 1; + keyRet = wc_falcon_init(ssl->peerFalconKey); + if (keyRet != 0) + return PEER_KEY_ERROR; + + keyRet = wc_falcon_set_level(ssl->peerFalconKey, level); + if (keyRet != 0) + return PEER_KEY_ERROR; + + keyRet = wc_Falcon_PublicKeyDecode(ssl->peerCert.sapkiDer, &tmpIdx, + ssl->peerFalconKey, + ssl->peerCert.sapkiLen); + if (keyRet != 0) + return PEER_KEY_ERROR; + + return 0; +} +#endif + /* handle processing TLS v1.3 certificate_verify (15) */ /* Parse and handle a TLS v1.3 CertificateVerify message. * @@ -9218,8 +9589,8 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, ret = 0; ssl->options.asyncState = TLS_ASYNC_BEGIN; XMEMSET(args, 0, sizeof(Dcv13Args)); - args->hashAlgo = sha_mac; - args->sigAlgo = anonymous_sa_algo; + ssl->options.peerHashAlgo = sha_mac; + ssl->options.peerSigAlgo = anonymous_sa_algo; args->idx = *inOutIdx; args->begin = *inOutIdx; #ifdef WOLFSSL_ASYNC_CRYPT @@ -9250,8 +9621,36 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, if ((args->idx - args->begin) + ENUM_LEN + ENUM_LEN > totalSz) { ERROR_OUT(BUFFER_ERROR, exit_dcv); } - ret = DecodeTls13SigAlg(input + args->idx, &args->hashAlgo, - &args->sigAlgo); + +#ifdef WOLFSSL_DUAL_ALG_CERTS + if (ssl->peerSigSpec == NULL) { + /* The peer did not respond. We didn't send CKS or they don't + * support it. Either way, we do not need to handle dual + * key/sig case. */ + ssl->sigSpec = NULL; + ssl->sigSpecSz = 0; + } + + /* If no CKS extension or either native or alternative, then just + * get a normal sigalgo. But if BOTH, then get the native and alt + * sig algos. */ + if (wolfSSL_is_server(ssl) || + ssl->sigSpec == NULL || + *ssl->sigSpec == WOLFSSL_CKS_SIGSPEC_NATIVE || + *ssl->sigSpec == WOLFSSL_CKS_SIGSPEC_ALTERNATIVE) { +#endif /* WOLFSSL_DUAL_ALG_CERTS */ + ret = DecodeTls13SigAlg(input + args->idx, + &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); + } +#endif /* WOLFSSL_DUAL_ALG_CERTS */ + if (ret < 0) goto exit_dcv; args->idx += OPAQUE16_LEN; @@ -9269,70 +9668,159 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, ERROR_OUT(BUFFER_ERROR, exit_dcv); } +#ifdef WOLFSSL_DUAL_ALG_CERTS + if (!wolfSSL_is_server(ssl) && + (ssl->sigSpec != NULL) && + (*ssl->sigSpec != WOLFSSL_CKS_SIGSPEC_NATIVE)) { + + word16 sa; + if (args->altSigAlgo == 0) + sa = ssl->options.peerSigAlgo; + else + sa = args->altSigAlgo; + + switch(sa) { + case dilithium_level2_sa_algo: + ret = decodeDilithiumKey(ssl, 2); + break; + case dilithium_level3_sa_algo: + ret = decodeDilithiumKey(ssl, 3); + break; + case dilithium_level5_sa_algo: + ret = decodeDilithiumKey(ssl, 5); + break; + case falcon_level1_sa_algo: + ret = decodeFalconKey(ssl, 1); + break; + case falcon_level5_sa_algo: + ret = decodeFalconKey(ssl, 5); + break; + default: + ERROR_OUT(PEER_KEY_ERROR, exit_dcv); + break; + } + + if (ret != 0) + ERROR_OUT(ret, exit_dcv); + + if (*ssl->sigSpec == WOLFSSL_CKS_SIGSPEC_ALTERNATIVE) { + /* Now swap in the alternative. We only support hybrid certs + * where native is RSA or ECC so check that either of those + * are present and then remove it. */ + if (ssl->peerRsaKeyPresent && + ssl->peerEccDsaKeyPresent) { + /* They shouldn't both be present. */ + ERROR_OUT(PEER_KEY_ERROR, exit_dcv); + } + else if (ssl->peerRsaKeyPresent) { + FreeKey(ssl, DYNAMIC_TYPE_RSA, + (void**)&ssl->peerRsaKey); + ssl->peerRsaKeyPresent = 0; + } + else if (ssl->peerEccDsaKeyPresent) { + FreeKey(ssl, DYNAMIC_TYPE_ECC, + (void**)&ssl->peerEccDsaKey); + ssl->peerEccDsaKeyPresent = 0; + } + else { + ERROR_OUT(WOLFSSL_NOT_IMPLEMENTED, exit_dcv); + } + } + else if (*ssl->sigSpec == WOLFSSL_CKS_SIGSPEC_BOTH) { + /* Use alternative public key to figure out the expected + * alt sig size. We only support Post-quantum key as SAPKI. + */ + switch(sa) { + case dilithium_level2_sa_algo: + case dilithium_level3_sa_algo: + case dilithium_level5_sa_algo: + ret = wc_dilithium_sig_size(ssl->peerDilithiumKey); + break; + case falcon_level1_sa_algo: + case falcon_level5_sa_algo: + ret = wc_falcon_sig_size(ssl->peerFalconKey); + break; + default: + ERROR_OUT(PEER_KEY_ERROR, exit_dcv); + break; + } + + if (ret <= 0) { + ERROR_OUT(PEER_KEY_ERROR, exit_dcv); + } + args->altSignatureSz = ret; + ret = 0; + } + else { + ERROR_OUT(WOLFSSL_NOT_IMPLEMENTED, exit_dcv); + } + } +#endif /* WOLFSSL_DUAL_ALG_CERTS */ + /* Check for public key of required type. */ /* Assume invalid unless signature algo matches the key provided */ validSigAlgo = 0; #ifdef HAVE_ED25519 - if (args->sigAlgo == ed25519_sa_algo) { + if (ssl->options.peerSigAlgo == ed25519_sa_algo) { WOLFSSL_MSG("Peer sent ED25519 sig"); validSigAlgo = (ssl->peerEd25519Key != NULL) && ssl->peerEd25519KeyPresent; } #endif #ifdef HAVE_ED448 - if (args->sigAlgo == ed448_sa_algo) { + if (ssl->options.peerSigAlgo == ed448_sa_algo) { WOLFSSL_MSG("Peer sent ED448 sig"); validSigAlgo = (ssl->peerEd448Key != NULL) && ssl->peerEd448KeyPresent; } #endif #ifdef HAVE_ECC - if (args->sigAlgo == ecc_dsa_sa_algo) { + if (ssl->options.peerSigAlgo == ecc_dsa_sa_algo) { WOLFSSL_MSG("Peer sent ECC sig"); validSigAlgo = (ssl->peerEccDsaKey != NULL) && ssl->peerEccDsaKeyPresent; } #endif #if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3) - if (args->sigAlgo == sm2_sa_algo) { + if (ssl->options.peerSigAlgo == sm2_sa_algo) { WOLFSSL_MSG("Peer sent SM2 sig"); validSigAlgo = (ssl->peerEccDsaKey != NULL) && ssl->peerEccDsaKeyPresent; } #endif #ifdef HAVE_PQC - if (args->sigAlgo == falcon_level1_sa_algo) { + if (ssl->options.peerSigAlgo == falcon_level1_sa_algo) { WOLFSSL_MSG("Peer sent Falcon Level 1 sig"); validSigAlgo = (ssl->peerFalconKey != NULL) && ssl->peerFalconKeyPresent; } - if (args->sigAlgo == falcon_level5_sa_algo) { + if (ssl->options.peerSigAlgo == falcon_level5_sa_algo) { WOLFSSL_MSG("Peer sent Falcon Level 5 sig"); validSigAlgo = (ssl->peerFalconKey != NULL) && ssl->peerFalconKeyPresent; } - if (args->sigAlgo == dilithium_level2_sa_algo) { + if (ssl->options.peerSigAlgo == dilithium_level2_sa_algo) { WOLFSSL_MSG("Peer sent Dilithium Level 2 sig"); validSigAlgo = (ssl->peerDilithiumKey != NULL) && ssl->peerDilithiumKeyPresent; } - if (args->sigAlgo == dilithium_level3_sa_algo) { + if (ssl->options.peerSigAlgo == dilithium_level3_sa_algo) { WOLFSSL_MSG("Peer sent Dilithium Level 3 sig"); validSigAlgo = (ssl->peerDilithiumKey != NULL) && ssl->peerDilithiumKeyPresent; } - if (args->sigAlgo == dilithium_level5_sa_algo) { + if (ssl->options.peerSigAlgo == dilithium_level5_sa_algo) { WOLFSSL_MSG("Peer sent Dilithium Level 5 sig"); validSigAlgo = (ssl->peerDilithiumKey != NULL) && ssl->peerDilithiumKeyPresent; } #endif #ifndef NO_RSA - if (args->sigAlgo == rsa_sa_algo) { + if (ssl->options.peerSigAlgo == rsa_sa_algo) { WOLFSSL_MSG("Peer sent PKCS#1.5 algo - not valid TLS 1.3"); ERROR_OUT(INVALID_PARAMETER, exit_dcv); } - if (args->sigAlgo == rsa_pss_sa_algo) { + if (ssl->options.peerSigAlgo == rsa_pss_sa_algo) { WOLFSSL_MSG("Peer sent RSA sig"); validSigAlgo = (ssl->peerRsaKey != NULL) && ssl->peerRsaKeyPresent; @@ -9343,14 +9831,48 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, ERROR_OUT(SIG_VERIFY_E, exit_dcv); } - sig->buffer = (byte*)XMALLOC(args->sz, ssl->heap, + sig->length = args->sz; +#ifdef WOLFSSL_DUAL_ALG_CERTS + if (!wolfSSL_is_server(ssl) && + ssl->sigSpec != NULL && + *ssl->sigSpec == WOLFSSL_CKS_SIGSPEC_BOTH) { + /* If its RSA, we only hybridize with RSA3072 which has a sig + * size of 384. For ECC, this is actually encoded as an RFC5912 + * formatted signature which means we can use the ASN APIs to + * figure out the length. Note that some post-quantum sig algs + * have variable length signatures (Falcon). That is why we + * don't do: + * sig->length -= args->altSignatureSz; */ + #define RSA3072_SIG_LEN 384 + if (ssl->options.peerSigAlgo == rsa_pss_sa_algo) { + sig->length = RSA3072_SIG_LEN; + } + else if (ssl->options.peerSigAlgo == ecc_dsa_sa_algo) { + word32 tmpIdx = args->idx; + sig->length = wc_SignatureGetSize(WC_SIGNATURE_TYPE_ECC, + ssl->peerEccDsaKey, + sizeof(*ssl->peerEccDsaKey)); + if (GetSequence(input, &tmpIdx, (int*)&sig->length, + args->sz) < 0) { + ERROR_OUT(SIG_VERIFY_E, exit_dcv); + } + /* We have to increment by the size of the header. */ + sig->length += tmpIdx - args->idx; + } + else { + ERROR_OUT(WOLFSSL_NOT_IMPLEMENTED, exit_dcv); + } + } +#endif + + sig->buffer = (byte*)XMALLOC(sig->length, ssl->heap, DYNAMIC_TYPE_SIGNATURE); + if (sig->buffer == NULL) { ERROR_OUT(MEMORY_E, exit_dcv); } - sig->length = args->sz; - XMEMCPY(sig->buffer, input + args->idx, args->sz); + XMEMCPY(sig->buffer, input + args->idx, sig->length); #ifdef HAVE_ECC if (ssl->peerEccDsaKeyPresent) { WOLFSSL_MSG("Doing ECC peer cert verify"); @@ -9365,11 +9887,11 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, if (ret != 0) goto exit_dcv; #if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3) - if (args->sigAlgo != sm2_sa_algo) + if (ssl->options.peerSigAlgo != sm2_sa_algo) #endif { ret = CreateECCEncodedSig(args->sigData, - args->sigDataSz, args->hashAlgo); + args->sigDataSz, ssl->options.peerHashAlgo); if (ret < 0) goto exit_dcv; args->sigDataSz = (word16)ret; @@ -9387,8 +9909,9 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, ERROR_OUT(MEMORY_E, exit_dcv); } - CreateSigData(ssl, args->sigData, &args->sigDataSz, 1); - ret = 0; + ret = CreateSigData(ssl, args->sigData, &args->sigDataSz, 1); + if (ret < 0) + goto exit_dcv; } #endif #ifdef HAVE_ED448 @@ -9401,34 +9924,39 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, ERROR_OUT(MEMORY_E, exit_dcv); } - CreateSigData(ssl, args->sigData, &args->sigDataSz, 1); - ret = 0; + ret = CreateSigData(ssl, args->sigData, &args->sigDataSz, 1); + if (ret < 0) + goto exit_dcv; } #endif #ifdef HAVE_PQC - if (ssl->peerFalconKeyPresent) { - WOLFSSL_MSG("Doing Falcon peer cert verify"); - - args->sigData = (byte*)XMALLOC(MAX_SIG_DATA_SZ, ssl->heap, + if (ssl->peerFalconKeyPresent || ssl->peerDilithiumKeyPresent) { + word16 sigDataSz; + byte *sigData = (byte*)XMALLOC(MAX_SIG_DATA_SZ, ssl->heap, DYNAMIC_TYPE_SIGNATURE); - if (args->sigData == NULL) { + if (sigData == NULL) { ERROR_OUT(MEMORY_E, exit_dcv); } - CreateSigData(ssl, args->sigData, &args->sigDataSz, 1); - ret = 0; - } - - if (ssl->peerDilithiumKeyPresent) { - WOLFSSL_MSG("Doing Dilithium peer cert verify"); - - args->sigData = (byte*)XMALLOC(MAX_SIG_DATA_SZ, ssl->heap, - DYNAMIC_TYPE_SIGNATURE); - if (args->sigData == NULL) { - ERROR_OUT(MEMORY_E, exit_dcv); + ret = CreateSigData(ssl, sigData, &sigDataSz, 1); + if (ret < 0) { + goto exit_dcv; } - CreateSigData(ssl, args->sigData, &args->sigDataSz, 1); +#ifdef WOLFSSL_DUAL_ALG_CERTS + if (!wolfSSL_is_server(ssl) && + ssl->sigSpec != NULL && + *ssl->sigSpec == WOLFSSL_CKS_SIGSPEC_BOTH) { + /* In this case (BOTH), the pq sig is the alternative. */ + args->altSigData = sigData; + args->altSigDataSz = sigDataSz; + } + else +#endif /* WOLFSSL_DUAL_ALG_CERTS */ + { + args->sigData = sigData; + args->sigDataSz = sigDataSz; + } ret = 0; } #endif @@ -9443,7 +9971,7 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, #ifndef NO_RSA if (ssl->peerRsaKey != NULL && ssl->peerRsaKeyPresent != 0) { ret = RsaVerify(ssl, sig->buffer, (word32)sig->length, &args->output, - args->sigAlgo, args->hashAlgo, ssl->peerRsaKey, + ssl->options.peerSigAlgo, ssl->options.peerHashAlgo, ssl->peerRsaKey, #ifdef HAVE_PK_CALLBACKS &ssl->buffers.peerRsaKey #else @@ -9459,7 +9987,7 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, #ifdef HAVE_ECC if (ssl->peerEccDsaKeyPresent) { #if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3) - if (args->sigAlgo == sm2_sa_algo) { + if (ssl->options.peerSigAlgo == sm2_sa_algo) { ret = Sm2wSm3Verify(ssl, TLS13_SM2_SIG_ID, TLS13_SM2_SIG_ID_SZ, input + args->idx, args->sz, args->sigData, args->sigDataSz, @@ -9468,7 +9996,7 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, else #endif { - ret = EccVerify(ssl, input + args->idx, args->sz, + ret = EccVerify(ssl, input + args->idx, sig->length, args->sigData, args->sigDataSz, ssl->peerEccDsaKey, #ifdef HAVE_PK_CALLBACKS @@ -9535,15 +10063,43 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, #if defined(HAVE_PQC) && defined(HAVE_FALCON) if (ssl->peerFalconKeyPresent) { int res = 0; + byte *sigIn = input + args->idx; + word32 sigInLen = args->sz; + byte *sigData = args->sigData; + word32 sigDataSz = args->sigDataSz; WOLFSSL_MSG("Doing Falcon peer cert verify"); - ret = wc_falcon_verify_msg(input + args->idx, args->sz, - args->sigData, args->sigDataSz, - &res, ssl->peerFalconKey); +#ifdef WOLFSSL_DUAL_ALG_CERTS + if (!wolfSSL_is_server(ssl) && + ssl->sigSpec != NULL && + *ssl->sigSpec == WOLFSSL_CKS_SIGSPEC_BOTH) { + /* Note: + sig->length; we are skipping the native sig. */ + sigIn = input + args->idx + sig->length; + sigInLen = args->sz - sig->length; + + /* For RSA, something different was verified. */ + if (ssl->peerRsaKeyPresent) { + sigData = args->altSigData; + sigDataSz = args->altSigDataSz; + } + } +#endif /* WOLFSSL_DUAL_ALG_CERTS */ + ret = wc_falcon_verify_msg(sigIn, sigInLen, + sigData, sigDataSz, + &res, ssl->peerFalconKey); if ((ret >= 0) && (res == 1)) { /* CLIENT/SERVER: data verified with public key from * certificate. */ - ssl->options.peerAuthGood = 1; +#ifdef WOLFSSL_DUAL_ALG_CERTS + if (!wolfSSL_is_server(ssl) && + ssl->sigSpec != NULL && + *ssl->sigSpec == WOLFSSL_CKS_SIGSPEC_BOTH) { + args->altPeerAuthGood = 1; + } + else +#endif /* WOLFSSL_DUAL_ALG_CERTS */ + ssl->options.peerAuthGood = 1; + FreeKey(ssl, DYNAMIC_TYPE_FALCON, (void**)&ssl->peerFalconKey); ssl->peerFalconKeyPresent = 0; @@ -9553,15 +10109,43 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, #if defined(HAVE_PQC) && defined(HAVE_DILITHIUM) if (ssl->peerDilithiumKeyPresent) { int res = 0; + byte *sigIn = input + args->idx; + word32 sigInLen = args->sz; + byte *sigData = args->sigData; + word32 sigDataSz = args->sigDataSz; WOLFSSL_MSG("Doing Dilithium peer cert verify"); - ret = wc_dilithium_verify_msg(input + args->idx, args->sz, - args->sigData, args->sigDataSz, +#ifdef WOLFSSL_DUAL_ALG_CERTS + if (!wolfSSL_is_server(ssl) && + ssl->sigSpec != NULL && + *ssl->sigSpec == WOLFSSL_CKS_SIGSPEC_BOTH) { + /* Go backwards from the end of the signature the size of + * the alt sig to find the beginning of the alt sig. */ + sigIn = input + args->idx + args->sz - args->altSignatureSz; + sigInLen = args->altSignatureSz; + /* For RSA, something different was verified. */ + if (ssl->peerRsaKeyPresent) { + sigData = args->altSigData; + sigDataSz = args->altSigDataSz; + } + } +#endif /* WOLFSSL_DUAL_ALG_CERTS */ + ret = wc_dilithium_verify_msg(sigIn, sigInLen, + sigData, sigDataSz, &res, ssl->peerDilithiumKey); if ((ret >= 0) && (res == 1)) { /* CLIENT/SERVER: data verified with public key from * certificate. */ - ssl->options.peerAuthGood = 1; +#ifdef WOLFSSL_DUAL_ALG_CERTS + if (!wolfSSL_is_server(ssl) && + ssl->sigSpec != NULL && + *ssl->sigSpec == WOLFSSL_CKS_SIGSPEC_BOTH) { + args->altPeerAuthGood = 1; + } + else +#endif /* WOLFSSL_DUAL_ALG_CERTS */ + ssl->options.peerAuthGood = 1; + FreeKey(ssl, DYNAMIC_TYPE_DILITHIUM, (void**)&ssl->peerDilithiumKey); ssl->peerDilithiumKeyPresent = 0; @@ -9583,8 +10167,8 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, { #if !defined(NO_RSA) && defined(WC_RSA_PSS) if (ssl->peerRsaKey != NULL && ssl->peerRsaKeyPresent != 0) { - ret = CheckRSASignature(ssl, args->sigAlgo, args->hashAlgo, - args->output, args->sendSz); + ret = CheckRSASignature(ssl, ssl->options.peerSigAlgo, + ssl->options.peerHashAlgo, args->output, args->sendSz); if (ret != 0) goto exit_dcv; @@ -9603,6 +10187,14 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, case TLS_ASYNC_FINALIZE: { +#ifdef WOLFSSL_DUAL_ALG_CERTS + if (!wolfSSL_is_server(ssl) && + ssl->options.peerAuthGood && + ssl->sigSpec != NULL && + *ssl->sigSpec == WOLFSSL_CKS_SIGSPEC_BOTH) { + ssl->options.peerAuthGood = args->altPeerAuthGood; + } +#endif /* WOLFSSL_DUAL_ALG_CERTS */ ssl->options.havePeerVerify = 1; /* Set final index */ @@ -9790,7 +10382,8 @@ int DoTls13Finished(WOLFSSL* ssl, const byte* input, word32* inOutIdx, if (sniff == NO_SNIFF) { /* Actually check verify data. */ - if (XMEMCMP(input + *inOutIdx, mac, size) != 0){ + if (size > WC_MAX_DIGEST_SIZE || + XMEMCMP(input + *inOutIdx, mac, size) != 0){ WOLFSSL_MSG("Verify finished error on hashes"); SendAlert(ssl, alert_fatal, decrypt_error); WOLFSSL_ERROR_VERBOSE(VERIFY_FINISHED_ERROR); @@ -10354,6 +10947,8 @@ static int SendTls13EndOfEarlyData(WOLFSSL* ssl) if (!ssl->options.groupMessages) ret = SendBuffered(ssl); + ssl->earlyData = done_early_data; + WOLFSSL_LEAVE("SendTls13EndOfEarlyData", ret); WOLFSSL_END(WC_FUNC_END_OF_EARLY_DATA_SEND); @@ -12053,7 +12648,7 @@ int wolfSSL_connect_TLSv13(WOLFSSL* ssl) } ssl->options.connectState = CLIENT_HELLO_SENT; - WOLFSSL_MSG("connect state: CLIENT_HELLO_SENT"); + WOLFSSL_MSG("TLSv13 connect state: CLIENT_HELLO_SENT"); #ifdef WOLFSSL_EARLY_DATA if (ssl->earlyData != no_early_data) { #if defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT) @@ -12484,6 +13079,30 @@ int wolfSSL_NoKeyShares(WOLFSSL* ssl) } #endif +#ifdef WOLFSSL_DUAL_ALG_CERTS +int wolfSSL_UseCKS(WOLFSSL* ssl, byte *sigSpec, word16 sigSpecSz) +{ + if (ssl == NULL || !IsAtLeastTLSv1_3(ssl->ctx->method->version) || + sigSpec == NULL || sigSpecSz == 0) + return BAD_FUNC_ARG; + + ssl->sigSpec = sigSpec; + ssl->sigSpecSz = sigSpecSz; + return WOLFSSL_SUCCESS; +} + +int wolfSSL_CTX_UseCKS(WOLFSSL_CTX* ctx, byte *sigSpec, word16 sigSpecSz) +{ + if (ctx == NULL || !IsAtLeastTLSv1_3(ctx->method->version) || + sigSpec == NULL || sigSpecSz == 0) + return BAD_FUNC_ARG; + + ctx->sigSpec = sigSpec; + ctx->sigSpecSz = sigSpecSz; + return WOLFSSL_SUCCESS; +} +#endif /* WOLFSSL_DUAL_ALG_CERTS */ + /* Do not send a ticket after TLS v1.3 handshake for resumption. * * ctx The SSL/TLS CTX object. @@ -12901,7 +13520,7 @@ void wolfSSL_set_psk_client_cs_callback(WOLFSSL* ssl, ssl->options.haveDH, ssl->options.haveECDSAsig, ssl->options.haveECC, TRUE, ssl->options.haveStaticECC, ssl->options.haveFalconSig, ssl->options.haveDilithiumSig, - ssl->options.haveAnon, TRUE, ssl->options.side); + ssl->options.useAnon, TRUE, ssl->options.side); } /* Set the PSK callback that returns the cipher suite for a client to use @@ -12954,7 +13573,7 @@ void wolfSSL_set_psk_client_tls13_callback(WOLFSSL* ssl, ssl->options.haveDH, ssl->options.haveECDSAsig, ssl->options.haveECC, TRUE, ssl->options.haveStaticECC, ssl->options.haveFalconSig, ssl->options.haveDilithiumSig, - ssl->options.haveAnon, TRUE, ssl->options.side); + ssl->options.useAnon, TRUE, ssl->options.side); } /* Set the PSK callback that returns the cipher suite for a server to use @@ -13004,7 +13623,7 @@ void wolfSSL_set_psk_server_tls13_callback(WOLFSSL* ssl, ssl->options.haveDH, ssl->options.haveECDSAsig, ssl->options.haveECC, TRUE, ssl->options.haveStaticECC, ssl->options.haveFalconSig, ssl->options.haveDilithiumSig, - ssl->options.haveAnon, TRUE, ssl->options.side); + ssl->options.useAnon, TRUE, ssl->options.side); } /* Get name of first supported cipher suite that uses the hash indicated. @@ -13753,6 +14372,7 @@ int wolfSSL_read_early_data(WOLFSSL* ssl, void* data, int sz, int* outSz) if (!IsAtLeastTLSv1_3(ssl->version)) return BAD_FUNC_ARG; + *outSz = 0; #ifndef NO_WOLFSSL_SERVER if (ssl->options.side == WOLFSSL_CLIENT_END) return SIDE_ERROR; |