From 136eaae4f14d8f903c2e18ba89c783930283567e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Wed, 7 Feb 2024 07:13:14 +0100 Subject: [PATCH] Improvements to dual alg certificates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Support for external keys (CryptoCb interface) * Support for usage in mutual authentication * better entity cert parsing * Fix for Zephyr port to support the feature * Check key support * Proper validation of signatures in certificate chains * Proper validation of peer cert with local issuer signature (alt pub key is cached now) * Support for ECC & RSA as alt keys with PQC as primary * Support for PQC certificate generation * Better support for hybrid signatures with variable length signatures * Support for primary and alternative private keys in a single file/buffer * More API support for alternative private keys Signed-off-by: Tobias Frauenschläger --- src/internal.c | 482 ++++++++++++--- src/ssl.c | 1086 +++++++++++++++++++++++++++------ src/tls.c | 4 +- src/tls13.c | 1095 +++++++++++++++++++++------------- src/x509.c | 177 ++++++ wolfcrypt/src/asn.c | 158 ++++- wolfcrypt/src/dilithium.c | 10 +- wolfcrypt/src/falcon.c | 8 +- wolfcrypt/src/pkcs12.c | 2 +- wolfcrypt/src/sphincs.c | 2 +- wolfssl/internal.h | 18 +- wolfssl/ssl.h | 22 + wolfssl/wolfcrypt/asn.h | 17 +- wolfssl/wolfcrypt/settings.h | 1 + 14 files changed, 2396 insertions(+), 686 deletions(-) diff --git a/src/internal.c b/src/internal.c index dd0cfd7f0..b401df8d7 100644 --- a/src/internal.c +++ b/src/internal.c @@ -2251,6 +2251,9 @@ int InitSSL_Ctx(WOLFSSL_CTX* ctx, WOLFSSL_METHOD* method, void* heap) #ifndef NO_CERTS ctx->privateKeyDevId = INVALID_DEVID; +#ifdef WOLFSSL_DUAL_ALG_CERTS + ctx->altPrivateKeyDevId = INVALID_DEVID; +#endif #endif #ifndef NO_DH @@ -4333,11 +4336,15 @@ void DecodeSigAlg(const byte* input, byte* hashAlgo, byte* hsType) #endif #ifdef HAVE_PQC case PQC_SA_MAJOR: - /* Hash performed as part of sign/verify operation. */ + /* Hash performed as part of sign/verify operation. + * However, if we want a dual alg signature with a + * classic algorithm as alternative, we need an explicit + * hash algo here. + */ #ifdef HAVE_FALCON if (input[1] == FALCON_LEVEL1_SA_MINOR) { *hsType = falcon_level1_sa_algo; - *hashAlgo = sha512_mac; + *hashAlgo = sha256_mac; } else if (input[1] == FALCON_LEVEL5_SA_MINOR) { *hsType = falcon_level5_sa_algo; @@ -4347,11 +4354,11 @@ void DecodeSigAlg(const byte* input, byte* hashAlgo, byte* hsType) #ifdef HAVE_DILITHIUM if (input[1] == DILITHIUM_LEVEL2_SA_MINOR) { *hsType = dilithium_level2_sa_algo; - *hashAlgo = sha512_mac; + *hashAlgo = sha256_mac; } else if (input[1] == DILITHIUM_LEVEL3_SA_MINOR) { *hsType = dilithium_level3_sa_algo; - *hashAlgo = sha512_mac; + *hashAlgo = sha384_mac; } else if (input[1] == DILITHIUM_LEVEL5_SA_MINOR) { *hsType = dilithium_level5_sa_algo; @@ -6761,9 +6768,12 @@ int SetSSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup) ssl->buffers.keySz = ctx->privateKeySz; ssl->buffers.keyDevId = ctx->privateKeyDevId; #ifdef WOLFSSL_DUAL_ALG_CERTS - ssl->buffers.altKey = ctx->altPrivateKey; - ssl->buffers.altKeySz = ctx->altPrivateKeySz; - ssl->buffers.altKeyType = ctx->altPrivateKeyType; + ssl->buffers.altKey = ctx->altPrivateKey; + ssl->buffers.altKeyType = ctx->altPrivateKeyType; + ssl->buffers.altKeyId = ctx->altPrivateKeyId; + ssl->buffers.altKeyLabel = ctx->altPrivateKeyLabel; + ssl->buffers.altKeySz = ctx->altPrivateKeySz; + ssl->buffers.altKeyDevId = ctx->altPrivateKeyDevId; #endif /* WOLFSSL_DUAL_ALG_CERTS */ #endif #if !defined(WOLFSSL_NO_CLIENT_AUTH) && \ @@ -12975,23 +12985,40 @@ int CopyDecodedToX509(WOLFSSL_X509* x509, DecodedCert* dCert) /* Copy over alternative sig and pubkey. In this case we will allocate new * buffers for them as we have no knowledge of when the DecodedCert is * freed. */ - x509->sapkiDer = (byte*)XMALLOC(dCert->sapkiLen, x509->heap, - DYNAMIC_TYPE_X509_EXT); - x509->altSigAlgDer = (byte*)XMALLOC(dCert->altSigAlgLen, x509->heap, + if (dCert->extSapkiSet) { + x509->sapkiDer = (byte*)XMALLOC(dCert->sapkiLen, x509->heap, DYNAMIC_TYPE_X509_EXT); - x509->altSigValDer = (byte*)XMALLOC(dCert->altSigValLen, x509->heap, - DYNAMIC_TYPE_X509_EXT); - if ((x509->sapkiDer != NULL) && (x509->altSigAlgDer != NULL) && - (x509->altSigValDer != NULL)) { - XMEMCPY(x509->sapkiDer, dCert->sapkiDer, dCert->sapkiLen); - XMEMCPY(x509->altSigAlgDer, dCert->altSigAlgDer, dCert->altSigAlgLen); - XMEMCPY(x509->altSigValDer, dCert->altSigValDer, dCert->altSigValLen); - x509->sapkiLen = dCert->sapkiLen; - x509->altSigAlgLen = dCert->altSigAlgLen; - x509->altSigValLen = dCert->altSigValLen; + if (x509->sapkiDer != NULL) { + XMEMCPY(x509->sapkiDer, dCert->sapkiDer, dCert->sapkiLen); + x509->sapkiLen = dCert->sapkiLen; + } + else { + ret = MEMORY_E; + } } - else { - ret = MEMORY_E; + if (dCert->extAltSigAlgSet) { + x509->altSigAlgDer = (byte*)XMALLOC(dCert->altSigAlgLen, x509->heap, + DYNAMIC_TYPE_X509_EXT); + if (x509->altSigAlgDer != NULL) { + XMEMCPY(x509->altSigAlgDer, dCert->altSigAlgDer, + dCert->altSigAlgLen); + x509->altSigAlgLen = dCert->altSigAlgLen; + } + else { + ret = MEMORY_E; + } + } + if (dCert->extAltSigValSet) { + x509->altSigValDer = (byte*)XMALLOC(dCert->altSigValLen, x509->heap, + DYNAMIC_TYPE_X509_EXT); + if (x509->altSigValDer != NULL) { + XMEMCPY(x509->altSigValDer, dCert->altSigValDer, + dCert->altSigValLen); + x509->altSigValLen = dCert->altSigValLen; + } + else { + ret = MEMORY_E; + } } #endif /* WOLFSSL_DUAL_ALG_CERTS */ @@ -13942,39 +13969,6 @@ PRAGMA_GCC_DIAG_POP alreadySigner = AlreadySigner(SSL_CM(ssl), subjectHash); } -#ifdef WOLFSSL_DUAL_ALG_CERTS - if ((ret == 0) && (args->dCert->sapkiDer != NULL)) { -#ifndef WOLFSSL_SMALL_STACK - byte der[MAX_CERT_VERIFY_SZ]; -#else - byte *der = (byte*)XMALLOC(MAX_CERT_VERIFY_SZ, ssl->heap, - DYNAMIC_TYPE_DCERT); - if (der == NULL) { - ret = MEMORY_E; - } -#endif /* ! WOLFSSL_SMALL_STACK */ - - if (ret == 0) { - ret = wc_GeneratePreTBS(args->dCert, der, MAX_CERT_VERIFY_SZ); - - if (ret > 0) { - ret = wc_ConfirmAltSignature(der, ret, - args->dCert->sapkiDer, args->dCert->sapkiLen, - args->dCert->sapkiOID, - args->dCert->altSigValDer, args->dCert->altSigValLen, - args->dCert->altSigAlgOID, ssl->heap); - } -#ifdef WOLFSSL_SMALL_STACK - XFREE(der, ssl->heap, DYNAMIC_TYPE_DCERT); -#endif /* WOLFSSL_SMALL_STACK */ - - if (ret == 0) { - WOLFSSL_MSG("Alternative signature has been verified!"); - } - } - } -#endif /* WOLFSSL_DUAL_ALG_CERTS */ - #ifdef WOLFSSL_SMALL_CERT_VERIFY /* get signature check failures from above */ if (ret == 0) @@ -27721,9 +27715,12 @@ int DecodePrivateKey(WOLFSSL *ssl, word16* length) ssl->hsType = DYNAMIC_TYPE_RSA; else if (ssl->buffers.keyType == ecc_dsa_sa_algo) ssl->hsType = DYNAMIC_TYPE_ECC; - else if (ssl->buffers.keyType == falcon_level5_sa_algo) + else if ((ssl->buffers.keyType == falcon_level1_sa_algo) || + (ssl->buffers.keyType == falcon_level5_sa_algo)) ssl->hsType = DYNAMIC_TYPE_FALCON; - else if (ssl->buffers.keyType == dilithium_level5_sa_algo) + else if ((ssl->buffers.keyType == dilithium_level2_sa_algo) || + (ssl->buffers.keyType == dilithium_level3_sa_algo) || + (ssl->buffers.keyType == dilithium_level5_sa_algo)) ssl->hsType = DYNAMIC_TYPE_DILITHIUM; ret = AllocKey(ssl, ssl->hsType, &ssl->hsKey); if (ret != 0) { @@ -27782,7 +27779,8 @@ int DecodePrivateKey(WOLFSSL *ssl, word16* length) ret = NOT_COMPILED_IN; #endif } - else if (ssl->buffers.keyType == falcon_level5_sa_algo) { + else if ((ssl->buffers.keyType == falcon_level1_sa_algo) || + (ssl->buffers.keyType == falcon_level5_sa_algo)) { #if defined(HAVE_PQC) && defined(HAVE_FALCON) if (ssl->buffers.keyLabel) { ret = wc_falcon_init_label((falcon_key*)ssl->hsKey, @@ -27795,6 +27793,14 @@ int DecodePrivateKey(WOLFSSL *ssl, word16* length) ssl->buffers.key->length, ssl->heap, ssl->buffers.keyDevId); } + if (ret == 0) { + if (ssl->buffers.keyType == falcon_level1_sa_algo) { + ret = wc_falcon_set_level((falcon_key*)ssl->hsKey, 1); + } + else if (ssl->buffers.keyType == falcon_level5_sa_algo) { + ret = wc_falcon_set_level((falcon_key*)ssl->hsKey, 5); + } + } if (ret == 0) { if (ssl->buffers.keySz < ssl->options.minFalconKeySz) { WOLFSSL_MSG("Falcon key size too small"); @@ -27808,7 +27814,9 @@ int DecodePrivateKey(WOLFSSL *ssl, word16* length) ret = NOT_COMPILED_IN; #endif } - else if (ssl->buffers.keyType == dilithium_level5_sa_algo) { + else if ((ssl->buffers.keyType == dilithium_level2_sa_algo) || + (ssl->buffers.keyType == dilithium_level3_sa_algo) || + (ssl->buffers.keyType == dilithium_level5_sa_algo)) { #if defined(HAVE_PQC) && defined(HAVE_DILITHIUM) if (ssl->buffers.keyLabel) { ret = wc_dilithium_init_label((dilithium_key*)ssl->hsKey, @@ -27821,6 +27829,17 @@ int DecodePrivateKey(WOLFSSL *ssl, word16* length) ssl->buffers.key->length, ssl->heap, ssl->buffers.keyDevId); } + if (ret == 0) { + if (ssl->buffers.keyType == dilithium_level2_sa_algo) { + ret = wc_dilithium_set_level((dilithium_key*)ssl->hsKey, 2); + } + else if (ssl->buffers.keyType == dilithium_level3_sa_algo) { + ret = wc_dilithium_set_level((dilithium_key*)ssl->hsKey, 3); + } + else if (ssl->buffers.keyType == dilithium_level5_sa_algo) { + ret = wc_dilithium_set_level((dilithium_key*)ssl->hsKey, 5); + } + } if (ret == 0) { if (ssl->buffers.keySz < ssl->options.minDilithiumKeySz) { WOLFSSL_MSG("Dilithium key size too small"); @@ -28116,13 +28135,14 @@ int DecodePrivateKey(WOLFSSL *ssl, word16* length) WOLFSSL_MSG("Using Falcon private key"); /* Check it meets the minimum Falcon key size requirements. */ - if (FALCON_MAX_KEY_SIZE < ssl->options.minFalconKeySz) { + keySz = wc_falcon_size((falcon_key*)ssl->hsKey); + if (keySz < ssl->options.minFalconKeySz) { WOLFSSL_MSG("Falcon key size too small"); ERROR_OUT(FALCON_KEY_SIZE_E, exit_dpk); } /* Return the maximum signature length. */ - *length = FALCON_MAX_SIG_SIZE; + *length = wc_falcon_sig_size((falcon_key*)ssl->hsKey); goto exit_dpk; } @@ -28187,13 +28207,14 @@ int DecodePrivateKey(WOLFSSL *ssl, word16* length) WOLFSSL_MSG("Using Dilithium private key"); /* Check it meets the minimum Dilithium key size requirements. */ - if (DILITHIUM_MAX_KEY_SIZE < ssl->options.minDilithiumKeySz) { + keySz = wc_dilithium_size((dilithium_key*)ssl->hsKey); + if (keySz < ssl->options.minDilithiumKeySz) { WOLFSSL_MSG("Dilithium key size too small"); ERROR_OUT(DILITHIUM_KEY_SIZE_E, exit_dpk); } /* Return the maximum signature length. */ - *length = DILITHIUM_MAX_SIG_SIZE; + *length = wc_dilithium_sig_size((dilithium_key*)ssl->hsKey); goto exit_dpk; } @@ -28213,12 +28234,15 @@ exit_dpk: return ret; } -#if defined(HAVE_PQC) && defined(WOLFSSL_DUAL_ALG_CERTS) -/* This is just like the above, but only consider Falcon and Dilthium and - * only for the alternative key; not the native key. */ +#if defined(WOLFSSL_DUAL_ALG_CERTS) +/* This is just like the above, but only consider RSA, ECC, Falcon and + * Dilthium; Furthermore, use the alternative key, not the native key. + */ int DecodeAltPrivateKey(WOLFSSL *ssl, word16* length) { int ret = BAD_FUNC_ARG; + int keySz; + word32 idx; /* make sure alt private key exists */ if (ssl->buffers.altKey == NULL || ssl->buffers.altKey->buffer == NULL) { @@ -28226,8 +28250,280 @@ int DecodeAltPrivateKey(WOLFSSL *ssl, word16* length) ERROR_OUT(NO_PRIVATE_KEY, exit_dapk); } +#ifdef WOLF_PRIVATE_KEY_ID + if (ssl->buffers.altKeyDevId != INVALID_DEVID && + (ssl->buffers.altKeyId || ssl->buffers.altKeyLabel)) { + if (ssl->buffers.altKeyType == rsa_sa_algo) + ssl->hsAltType = DYNAMIC_TYPE_RSA; + else if (ssl->buffers.altKeyType == ecc_dsa_sa_algo) + ssl->hsAltType = DYNAMIC_TYPE_ECC; + else if ((ssl->buffers.altKeyType == falcon_level1_sa_algo) || + (ssl->buffers.altKeyType == falcon_level5_sa_algo)) + ssl->hsAltType = DYNAMIC_TYPE_FALCON; + else if ((ssl->buffers.altKeyType == dilithium_level2_sa_algo) || + (ssl->buffers.altKeyType == dilithium_level3_sa_algo) || + (ssl->buffers.altKeyType == dilithium_level5_sa_algo)) + ssl->hsAltType = DYNAMIC_TYPE_DILITHIUM; + ret = AllocKey(ssl, ssl->hsAltType, &ssl->hsAltKey); + if (ret != 0) { + goto exit_dapk; + } + + if (ssl->buffers.altKeyType == rsa_sa_algo) { + #ifndef NO_RSA + if (ssl->buffers.altKeyLabel) { + ret = wc_InitRsaKey_Label((RsaKey*)ssl->hsAltKey, + (char*)ssl->buffers.altKey->buffer, + ssl->heap, ssl->buffers.altKeyDevId); + } + else if (ssl->buffers.altKeyId) { + ret = wc_InitRsaKey_Id((RsaKey*)ssl->hsAltKey, + ssl->buffers.altKey->buffer, + ssl->buffers.altKey->length, ssl->heap, + ssl->buffers.altKeyDevId); + } + if (ret == 0) { + if (ssl->buffers.altKeySz < ssl->options.minRsaKeySz) { + WOLFSSL_MSG("RSA key size too small"); + ERROR_OUT(RSA_KEY_SIZE_E, exit_dapk); + } + + /* Return the maximum signature length. */ + *length = (word16)ssl->buffers.altKeySz; + } + #else + ret = NOT_COMPILED_IN; + #endif + } + else if (ssl->buffers.altKeyType == ecc_dsa_sa_algo) { + #ifdef HAVE_ECC + if (ssl->buffers.altKeyLabel) { + ret = wc_ecc_init_label((ecc_key*)ssl->hsAltKey, + (char*)ssl->buffers.altKey->buffer, + ssl->heap, ssl->buffers.altKeyDevId); + } + else if (ssl->buffers.altKeyId) { + ret = wc_ecc_init_id((ecc_key*)ssl->hsAltKey, + ssl->buffers.altKey->buffer, + ssl->buffers.altKey->length, ssl->heap, + ssl->buffers.altKeyDevId); + } + if (ret == 0) { + if (ssl->buffers.altKeySz < ssl->options.minEccKeySz) { + WOLFSSL_MSG("ECC key size too small"); + ERROR_OUT(ECC_KEY_SIZE_E, exit_dapk); + } + + /* Return the maximum signature length. */ + *length = (word16)wc_ecc_sig_size_calc(ssl->buffers.altKeySz); + } + #else + ret = NOT_COMPILED_IN; + #endif + } + else if ((ssl->buffers.altKeyType == falcon_level1_sa_algo) || + (ssl->buffers.altKeyType == falcon_level5_sa_algo)) { + #if defined(HAVE_PQC) && defined(HAVE_FALCON) + if (ssl->buffers.altKeyLabel) { + ret = wc_falcon_init_label((falcon_key*)ssl->hsAltKey, + (char*)ssl->buffers.altKey->buffer, + ssl->heap, ssl->buffers.altKeyDevId); + } + else if (ssl->buffers.altKeyId) { + ret = wc_falcon_init_id((falcon_key*)ssl->hsAltKey, + ssl->buffers.altKey->buffer, + ssl->buffers.altKey->length, ssl->heap, + ssl->buffers.altKeyDevId); + } + if (ret == 0) { + if (ssl->buffers.altKeyType == falcon_level1_sa_algo) { + ret = wc_falcon_set_level((falcon_key*)ssl->hsAltKey, 1); + } + else if (ssl->buffers.altKeyType == falcon_level5_sa_algo) { + ret = wc_falcon_set_level((falcon_key*)ssl->hsAltKey, 5); + } + } + if (ret == 0) { + if (ssl->buffers.altKeySz < ssl->options.minFalconKeySz) { + WOLFSSL_MSG("Falcon key size too small"); + ERROR_OUT(FALCON_KEY_SIZE_E, exit_dapk); + } + + /* Return the maximum signature length. */ + *length = (word16) + wc_falcon_sig_size((falcon_key*)ssl->hsAltKey); + } + #else + ret = NOT_COMPILED_IN; + #endif + } + else if ((ssl->buffers.altKeyType == dilithium_level2_sa_algo) || + (ssl->buffers.altKeyType == dilithium_level3_sa_algo) || + (ssl->buffers.altKeyType == dilithium_level5_sa_algo)) { + #if defined(HAVE_PQC) && defined(HAVE_DILITHIUM) + if (ssl->buffers.altKeyLabel) { + ret = wc_dilithium_init_label((dilithium_key*)ssl->hsAltKey, + (char*)ssl->buffers.altKey->buffer, + ssl->heap, ssl->buffers.altKeyDevId); + } + else if (ssl->buffers.altKeyId) { + ret = wc_dilithium_init_id((dilithium_key*)ssl->hsAltKey, + ssl->buffers.altKey->buffer, + ssl->buffers.altKey->length, ssl->heap, + ssl->buffers.altKeyDevId); + } + if (ret == 0) { + if (ssl->buffers.altKeyType == dilithium_level2_sa_algo) { + ret = wc_dilithium_set_level( + (dilithium_key*)ssl->hsAltKey, 2); + } + else if (ssl->buffers.altKeyType == dilithium_level3_sa_algo) { + ret = wc_dilithium_set_level( + (dilithium_key*)ssl->hsAltKey, 3); + } + else if (ssl->buffers.altKeyType == dilithium_level5_sa_algo) { + ret = wc_dilithium_set_level( + (dilithium_key*)ssl->hsAltKey, 5); + } + } + if (ret == 0) { + if (ssl->buffers.altKeySz < ssl->options.minDilithiumKeySz) { + WOLFSSL_MSG("Dilithium key size too small"); + ERROR_OUT(DILITHIUM_KEY_SIZE_E, exit_dapk); + } + + /* Return the maximum signature length. */ + *length = (word16)wc_dilithium_sig_size( + (dilithium_key*)ssl->hsAltKey); + } + #else + ret = NOT_COMPILED_IN; + #endif + } + goto exit_dapk; + } +#endif /* WOLF_PRIVATE_KEY_ID */ + +#ifndef NO_RSA + if (ssl->buffers.altKeyType == rsa_sa_algo || + ssl->buffers.altKeyType == 0) { + ssl->hsAltType = DYNAMIC_TYPE_RSA; + ret = AllocKey(ssl, ssl->hsAltType, &ssl->hsAltKey); + if (ret != 0) { + goto exit_dapk; + } + + WOLFSSL_MSG("Trying RSA private key"); + + /* Set start of data to beginning of buffer. */ + idx = 0; + /* Decode the key assuming it is an RSA private key. */ + ret = wc_RsaPrivateKeyDecode(ssl->buffers.altKey->buffer, &idx, + (RsaKey*)ssl->hsAltKey, ssl->buffers.altKey->length); + #ifdef WOLF_PRIVATE_KEY_ID + /* if using external key then allow using a public key */ + if (ret != 0 && (ssl->devId != INVALID_DEVID + #ifdef HAVE_PK_CALLBACKS + || wolfSSL_CTX_IsPrivatePkSet(ssl->ctx) + #endif + )) { + WOLFSSL_MSG("Trying RSA public key with crypto callbacks"); + idx = 0; + ret = wc_RsaPublicKeyDecode(ssl->buffers.altKey->buffer, &idx, + (RsaKey*)ssl->hsAltKey, ssl->buffers.altKey->length); + } + #endif + if (ret == 0) { + WOLFSSL_MSG("Using RSA private key"); + + /* It worked so check it meets minimum key size requirements. */ + keySz = wc_RsaEncryptSize((RsaKey*)ssl->hsAltKey); + if (keySz < 0) { /* check if keySz has error case */ + ERROR_OUT(keySz, exit_dapk); + } + + if (keySz < ssl->options.minRsaKeySz) { + WOLFSSL_MSG("RSA key size too small"); + ERROR_OUT(RSA_KEY_SIZE_E, exit_dapk); + } + + /* Return the maximum signature length. */ + *length = (word16)keySz; + + goto exit_dapk; + } + } +#endif /* !NO_RSA */ + +#ifdef HAVE_ECC +#ifndef NO_RSA + FreeKey(ssl, ssl->hsAltType, (void**)&ssl->hsAltKey); +#endif /* !NO_RSA */ + + if (ssl->buffers.altKeyType == ecc_dsa_sa_algo || + ssl->buffers.altKeyType == 0 + #if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3) + || ssl->buffers.altKeyType == sm2_sa_algo + #endif + ) { + ssl->hsAltType = DYNAMIC_TYPE_ECC; + ret = AllocKey(ssl, ssl->hsAltType, &ssl->hsAltKey); + if (ret != 0) { + goto exit_dapk; + } + + #ifndef NO_RSA + WOLFSSL_MSG("Trying ECC private key, RSA didn't work"); + #else + WOLFSSL_MSG("Trying ECC private key"); + #endif + + /* Set start of data to beginning of buffer. */ + idx = 0; + /* Decode the key assuming it is an ECC private key. */ + ret = wc_EccPrivateKeyDecode(ssl->buffers.altKey->buffer, &idx, + (ecc_key*)ssl->hsAltKey, + ssl->buffers.altKey->length); + #ifdef WOLF_PRIVATE_KEY_ID + /* if using external key then allow using a public key */ + if (ret != 0 && (ssl->devId != INVALID_DEVID + #ifdef HAVE_PK_CALLBACKS + || wolfSSL_CTX_IsPrivatePkSet(ssl->ctx) + #endif + )) { + WOLFSSL_MSG("Trying ECC public key with crypto callbacks"); + idx = 0; + ret = wc_EccPublicKeyDecode(ssl->buffers.altKey->buffer, &idx, + (ecc_key*)ssl->hsAltKey, + ssl->buffers.altKey->length); + } + #endif + if (ret == 0) { + WOLFSSL_MSG("Using ECC private key"); + + /* Check it meets the minimum ECC key size requirements. */ + keySz = wc_ecc_size((ecc_key*)ssl->hsAltKey); + if (keySz < ssl->options.minEccKeySz) { + WOLFSSL_MSG("ECC key size too small"); + ERROR_OUT(ECC_KEY_SIZE_E, exit_dapk); + } + + /* Return the maximum signature length. */ + *length = (word16)wc_ecc_sig_size((ecc_key*)ssl->hsAltKey); + + goto exit_dapk; + } + } +#endif +#if defined(HAVE_PQC) +#if defined(HAVE_FALCON) + #if !defined(NO_RSA) || defined(HAVE_ECC) + FreeKey(ssl, ssl->hsAltType, (void**)&ssl->hsAltKey); + #endif + if (ssl->buffers.altKeyType == falcon_level1_sa_algo || - ssl->buffers.altKeyType == falcon_level5_sa_algo) { + ssl->buffers.altKeyType == falcon_level5_sa_algo || + ssl->buffers.altKeyType == 0) { ssl->hsAltType = DYNAMIC_TYPE_FALCON; ret = AllocKey(ssl, ssl->hsAltType, &ssl->hsAltKey); @@ -28242,14 +28538,25 @@ int DecodeAltPrivateKey(WOLFSSL *ssl, word16* length) ret = wc_falcon_set_level((falcon_key*)ssl->hsAltKey, 5); } else { + /* What if ssl->buffers.keyType is 0? We might want to do something + * more graceful here. */ ret = ALGO_ID_E; } if (ret != 0) { goto exit_dapk; } - WOLFSSL_MSG("Trying Falcon private key"); + #if defined(HAVE_ECC) + WOLFSSL_MSG("Trying Falcon private key, ECC didn't work"); + #elif !defined(NO_RSA) + WOLFSSL_MSG("Trying Falcon private key, RSA didn't work"); + #else + WOLFSSL_MSG("Trying Falcon private key"); + #endif + + /* Set start of data to beginning of buffer. */ + idx = 0; /* Decode the key assuming it is a Falcon private key. */ ret = wc_falcon_import_private_only(ssl->buffers.altKey->buffer, ssl->buffers.altKey->length, @@ -28258,21 +28565,28 @@ int DecodeAltPrivateKey(WOLFSSL *ssl, word16* length) WOLFSSL_MSG("Using Falcon private key"); /* Check it meets the minimum Falcon key size requirements. */ - if (FALCON_MAX_KEY_SIZE < ssl->options.minFalconKeySz) { + keySz = wc_falcon_size((falcon_key*)ssl->hsAltKey); + if (keySz < ssl->options.minFalconKeySz) { WOLFSSL_MSG("Falcon key size too small"); ERROR_OUT(FALCON_KEY_SIZE_E, exit_dapk); } + /* Return the maximum signature length. */ *length = wc_falcon_sig_size((falcon_key*)ssl->hsAltKey); goto exit_dapk; } } - FreeKey(ssl, ssl->hsAltType, (void**)&ssl->hsAltKey); +#endif /* HAVE_FALCON */ +#if defined(HAVE_DILITHIUM) + #if !defined(NO_RSA) || defined(HAVE_ECC) + FreeKey(ssl, ssl->hsAltType, (void**)&ssl->hsAltKey); + #endif if (ssl->buffers.altKeyType == dilithium_level2_sa_algo || ssl->buffers.altKeyType == dilithium_level3_sa_algo || - ssl->buffers.altKeyType == dilithium_level5_sa_algo) { + ssl->buffers.altKeyType == dilithium_level5_sa_algo || + ssl->buffers.altKeyType == 0) { ssl->hsAltType = DYNAMIC_TYPE_DILITHIUM; ret = AllocKey(ssl, ssl->hsAltType, &ssl->hsAltKey); @@ -28290,6 +28604,8 @@ int DecodeAltPrivateKey(WOLFSSL *ssl, word16* length) ret = wc_dilithium_set_level((dilithium_key*)ssl->hsAltKey, 5); } else { + /* What if ssl->buffers.keyType is 0? We might want to do something + * more graceful here. */ ret = ALGO_ID_E; } @@ -28297,8 +28613,18 @@ int DecodeAltPrivateKey(WOLFSSL *ssl, word16* length) goto exit_dapk; } - WOLFSSL_MSG("Trying Dilithium private key"); + #if defined(HAVE_FALCON) + WOLFSSL_MSG("Trying Dilithium private key, Falcon didn't work"); + #elif defined(HAVE_ECC) + WOLFSSL_MSG("Trying Dilithium private key, ECC didn't work"); + #elif !defined(NO_RSA) + WOLFSSL_MSG("Trying Dilithium private key, RSA didn't work"); + #else + WOLFSSL_MSG("Trying Dilithium private key"); + #endif + /* Set start of data to beginning of buffer. */ + idx = 0; /* Decode the key assuming it is a Dilithium private key. */ ret = wc_dilithium_import_private_only(ssl->buffers.altKey->buffer, ssl->buffers.altKey->length, @@ -28307,16 +28633,24 @@ int DecodeAltPrivateKey(WOLFSSL *ssl, word16* length) WOLFSSL_MSG("Using Dilithium private key"); /* Check it meets the minimum Dilithium key size requirements. */ - if (DILITHIUM_MAX_KEY_SIZE < ssl->options.minDilithiumKeySz) { + keySz = wc_dilithium_size((dilithium_key*)ssl->hsAltKey); + if (keySz < ssl->options.minDilithiumKeySz) { WOLFSSL_MSG("Dilithium key size too small"); ERROR_OUT(DILITHIUM_KEY_SIZE_E, exit_dapk); } + /* Return the maximum signature length. */ *length = wc_dilithium_sig_size((dilithium_key*)ssl->hsAltKey); goto exit_dapk; } } +#endif /* HAVE_DILITHIUM */ +#endif /* HAVE_PQC */ + + (void)idx; + (void)keySz; + (void)length; exit_dapk: if (ret != 0) { @@ -28325,7 +28659,7 @@ exit_dapk: return ret; } -#endif /* HAVE_PQC && WOLFSSL_DUAL_ALG_CERTS */ +#endif /* WOLFSSL_DUAL_ALG_CERTS */ #endif /* WOLFSSL_TLS13 || !NO_WOLFSSL_CLIENT */ #if defined(WOLFSSL_TLS13) && !defined(WOLFSSL_NO_TLS12) diff --git a/src/ssl.c b/src/ssl.c index adb0e5a39..7f44bbc5d 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -122,6 +122,9 @@ #if defined(HAVE_DILITHIUM) #include #endif /* HAVE_DILITHIUM */ + #if defined(HAVE_SPHINCS) + #include + #endif /* HAVE_SPHINCS */ #endif /* HAVE_PQC */ #if defined(OPENSSL_ALL) || defined(HAVE_STUNNEL) #ifdef HAVE_OCSP @@ -5919,8 +5922,19 @@ int AddCA(WOLFSSL_CERT_MANAGER* cm, DerBuffer** pDer, int type, int verify) } #ifdef WOLFSSL_DUAL_ALG_CERTS - signer->sapkiDer = cert->sapkiDer; - signer->sapkiLen = cert->sapkiLen; + if (cert->extSapkiSet && cert->sapkiLen > 0) { + /* Allocated space for alternative public key. */ + signer->sapkiDer = (byte*)XMALLOC(cert->sapkiLen, cm->heap, + DYNAMIC_TYPE_PUBLIC_KEY); + if (signer->sapkiDer == NULL) { + ret = MEMORY_E; + } + else { + XMEMCPY(signer->sapkiDer, cert->sapkiDer, cert->sapkiLen); + signer->sapkiLen = cert->sapkiLen; + signer->sapkiOID = cert->sapkiOID; + } + } #endif /* WOLFSSL_DUAL_ALG_CERTS */ if (cert->subjectCNStored) { @@ -6518,11 +6532,12 @@ static int ProcessUserChain(WOLFSSL_CTX* ctx, const unsigned char* buff, (HAVE_FIPS_VERSION > 2)) static int ProcessBufferTryDecodeRsa(WOLFSSL_CTX* ctx, WOLFSSL* ssl, DerBuffer* der, int* keySz, word32* idx, int* resetSuites, int* keyFormat, - int devId) + int devId, int type) { int ret; (void)devId; + (void)type; *idx = 0; ret = wc_RsaPrivateKeyValidate(der->buffer, idx, keySz, der->length); @@ -6566,12 +6581,30 @@ static int ProcessBufferTryDecodeRsa(WOLFSSL_CTX* ctx, WOLFSSL* ssl, } if (ssl) { - ssl->buffers.keyType = rsa_sa_algo; - ssl->buffers.keySz = *keySz; + #ifdef WOLFSSL_DUAL_ALG_CERTS + if (type == ALT_PRIVATEKEY_TYPE) { + ssl->buffers.altKeyType = rsa_sa_algo; + ssl->buffers.altKeySz = *keySz; + } + else + #endif /* WOLFSSL_DUAL_ALG_CERTS */ + { + ssl->buffers.keyType = rsa_sa_algo; + ssl->buffers.keySz = *keySz; + } } else { - ctx->privateKeyType = rsa_sa_algo; - ctx->privateKeySz = *keySz; + #ifdef WOLFSSL_DUAL_ALG_CERTS + if (type == ALT_PRIVATEKEY_TYPE) { + ctx->altPrivateKeyType = rsa_sa_algo; + ctx->altPrivateKeySz = *keySz; + } + else + #endif /* WOLFSSL_DUAL_ALG_CERTS */ + { + ctx->privateKeyType = rsa_sa_algo; + ctx->privateKeySz = *keySz; + } } *keyFormat = RSAk; @@ -6587,10 +6620,12 @@ static int ProcessBufferTryDecodeRsa(WOLFSSL_CTX* ctx, WOLFSSL* ssl, #else static int ProcessBufferTryDecodeRsa(WOLFSSL_CTX* ctx, WOLFSSL* ssl, DerBuffer* der, int* keySz, word32* idx, int* resetSuites, int* keyFormat, - void* heap, int devId) + void* heap, int devId, int type) { int ret; + (void)type; + /* make sure RSA key can be used */ #ifdef WOLFSSL_SMALL_STACK RsaKey* key; @@ -6643,12 +6678,30 @@ static int ProcessBufferTryDecodeRsa(WOLFSSL_CTX* ctx, WOLFSSL* ssl, } if (ssl) { - ssl->buffers.keyType = rsa_sa_algo; - ssl->buffers.keySz = *keySz; + #ifdef WOLFSSL_DUAL_ALG_CERTS + if (type == ALT_PRIVATEKEY_TYPE) { + ssl->buffers.altKeyType = rsa_sa_algo; + ssl->buffers.altKeySz = *keySz; + } + else + #endif /* WOLFSSL_DUAL_ALG_CERTS */ + { + ssl->buffers.keyType = rsa_sa_algo; + ssl->buffers.keySz = *keySz; + } } else { - ctx->privateKeyType = rsa_sa_algo; - ctx->privateKeySz = *keySz; + #ifdef WOLFSSL_DUAL_ALG_CERTS + if (type == ALT_PRIVATEKEY_TYPE) { + ctx->altPrivateKeyType = rsa_sa_algo; + ctx->altPrivateKeySz = *keySz; + } + else + #endif /* WOLFSSL_DUAL_ALG_CERTS */ + { + ctx->privateKeyType = rsa_sa_algo; + ctx->privateKeySz = *keySz; + } } *keyFormat = RSAk; @@ -6674,7 +6727,7 @@ static int ProcessBufferTryDecodeRsa(WOLFSSL_CTX* ctx, WOLFSSL* ssl, #ifdef HAVE_ECC static int ProcessBufferTryDecodeEcc(WOLFSSL_CTX* ctx, WOLFSSL* ssl, DerBuffer* der, int* keySz, word32* idx, int* resetSuites, int* keyFormat, - void* heap, int devId) + void* heap, int devId, int type) { int ret = 0; /* make sure ECC key can be used */ @@ -6684,6 +6737,8 @@ static int ProcessBufferTryDecodeEcc(WOLFSSL_CTX* ctx, WOLFSSL* ssl, ecc_key key[1]; #endif + (void)type; + #ifdef WOLFSSL_SMALL_STACK key = (ecc_key*)XMALLOC(sizeof(ecc_key), heap, DYNAMIC_TYPE_ECC); if (key == NULL) @@ -6716,26 +6771,42 @@ static int ProcessBufferTryDecodeEcc(WOLFSSL_CTX* ctx, WOLFSSL* ssl, *keyFormat = ECDSAk; if (ssl) { - ssl->options.haveStaticECC = 1; - ssl->buffers.keyType = ecc_dsa_sa_algo; - #ifdef WOLFSSL_SM2 - if (key->dp->id == ECC_SM2P256V1) - ssl->buffers.keyType = sm2_sa_algo; + #ifdef WOLFSSL_DUAL_ALG_CERTS + if (type == ALT_PRIVATEKEY_TYPE) { + ssl->buffers.altKeyType = ecc_dsa_sa_algo; + ssl->buffers.altKeySz = *keySz; + } else - #endif - ssl->buffers.keyType = ecc_dsa_sa_algo; - ssl->buffers.keySz = *keySz; + #endif /* WOLFSSL_DUAL_ALG_CERTS */ + { + ssl->options.haveStaticECC = 1; + #ifdef WOLFSSL_SM2 + if (key->dp->id == ECC_SM2P256V1) + ssl->buffers.keyType = sm2_sa_algo; + else + #endif + ssl->buffers.keyType = ecc_dsa_sa_algo; + ssl->buffers.keySz = *keySz; + } } else { - ctx->haveStaticECC = 1; - ctx->privateKeyType = ecc_dsa_sa_algo; - #ifdef WOLFSSL_SM2 - if (key->dp->id == ECC_SM2P256V1) - ctx->privateKeyType = sm2_sa_algo; + #ifdef WOLFSSL_DUAL_ALG_CERTS + if (type == ALT_PRIVATEKEY_TYPE) { + ctx->altPrivateKeyType = ecc_dsa_sa_algo; + ctx->altPrivateKeySz = *keySz; + } else - #endif - ctx->privateKeyType = ecc_dsa_sa_algo; - ctx->privateKeySz = *keySz; + #endif /* WOLFSSL_DUAL_ALG_CERTS */ + { + ctx->haveStaticECC = 1; + #ifdef WOLFSSL_SM2 + if (key->dp->id == ECC_SM2P256V1) + ctx->privateKeyType = sm2_sa_algo; + else + #endif + ctx->privateKeyType = ecc_dsa_sa_algo; + ctx->privateKeySz = *keySz; + } } if (ssl && ssl->options.side == WOLFSSL_SERVER_END) { @@ -6952,7 +7023,7 @@ static int ProcessBufferTryDecodeFalcon(WOLFSSL_CTX* ctx, WOLFSSL* ssl, /* check for minimum key size and then free */ int minKeySz = ssl ? ssl->options.minFalconKeySz : ctx->minFalconKeySz; - *keySz = FALCON_MAX_KEY_SIZE; + *keySz = wc_falcon_size(key); if (*keySz < minKeySz) { WOLFSSL_MSG("Falcon private key too small"); ret = FALCON_KEY_SIZE_E; @@ -7058,7 +7129,7 @@ static int ProcessBufferTryDecodeDilithium(WOLFSSL_CTX* ctx, WOLFSSL* ssl, /* check for minimum key size and then free */ int minKeySz = ssl ? ssl->options.minDilithiumKeySz : ctx->minDilithiumKeySz; - *keySz = DILITHIUM_MAX_KEY_SIZE; + *keySz = wc_dilithium_size(key); if (*keySz < minKeySz) { WOLFSSL_MSG("Dilithium private key too small"); ret = DILITHIUM_KEY_SIZE_E; @@ -7159,10 +7230,10 @@ static int ProcessBufferTryDecode(WOLFSSL_CTX* ctx, WOLFSSL* ssl, #if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \ (HAVE_FIPS_VERSION > 2)) ret = ProcessBufferTryDecodeRsa(ctx, ssl, der, keySz, idx, resetSuites, - keyFormat, devId); + keyFormat, devId, type); #else ret = ProcessBufferTryDecodeRsa(ctx, ssl, der, keySz, idx, resetSuites, - keyFormat, heap, devId); + keyFormat, heap, devId, type); #endif if (ret != 0) return ret; @@ -7175,7 +7246,7 @@ static int ProcessBufferTryDecode(WOLFSSL_CTX* ctx, WOLFSSL* ssl, #endif ) { ret = ProcessBufferTryDecodeEcc(ctx, ssl, der, keySz, idx, resetSuites, - keyFormat, heap, devId); + keyFormat, heap, devId, type); if (ret != 0) return ret; } @@ -7428,6 +7499,9 @@ int ProcessBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff, ForceZero(ssl->buffers.key->buffer, ssl->buffers.key->length); FreeDer(&ssl->buffers.key); } + ssl->buffers.keyId = 0; + ssl->buffers.keyLabel = 0; + ssl->buffers.keyDevId = INVALID_DEVID; ssl->buffers.key = der; #ifdef WOLFSSL_CHECK_MEM_ZERO wc_MemZero_Add("SSL Buffers key", der->buffer, der->length); @@ -7439,6 +7513,9 @@ int ProcessBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff, ForceZero(ctx->privateKey->buffer, ctx->privateKey->length); } FreeDer(&ctx->privateKey); + ctx->privateKeyId = 0; + ctx->privateKeyLabel = 0; + ctx->privateKeyDevId = INVALID_DEVID; ctx->privateKey = der; #ifdef WOLFSSL_CHECK_MEM_ZERO wc_MemZero_Add("CTX private key", der->buffer, der->length); @@ -7454,6 +7531,9 @@ int ProcessBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff, ssl->buffers.altKey->length); FreeDer(&ssl->buffers.altKey); } + ssl->buffers.altKeyId = 0; + ssl->buffers.altKeyLabel = 0; + ssl->buffers.altKeyDevId = INVALID_DEVID; ssl->buffers.altKey = der; #ifdef WOLFSSL_CHECK_MEM_ZERO wc_MemZero_Add("SSL Buffers key", der->buffer, der->length); @@ -7467,6 +7547,9 @@ int ProcessBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff, ctx->altPrivateKey->length); } FreeDer(&ctx->altPrivateKey); + ctx->altPrivateKeyId = 0; + ctx->altPrivateKeyLabel = 0; + ctx->altPrivateKeyDevId = INVALID_DEVID; ctx->altPrivateKey = der; #ifdef WOLFSSL_CHECK_MEM_ZERO wc_MemZero_Add("CTX private key", der->buffer, der->length); @@ -7570,9 +7653,7 @@ int ProcessBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff, #else DecodedCert cert[1]; #endif - #ifdef WOLF_PRIVATE_KEY_ID int keyType = 0; - #endif #ifdef WOLFSSL_SMALL_STACK cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), heap, @@ -7773,9 +7854,7 @@ int ProcessBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff, case RSAPSSk: #endif case RSAk: - #ifdef WOLF_PRIVATE_KEY_ID keyType = rsa_sa_algo; - #endif /* Determine RSA key size by parsing public key */ idx = 0; ret = wc_RsaPublicKeyDecode_ex(cert->publicKey, &idx, @@ -7803,9 +7882,7 @@ int ProcessBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff, #endif /* !NO_RSA */ #ifdef HAVE_ECC case ECDSAk: - #ifdef WOLF_PRIVATE_KEY_ID keyType = ecc_dsa_sa_algo; - #endif /* Determine ECC key size based on curve */ #ifdef WOLFSSL_CUSTOM_CURVES if (cert->pkCurveOID == 0 && cert->pkCurveSize != 0) { @@ -7836,9 +7913,7 @@ int ProcessBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff, #endif /* HAVE_ECC */ #if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3) case SM2k: - #ifdef WOLF_PRIVATE_KEY_ID keyType = sm2_sa_algo; - #endif /* Determine ECC key size based on curve */ keySz = wc_ecc_get_curve_size_from_id( wc_ecc_get_oid(cert->pkCurveOID, NULL, NULL)); @@ -7860,9 +7935,7 @@ int ProcessBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff, #endif /* HAVE_ED25519 */ #ifdef HAVE_ED25519 case ED25519k: - #ifdef WOLF_PRIVATE_KEY_ID keyType = ed25519_sa_algo; - #endif /* ED25519 is fixed key size */ keySz = ED25519_KEY_SIZE; if (ssl && !ssl->options.verifyNone) { @@ -7883,9 +7956,7 @@ int ProcessBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff, #endif /* HAVE_ED25519 */ #ifdef HAVE_ED448 case ED448k: - #ifdef WOLF_PRIVATE_KEY_ID keyType = ed448_sa_algo; - #endif /* ED448 is fixed key size */ keySz = ED448_KEY_SIZE; if (ssl && !ssl->options.verifyNone) { @@ -7907,12 +7978,28 @@ int ProcessBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff, #if defined(HAVE_PQC) #if defined(HAVE_FALCON) case FALCON_LEVEL1k: - case FALCON_LEVEL5k: - #ifdef WOLF_PRIVATE_KEY_ID - keyType = falcon_level5_sa_algo; - #endif + keyType = falcon_level1_sa_algo; /* Falcon is fixed key size */ - keySz = FALCON_MAX_KEY_SIZE; + keySz = FALCON_LEVEL1_KEY_SIZE; + if (ssl && !ssl->options.verifyNone) { + if (ssl->options.minFalconKeySz < 0 || + keySz < (int)ssl->options.minFalconKeySz) { + ret = FALCON_KEY_SIZE_E; + WOLFSSL_MSG("Certificate Falcon key size error"); + } + } + else if (ctx && !ctx->verifyNone) { + if (ctx->minFalconKeySz < 0 || + keySz < (int)ctx->minFalconKeySz) { + ret = FALCON_KEY_SIZE_E; + WOLFSSL_MSG("Certificate Falcon key size error"); + } + } + break; + case FALCON_LEVEL5k: + keyType = falcon_level5_sa_algo; + /* Falcon is fixed key size */ + keySz = FALCON_LEVEL5_KEY_SIZE; if (ssl && !ssl->options.verifyNone) { if (ssl->options.minFalconKeySz < 0 || keySz < (int)ssl->options.minFalconKeySz) { @@ -7931,13 +8018,47 @@ int ProcessBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff, #endif /* HAVE_FALCON */ #if defined(HAVE_DILITHIUM) case DILITHIUM_LEVEL2k: - case DILITHIUM_LEVEL3k: - case DILITHIUM_LEVEL5k: - #ifdef WOLF_PRIVATE_KEY_ID - keyType = dilithium_level5_sa_algo; - #endif + keyType = dilithium_level2_sa_algo; /* Dilithium is fixed key size */ - keySz = DILITHIUM_MAX_KEY_SIZE; + keySz = DILITHIUM_LEVEL2_KEY_SIZE; + if (ssl && !ssl->options.verifyNone) { + if (ssl->options.minDilithiumKeySz < 0 || + keySz < (int)ssl->options.minDilithiumKeySz) { + ret = DILITHIUM_KEY_SIZE_E; + WOLFSSL_MSG("Certificate Dilithium key size error"); + } + } + else if (ctx && !ctx->verifyNone) { + if (ctx->minDilithiumKeySz < 0 || + keySz < (int)ctx->minDilithiumKeySz) { + ret = DILITHIUM_KEY_SIZE_E; + WOLFSSL_MSG("Certificate Dilithium key size error"); + } + } + break; + case DILITHIUM_LEVEL3k: + keyType = dilithium_level3_sa_algo; + /* Dilithium is fixed key size */ + keySz = DILITHIUM_LEVEL3_KEY_SIZE; + if (ssl && !ssl->options.verifyNone) { + if (ssl->options.minDilithiumKeySz < 0 || + keySz < (int)ssl->options.minDilithiumKeySz) { + ret = DILITHIUM_KEY_SIZE_E; + WOLFSSL_MSG("Certificate Dilithium key size error"); + } + } + else if (ctx && !ctx->verifyNone) { + if (ctx->minDilithiumKeySz < 0 || + keySz < (int)ctx->minDilithiumKeySz) { + ret = DILITHIUM_KEY_SIZE_E; + WOLFSSL_MSG("Certificate Dilithium key size error"); + } + } + break; + case DILITHIUM_LEVEL5k: + keyType = dilithium_level5_sa_algo; + /* Dilithium is fixed key size */ + keySz = DILITHIUM_LEVEL5_KEY_SIZE; if (ssl && !ssl->options.verifyNone) { if (ssl->options.minDilithiumKeySz < 0 || keySz < (int)ssl->options.minDilithiumKeySz) { @@ -7961,7 +8082,6 @@ int ProcessBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff, break; /* do no check if not a case for the key */ } - #ifdef WOLF_PRIVATE_KEY_ID if (ssl != NULL) { ssl->buffers.keyType = (byte)keyType; ssl->buffers.keySz = keySz; @@ -7970,7 +8090,275 @@ int ProcessBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff, ctx->privateKeyType = (byte)keyType; ctx->privateKeySz = keySz; } - #endif + + #ifdef WOLFSSL_DUAL_ALG_CERTS + keyType = 0; + keySz = 0; + /* check alternative key size of cert */ + switch (cert->sapkiOID) { + #ifndef NO_RSA + #ifdef WC_RSA_PSS + case RSAPSSk: + #endif + case RSAk: + keyType = rsa_sa_algo; + /* Determine RSA key size by parsing public key */ + idx = 0; + ret = wc_RsaPublicKeyDecode_ex(cert->sapkiDer, &idx, + cert->sapkiLen, NULL, (word32*)&keySz, NULL, NULL); + if (ret < 0) + break; + + if (ssl && !ssl->options.verifyNone) { + if (ssl->options.minRsaKeySz < 0 || + keySz < (int)ssl->options.minRsaKeySz || + keySz > (RSA_MAX_SIZE / 8)) { + ret = RSA_KEY_SIZE_E; + WOLFSSL_MSG("Certificate RSA key size too small"); + } + } + else if (ctx && !ctx->verifyNone) { + if (ctx->minRsaKeySz < 0 || + keySz < (int)ctx->minRsaKeySz || + keySz > (RSA_MAX_SIZE / 8)) { + ret = RSA_KEY_SIZE_E; + WOLFSSL_MSG("Certificate RSA key size too small"); + } + } + break; + #endif /* !NO_RSA */ + #ifdef HAVE_ECC + case ECDSAk: + { + #ifdef WOLFSSL_SMALL_STACK + ecc_key* temp_key = NULL; + #else + ecc_key temp_key[1]; + #endif + keyType = ecc_dsa_sa_algo; + + #ifdef WOLFSSL_SMALL_STACK + temp_key = (ecc_key*)XMALLOC(sizeof(ecc_key), heap, + DYNAMIC_TYPE_ECC); + if (temp_key == NULL) + ret = MEMORY_E; + #endif + + /* Determine ECC key size. We have to decode the sapki for + * that. */ + if (ret == 0) { + ret = wc_ecc_init_ex(temp_key, heap, INVALID_DEVID); + } + if (ret == 0) { + idx = 0; + ret = wc_EccPublicKeyDecode(cert->sapkiDer, &idx, temp_key, + cert->sapkiLen); + } + if (ret == 0) { + keySz = wc_ecc_size(temp_key); + } + wc_ecc_free(temp_key); + #ifdef WOLFSSL_SMALL_STACK + XFREE(temp_key, heap, DYNAMIC_TYPE_ECC); + #endif + + if (ssl && !ssl->options.verifyNone) { + if (ssl->options.minEccKeySz < 0 || + keySz < (int)ssl->options.minEccKeySz) { + ret = ECC_KEY_SIZE_E; + WOLFSSL_MSG("Certificate ECC key size error"); + } + } + else if (ctx && !ctx->verifyNone) { + if (ctx->minEccKeySz < 0 || + keySz < (int)ctx->minEccKeySz) { + ret = ECC_KEY_SIZE_E; + WOLFSSL_MSG("Certificate ECC key size error"); + } + } + break; + } + #endif /* HAVE_ECC */ + #if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3) + case SM2k: + keyType = sm2_sa_algo; + /* Determine ECC key size based on curve */ + keySz = wc_ecc_get_curve_size_from_id( + wc_ecc_get_oid(cert->pkCurveOID, NULL, NULL)); + if (ssl && !ssl->options.verifyNone) { + if (ssl->options.minEccKeySz < 0 || + keySz < (int)ssl->options.minEccKeySz) { + ret = ECC_KEY_SIZE_E; + WOLFSSL_MSG("Certificate Ed key size error"); + } + } + else if (ctx && !ctx->verifyNone) { + if (ctx->minEccKeySz < 0 || + keySz < (int)ctx->minEccKeySz) { + ret = ECC_KEY_SIZE_E; + WOLFSSL_MSG("Certificate ECC key size error"); + } + } + break; + #endif /* HAVE_ED25519 */ + #ifdef HAVE_ED25519 + case ED25519k: + keyType = ed25519_sa_algo; + /* ED25519 is fixed key size */ + keySz = ED25519_KEY_SIZE; + if (ssl && !ssl->options.verifyNone) { + if (ssl->options.minEccKeySz < 0 || + keySz < (int)ssl->options.minEccKeySz) { + ret = ECC_KEY_SIZE_E; + WOLFSSL_MSG("Certificate Ed key size error"); + } + } + else if (ctx && !ctx->verifyNone) { + if (ctx->minEccKeySz < 0 || + keySz < (int)ctx->minEccKeySz) { + ret = ECC_KEY_SIZE_E; + WOLFSSL_MSG("Certificate ECC key size error"); + } + } + break; + #endif /* HAVE_ED25519 */ + #ifdef HAVE_ED448 + case ED448k: + keyType = ed448_sa_algo; + /* ED448 is fixed key size */ + keySz = ED448_KEY_SIZE; + if (ssl && !ssl->options.verifyNone) { + if (ssl->options.minEccKeySz < 0 || + keySz < (int)ssl->options.minEccKeySz) { + ret = ECC_KEY_SIZE_E; + WOLFSSL_MSG("Certificate Ed key size error"); + } + } + else if (ctx && !ctx->verifyNone) { + if (ctx->minEccKeySz < 0 || + keySz < (int)ctx->minEccKeySz) { + ret = ECC_KEY_SIZE_E; + WOLFSSL_MSG("Certificate ECC key size error"); + } + } + break; + #endif /* HAVE_ED448 */ + #if defined(HAVE_PQC) + #if defined(HAVE_FALCON) + case FALCON_LEVEL1k: + keyType = falcon_level1_sa_algo; + /* Falcon is fixed key size */ + keySz = FALCON_LEVEL1_KEY_SIZE; + if (ssl && !ssl->options.verifyNone) { + if (ssl->options.minFalconKeySz < 0 || + keySz < (int)ssl->options.minFalconKeySz) { + ret = FALCON_KEY_SIZE_E; + WOLFSSL_MSG("Certificate Falcon key size error"); + } + } + else if (ctx && !ctx->verifyNone) { + if (ctx->minFalconKeySz < 0 || + keySz < (int)ctx->minFalconKeySz) { + ret = FALCON_KEY_SIZE_E; + WOLFSSL_MSG("Certificate Falcon key size error"); + } + } + break; + case FALCON_LEVEL5k: + keyType = falcon_level5_sa_algo; + /* Falcon is fixed key size */ + keySz = FALCON_LEVEL5_KEY_SIZE; + if (ssl && !ssl->options.verifyNone) { + if (ssl->options.minFalconKeySz < 0 || + keySz < (int)ssl->options.minFalconKeySz) { + ret = FALCON_KEY_SIZE_E; + WOLFSSL_MSG("Certificate Falcon key size error"); + } + } + else if (ctx && !ctx->verifyNone) { + if (ctx->minFalconKeySz < 0 || + keySz < (int)ctx->minFalconKeySz) { + ret = FALCON_KEY_SIZE_E; + WOLFSSL_MSG("Certificate Falcon key size error"); + } + } + break; + #endif /* HAVE_FALCON */ + #if defined(HAVE_DILITHIUM) + case DILITHIUM_LEVEL2k: + keyType = dilithium_level2_sa_algo; + /* Dilithium is fixed key size */ + keySz = DILITHIUM_LEVEL2_KEY_SIZE; + if (ssl && !ssl->options.verifyNone) { + if (ssl->options.minDilithiumKeySz < 0 || + keySz < (int)ssl->options.minDilithiumKeySz) { + ret = DILITHIUM_KEY_SIZE_E; + WOLFSSL_MSG("Certificate Dilithium key size error"); + } + } + else if (ctx && !ctx->verifyNone) { + if (ctx->minDilithiumKeySz < 0 || + keySz < (int)ctx->minDilithiumKeySz) { + ret = DILITHIUM_KEY_SIZE_E; + WOLFSSL_MSG("Certificate Dilithium key size error"); + } + } + break; + case DILITHIUM_LEVEL3k: + keyType = dilithium_level3_sa_algo; + /* Dilithium is fixed key size */ + keySz = DILITHIUM_LEVEL3_KEY_SIZE; + if (ssl && !ssl->options.verifyNone) { + if (ssl->options.minDilithiumKeySz < 0 || + keySz < (int)ssl->options.minDilithiumKeySz) { + ret = DILITHIUM_KEY_SIZE_E; + WOLFSSL_MSG("Certificate Dilithium key size error"); + } + } + else if (ctx && !ctx->verifyNone) { + if (ctx->minDilithiumKeySz < 0 || + keySz < (int)ctx->minDilithiumKeySz) { + ret = DILITHIUM_KEY_SIZE_E; + WOLFSSL_MSG("Certificate Dilithium key size error"); + } + } + break; + case DILITHIUM_LEVEL5k: + keyType = dilithium_level5_sa_algo; + /* Dilithium is fixed key size */ + keySz = DILITHIUM_LEVEL5_KEY_SIZE; + if (ssl && !ssl->options.verifyNone) { + if (ssl->options.minDilithiumKeySz < 0 || + keySz < (int)ssl->options.minDilithiumKeySz) { + ret = DILITHIUM_KEY_SIZE_E; + WOLFSSL_MSG("Certificate Dilithium key size error"); + } + } + else if (ctx && !ctx->verifyNone) { + if (ctx->minDilithiumKeySz < 0 || + keySz < (int)ctx->minDilithiumKeySz) { + ret = DILITHIUM_KEY_SIZE_E; + WOLFSSL_MSG("Certificate Dilithium key size error"); + } + } + break; + #endif /* HAVE_DILITHIUM */ + #endif /* HAVE_PQC */ + + default: + WOLFSSL_MSG("No alt key size check done on certificate"); + break; /* do no check if not a case for the key */ + } + + if (ssl != NULL) { + ssl->buffers.altKeyType = (byte)keyType; + ssl->buffers.altKeySz = keySz; + } + else if (ctx != NULL) { + ctx->altPrivateKeyType = (byte)keyType; + ctx->altPrivateKeySz = keySz; + } + #endif /* WOLFSSL_DUAL_ALG_CERTS */ FreeDecodedCert(cert); #ifdef WOLFSSL_SMALL_STACK @@ -8399,6 +8787,25 @@ int ProcessFile(WOLFSSL_CTX* ctx, const char* fname, int format, int type, #ifdef HAVE_CRL else if (type == CRL_TYPE) ret = BufferLoadCRL(crl, myBuffer, sz, format, verify); +#endif +#ifdef WOLFSSL_DUAL_ALG_CERTS + else if (type == PRIVATEKEY_TYPE) + { + /* When support for dual algorithm certificates is enabled, the + * private key file may contain both the primary and the + * alternative private key. Hence, we have to parse both of them. + */ + long consumed = 0; + + ret = ProcessBuffer(ctx, myBuffer, sz, format, PRIVATEKEY_TYPE, + ssl, &consumed, 0, verify); + + if (ret == WOLFSSL_SUCCESS && consumed < sz) { + ret = ProcessBuffer(ctx, myBuffer + consumed, sz - consumed, + format, ALT_PRIVATEKEY_TYPE, ssl, NULL, 0, + verify); + } + } #endif else ret = ProcessBuffer(ctx, myBuffer, sz, format, type, ssl, NULL, @@ -9222,12 +9629,134 @@ int wolfSSL_CTX_SetTmpDH_file(WOLFSSL_CTX* ctx, const char* fname, int format) #endif /* NO_FILESYSTEM */ #ifndef NO_CHECK_PRIVATE_KEY + +#ifdef WOLF_PRIVATE_KEY_ID +/* Check private against public in certificate for match using external + * device with given devId */ +static int check_cert_key_dev(word32 keyOID, byte* privKey, word32 privSz, + const byte* pubKey, word32 pubSz, int label, int id, void* heap, int devId) +{ + int ret = 0; + int type = 0; + void *pkey = NULL; + + if (privKey == NULL) { + return MISSING_KEY; + } + +#ifndef NO_RSA + if (keyOID == RSAk) { + type = DYNAMIC_TYPE_RSA; + } +#ifdef WC_RSA_PSS + if (keyOID == RSAPSSk) { + type = DYNAMIC_TYPE_RSA; + } +#endif +#endif +#ifdef HAVE_ECC + if (keyOID == ECDSAk) { + type = DYNAMIC_TYPE_ECC; + } +#endif +#if defined(HAVE_PQC) && defined(HAVE_DILITHIUM) + if ((keyOID == DILITHIUM_LEVEL2k) || + (keyOID == DILITHIUM_LEVEL3k) || + (keyOID == DILITHIUM_LEVEL5k)) { + type = DYNAMIC_TYPE_DILITHIUM; + } +#endif +#if defined(HAVE_PQC) && defined(HAVE_FALCON) + if ((keyOID == FALCON_LEVEL1k) || + (keyOID == FALCON_LEVEL5k)) { + type = DYNAMIC_TYPE_FALCON; + } +#endif + + ret = CreateDevPrivateKey(&pkey, privKey, privSz, type, label, id, + heap, devId); + #ifdef WOLF_CRYPTO_CB + if (ret == 0) { + #ifndef NO_RSA + if (keyOID == RSAk + #ifdef WC_RSA_PSS + || keyOID == RSAPSSk + #endif + ) { + ret = wc_CryptoCb_RsaCheckPrivKey((RsaKey*)pkey, pubKey, pubSz); + } + #endif + #ifdef HAVE_ECC + if (keyOID == ECDSAk) { + ret = wc_CryptoCb_EccCheckPrivKey((ecc_key*)pkey, pubKey, pubSz); + } + #endif + #if defined(HAVE_PQC) && defined(HAVE_DILITHIUM) + if ((keyOID == DILITHIUM_LEVEL2k) || + (keyOID == DILITHIUM_LEVEL3k) || + (keyOID == DILITHIUM_LEVEL5k)) { + ret = wc_CryptoCb_PqcSignatureCheckPrivKey(pkey, + WC_PQC_SIG_TYPE_DILITHIUM, + pubKey, pubSz); + } + #endif + #if defined(HAVE_PQC) && defined(HAVE_FALCON) + if ((keyOID == FALCON_LEVEL1k) || + (keyOID == FALCON_LEVEL5k)) { + ret = wc_CryptoCb_PqcSignatureCheckPrivKey(pkey, + WC_PQC_SIG_TYPE_FALCON, + pubKey, pubSz); + } + #endif + } + #else + /* devId was set, don't check, for now */ + /* TODO: Add callback for private key check? */ + (void) pubKey; + (void) pubSz; + #endif + if (pkey != NULL) { + #ifndef NO_RSA + if (keyOID == RSAk + #ifdef WC_RSA_PSS + || keyOID == RSAPSSk + #endif + ) { + wc_FreeRsaKey((RsaKey*)pkey); + } + #endif + #ifdef HAVE_ECC + if (keyOID == ECDSAk) { + wc_ecc_free((ecc_key*)pkey); + } + #endif + #if defined(HAVE_PQC) && defined(HAVE_DILITHIUM) + if ((keyOID == DILITHIUM_LEVEL2k) || + (keyOID == DILITHIUM_LEVEL3k) || + (keyOID == DILITHIUM_LEVEL5k)) { + wc_dilithium_free((dilithium_key*)pkey); + } + #endif + #if defined(HAVE_PQC) && defined(HAVE_FALCON) + if ((keyOID == FALCON_LEVEL1k) || + (keyOID == FALCON_LEVEL5k)) { + wc_falcon_free((falcon_key*)pkey); + } + #endif + XFREE(pkey, heap, type); + } + + return ret; +} +#endif /* WOLF_PRIVATE_KEY_ID */ + /* Check private against public in certificate for match * * Returns WOLFSSL_SUCCESS on good private key * WOLFSSL_FAILURE if mismatched */ -static int check_cert_key(DerBuffer* cert, DerBuffer* key, void* heap, - int devId, int isKeyLabel, int isKeyId) +static int check_cert_key(DerBuffer* cert, DerBuffer* key, DerBuffer* altKey, + void* heap, int devId, int isKeyLabel, int isKeyId, int altDevId, + int isAltKeyLabel, int isAltKeyId) { #ifdef WOLFSSL_SMALL_STACK DecodedCert* der = NULL; @@ -9245,7 +9774,7 @@ static int check_cert_key(DerBuffer* cert, DerBuffer* key, void* heap, } #ifdef WOLFSSL_SMALL_STACK - der = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL, DYNAMIC_TYPE_DCERT); + der = (DecodedCert*)XMALLOC(sizeof(DecodedCert), heap, DYNAMIC_TYPE_DCERT); if (der == NULL) return MEMORY_E; #endif @@ -9256,7 +9785,7 @@ static int check_cert_key(DerBuffer* cert, DerBuffer* key, void* heap, if (ParseCertRelative(der, CERT_TYPE, NO_VERIFY, NULL) != 0) { FreeDecodedCert(der); #ifdef WOLFSSL_SMALL_STACK - XFREE(der, NULL, DYNAMIC_TYPE_DCERT); + XFREE(der, heap, DYNAMIC_TYPE_DCERT); #endif return WOLFSSL_FAILURE; } @@ -9265,110 +9794,9 @@ static int check_cert_key(DerBuffer* cert, DerBuffer* key, void* heap, buff = key->buffer; #ifdef WOLF_PRIVATE_KEY_ID if (devId != INVALID_DEVID) { - int type = 0; - void *pkey = NULL; - - #ifndef NO_RSA - if (der->keyOID == RSAk) { - type = DYNAMIC_TYPE_RSA; - } - #ifdef WC_RSA_PSS - if (der->keyOID == RSAPSSk) { - type = DYNAMIC_TYPE_RSA; - } - #endif - #endif - #ifdef HAVE_ECC - if (der->keyOID == ECDSAk) { - type = DYNAMIC_TYPE_ECC; - } - #endif - #if defined(HAVE_PQC) && defined(HAVE_DILITHIUM) - if ((der->keyOID == DILITHIUM_LEVEL2k) || - (der->keyOID == DILITHIUM_LEVEL3k) || - (der->keyOID == DILITHIUM_LEVEL5k)) { - type = DYNAMIC_TYPE_DILITHIUM; - } - #endif - #if defined(HAVE_PQC) && defined(HAVE_FALCON) - if ((der->keyOID == FALCON_LEVEL1k) || - (der->keyOID == FALCON_LEVEL5k)) { - type = DYNAMIC_TYPE_FALCON; - } - #endif - - ret = CreateDevPrivateKey(&pkey, buff, size, type, - isKeyLabel, isKeyId, heap, devId); - #ifdef WOLF_CRYPTO_CB - if (ret == 0) { - #ifndef NO_RSA - if (der->keyOID == RSAk - #ifdef WC_RSA_PSS - || der->keyOID == RSAPSSk - #endif - ) { - ret = wc_CryptoCb_RsaCheckPrivKey((RsaKey*)pkey, - der->publicKey, der->pubKeySize); - } - #endif - #ifdef HAVE_ECC - if (der->keyOID == ECDSAk) { - ret = wc_CryptoCb_EccCheckPrivKey((ecc_key*)pkey, - der->publicKey, der->pubKeySize); - } - #endif - #if defined(HAVE_PQC) && defined(HAVE_DILITHIUM) - if ((der->keyOID == DILITHIUM_LEVEL2k) || - (der->keyOID == DILITHIUM_LEVEL3k) || - (der->keyOID == DILITHIUM_LEVEL5k)) { - ret = wc_CryptoCb_PqcSignatureCheckPrivKey(pkey, - WC_PQC_SIG_TYPE_DILITHIUM, - der->publicKey, der->pubKeySize); - } - #endif - #if defined(HAVE_PQC) && defined(HAVE_FALCON) - if ((der->keyOID == FALCON_LEVEL1k) || - (der->keyOID == FALCON_LEVEL5k)) { - ret = wc_CryptoCb_PqcSignatureCheckPrivKey(pkey, - WC_PQC_SIG_TYPE_FALCON, - der->publicKey, der->pubKeySize); - } - #endif - } - #else - /* devId was set, don't check, for now */ - /* TODO: Add callback for private key check? */ - #endif - if (pkey != NULL) { - #ifndef NO_RSA - if (der->keyOID == RSAk - #ifdef WC_RSA_PSS - || der->keyOID == RSAPSSk - #endif - ) { - wc_FreeRsaKey((RsaKey*)pkey); - } - #endif - #ifdef HAVE_ECC - if (der->keyOID == ECDSAk) { - wc_ecc_free((ecc_key*)pkey); - } - #endif - #if defined(HAVE_PQC) && defined(HAVE_DILITHIUM) - if ((der->keyOID == DILITHIUM_LEVEL2k) || - (der->keyOID == DILITHIUM_LEVEL3k) || - (der->keyOID == DILITHIUM_LEVEL5k)) { - wc_dilithium_free((dilithium_key*)pkey); - } - #endif - #if defined(HAVE_PQC) && defined(HAVE_FALCON) - if ((der->keyOID == FALCON_LEVEL1k) || - (der->keyOID == FALCON_LEVEL5k)) { - wc_falcon_free((falcon_key*)pkey); - } - #endif - XFREE(pkey, heap, type); - } + ret = check_cert_key_dev(der->keyOID, buff, size, der->publicKey, + der->pubKeySize, isKeyLabel, isKeyId, heap, + devId); if (ret != CRYPTOCB_UNAVAILABLE) { ret = (ret == 0) ? WOLFSSL_SUCCESS: WOLFSSL_FAILURE; } @@ -9381,17 +9809,83 @@ static int check_cert_key(DerBuffer* cert, DerBuffer* key, void* heap, if (ret == CRYPTOCB_UNAVAILABLE) #endif /* WOLF_PRIVATE_KEY_ID */ { - ret = wc_CheckPrivateKeyCert(buff, size, der); + ret = wc_CheckPrivateKeyCert(buff, size, der, 0); ret = (ret == 1) ? WOLFSSL_SUCCESS: WOLFSSL_FAILURE; } + +#ifdef WOLFSSL_DUAL_ALG_CERTS + if (ret == WOLFSSL_SUCCESS && der->extSapkiSet && der->sapkiDer != NULL) { + /* Certificate contains an alternative public key. Hence, we also + * need an alternative private key. */ + if (altKey == NULL) { + ret = MISSING_KEY; + buff = NULL; + size = 0; + } + else { + size = altKey->length; + buff = altKey->buffer; + } +#ifdef WOLF_PRIVATE_KEY_ID + if (ret == WOLFSSL_SUCCESS && altDevId != INVALID_DEVID) { + /* We have to decode the public key first */ + word32 idx = 0; + /* Dilithium has the largest public key at the moment */ + word32 pubKeyLen = DILITHIUM_MAX_PUB_KEY_SIZE; + byte* decodedPubKey = (byte*)XMALLOC(pubKeyLen, heap, + DYNAMIC_TYPE_PUBLIC_KEY); + if (decodedPubKey == NULL) { + ret = MEMORY_E; + } + if (ret == WOLFSSL_SUCCESS) { + if (der->sapkiOID == RSAk || der->sapkiOID == ECDSAk) { + /* Simply copy the data */ + XMEMCPY(decodedPubKey, der->sapkiDer, der->sapkiLen); + pubKeyLen = der->sapkiLen; + ret = 0; + } + else { + ret = DecodeAsymKeyPublic(der->sapkiDer, &idx, + der->sapkiLen, decodedPubKey, + &pubKeyLen, der->sapkiOID); + } + } + if (ret == 0) { + ret = check_cert_key_dev(der->sapkiOID, buff, size, + decodedPubKey, pubKeyLen, + isAltKeyLabel, isAltKeyId, + heap, altDevId); + } + XFREE(decodedPubKey, heap, DYNAMIC_TYPE_PUBLIC_KEY); + if (ret != CRYPTOCB_UNAVAILABLE) { + ret = (ret == 0) ? WOLFSSL_SUCCESS: WOLFSSL_FAILURE; + } + } + else { + /* fall through if unavailable */ + ret = CRYPTOCB_UNAVAILABLE; + } + + if (ret == CRYPTOCB_UNAVAILABLE) +#endif /* WOLF_PRIVATE_KEY_ID */ + { + ret = wc_CheckPrivateKeyCert(buff, size, der, 1); + ret = (ret == 1) ? WOLFSSL_SUCCESS: WOLFSSL_FAILURE; + } + } +#endif /* WOLFSSL_DUAL_ALG_CERTS */ FreeDecodedCert(der); #ifdef WOLFSSL_SMALL_STACK - XFREE(der, NULL, DYNAMIC_TYPE_DCERT); + XFREE(der, heap, DYNAMIC_TYPE_DCERT); #endif (void)devId; (void)isKeyLabel; (void)isKeyId; + (void)altKey; + (void)altDevId; + (void)isAltKeyLabel; + (void)isAltKeyId; return ret; } @@ -9407,8 +9901,17 @@ int wolfSSL_CTX_check_private_key(const WOLFSSL_CTX* ctx) if (ctx == NULL) { return WOLFSSL_FAILURE; } - return check_cert_key(ctx->certificate, ctx->privateKey, ctx->heap, - ctx->privateKeyDevId, ctx->privateKeyLabel, ctx->privateKeyId); + +#ifdef WOLFSSL_DUAL_ALG_CERTS + return check_cert_key(ctx->certificate, ctx->privateKey, ctx->altPrivateKey, + ctx->heap, ctx->privateKeyDevId, ctx->privateKeyLabel, + ctx->privateKeyId, ctx->altPrivateKeyDevId, ctx->altPrivateKeyLabel, + ctx->altPrivateKeyId); +#else + return check_cert_key(ctx->certificate, ctx->privateKey, NULL, ctx->heap, + ctx->privateKeyDevId, ctx->privateKeyLabel, ctx->privateKeyId, + INVALID_DEVID, 0, 0); +#endif } #endif /* !NO_CHECK_PRIVATE_KEY */ @@ -10440,8 +10943,16 @@ int wolfSSL_check_private_key(const WOLFSSL* ssl) if (ssl == NULL) { return WOLFSSL_FAILURE; } - return check_cert_key(ssl->buffers.certificate, ssl->buffers.key, ssl->heap, - ssl->buffers.keyDevId, ssl->buffers.keyLabel, ssl->buffers.keyId); +#ifdef WOLFSSL_DUAL_ALG_CERTS + return check_cert_key(ssl->buffers.certificate, ssl->buffers.key, + ssl->buffers.altKey, ssl->heap, ssl->buffers.keyDevId, + ssl->buffers.keyLabel, ssl->buffers.keyId, ssl->buffers.altKeyDevId, + ssl->buffers.altKeyLabel, ssl->buffers.altKeyId); +#else + return check_cert_key(ssl->buffers.certificate, ssl->buffers.key, NULL, + ssl->heap, ssl->buffers.keyDevId, ssl->buffers.keyLabel, + ssl->buffers.keyId, INVALID_DEVID, 0, 0); +#endif } #endif /* !NO_CHECK_PRIVATE_KEY */ @@ -16041,14 +16552,44 @@ int wolfSSL_set_compression(WOLFSSL* ssl) const unsigned char* in, long sz, int format) { int ret = WOLFSSL_FAILURE; + long consumed = 0; WOLFSSL_ENTER("wolfSSL_CTX_use_PrivateKey_buffer"); - ret = ProcessBuffer(ctx, in, sz, format, PRIVATEKEY_TYPE, NULL, NULL, - 0, GET_VERIFY_SETTING_CTX(ctx)); + ret = ProcessBuffer(ctx, in, sz, format, PRIVATEKEY_TYPE, NULL, + &consumed, 0, GET_VERIFY_SETTING_CTX(ctx)); + + #ifdef WOLFSSL_DUAL_ALG_CERTS + if (ret == WOLFSSL_SUCCESS && consumed < sz) { + /* When support for dual algorithm certificates is enabled, the + * buffer may contain both the primary and the alternative + * private key. Hence, we have to parse both of them. + */ + ret = ProcessBuffer(ctx, in + consumed, sz - consumed, format, + ALT_PRIVATEKEY_TYPE, NULL, NULL, 0, + GET_VERIFY_SETTING_CTX(ctx)); + } + #endif + WOLFSSL_LEAVE("wolfSSL_CTX_use_PrivateKey_buffer", ret); return ret; } + +#ifdef WOLFSSL_DUAL_ALG_CERTS + int wolfSSL_CTX_use_AltPrivateKey_buffer(WOLFSSL_CTX* ctx, + const unsigned char* in, long sz, int format) + { + int ret = WOLFSSL_FAILURE; + + WOLFSSL_ENTER("wolfSSL_CTX_use_AltPrivateKey_buffer"); + ret = ProcessBuffer(ctx, in, sz, format, ALT_PRIVATEKEY_TYPE, NULL, + NULL, 0, GET_VERIFY_SETTING_CTX(ctx)); + WOLFSSL_LEAVE("wolfSSL_CTX_use_AltPrivateKey_buffer", ret); + return ret; + } +#endif /* WOLFSSL_DUAL_ALG_CERTS */ + + #ifdef WOLF_PRIVATE_KEY_ID int wolfSSL_CTX_use_PrivateKey_id(WOLFSSL_CTX* ctx, const unsigned char* id, long sz, int devId, long keySz) @@ -16058,6 +16599,13 @@ int wolfSSL_set_compression(WOLFSSL* ssl) if (ret == WOLFSSL_SUCCESS) ctx->privateKeySz = (word32)keySz; + #ifdef WOLFSSL_DUAL_ALG_CERTS + if (ret == WOLFSSL_SUCCESS) + /* Set the ID for the alternative key, too. User can still + * override that afterwards. */ + ret = wolfSSL_CTX_use_AltPrivateKey_id(ctx, id, sz, devId, keySz); + #endif + return ret; } @@ -16079,6 +16627,13 @@ int wolfSSL_set_compression(WOLFSSL* ssl) ret = WOLFSSL_SUCCESS; } + #ifdef WOLFSSL_DUAL_ALG_CERTS + if (ret == WOLFSSL_SUCCESS) + /* Set the ID for the alternative key, too. User can still + * override that afterwards. */ + ret = wolfSSL_CTX_use_AltPrivateKey_Id(ctx, id, sz, devId); + #endif + return ret; } @@ -16101,10 +16656,75 @@ int wolfSSL_set_compression(WOLFSSL* ssl) ret = WOLFSSL_SUCCESS; } + #ifdef WOLFSSL_DUAL_ALG_CERTS + if (ret == WOLFSSL_SUCCESS) + /* Set the label for the alternative key, too. User can still + * override that afterwards. */ + ret = wolfSSL_CTX_use_AltPrivateKey_Label(ctx, label, devId); + #endif + return ret; } #endif /* WOLF_PRIVATE_KEY_ID */ +#if defined(WOLF_PRIVATE_KEY_ID) && defined(WOLFSSL_DUAL_ALG_CERTS) + int wolfSSL_CTX_use_AltPrivateKey_id(WOLFSSL_CTX* ctx, + const unsigned char* id, + long sz, int devId, long keySz) + { + int ret = wolfSSL_CTX_use_AltPrivateKey_Id(ctx, id, sz, devId); + + if (ret == WOLFSSL_SUCCESS) + ctx->altPrivateKeySz = (word32)keySz; + + return ret; + } + + int wolfSSL_CTX_use_AltPrivateKey_Id(WOLFSSL_CTX* ctx, + const unsigned char* id, + long sz, int devId) + { + int ret = WOLFSSL_FAILURE; + + FreeDer(&ctx->altPrivateKey); + if (AllocDer(&ctx->altPrivateKey, (word32)sz, ALT_PRIVATEKEY_TYPE, + ctx->heap) == 0) { + XMEMCPY(ctx->altPrivateKey->buffer, id, sz); + ctx->altPrivateKeyId = 1; + if (devId != INVALID_DEVID) + ctx->altPrivateKeyDevId = devId; + else + ctx->altPrivateKeyDevId = ctx->devId; + + ret = WOLFSSL_SUCCESS; + } + + return ret; + } + + int wolfSSL_CTX_use_AltPrivateKey_Label(WOLFSSL_CTX* ctx, const char* label, + int devId) + { + int ret = WOLFSSL_FAILURE; + word32 sz = (word32)XSTRLEN(label) + 1; + + FreeDer(&ctx->altPrivateKey); + if (AllocDer(&ctx->altPrivateKey, (word32)sz, ALT_PRIVATEKEY_TYPE, + ctx->heap) == 0) { + XMEMCPY(ctx->altPrivateKey->buffer, label, sz); + ctx->altPrivateKeyLabel = 1; + if (devId != INVALID_DEVID) + ctx->altPrivateKeyDevId = devId; + else + ctx->altPrivateKeyDevId = ctx->devId; + + ret = WOLFSSL_SUCCESS; + } + + return ret; + } +#endif /* WOLF_PRIVATE_KEY_ID && WOLFSSL_DUAL_ALG_CERTS */ + int wolfSSL_CTX_use_certificate_chain_buffer_format(WOLFSSL_CTX* ctx, const unsigned char* in, long sz, int format) { @@ -16244,14 +16864,45 @@ int wolfSSL_set_compression(WOLFSSL* ssl) int wolfSSL_use_PrivateKey_buffer(WOLFSSL* ssl, const unsigned char* in, long sz, int format) { + int ret = WOLFSSL_FAILURE; + long consumed = 0; + WOLFSSL_ENTER("wolfSSL_use_PrivateKey_buffer"); if (ssl == NULL) return BAD_FUNC_ARG; - return ProcessBuffer(ssl->ctx, in, sz, format, PRIVATEKEY_TYPE, - ssl, NULL, 0, GET_VERIFY_SETTING_SSL(ssl)); + ret = ProcessBuffer(ssl->ctx, in, sz, format, PRIVATEKEY_TYPE, + ssl, &consumed, 0, GET_VERIFY_SETTING_SSL(ssl)); + + #ifdef WOLFSSL_DUAL_ALG_CERTS + if (ret == WOLFSSL_SUCCESS && consumed < sz) { + /* When support for dual algorithm certificates is enabled, the + * buffer may contain both the primary and the alternative + * private key. Hence, we have to parse both of them. + */ + ret = ProcessBuffer(ssl->ctx, in + consumed, sz - consumed, format, + ALT_PRIVATEKEY_TYPE, ssl, NULL, 0, + GET_VERIFY_SETTING_SSL(ssl)); + } + #endif + + return ret; } +#ifdef WOLFSSL_DUAL_ALG_CERTS + int wolfSSL_use_AltPrivateKey_buffer(WOLFSSL* ssl, const unsigned char* in, + long sz, int format) + { + int ret = WOLFSSL_FAILURE; + + WOLFSSL_ENTER("wolfSSL_use_AltPrivateKey_buffer"); + ret = ProcessBuffer(ssl->ctx, in, sz, format, ALT_PRIVATEKEY_TYPE, ssl, + NULL, 0, GET_VERIFY_SETTING_SSL(ssl)); + WOLFSSL_LEAVE("wolfSSL_use_AltPrivateKey_buffer", ret); + return ret; + } +#endif /* WOLFSSL_DUAL_ALG_CERTS */ + #ifdef WOLF_PRIVATE_KEY_ID int wolfSSL_use_PrivateKey_id(WOLFSSL* ssl, const unsigned char* id, long sz, int devId, long keySz) @@ -16261,6 +16912,13 @@ int wolfSSL_set_compression(WOLFSSL* ssl) if (ret == WOLFSSL_SUCCESS) ssl->buffers.keySz = (word32)keySz; + #ifdef WOLFSSL_DUAL_ALG_CERTS + if (ret == WOLFSSL_SUCCESS) + /* Set the ID for the alternative key, too. User can still + * override that afterwards. */ + ret = wolfSSL_use_AltPrivateKey_id(ssl, id, sz, devId, keySz); + #endif + return ret; } @@ -16284,6 +16942,13 @@ int wolfSSL_set_compression(WOLFSSL* ssl) ret = WOLFSSL_SUCCESS; } + #ifdef WOLFSSL_DUAL_ALG_CERTS + if (ret == WOLFSSL_SUCCESS) + /* Set the ID for the alternative key, too. User can still + * override that afterwards. */ + ret = wolfSSL_use_AltPrivateKey_Id(ssl, id, sz, devId); + #endif + return ret; } @@ -16307,10 +16972,77 @@ int wolfSSL_set_compression(WOLFSSL* ssl) ret = WOLFSSL_SUCCESS; } + #ifdef WOLFSSL_DUAL_ALG_CERTS + if (ret == WOLFSSL_SUCCESS) + /* Set the label for the alternative key, too. User can still + * override that afterwards. */ + ret = wolfSSL_use_AltPrivateKey_Label(ssl, label, devId); + #endif + return ret; } #endif /* WOLF_PRIVATE_KEY_ID */ +#if defined(WOLF_PRIVATE_KEY_ID) && defined(WOLFSSL_DUAL_ALG_CERTS) + int wolfSSL_use_AltPrivateKey_id(WOLFSSL* ssl, const unsigned char* id, + long sz, int devId, long keySz) + { + int ret = wolfSSL_use_AltPrivateKey_Id(ssl, id, sz, devId); + + if (ret == WOLFSSL_SUCCESS) + ssl->buffers.altKeySz = (word32)keySz; + + return ret; + } + + int wolfSSL_use_AltPrivateKey_Id(WOLFSSL* ssl, const unsigned char* id, + long sz, int devId) + { + int ret = WOLFSSL_FAILURE; + + if (ssl->buffers.weOwnAltKey) + FreeDer(&ssl->buffers.altKey); + if (AllocDer(&ssl->buffers.altKey, (word32)sz, ALT_PRIVATEKEY_TYPE, + ssl->heap) == 0) { + XMEMCPY(ssl->buffers.altKey->buffer, id, sz); + ssl->buffers.weOwnAltKey = 1; + ssl->buffers.altKeyId = 1; + if (devId != INVALID_DEVID) + ssl->buffers.altKeyDevId = devId; + else + ssl->buffers.altKeyDevId = ssl->devId; + + ret = WOLFSSL_SUCCESS; + } + + return ret; + } + + int wolfSSL_use_AltPrivateKey_Label(WOLFSSL* ssl, const char* label, + int devId) + { + int ret = WOLFSSL_FAILURE; + word32 sz = (word32)XSTRLEN(label) + 1; + + if (ssl->buffers.weOwnAltKey) + FreeDer(&ssl->buffers.altKey); + if (AllocDer(&ssl->buffers.altKey, (word32)sz, ALT_PRIVATEKEY_TYPE, + ssl->heap) == 0) { + XMEMCPY(ssl->buffers.altKey->buffer, label, sz); + ssl->buffers.weOwnAltKey = 1; + ssl->buffers.altKeyLabel = 1; + if (devId != INVALID_DEVID) + ssl->buffers.altKeyDevId = devId; + else + ssl->buffers.altKeyDevId = ssl->devId; + + ret = WOLFSSL_SUCCESS; + } + + return ret; + } +#endif /* WOLF_PRIVATE_KEY_ID && WOLFSSL_DUAL_ALG_CERTS */ + int wolfSSL_use_certificate_chain_buffer_format(WOLFSSL* ssl, const unsigned char* in, long sz, int format) { diff --git a/src/tls.c b/src/tls.c index 4309019b2..99dacb67d 100644 --- a/src/tls.c +++ b/src/tls.c @@ -9583,7 +9583,7 @@ int TLSX_CKS_Parse(WOLFSSL* ssl, byte* input, word16 length, case WOLFSSL_CKS_SIGSPEC_EXTERNAL: default: /* All other values (including external) are not. */ - return WOLFSSL_NOT_IMPLEMENTED; + return BAD_FUNC_ARG; } } @@ -9618,7 +9618,7 @@ int TLSX_CKS_Parse(WOLFSSL* ssl, byte* input, word16 length, for (j = 0; j < length; j++) { if (ssl->sigSpec[i] == input[j]) { /* Got the match, set to this one. */ - ret = wolfSSL_UseCKS(ssl, &ssl->peerSigSpec[i], 1); + ret = wolfSSL_UseCKS(ssl, &ssl->sigSpec[i], 1); if (ret == WOLFSSL_SUCCESS) { ret = TLSX_UseCKS(&ssl->extensions, ssl, ssl->heap); TLSX_SetResponse(ssl, TLSX_CKS); diff --git a/src/tls13.c b/src/tls13.c index b8be4ed18..32ce1a654 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -7825,9 +7825,19 @@ static WC_INLINE void EncodeSigAlg(byte hashAlgo, byte hsType, byte* output) #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 +#define HYBRID_P256_FALCON_LEVEL1_SA_MINOR 0xAF +#define HYBRID_RSA3072_FALCON_LEVEL1_SA_MINOR 0xB0 +#define HYBRID_P521_FALCON_LEVEL5_SA_MINOR 0xB2 + +/* Custom defined ones for PQC first */ +#define HYBRID_DILITHIUM_LEVEL2_P256_SA_MINOR 0xD1 +#define HYBRID_DILITHIUM_LEVEL2_RSA3072_SA_MINOR 0xD2 +#define HYBRID_DILITHIUM_LEVEL3_P384_SA_MINOR 0xD3 +#define HYBRID_DILITHIUM_LEVEL5_P521_SA_MINOR 0xD4 +#define HYBRID_FALCON_LEVEL1_P256_SA_MINOR 0xD5 +#define HYBRID_FALCON_LEVEL1_RSA3072_SA_MINOR 0xD6 +#define HYBRID_FALCON_LEVEL5_P521_SA_MINOR 0xD7 + static void EncodeDualSigAlg(byte sigAlg, byte altSigAlg, byte* output) { @@ -7850,15 +7860,46 @@ static void EncodeDualSigAlg(byte sigAlg, byte altSigAlg, byte* output) 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) { + 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) { + 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) { + else if (sigAlg == ecc_dsa_sa_algo && + altSigAlg == falcon_level5_sa_algo) { output[1] = HYBRID_P521_FALCON_LEVEL5_SA_MINOR; } + else if (sigAlg == dilithium_level2_sa_algo && + altSigAlg == ecc_dsa_sa_algo) { + output[1] = HYBRID_DILITHIUM_LEVEL2_P256_SA_MINOR; + } + else if (sigAlg == dilithium_level2_sa_algo && + altSigAlg == rsa_pss_sa_algo) { + output[1] = HYBRID_DILITHIUM_LEVEL2_RSA3072_SA_MINOR; + } + else if (sigAlg == dilithium_level3_sa_algo && + altSigAlg == ecc_dsa_sa_algo) { + output[1] = HYBRID_DILITHIUM_LEVEL3_P384_SA_MINOR; + } + else if (sigAlg == dilithium_level5_sa_algo && + altSigAlg == ecc_dsa_sa_algo) { + output[1] = HYBRID_DILITHIUM_LEVEL5_P521_SA_MINOR; + } + else if (sigAlg == falcon_level1_sa_algo && + altSigAlg == ecc_dsa_sa_algo) { + output[1] = HYBRID_FALCON_LEVEL1_P256_SA_MINOR; + } + else if (sigAlg == falcon_level1_sa_algo && + altSigAlg == rsa_pss_sa_algo) { + output[1] = HYBRID_FALCON_LEVEL1_RSA3072_SA_MINOR; + } + else if (sigAlg == falcon_level5_sa_algo && + altSigAlg == ecc_dsa_sa_algo) { + output[1] = HYBRID_FALCON_LEVEL5_P521_SA_MINOR; + } if (output[1] != 0x0) { output[0] = HYBRID_SA_MAJOR; @@ -7976,39 +8017,74 @@ static WC_INLINE int DecodeTls13HybridSigAlg(byte* input, byte* hashAlg, if (input[1] == HYBRID_P256_DILITHIUM_LEVEL2_SA_MINOR) { *sigAlg = ecc_dsa_sa_algo; - *hashAlg = 4; /* WC_HASH_TYPE_SHA? Reviewer? */ + *hashAlg = sha256_mac; *altSigAlg = dilithium_level2_sa_algo; } else if (input[1] == HYBRID_RSA3072_DILITHIUM_LEVEL2_SA_MINOR) { *sigAlg = rsa_pss_sa_algo; - *hashAlg = 4; + *hashAlg = sha256_mac; *altSigAlg = dilithium_level2_sa_algo; } else if (input[1] == HYBRID_P384_DILITHIUM_LEVEL3_SA_MINOR) { *sigAlg = ecc_dsa_sa_algo; - *hashAlg = 5; + *hashAlg = sha384_mac; *altSigAlg = dilithium_level3_sa_algo; } else if (input[1] == HYBRID_P521_DILITHIUM_LEVEL5_SA_MINOR) { *sigAlg = ecc_dsa_sa_algo; - *hashAlg = 6; + *hashAlg = sha512_mac; *altSigAlg = dilithium_level5_sa_algo; } else if (input[1] == HYBRID_P256_FALCON_LEVEL1_SA_MINOR) { *sigAlg = ecc_dsa_sa_algo; - *hashAlg = 4; + *hashAlg = sha256_mac; *altSigAlg = falcon_level1_sa_algo; } else if (input[1] == HYBRID_RSA3072_FALCON_LEVEL1_SA_MINOR) { *sigAlg = rsa_pss_sa_algo; - *hashAlg = 4; + *hashAlg = sha256_mac; *altSigAlg = falcon_level1_sa_algo; } else if (input[1] == HYBRID_P521_FALCON_LEVEL5_SA_MINOR) { *sigAlg = ecc_dsa_sa_algo; - *hashAlg = 6; + *hashAlg = sha512_mac; *altSigAlg = falcon_level5_sa_algo; } + else if (input[1] == HYBRID_DILITHIUM_LEVEL2_P256_SA_MINOR) { + *sigAlg = dilithium_level2_sa_algo; + *hashAlg = sha256_mac; + *altSigAlg = ecc_dsa_sa_algo; + } + else if (input[1] == HYBRID_DILITHIUM_LEVEL2_RSA3072_SA_MINOR) { + *sigAlg = dilithium_level2_sa_algo; + *hashAlg = sha256_mac; + *altSigAlg = rsa_pss_sa_algo; + } + else if (input[1] == HYBRID_DILITHIUM_LEVEL3_P384_SA_MINOR) { + *sigAlg = dilithium_level3_sa_algo; + *hashAlg = sha384_mac; + *altSigAlg = ecc_dsa_sa_algo; + } + else if (input[1] == HYBRID_DILITHIUM_LEVEL5_P521_SA_MINOR) { + *sigAlg = dilithium_level5_sa_algo; + *hashAlg = sha512_mac; + *altSigAlg = ecc_dsa_sa_algo; + } + else if (input[1] == HYBRID_FALCON_LEVEL1_P256_SA_MINOR) { + *sigAlg = falcon_level1_sa_algo; + *hashAlg = sha256_mac; + *altSigAlg = ecc_dsa_sa_algo; + } + else if (input[1] == HYBRID_FALCON_LEVEL1_RSA3072_SA_MINOR) { + *sigAlg = falcon_level1_sa_algo; + *hashAlg = sha256_mac; + *altSigAlg = rsa_pss_sa_algo; + } + else if (input[1] == HYBRID_FALCON_LEVEL5_P521_SA_MINOR) { + *sigAlg = falcon_level5_sa_algo; + *hashAlg = sha512_mac; + *altSigAlg = ecc_dsa_sa_algo; + } else { return INVALID_PARAMETER; } @@ -8672,7 +8748,9 @@ typedef struct Scv13Args { word16 sigDataSz; #ifdef WOLFSSL_DUAL_ALG_CERTS byte altSigAlgo; - word16 altSigLen; /* Only used in the case of both native and alt. */ + word32 altSigLen; /* Only used in the case of both native and alt. */ + byte* altSigData; + word16 altSigDataSz; #endif } Scv13Args; @@ -8686,6 +8764,12 @@ static void FreeScv13Args(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 } /* handle generation TLS v1.3 certificate_verify (15) */ @@ -8701,7 +8785,10 @@ static void FreeScv13Args(WOLFSSL* ssl, void* pArgs) static int SendTls13CertificateVerify(WOLFSSL* ssl) { int ret = 0; - buffer* sig = &ssl->buffers.sig; +#ifndef NO_RSA + /* Use this as a temporary buffer for RSA signature verification. */ + buffer* rsaSigBuf = &ssl->buffers.sig; +#endif #ifdef WOLFSSL_ASYNC_CRYPT Scv13Args* args = NULL; WOLFSSL_ASSERT_SIZEOF_GE(ssl->async->args, *args); @@ -8817,11 +8904,10 @@ static int SendTls13CertificateVerify(WOLFSSL* ssl) } else { #ifdef WOLFSSL_DUAL_ALG_CERTS - if (wolfSSL_is_server(ssl) && - ssl->sigSpec != NULL && + if (ssl->sigSpec != NULL && *ssl->sigSpec == WOLFSSL_CKS_SIGSPEC_ALTERNATIVE) { /* In the case of alternative, we swap in the alt. */ - if (ssl->ctx->altPrivateKey == NULL) { + if (ssl->buffers.altKey == NULL) { ERROR_OUT(NO_PRIVATE_KEY, exit_scv); } ssl->buffers.keyType = ssl->buffers.altKeyType; @@ -8831,24 +8917,21 @@ static int SendTls13CertificateVerify(WOLFSSL* ssl) 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; + /* Swap keys */ + ssl->buffers.key = ssl->buffers.altKey; + ssl->buffers.weOwnKey = ssl->buffers.weOwnAltKey; } #endif /* WOLFSSL_DUAL_ALG_CERTS */ - ret = DecodePrivateKey(ssl, &args->length); + ret = DecodePrivateKey(ssl, (word16*)&args->sigLen); if (ret != 0) goto exit_scv; } - if (rem < 0 || args->length > rem) { + if (rem < 0 || (int)args->sigLen > rem) { ERROR_OUT(BUFFER_E, exit_scv); } - if (args->length == 0) { + if (args->sigLen == 0) { ERROR_OUT(NO_PRIVATE_KEY, exit_scv); } @@ -8921,7 +9004,7 @@ static int SendTls13CertificateVerify(WOLFSSL* ssl) ERROR_OUT(ALGO_ID_E, exit_scv); } -#ifdef WOLFSSL_DUAL_ALG_CERTS + #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 @@ -8930,8 +9013,7 @@ static int SendTls13CertificateVerify(WOLFSSL* ssl) ssl->sigSpecSz = 0; } - if (wolfSSL_is_server(ssl) && - ssl->sigSpec != NULL && + if (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 @@ -8940,21 +9022,27 @@ static int SendTls13CertificateVerify(WOLFSSL* ssl) ERROR_OUT(NO_PRIVATE_KEY, exit_scv); } - if (ssl->buffers.altKeyType == falcon_level1_sa_algo || + /* After this call, args->altSigLen has the length we need for + * the alternative signature. */ + ret = DecodeAltPrivateKey(ssl, (word16*)&args->altSigLen); + if (ret != 0) + goto exit_scv; + + if (ssl->buffers.altKeyType == ecc_dsa_sa_algo || + 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 if (ssl->buffers.altKeyType == rsa_sa_algo && + ssl->hsAltType == DYNAMIC_TYPE_RSA) { + args->altSigAlgo = rsa_pss_sa_algo; + } 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) { @@ -8962,57 +9050,79 @@ static int SendTls13CertificateVerify(WOLFSSL* ssl) } } else -#endif /* WOLFSSL_DUAL_ALG_CERTS */ + #endif /* WOLFSSL_DUAL_ALG_CERTS */ EncodeSigAlg(ssl->options.hashAlgo, args->sigAlgo, args->verify); if (args->sigData == NULL) { - if (ssl->hsType == DYNAMIC_TYPE_RSA) { - int sigLen = MAX_SIG_DATA_SZ; - if (args->length > MAX_SIG_DATA_SZ) - sigLen = args->length; - args->sigData = (byte*)XMALLOC(sigLen, ssl->heap, - DYNAMIC_TYPE_SIGNATURE); - } - else { - args->sigData = (byte*)XMALLOC(MAX_SIG_DATA_SZ, ssl->heap, - DYNAMIC_TYPE_SIGNATURE); + word32 sigLen = MAX_SIG_DATA_SZ; + if ((ssl->hsType == DYNAMIC_TYPE_RSA) && + (args->sigLen > MAX_SIG_DATA_SZ)) { + /* We store the RSA signature in the sigData buffer + * temporarly, hence its size must be fitting. */ + sigLen = args->sigLen; } + args->sigData = (byte*)XMALLOC(sigLen, ssl->heap, + DYNAMIC_TYPE_SIGNATURE); if (args->sigData == NULL) { ERROR_OUT(MEMORY_E, exit_scv); } } + #ifdef WOLFSSL_DUAL_ALG_CERTS + if ((ssl->sigSpec != NULL) && + (*ssl->sigSpec == WOLFSSL_CKS_SIGSPEC_BOTH) && + (args->altSigData == NULL)) { + word32 sigLen = MAX_SIG_DATA_SZ; + if (ssl->hsAltType == DYNAMIC_TYPE_RSA && + args->altSigLen > MAX_SIG_DATA_SZ) { + /* We store the RSA signature in the sigData buffer + * temporarly, hence its size must be fitting. */ + sigLen = args->altSigLen; + } + args->altSigData = (byte*)XMALLOC(sigLen, ssl->heap, + DYNAMIC_TYPE_SIGNATURE); + if (args->altSigData == NULL) { + ERROR_OUT(MEMORY_E, exit_scv); + } + } + #endif /* WOLFSSL_DUAL_ALG_CERTS */ + /* Create the data to be signed. */ ret = CreateSigData(ssl, args->sigData, &args->sigDataSz, 0); if (ret != 0) goto exit_scv; + #ifdef WOLFSSL_DUAL_ALG_CERTS + if ((ssl->sigSpec != NULL) && + (*ssl->sigSpec == WOLFSSL_CKS_SIGSPEC_BOTH)) { + XMEMCPY(args->altSigData, args->sigData, args->sigDataSz); + args->altSigDataSz = args->sigDataSz; + } + #endif /* WOLFSSL_DUAL_ALG_CERTS */ + #ifndef NO_RSA if (ssl->hsType == DYNAMIC_TYPE_RSA) { /* build encoded signature buffer */ - sig->length = WC_MAX_DIGEST_SIZE; - sig->buffer = (byte*)XMALLOC(sig->length, ssl->heap, - DYNAMIC_TYPE_SIGNATURE); - if (sig->buffer == NULL) { + rsaSigBuf->length = WC_MAX_DIGEST_SIZE; + rsaSigBuf->buffer = (byte*)XMALLOC(rsaSigBuf->length, ssl->heap, + DYNAMIC_TYPE_SIGNATURE); + if (rsaSigBuf->buffer == NULL) { ERROR_OUT(MEMORY_E, exit_scv); } - ret = CreateRSAEncodedSig(sig->buffer, args->sigData, + ret = CreateRSAEncodedSig(rsaSigBuf->buffer, args->sigData, args->sigDataSz, args->sigAlgo, ssl->options.hashAlgo); if (ret < 0) goto exit_scv; - sig->length = ret; + rsaSigBuf->length = ret; ret = 0; - - /* Maximum size of RSA Signature. */ - args->sigLen = args->length; } #endif /* !NO_RSA */ #ifdef HAVE_ECC if (ssl->hsType == DYNAMIC_TYPE_ECC) { - sig->length = args->sendSz - args->idx - HASH_SIG_SIZE - - VERIFY_HEADER; + args->sigLen = args->sendSz - args->idx - HASH_SIG_SIZE - + VERIFY_HEADER; #if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3) if (ssl->buffers.keyType != sm2_sa_algo) #endif @@ -9032,7 +9142,7 @@ static int SendTls13CertificateVerify(WOLFSSL* ssl) if (ret < 0) { ERROR_OUT(ret, exit_scv); } - sig->length = ED25519_SIG_SIZE; + args->sigLen = ED25519_SIG_SIZE; } #endif /* HAVE_ED25519 */ #ifdef HAVE_ED448 @@ -9041,23 +9151,60 @@ static int SendTls13CertificateVerify(WOLFSSL* ssl) if (ret < 0) { ERROR_OUT(ret, exit_scv); } - sig->length = ED448_SIG_SIZE; + args->sigLen = ED448_SIG_SIZE; } #endif /* HAVE_ED448 */ #if defined(HAVE_PQC) #if defined(HAVE_FALCON) if (ssl->hsType == DYNAMIC_TYPE_FALCON) { - sig->length = FALCON_MAX_SIG_SIZE; + args->sigLen = FALCON_MAX_SIG_SIZE; } - #endif + #endif /* HAVE_FALCON */ #if defined(HAVE_DILITHIUM) if (ssl->hsType == DYNAMIC_TYPE_DILITHIUM) { - sig->length = DILITHIUM_MAX_SIG_SIZE; + args->sigLen = DILITHIUM_MAX_SIG_SIZE; } - #endif + #endif /* HAVE_DILITHIUM */ #endif /* HAVE_PQC */ + #ifdef WOLFSSL_DUAL_ALG_CERTS + if (ssl->sigSpec != NULL && + *ssl->sigSpec == WOLFSSL_CKS_SIGSPEC_BOTH) { + + #ifndef NO_RSA + if (ssl->hsAltType == DYNAMIC_TYPE_RSA) { + /* build encoded signature buffer */ + rsaSigBuf->length = WC_MAX_DIGEST_SIZE; + rsaSigBuf->buffer = (byte*)XMALLOC(rsaSigBuf->length, + ssl->heap, + DYNAMIC_TYPE_SIGNATURE); + if (rsaSigBuf->buffer == NULL) { + ERROR_OUT(MEMORY_E, exit_scv); + } + + ret = CreateRSAEncodedSig(rsaSigBuf->buffer, + args->altSigData, args->altSigDataSz, + args->altSigAlgo, ssl->options.hashAlgo); + if (ret < 0) + goto exit_scv; + rsaSigBuf->length = ret; + ret = 0; + } + #endif /* !NO_RSA */ + #ifdef HAVE_ECC + if (ssl->hsAltType == DYNAMIC_TYPE_ECC) { + ret = CreateECCEncodedSig(args->altSigData, + args->altSigDataSz, ssl->options.hashAlgo); + if (ret < 0) + goto exit_scv; + args->altSigDataSz = (word16)ret; + ret = 0; + } + #endif /* HAVE_ECC */ + } + #endif /* WOLFSSL_DUAL_ALG_CERTS */ + /* Advance state and proceed */ ssl->options.asyncState = TLS_ASYNC_DO; } /* case TLS_ASYNC_BUILD */ @@ -9065,21 +9212,30 @@ static int SendTls13CertificateVerify(WOLFSSL* ssl) case TLS_ASYNC_DO: { + byte* sigOut = args->verify + HASH_SIG_SIZE + VERIFY_HEADER; + #ifdef WOLFSSL_DUAL_ALG_CERTS + if (ssl->sigSpec != NULL && + *ssl->sigSpec == WOLFSSL_CKS_SIGSPEC_BOTH) { + /* As we have two signatures in the message, we store + * the length of each before the actual signature. This + * is necessary, as we could have two algorithms with + * variable length signatures. */ + sigOut += OPAQUE16_LEN; + } + #endif #ifdef HAVE_ECC if (ssl->hsType == DYNAMIC_TYPE_ECC) { #if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3) if (ssl->buffers.keyType == sm2_sa_algo) { ret = Sm2wSm3Sign(ssl, TLS13_SM2_SIG_ID, TLS13_SM2_SIG_ID_SZ, args->sigData, args->sigDataSz, - args->verify + HASH_SIG_SIZE + VERIFY_HEADER, - (word32*)&sig->length, (ecc_key*)ssl->hsKey, NULL); + sigOut, &args->sigLen, (ecc_key*)ssl->hsKey, NULL); } else #endif { ret = EccSign(ssl, args->sigData, args->sigDataSz, - args->verify + HASH_SIG_SIZE + VERIFY_HEADER, - (word32*)&sig->length, (ecc_key*)ssl->hsKey, + sigOut, &args->sigLen, (ecc_key*)ssl->hsKey, #ifdef HAVE_PK_CALLBACKS ssl->buffers.key #else @@ -9087,127 +9243,62 @@ 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; + args->length = (word16)args->sigLen; } #endif /* HAVE_ECC */ #ifdef HAVE_ED25519 if (ssl->hsType == DYNAMIC_TYPE_ED25519) { ret = Ed25519Sign(ssl, args->sigData, args->sigDataSz, - args->verify + HASH_SIG_SIZE + VERIFY_HEADER, - (word32*)&sig->length, (ed25519_key*)ssl->hsKey, + sigOut, &args->sigLen, (ed25519_key*)ssl->hsKey, #ifdef HAVE_PK_CALLBACKS ssl->buffers.key #else NULL #endif ); - args->length = (word16)sig->length; + args->length = (word16)args->sigLen; } #endif #ifdef HAVE_ED448 if (ssl->hsType == DYNAMIC_TYPE_ED448) { ret = Ed448Sign(ssl, args->sigData, args->sigDataSz, - args->verify + HASH_SIG_SIZE + VERIFY_HEADER, - (word32*)&sig->length, (ed448_key*)ssl->hsKey, + sigOut, &args->sigLen, (ed448_key*)ssl->hsKey, #ifdef HAVE_PK_CALLBACKS ssl->buffers.key #else NULL #endif ); - args->length = (word16)sig->length; + args->length = (word16)args->sigLen; } #endif #if defined(HAVE_PQC) #if defined(HAVE_FALCON) if (ssl->hsType == DYNAMIC_TYPE_FALCON) { ret = wc_falcon_sign_msg(args->sigData, args->sigDataSz, - args->verify + HASH_SIG_SIZE + - VERIFY_HEADER, (word32*)&sig->length, + sigOut, &args->sigLen, (falcon_key*)ssl->hsKey, ssl->rng); - args->length = (word16)sig->length; + args->length = (word16)args->sigLen; } - #endif + #endif /* HAVE_FALCON */ #if defined(HAVE_DILITHIUM) if (ssl->hsType == DYNAMIC_TYPE_DILITHIUM) { ret = wc_dilithium_sign_msg(args->sigData, args->sigDataSz, - args->verify + HASH_SIG_SIZE + - VERIFY_HEADER, (word32*)&sig->length, + sigOut, &args->sigLen, (dilithium_key*)ssl->hsKey, ssl->rng); - args->length = (word16)sig->length; + args->length = (word16)args->sigLen; } - #endif + #endif /* HAVE_DILITHIUM */ #endif /* HAVE_PQC */ #ifndef NO_RSA if (ssl->hsType == DYNAMIC_TYPE_RSA) { - ret = RsaSign(ssl, sig->buffer, (word32)sig->length, - args->verify + HASH_SIG_SIZE + VERIFY_HEADER, &args->sigLen, - args->sigAlgo, ssl->options.hashAlgo, - (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 */ - + ret = RsaSign(ssl, rsaSigBuf->buffer, (word32)rsaSigBuf->length, + sigOut, &args->sigLen, args->sigAlgo, + ssl->options.hashAlgo, (RsaKey*)ssl->hsKey, + ssl->buffers.key); if (ret == 0) { args->length = (word16)args->sigLen; - - XMEMCPY(args->sigData, - args->verify + HASH_SIG_SIZE + VERIFY_HEADER, - args->sigLen); + XMEMCPY(args->sigData, sigOut, args->sigLen); } } #endif /* !NO_RSA */ @@ -9217,10 +9308,78 @@ 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 */ + #ifdef WOLFSSL_DUAL_ALG_CERTS + if (ssl->sigSpec != NULL && + *ssl->sigSpec == WOLFSSL_CKS_SIGSPEC_BOTH) { + /* Add signature length for the first signature. */ + c16toa((word16)args->sigLen, sigOut - OPAQUE16_LEN); + args->length += OPAQUE16_LEN; + + /* Advance our pointer to where we store the alt signature. + * We also add additional space for the length field of the + * second signature. */ + sigOut += args->sigLen + OPAQUE16_LEN; + + /* Generate the alternative signature */ + #ifdef HAVE_ECC + if (ssl->hsAltType == DYNAMIC_TYPE_ECC) { + ret = EccSign(ssl, args->altSigData, args->altSigDataSz, + sigOut, &args->altSigLen, + (ecc_key*)ssl->hsAltKey, + #ifdef HAVE_PK_CALLBACKS + ssl->buffers.altKey + #else + NULL + #endif + ); + } + #endif /* HAVE_ECC */ + #ifndef NO_RSA + if (ssl->hsAltType == DYNAMIC_TYPE_RSA) { + ret = RsaSign(ssl, rsaSigBuf->buffer, + (word32)rsaSigBuf->length, sigOut, + &args->altSigLen, args->altSigAlgo, + ssl->options.hashAlgo, (RsaKey*)ssl->hsAltKey, + ssl->buffers.altKey); + + if (ret == 0) { + XMEMCPY(args->altSigData, sigOut, args->altSigLen); + } + } + #endif /* !NO_RSA */ + #if defined(HAVE_PQC) + #if defined(HAVE_FALCON) + if (ssl->hsAltType == DYNAMIC_TYPE_FALCON) { + ret = wc_falcon_sign_msg(args->altSigData, + args->altSigDataSz, sigOut, + &args->altSigLen, + (falcon_key*)ssl->hsAltKey, + ssl->rng); + } + #endif /* HAVE_FALCON */ + #if defined(HAVE_DILITHIUM) + if (ssl->hsAltType == DYNAMIC_TYPE_DILITHIUM) { + ret = wc_dilithium_sign_msg(args->altSigData, + args->altSigDataSz, sigOut, + &args->altSigLen, + (dilithium_key*)ssl->hsAltKey, + ssl->rng); + } + #endif /* HAVE_DILITHIUM */ + #endif /* HAVE_PQC */ + + /* Check for error */ + if (ret != 0) { + goto exit_scv; + } + + /* Add signature length for the alternative signature. */ + c16toa((word16)args->altSigLen, sigOut - OPAQUE16_LEN); + + /* Add length of the alt sig to the total length */ + args->length += args->altSigLen + OPAQUE16_LEN; + } + #endif /* WOLFSSL_DUAL_ALG_CERTS */ /* Add signature length. */ c16toa(args->length, args->verify + HASH_SIG_SIZE); @@ -9236,38 +9395,72 @@ static int SendTls13CertificateVerify(WOLFSSL* ssl) if (ssl->hsType == DYNAMIC_TYPE_RSA) { /* check for signature faults */ ret = VerifyRsaSign(ssl, args->sigData, args->sigLen, - sig->buffer, (word32)sig->length, args->sigAlgo, + rsaSigBuf->buffer, (word32)rsaSigBuf->length, args->sigAlgo, ssl->options.hashAlgo, (RsaKey*)ssl->hsKey, - ssl->buffers.key - ); + ssl->buffers.key); } + #ifdef WOLFSSL_DUAL_ALG_CERTS + if (ssl->sigSpec != NULL && + *ssl->sigSpec == WOLFSSL_CKS_SIGSPEC_BOTH && + ssl->hsAltType == DYNAMIC_TYPE_RSA) { + /* check for signature faults */ + ret = VerifyRsaSign(ssl, args->altSigData, args->altSigLen, + rsaSigBuf->buffer, (word32)rsaSigBuf->length, + args->altSigAlgo, ssl->options.hashAlgo, + (RsaKey*)ssl->hsAltKey, ssl->buffers.altKey); + } + #endif /* WOLFSSL_DUAL_ALG_CERTS */ #endif /* !NO_RSA */ #if defined(HAVE_ECC) && defined(WOLFSSL_CHECK_SIG_FAULTS) if (ssl->hsType == DYNAMIC_TYPE_ECC) { + byte* sigOut = args->verify + HASH_SIG_SIZE + VERIFY_HEADER; + #ifdef WOLFSSL_DUAL_ALG_CERTS + if (ssl->sigSpec != NULL && + *ssl->sigSpec == WOLFSSL_CKS_SIGSPEC_BOTH) { + /* Add our length offset. */ + sigOut += OPAQUE16_LEN; + } + #endif #if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3) if (ssl->buffers.keyType == sm2_sa_algo) { ret = Sm2wSm3Verify(ssl, TLS13_SM2_SIG_ID, TLS13_SM2_SIG_ID_SZ, - args->verify + HASH_SIG_SIZE + VERIFY_HEADER, - sig->length, args->sigData, args->sigDataSz, + sigOut, args->sigLen, args->sigData, args->sigDataSz, (ecc_key*)ssl->hsKey, NULL); } else #endif { - ret = EccVerify(ssl, - args->verify + HASH_SIG_SIZE + VERIFY_HEADER, - sig->length, args->sigData, args->sigDataSz, - (ecc_key*)ssl->hsKey, + ret = EccVerify(ssl, sigOut, args->sigLen, + args->sigData, args->sigDataSz, + (ecc_key*)ssl->hsKey, #ifdef HAVE_PK_CALLBACKS - ssl->buffers.key + ssl->buffers.key #else - NULL + NULL #endif - ); + ); } } - #endif + #ifdef WOLFSSL_DUAL_ALG_CERTS + if (ssl->sigSpec != NULL && + *ssl->sigSpec == WOLFSSL_CKS_SIGSPEC_BOTH && + ssl->hsAltType == DYNAMIC_TYPE_ECC) { + /* check for signature faults */ + byte* sigOut = args->verify + HASH_SIG_SIZE + VERIFY_HEADER + + args->sigLen + OPAQUE16_LEN + OPAQUE16_LEN; + ret = EccVerify(ssl, sigOut, args->altSigLen, + args->altSigData, args->altSigDataSz, + (ecc_key*)ssl->hsAltKey, + #ifdef HAVE_PK_CALLBACKS + ssl->buffers.altKey + #else + NULL + #endif + ); + } + #endif /* WOLFSSL_DUAL_ALG_CERTS */ + #endif /* HAVE_ECC && WOLFSSL_CHECK_SIG_FAULTS */ /* Check for error */ if (ret != 0) { @@ -9286,7 +9479,7 @@ static int SendTls13CertificateVerify(WOLFSSL* ssl) VERIFY_HEADER, certificate_verify, ssl); args->sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ + - args->length + HASH_SIG_SIZE + VERIFY_HEADER; + args->length + HASH_SIG_SIZE + VERIFY_HEADER; #ifdef WOLFSSL_DTLS13 if (ssl->options.dtls) args->sendSz += recordLayerHdrExtra + DTLS_HANDSHAKE_EXTRA; @@ -9470,6 +9663,54 @@ static void FreeDcv13Args(WOLFSSL* ssl, void* pArgs) } #ifdef WOLFSSL_DUAL_ALG_CERTS +/* ssl->peerCert->sapkiDer is the alternative public key. Hopefully it is a + * RSA public key. Convert it into a usable public key. */ +static int decodeRsaKey(WOLFSSL* ssl) +{ + int keyRet; + word32 tmpIdx = 0; + + if (ssl->peerRsaKeyPresent) + return INVALID_PARAMETER; + + keyRet = AllocKey(ssl, DYNAMIC_TYPE_RSA, (void**)&ssl->peerRsaKey); + if (keyRet != 0) + return PEER_KEY_ERROR; + + ssl->peerRsaKeyPresent = 1; + keyRet = wc_RsaPublicKeyDecode(ssl->peerCert.sapkiDer, &tmpIdx, + ssl->peerRsaKey, + ssl->peerCert.sapkiLen); + if (keyRet != 0) + return PEER_KEY_ERROR; + + return 0; +} + +/* ssl->peerCert->sapkiDer is the alternative public key. Hopefully it is a + * ECC public key. Convert it into a usable public key. */ +static int decodeEccKey(WOLFSSL* ssl) +{ + int keyRet; + word32 tmpIdx = 0; + + if (ssl->peerEccDsaKeyPresent) + return INVALID_PARAMETER; + + keyRet = AllocKey(ssl, DYNAMIC_TYPE_ECC, (void**)&ssl->peerEccDsaKey); + if (keyRet != 0) + return PEER_KEY_ERROR; + + ssl->peerEccDsaKeyPresent = 1; + keyRet = wc_EccPublicKeyDecode(ssl->peerCert.sapkiDer, &tmpIdx, + ssl->peerEccDsaKey, + ssl->peerCert.sapkiLen); + if (keyRet != 0) + return PEER_KEY_ERROR; + + return 0; +} + /* 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) @@ -9486,10 +9727,6 @@ static int decodeDilithiumKey(WOLFSSL* ssl, int level) 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; @@ -9518,10 +9755,6 @@ static int decodeFalconKey(WOLFSSL* ssl, int level) 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; @@ -9534,7 +9767,7 @@ static int decodeFalconKey(WOLFSSL* ssl, int level) return 0; } -#endif +#endif /* WOLFSSL_DUAL_ALG_CERTS */ /* handle processing TLS v1.3 certificate_verify (15) */ /* Parse and handle a TLS v1.3 CertificateVerify message. @@ -9551,7 +9784,11 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, word32* inOutIdx, word32 totalSz) { int ret = 0; - buffer* sig = &ssl->buffers.sig; + byte* sig = NULL; +#ifndef NO_RSA + /* Use this as a temporary buffer for RSA signature verification. */ + buffer* rsaSigBuf = &ssl->buffers.sig; +#endif #ifdef WOLFSSL_ASYNC_CRYPT Dcv13Args* args = NULL; WOLFSSL_ASSERT_SIZEOF_GE(ssl->async->args, *args); @@ -9638,8 +9875,7 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, /* 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 || + if (ssl->sigSpec == NULL || *ssl->sigSpec == WOLFSSL_CKS_SIGSPEC_NATIVE || *ssl->sigSpec == WOLFSSL_CKS_SIGSPEC_ALTERNATIVE) { #endif /* WOLFSSL_DUAL_ALG_CERTS */ @@ -9673,8 +9909,7 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, } #ifdef WOLFSSL_DUAL_ALG_CERTS - if (!wolfSSL_is_server(ssl) && - (ssl->sigSpec != NULL) && + if ((ssl->sigSpec != NULL) && (*ssl->sigSpec != WOLFSSL_CKS_SIGSPEC_NATIVE)) { word16 sa; @@ -9684,6 +9919,12 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, sa = args->altSigAlgo; switch(sa) { + case rsa_pss_sa_algo: + ret = decodeRsaKey(ssl); + break; + case ecc_dsa_sa_algo: + ret = decodeEccKey(ssl); + break; case dilithium_level2_sa_algo: ret = decodeDilithiumKey(ssl, 2); break; @@ -9708,55 +9949,37 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, 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) { + /* Now swap in the alternative by removing the native. + * sa contains the alternative signature type. */ + if (ssl->peerRsaKeyPresent && sa != rsa_pss_sa_algo) { FreeKey(ssl, DYNAMIC_TYPE_RSA, (void**)&ssl->peerRsaKey); ssl->peerRsaKeyPresent = 0; } - else if (ssl->peerEccDsaKeyPresent) { + else if (ssl->peerEccDsaKeyPresent && + sa != ecc_dsa_sa_algo) { FreeKey(ssl, DYNAMIC_TYPE_ECC, (void**)&ssl->peerEccDsaKey); ssl->peerEccDsaKeyPresent = 0; } + else if (ssl->peerDilithiumKeyPresent && + sa != dilithium_level2_sa_algo && + sa != dilithium_level3_sa_algo && + sa != dilithium_level5_sa_algo) { + FreeKey(ssl, DYNAMIC_TYPE_DILITHIUM, + (void**)&ssl->peerDilithiumKey); + ssl->peerDilithiumKeyPresent = 0; + } + else if (ssl->peerFalconKeyPresent && + sa != falcon_level1_sa_algo && + sa != falcon_level5_sa_algo) { + FreeKey(ssl, DYNAMIC_TYPE_FALCON, + (void**)&ssl->peerFalconKey); + ssl->peerFalconKeyPresent = 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 */ @@ -9835,61 +10058,86 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, ERROR_OUT(SIG_VERIFY_E, exit_dcv); } - sig->length = args->sz; + args->sigSz = args->sz; #ifdef WOLFSSL_DUAL_ALG_CERTS - if (!wolfSSL_is_server(ssl) && - ssl->sigSpec != NULL && + if (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); + /* In case we received two signatures, both of them are encoded + * with their size as 16-bit integeter prior in memory. Hence, + * we can decode both lengths here now. */ + word32 tmpIdx = args->idx; + ato16(input + tmpIdx, (word16*)&args->sigSz); + + tmpIdx += OPAQUE16_LEN + args->sigSz; + ato16(input + tmpIdx, (word16*)&args->altSignatureSz); + + if (args->sz != (args->sigSz + args->altSignatureSz + + OPAQUE16_LEN + OPAQUE16_LEN)) { + ERROR_OUT(BUFFER_ERROR, exit_dcv); } } -#endif +#endif /* WOLFSSL_DUAL_ALG_CERTS */ - sig->buffer = (byte*)XMALLOC(sig->length, ssl->heap, + #if !defined(NO_RSA) && defined(WC_RSA_PSS) + /* In case we have to verify an RSA signature, we have to store the + * signature in the 'rsaSigBuf' structure for further processing. + */ + if (ssl->peerRsaKey != NULL && ssl->peerRsaKeyPresent != 0) { + word32 sigSz = args->sigSz; + sig = input + args->idx; + #ifdef WOLFSSL_DUAL_ALG_CERTS + /* Check if our alternative signature was RSA */ + if (ssl->sigSpec != NULL && + *ssl->sigSpec == WOLFSSL_CKS_SIGSPEC_BOTH) { + if (ssl->options.peerSigAlgo != rsa_pss_sa_algo) { + /* We have to skip the first signature (length field + * and signature itself) and the length field of the + * alternative signature. */ + sig += OPAQUE16_LEN + OPAQUE16_LEN + args->sigSz; + sigSz = args->altSignatureSz; + } + else { + /* We have to skip the length field */ + sig += OPAQUE16_LEN; + } + } + #endif + rsaSigBuf->buffer = (byte*)XMALLOC(sigSz, ssl->heap, DYNAMIC_TYPE_SIGNATURE); + if (rsaSigBuf->buffer == NULL) { + ERROR_OUT(MEMORY_E, exit_dcv); + } + rsaSigBuf->length = sigSz; + XMEMCPY(rsaSigBuf->buffer, sig, rsaSigBuf->length); + } + #endif /* !NO_RSA && WC_RSA_PSS */ - if (sig->buffer == NULL) { + args->sigData = (byte*)XMALLOC(MAX_SIG_DATA_SZ, ssl->heap, + DYNAMIC_TYPE_SIGNATURE); + if (args->sigData == NULL) { ERROR_OUT(MEMORY_E, exit_dcv); } - XMEMCPY(sig->buffer, input + args->idx, sig->length); - #ifdef HAVE_ECC - if (ssl->peerEccDsaKeyPresent) { - WOLFSSL_MSG("Doing ECC peer cert verify"); + ret = CreateSigData(ssl, args->sigData, &args->sigDataSz, 1); + if (ret < 0) + goto exit_dcv; - args->sigData = (byte*)XMALLOC(MAX_SIG_DATA_SZ, ssl->heap, + #ifdef WOLFSSL_DUAL_ALG_CERTS + if ((ssl->sigSpec != NULL) && + (*ssl->sigSpec == WOLFSSL_CKS_SIGSPEC_BOTH)) { + args->altSigData = (byte*)XMALLOC(MAX_SIG_DATA_SZ, ssl->heap, DYNAMIC_TYPE_SIGNATURE); - if (args->sigData == NULL) { + if (args->altSigData == NULL) { ERROR_OUT(MEMORY_E, exit_dcv); } + XMEMCPY(args->altSigData, args->sigData, args->sigDataSz); + args->altSigDataSz = args->sigDataSz; + } + #endif /* WOLFSSL_DUAL_ALG_CERTS */ - ret = CreateSigData(ssl, args->sigData, &args->sigDataSz, 1); - if (ret != 0) - goto exit_dcv; + #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 @@ -9902,68 +10150,21 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, ret = 0; } } - #endif - #ifdef HAVE_ED25519 - if (ssl->peerEd25519KeyPresent) { - WOLFSSL_MSG("Doing ED25519 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, args->sigData, &args->sigDataSz, 1); - if (ret < 0) - goto exit_dcv; + #ifdef WOLFSSL_DUAL_ALG_CERTS + if ((ssl->sigSpec != NULL) && + (*ssl->sigSpec == WOLFSSL_CKS_SIGSPEC_BOTH) && + (args->altSigAlgo == ecc_dsa_sa_algo) && + (ssl->peerEccDsaKeyPresent)) { + ret = CreateECCEncodedSig(args->altSigData, + args->altSigDataSz, ssl->options.peerHashAlgo); + if (ret < 0) + goto exit_dcv; + args->altSigDataSz = (word16)ret; + ret = 0; } - #endif - #ifdef HAVE_ED448 - if (ssl->peerEd448KeyPresent) { - WOLFSSL_MSG("Doing ED448 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, args->sigData, &args->sigDataSz, 1); - if (ret < 0) - goto exit_dcv; - } - #endif - #ifdef HAVE_PQC - if (ssl->peerFalconKeyPresent || ssl->peerDilithiumKeyPresent) { - word16 sigDataSz; - byte *sigData = (byte*)XMALLOC(MAX_SIG_DATA_SZ, ssl->heap, - DYNAMIC_TYPE_SIGNATURE); - if (sigData == NULL) { - ERROR_OUT(MEMORY_E, exit_dcv); - } - - ret = CreateSigData(ssl, sigData, &sigDataSz, 1); - if (ret < 0) { - goto exit_dcv; - } - -#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 + #endif /* WOLFSSL_DUAL_ALG_CERTS */ + #endif /* HAVE_ECC */ /* Advance state and proceed */ ssl->options.asyncState = TLS_ASYNC_DO; @@ -9972,16 +10173,31 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, case TLS_ASYNC_DO: { + sig = input + args->idx; + #ifdef WOLFSSL_DUAL_ALG_CERTS + if (ssl->sigSpec != NULL && + *ssl->sigSpec == WOLFSSL_CKS_SIGSPEC_BOTH) { + /* As we have two signatures in the message, we stored + * the length of each before the actual signature. This + * is necessary, as we could have two algorithms with + * variable length signatures. */ + sig += OPAQUE16_LEN; + } + #endif #ifndef NO_RSA - if (ssl->peerRsaKey != NULL && ssl->peerRsaKeyPresent != 0) { - ret = RsaVerify(ssl, sig->buffer, (word32)sig->length, &args->output, - ssl->options.peerSigAlgo, ssl->options.peerHashAlgo, ssl->peerRsaKey, + if ((ssl->options.peerSigAlgo == rsa_pss_sa_algo) && + (ssl->peerRsaKey != NULL) && (ssl->peerRsaKeyPresent != 0)) { + WOLFSSL_MSG("Doing RSA peer cert verify"); + ret = RsaVerify(ssl, rsaSigBuf->buffer, + (word32)rsaSigBuf->length, &args->output, + ssl->options.peerSigAlgo, + ssl->options.peerHashAlgo, ssl->peerRsaKey, #ifdef HAVE_PK_CALLBACKS - &ssl->buffers.peerRsaKey + &ssl->buffers.peerRsaKey #else - NULL + NULL #endif - ); + ); if (ret >= 0) { args->sendSz = ret; ret = 0; @@ -9989,18 +10205,20 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, } #endif /* !NO_RSA */ #ifdef HAVE_ECC - if (ssl->peerEccDsaKeyPresent) { + if ((ssl->options.peerSigAlgo == ecc_dsa_sa_algo) && + (ssl->peerEccDsaKeyPresent)) { #if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3) if (ssl->options.peerSigAlgo == sm2_sa_algo) { ret = Sm2wSm3Verify(ssl, TLS13_SM2_SIG_ID, - TLS13_SM2_SIG_ID_SZ, input + args->idx, args->sz, + TLS13_SM2_SIG_ID_SZ, sig, args->sigSz, args->sigData, args->sigDataSz, ssl->peerEccDsaKey, NULL); } else #endif { - ret = EccVerify(ssl, input + args->idx, sig->length, + WOLFSSL_MSG("Doing ECC peer cert verify"); + ret = EccVerify(ssl, sig, args->sigSz, args->sigData, args->sigDataSz, ssl->peerEccDsaKey, #ifdef HAVE_PK_CALLBACKS @@ -10008,21 +10226,24 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, #else NULL #endif - ); + ); } if (ret >= 0) { /* CLIENT/SERVER: data verified with public key from * certificate. */ ssl->options.peerAuthGood = 1; + FreeKey(ssl, DYNAMIC_TYPE_ECC, (void**)&ssl->peerEccDsaKey); ssl->peerEccDsaKeyPresent = 0; } } #endif /* HAVE_ECC */ #ifdef HAVE_ED25519 - if (ssl->peerEd25519KeyPresent) { - ret = Ed25519Verify(ssl, input + args->idx, args->sz, + if ((ssl->options.peerSigAlgo == ed25519_sa_algo) && + (ssl->peerEd25519KeyPresent)) { + WOLFSSL_MSG("Doing ED25519 peer cert verify"); + ret = Ed25519Verify(ssl, sig, args->sigSz, args->sigData, args->sigDataSz, ssl->peerEd25519Key, #ifdef HAVE_PK_CALLBACKS @@ -10030,7 +10251,7 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, #else NULL #endif - ); + ); if (ret >= 0) { /* CLIENT/SERVER: data verified with public key from @@ -10043,8 +10264,10 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, } #endif #ifdef HAVE_ED448 - if (ssl->peerEd448KeyPresent) { - ret = Ed448Verify(ssl, input + args->idx, args->sz, + if ((ssl->options.peerSigAlgo == ed448_sa_algo) && + (ssl->peerEd448KeyPresent)) { + WOLFSSL_MSG("Doing ED448 peer cert verify"); + ret = Ed448Verify(ssl, sig, args->sigSz, args->sigData, args->sigDataSz, ssl->peerEd448Key, #ifdef HAVE_PK_CALLBACKS @@ -10065,44 +10288,19 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, } #endif #if defined(HAVE_PQC) && defined(HAVE_FALCON) - if (ssl->peerFalconKeyPresent) { + if (((ssl->options.peerSigAlgo == falcon_level1_sa_algo) || + (ssl->options.peerSigAlgo == falcon_level5_sa_algo)) && + (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"); -#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, + ret = wc_falcon_verify_msg(sig, args->sigSz, + args->sigData, args->sigDataSz, &res, ssl->peerFalconKey); if ((ret >= 0) && (res == 1)) { /* CLIENT/SERVER: data verified with public key from * certificate. */ -#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; + ssl->options.peerAuthGood = 1; FreeKey(ssl, DYNAMIC_TYPE_FALCON, (void**)&ssl->peerFalconKey); @@ -10111,44 +10309,20 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, } #endif /* HAVE_PQC && HAVE_FALCON */ #if defined(HAVE_PQC) && defined(HAVE_DILITHIUM) - if (ssl->peerDilithiumKeyPresent) { + if (((ssl->options.peerSigAlgo == dilithium_level2_sa_algo) || + (ssl->options.peerSigAlgo == dilithium_level3_sa_algo) || + (ssl->options.peerSigAlgo == dilithium_level5_sa_algo)) && + (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"); -#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, + ret = wc_dilithium_verify_msg(sig, args->sigSz, + args->sigData, args->sigDataSz, &res, ssl->peerDilithiumKey); if ((ret >= 0) && (res == 1)) { /* CLIENT/SERVER: data verified with public key from * certificate. */ -#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; + ssl->options.peerAuthGood = 1; FreeKey(ssl, DYNAMIC_TYPE_DILITHIUM, (void**)&ssl->peerDilithiumKey); @@ -10162,6 +10336,110 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, goto exit_dcv; } + #ifdef WOLFSSL_DUAL_ALG_CERTS + if (ssl->sigSpec != NULL && + *ssl->sigSpec == WOLFSSL_CKS_SIGSPEC_BOTH) { + /* Move forward to the alternative signature. */ + sig += args->sigSz + OPAQUE16_LEN; + + /* Verify the alternative signature */ + #ifndef NO_RSA + if ((args->altSigAlgo == rsa_pss_sa_algo) && + (ssl->peerRsaKey != NULL) && + (ssl->peerRsaKeyPresent != 0)) { + WOLFSSL_MSG("Doing RSA peer cert alt verify"); + ret = RsaVerify(ssl, rsaSigBuf->buffer, + (word32)rsaSigBuf->length, + &args->output, args->altSigAlgo, + ssl->options.peerHashAlgo, ssl->peerRsaKey, + #ifdef HAVE_PK_CALLBACKS + &ssl->buffers.peerRsaKey + #else + NULL + #endif + ); + if (ret >= 0) { + args->sendSz = ret; + ret = 0; + } + } + #endif /* !NO_RSA */ + #ifdef HAVE_ECC + if ((args->altSigAlgo == ecc_dsa_sa_algo) && + (ssl->peerEccDsaKeyPresent)) { + WOLFSSL_MSG("Doing ECC peer cert alt verify"); + ret = EccVerify(ssl, sig, args->altSignatureSz, + args->altSigData, args->altSigDataSz, + ssl->peerEccDsaKey, + #ifdef HAVE_PK_CALLBACKS + &ssl->buffers.peerEccDsaKey + #else + NULL + #endif + ); + + if (ret >= 0) { + /* CLIENT/SERVER: data verified with public key from + * certificate. */ + args->altPeerAuthGood = 1; + + FreeKey(ssl, DYNAMIC_TYPE_ECC, + (void**)&ssl->peerEccDsaKey); + ssl->peerEccDsaKeyPresent = 0; + } + } + #endif /* HAVE_ECC */ + #if defined(HAVE_PQC) && defined(HAVE_FALCON) + if (((args->altSigAlgo == falcon_level1_sa_algo) || + (args->altSigAlgo == falcon_level5_sa_algo)) && + (ssl->peerFalconKeyPresent)) { + int res = 0; + WOLFSSL_MSG("Doing Falcon peer cert alt verify"); + ret = wc_falcon_verify_msg(sig, args->altSignatureSz, + args->altSigData, args->altSigDataSz, + &res, ssl->peerFalconKey); + + if ((ret >= 0) && (res == 1)) { + /* CLIENT/SERVER: data verified with public key from + * certificate. */ + args->altPeerAuthGood = 1; + + FreeKey(ssl, DYNAMIC_TYPE_FALCON, + (void**)&ssl->peerFalconKey); + ssl->peerFalconKeyPresent = 0; + } + } + #endif /* HAVE_PQC && HAVE_FALCON */ + #if defined(HAVE_PQC) && defined(HAVE_DILITHIUM) + if (((args->altSigAlgo == dilithium_level2_sa_algo) || + (args->altSigAlgo == dilithium_level3_sa_algo) || + (args->altSigAlgo == dilithium_level5_sa_algo)) && + (ssl->peerDilithiumKeyPresent)) { + int res = 0; + WOLFSSL_MSG("Doing Dilithium peer cert alt verify"); + ret = wc_dilithium_verify_msg(sig, args->altSignatureSz, + args->altSigData, args->altSigDataSz, + &res, ssl->peerDilithiumKey); + + if ((ret >= 0) && (res == 1)) { + /* CLIENT/SERVER: data verified with public key from + * certificate. */ + args->altPeerAuthGood = 1; + + FreeKey(ssl, DYNAMIC_TYPE_DILITHIUM, + (void**)&ssl->peerDilithiumKey); + ssl->peerDilithiumKeyPresent = 0; + } + } + #endif /* HAVE_PQC && HAVE_DILITHIUM */ + + /* Check for error */ + if (ret != 0) { + goto exit_dcv; + } + } + #endif /* WOLFSSL_DUAL_ALG_CERTS */ + /* Advance state and proceed */ ssl->options.asyncState = TLS_ASYNC_VERIFY; } /* case TLS_ASYNC_DO */ @@ -10171,7 +10449,16 @@ 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, ssl->options.peerSigAlgo, + int sigAlgo = ssl->options.peerSigAlgo; + #ifdef WOLFSSL_DUAL_ALG_CERTS + /* Check if our alternative signature was RSA */ + if (ssl->sigSpec != NULL && + *ssl->sigSpec == WOLFSSL_CKS_SIGSPEC_BOTH && + ssl->options.peerSigAlgo != rsa_pss_sa_algo) { + sigAlgo = args->altSigAlgo; + } + #endif + ret = CheckRSASignature(ssl, sigAlgo, ssl->options.peerHashAlgo, args->output, args->sendSz); if (ret != 0) goto exit_dcv; @@ -10180,7 +10467,16 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, * certificate. */ ssl->peerRsaKeyPresent = 0; FreeKey(ssl, DYNAMIC_TYPE_RSA, (void**)&ssl->peerRsaKey); - ssl->options.peerAuthGood = 1; + #ifdef WOLFSSL_DUAL_ALG_CERTS + /* Check if our alternative signature was RSA */ + if (ssl->sigSpec != NULL && + *ssl->sigSpec == WOLFSSL_CKS_SIGSPEC_BOTH && + ssl->options.peerSigAlgo != rsa_pss_sa_algo) { + args->altPeerAuthGood = 1; + } + else + #endif + ssl->options.peerAuthGood = 1; } #endif /* !NO_RSA && WC_RSA_PSS */ @@ -10192,8 +10488,7 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, case TLS_ASYNC_FINALIZE: { #ifdef WOLFSSL_DUAL_ALG_CERTS - if (!wolfSSL_is_server(ssl) && - ssl->options.peerAuthGood && + if (ssl->options.peerAuthGood && ssl->sigSpec != NULL && *ssl->sigSpec == WOLFSSL_CKS_SIGSPEC_BOTH) { ssl->options.peerAuthGood = args->altPeerAuthGood; diff --git a/src/x509.c b/src/x509.c index eefa69cb2..f39df7743 100644 --- a/src/x509.c +++ b/src/x509.c @@ -10171,6 +10171,15 @@ WOLF_STACK_OF(WOLFSSL_X509)* wolfSSL_X509_chain_up_ref( #endif #ifndef NO_DSA DsaKey* dsa = NULL; + #endif + #if defined(HAVE_PQC) && defined(HAVE_FALCON) + falcon_key* falcon = NULL; + #endif + #if defined(HAVE_PQC) && defined(HAVE_DILITHIUM) + dilithium_key* dilithium = NULL; + #endif + #if defined(HAVE_PQC) && defined(HAVE_SPHINCS) + sphincs_key* sphincs = NULL; #endif WC_RNG rng; word32 idx = 0; @@ -10297,6 +10306,148 @@ WOLF_STACK_OF(WOLFSSL_X509)* wolfSSL_X509_chain_up_ref( } key = (void*)dsa; } + #endif + #if defined(HAVE_PQC) && defined(HAVE_FALCON) + if ((x509->pubKeyOID == FALCON_LEVEL1k) || + (x509->pubKeyOID == FALCON_LEVEL5k)) { + falcon = (falcon_key*)XMALLOC(sizeof(falcon_key), NULL, + DYNAMIC_TYPE_FALCON); + if (falcon == NULL) { + WOLFSSL_MSG("Failed to allocate memory for falcon_key"); + XFREE(cert, NULL, DYNAMIC_TYPE_CERT); + return WOLFSSL_FAILURE; + } + + ret = wc_falcon_init(falcon); + if (ret != 0) { + XFREE(falcon, NULL, DYNAMIC_TYPE_FALCON); + XFREE(cert, NULL, DYNAMIC_TYPE_CERT); + return ret; + } + + if (x509->pubKeyOID == FALCON_LEVEL1k) { + type = FALCON_LEVEL1_TYPE; + wc_falcon_set_level(falcon, 1); + } + else if (x509->pubKeyOID == FALCON_LEVEL5k) { + type = FALCON_LEVEL5_TYPE; + wc_falcon_set_level(falcon, 5); + } + + ret = wc_Falcon_PublicKeyDecode(x509->pubKey.buffer, &idx, falcon, + x509->pubKey.length); + if (ret != 0) { + WOLFSSL_ERROR_VERBOSE(ret); + wc_falcon_free(falcon); + XFREE(falcon, NULL, DYNAMIC_TYPE_FALCON); + XFREE(cert, NULL, DYNAMIC_TYPE_CERT); + return ret; + } + key = (void*)falcon; + } + #endif + #if defined(HAVE_PQC) && defined(HAVE_DILITHIUM) + if ((x509->pubKeyOID == DILITHIUM_LEVEL2k) || + (x509->pubKeyOID == DILITHIUM_LEVEL3k) || + (x509->pubKeyOID == DILITHIUM_LEVEL5k)) { + dilithium = (dilithium_key*)XMALLOC(sizeof(dilithium_key), NULL, + DYNAMIC_TYPE_DILITHIUM); + if (dilithium == NULL) { + WOLFSSL_MSG("Failed to allocate memory for dilithium_key"); + XFREE(cert, NULL, DYNAMIC_TYPE_CERT); + return WOLFSSL_FAILURE; + } + + ret = wc_dilithium_init(dilithium); + if (ret != 0) { + XFREE(dilithium, NULL, DYNAMIC_TYPE_DILITHIUM); + XFREE(cert, NULL, DYNAMIC_TYPE_CERT); + return ret; + } + + if (x509->pubKeyOID == DILITHIUM_LEVEL2k) { + type = DILITHIUM_LEVEL2_TYPE; + wc_dilithium_set_level(dilithium, 2); + } + else if (x509->pubKeyOID == DILITHIUM_LEVEL3k) { + type = DILITHIUM_LEVEL3_TYPE; + wc_dilithium_set_level(dilithium, 3); + } + else if (x509->pubKeyOID == DILITHIUM_LEVEL5k) { + type = DILITHIUM_LEVEL5_TYPE; + wc_dilithium_set_level(dilithium, 5); + } + + ret = wc_Dilithium_PublicKeyDecode(x509->pubKey.buffer, &idx, + dilithium, x509->pubKey.length); + if (ret != 0) { + WOLFSSL_ERROR_VERBOSE(ret); + wc_dilithium_free(dilithium); + XFREE(dilithium, NULL, DYNAMIC_TYPE_DILITHIUM); + XFREE(cert, NULL, DYNAMIC_TYPE_CERT); + return ret; + } + key = (void*)dilithium; + } + #endif + #if defined(HAVE_PQC) && defined(HAVE_SPHINCS) + if ((x509->pubKeyOID == SPHINCS_FAST_LEVEL1k) || + (x509->pubKeyOID == SPHINCS_FAST_LEVEL3k) || + (x509->pubKeyOID == SPHINCS_FAST_LEVEL5k) || + (x509->pubKeyOID == SPHINCS_SMALL_LEVEL1k) || + (x509->pubKeyOID == SPHINCS_SMALL_LEVEL3k) || + (x509->pubKeyOID == SPHINCS_SMALL_LEVEL5k)) { + sphincs = (sphincs_key*)XMALLOC(sizeof(sphincs_key), NULL, + DYNAMIC_TYPE_SPHINCS); + if (sphincs == NULL) { + WOLFSSL_MSG("Failed to allocate memory for sphincs_key"); + XFREE(cert, NULL, DYNAMIC_TYPE_CERT); + return WOLFSSL_FAILURE; + } + + ret = wc_sphincs_init(sphincs); + if (ret != 0) { + XFREE(sphincs, NULL, DYNAMIC_TYPE_SPHINCS); + XFREE(cert, NULL, DYNAMIC_TYPE_CERT); + return ret; + } + + if (x509->pubKeyOID == SPHINCS_FAST_LEVEL1k) { + type = SPHINCS_FAST_LEVEL1_TYPE; + wc_sphincs_set_level_and_optim(sphincs, 1, FAST_VARIANT); + } + else if (x509->pubKeyOID == SPHINCS_FAST_LEVEL3k) { + type = SPHINCS_FAST_LEVEL3_TYPE; + wc_sphincs_set_level_and_optim(sphincs, 3, FAST_VARIANT); + } + else if (x509->pubKeyOID == SPHINCS_FAST_LEVEL3k) { + type = SPHINCS_FAST_LEVEL5_TYPE; + wc_sphincs_set_level_and_optim(sphincs, 5, FAST_VARIANT); + } + else if (x509->pubKeyOID == SPHINCS_SMALL_LEVEL1k) { + type = SPHINCS_SMALL_LEVEL1_TYPE; + wc_sphincs_set_level_and_optim(sphincs, 1, SMALL_VARIANT); + } + else if (x509->pubKeyOID == SPHINCS_SMALL_LEVEL3k) { + type = SPHINCS_SMALL_LEVEL3_TYPE; + wc_sphincs_set_level_and_optim(sphincs, 3, SMALL_VARIANT); + } + else if (x509->pubKeyOID == SPHINCS_SMALL_LEVEL3k) { + type = SPHINCS_SMALL_LEVEL5_TYPE; + wc_sphincs_set_level_and_optim(sphincs, 5, SMALL_VARIANT); + } + + ret = wc_Sphincs_PublicKeyDecode(x509->pubKey.buffer, &idx, sphincs, + x509->pubKey.length); + if (ret != 0) { + WOLFSSL_ERROR_VERBOSE(ret); + wc_sphincs_free(sphincs); + XFREE(sphincs, NULL, DYNAMIC_TYPE_SPHINCS); + XFREE(cert, NULL, DYNAMIC_TYPE_CERT); + return ret; + } + key = (void*)sphincs; + } #endif if (key == NULL) { WOLFSSL_MSG("No public key found for certificate"); @@ -10397,6 +10548,32 @@ cleanup: wc_FreeDsaKey(dsa); XFREE(dsa, NULL, DYNAMIC_TYPE_DSA); } + #endif + #if defined(HAVE_PQC) && defined(HAVE_FALCON) + if ((x509->pubKeyOID == FALCON_LEVEL1k) || + (x509->pubKeyOID == FALCON_LEVEL5k)) { + wc_falcon_free(falcon); + XFREE(falcon, NULL, DYNAMIC_TYPE_FALCON); + } + #endif + #if defined(HAVE_PQC) && defined(HAVE_DILITHIUM) + if ((x509->pubKeyOID == DILITHIUM_LEVEL2k) || + (x509->pubKeyOID == DILITHIUM_LEVEL3k) || + (x509->pubKeyOID == DILITHIUM_LEVEL5k)) { + wc_dilithium_free(dilithium); + XFREE(dilithium, NULL, DYNAMIC_TYPE_DILITHIUM); + } + #endif + #if defined(HAVE_PQC) && defined(HAVE_SPHINCS) + if ((x509->pubKeyOID == SPHINCS_FAST_LEVEL1k) || + (x509->pubKeyOID == SPHINCS_FAST_LEVEL3k) || + (x509->pubKeyOID == SPHINCS_FAST_LEVEL5k) || + (x509->pubKeyOID == SPHINCS_SMALL_LEVEL1k) || + (x509->pubKeyOID == SPHINCS_SMALL_LEVEL3k) || + (x509->pubKeyOID == SPHINCS_SMALL_LEVEL5k)) { + wc_sphincs_free(sphincs); + XFREE(sphincs, NULL, DYNAMIC_TYPE_SPHINCS); + } #endif XFREE(cert, NULL, DYNAMIC_TYPE_CERT); diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 3d80e8708..997f0dfc5 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -7770,17 +7770,59 @@ int wc_CheckPrivateKey(const byte* privKey, word32 privKeySz, * return 1 (true) on match * return 0 or negative value on failure/error * - * key : buffer holding DER format key - * keySz : size of key buffer - * der : a initialized and parsed DecodedCert holding a certificate */ -int wc_CheckPrivateKeyCert(const byte* key, word32 keySz, DecodedCert* der) + * key : buffer holding DER format key + * keySz : size of key buffer + * der : a initialized and parsed DecodedCert holding a certificate + * checkAlt : indicate if we check primary or alternative key + */ +int wc_CheckPrivateKeyCert(const byte* key, word32 keySz, DecodedCert* der, + int checkAlt) { + int ret = 0; + if (key == NULL || der == NULL) { return BAD_FUNC_ARG; } - return wc_CheckPrivateKey(key, keySz, der->publicKey, - der->pubKeySize, (enum Key_Sum) der->keyOID); +#ifdef WOLFSSL_DUAL_ALG_CERTS + if (checkAlt && der->sapkiDer != NULL) { + /* We have to decode the public key first */ + word32 idx = 0; + /* Dilithium has the largest public key at the moment */ + word32 pubKeyLen = DILITHIUM_MAX_PUB_KEY_SIZE; + byte* decodedPubKey = (byte*)XMALLOC(pubKeyLen, NULL, + DYNAMIC_TYPE_PUBLIC_KEY); + if (decodedPubKey == NULL) { + ret = MEMORY_E; + } + if (ret == 0) { + if (der->sapkiOID == RSAk || der->sapkiOID == ECDSAk) { + /* Simply copy the data */ + XMEMCPY(decodedPubKey, der->sapkiDer, der->sapkiLen); + pubKeyLen = der->sapkiLen; + } + else { + ret = DecodeAsymKeyPublic(der->sapkiDer, &idx, der->sapkiLen, + decodedPubKey, &pubKeyLen, + der->sapkiOID); + } + } + if (ret == 0) { + ret = wc_CheckPrivateKey(key, keySz, decodedPubKey, pubKeyLen, + (enum Key_Sum) der->sapkiOID); + } + XFREE(decodedPubKey, NULL, DYNAMIC_TYPE_PUBLIC_KEY); + } + else +#endif + { + ret = wc_CheckPrivateKey(key, keySz, der->publicKey, + der->pubKeySize, (enum Key_Sum) der->keyOID); + } + + (void)checkAlt; + + return ret; } #endif /* HAVE_PKCS12 || !NO_CHECK_PRIVATE_KEY */ @@ -15585,8 +15627,15 @@ int DecodeToKey(DecodedCert* cert, int verify) int ret; int badDate = 0; +#ifdef WOLFSSL_DUAL_ALG_CERTS + /* Call internal version and decode completely to also handle extensions. + * This is required to parse a potential alternative public key in the + * SubjectAlternativeKey extension. */ + ret = DecodeCertInternal(cert, verify, NULL, &badDate, 0, 0); +#else /* Call internal version and stop after public key. */ ret = DecodeCertInternal(cert, verify, NULL, &badDate, 0, 1); +#endif /* Always return date errors. */ if (ret == 0) { ret = badDate; @@ -23753,6 +23802,45 @@ int ParseCertRelative(DecodedCert* cert, int type, int verify, void* cm) WOLFSSL_ERROR_VERBOSE(ret); return ret; } + + #ifdef WOLFSSL_DUAL_ALG_CERTS + if ((ret == 0) && cert->extAltSigAlgSet && + cert->extAltSigValSet) { + #ifndef WOLFSSL_SMALL_STACK + byte der[MAX_CERT_VERIFY_SZ]; + #else + byte *der = (byte*)XMALLOC(MAX_CERT_VERIFY_SZ, ssl->heap, + DYNAMIC_TYPE_DCERT); + if (der == NULL) { + ret = MEMORY_E; + } + #endif /* ! WOLFSSL_SMALL_STACK */ + + if (ret == 0) { + ret = wc_GeneratePreTBS(cert, der, MAX_CERT_VERIFY_SZ); + + if (ret > 0) { + ret = ConfirmSignature(&cert->sigCtx, der, ret, + cert->ca->sapkiDer, cert->ca->sapkiLen, + cert->ca->sapkiOID, cert->altSigValDer, + cert->altSigValLen, cert->altSigAlgOID, + NULL, 0, NULL); + } + #ifdef WOLFSSL_SMALL_STACK + XFREE(der, ssl->heap, DYNAMIC_TYPE_DCERT); + #endif /* WOLFSSL_SMALL_STACK */ + + if (ret != 0) { + WOLFSSL_MSG("Confirm alternative signature failed"); + WOLFSSL_ERROR_VERBOSE(ret); + return ret; + } + else { + WOLFSSL_MSG("Alt signature has been verified!"); + } + } + } + #endif /* WOLFSSL_DUAL_ALG_CERTS */ } #ifndef IGNORE_NAME_CONSTRAINTS if (verify == VERIFY || verify == VERIFY_OCSP || @@ -23852,6 +23940,9 @@ void FreeSigner(Signer* signer, void* heap) (void)heap; XFREE(signer->name, heap, DYNAMIC_TYPE_SUBJECT_CN); XFREE((void*)signer->publicKey, heap, DYNAMIC_TYPE_PUBLIC_KEY); +#ifdef WOLFSSL_DUAL_ALG_CERTS + XFREE(signer->sapkiDer, heap, DYNAMIC_TYPE_PUBLIC_KEY); +#endif #ifndef IGNORE_NAME_CONSTRAINTS if (signer->permittedNames) FreeNameSubtrees(signer->permittedNames, heap); @@ -28190,7 +28281,8 @@ int SetName(byte* output, word32 outputSz, CertName* name) static int EncodePublicKey(int keyType, byte* output, int outLen, RsaKey* rsaKey, ecc_key* eccKey, ed25519_key* ed25519Key, ed448_key* ed448Key, - DsaKey* dsaKey) + DsaKey* dsaKey, falcon_key* falconKey, + dilithium_key* dilithiumKey, sphincs_key* sphincsKey) { int ret = 0; @@ -28200,6 +28292,9 @@ static int EncodePublicKey(int keyType, byte* output, int outLen, (void)ed25519Key; (void)ed448Key; (void)dsaKey; + (void)falconKey; + (void)dilithiumKey; + (void)sphincsKey; switch (keyType) { #ifndef NO_RSA @@ -28235,6 +28330,41 @@ static int EncodePublicKey(int keyType, byte* output, int outLen, } break; #endif + #if defined(HAVE_PQC) && defined(HAVE_FALCON) + case FALCON_LEVEL1_KEY: + case FALCON_LEVEL5_KEY: + ret = wc_Falcon_PublicKeyToDer(falconKey, output, + (word32)outLen, 1); + if (ret <= 0) { + ret = PUBLIC_KEY_E; + } + break; + #endif /* HAVE_PQC && HAVE_FALCON */ + #if defined(HAVE_PQC) && defined(HAVE_DILITHIUM) + case DILITHIUM_LEVEL2_KEY: + case DILITHIUM_LEVEL3_KEY: + case DILITHIUM_LEVEL5_KEY: + ret = wc_Dilithium_PublicKeyToDer(dilithiumKey, output, + (word32)outLen, 1); + if (ret <= 0) { + ret = PUBLIC_KEY_E; + } + break; + #endif /* HAVE_PQC && HAVE_DILITHIUM */ + #if defined(HAVE_PQC) && defined(HAVE_SPHINCS) + case SPHINCS_FAST_LEVEL1_KEY: + case SPHINCS_FAST_LEVEL3_KEY: + case SPHINCS_FAST_LEVEL5_KEY: + case SPHINCS_SMALL_LEVEL1_KEY: + case SPHINCS_SMALL_LEVEL3_KEY: + case SPHINCS_SMALL_LEVEL5_KEY: + ret = wc_Sphincs_PublicKeyToDer(sphincsKey, output, + (word32)outLen, 1); + if (ret <= 0) { + ret = PUBLIC_KEY_E; + } + break; + #endif /* HAVE_PQC && HAVE_SPHINCS */ default: ret = PUBLIC_KEY_E; break; @@ -30001,7 +30131,8 @@ static int MakeAnyCert(Cert* cert, byte* derBuffer, word32 derSz, if (ret >= 0) { /* Calculate public key encoding size. */ ret = EncodePublicKey(cert->keyType, NULL, 0, rsaKey, - eccKey, ed25519Key, ed448Key, dsaKey); + eccKey, ed25519Key, ed448Key, dsaKey, falconKey, + dilithiumKey, sphincsKey); publicKeySz = (word32)ret; } if (ret >= 0) { @@ -30181,7 +30312,8 @@ static int MakeAnyCert(Cert* cert, byte* derBuffer, word32 derSz, .data.buffer.data, (int)dataASN[X509CERTASN_IDX_TBS_SPUBKEYINFO_SEQ] .data.buffer.length, - rsaKey, eccKey, ed25519Key, ed448Key, dsaKey); + rsaKey, eccKey, ed25519Key, ed448Key, dsaKey, + falconKey, dilithiumKey, sphincsKey); } if ((ret >= 0) && (!dataASN[X509CERTASN_IDX_TBS_EXT_SEQ].noOut)) { /* Encode extensions into buffer. */ @@ -30262,6 +30394,7 @@ int wc_MakeCert(Cert* cert, byte* derBuffer, word32 derSz, RsaKey* rsaKey, NULL, NULL, NULL, NULL); } + #ifdef WOLFSSL_CERT_REQ #ifndef WOLFSSL_ASN_TEMPLATE @@ -31048,7 +31181,8 @@ static int MakeCertReq(Cert* cert, byte* derBuffer, word32 derSz, if (ret >= 0) { /* Determine encode public key size. */ ret = EncodePublicKey(cert->keyType, NULL, 0, rsaKey, - eccKey, ed25519Key, ed448Key, dsaKey); + eccKey, ed25519Key, ed448Key, dsaKey, falconKey, + dilithiumKey, sphincsKey); publicKeySz = (word32)ret; } if (ret >= 0) { @@ -31162,7 +31296,8 @@ static int MakeCertReq(Cert* cert, byte* derBuffer, word32 derSz, ret = EncodePublicKey(cert->keyType, (byte*)dataASN[CERTREQBODYASN_IDX_SPUBKEYINFO_SEQ].data.buffer.data, (int)dataASN[CERTREQBODYASN_IDX_SPUBKEYINFO_SEQ].data.buffer.length, - rsaKey, eccKey, ed25519Key, ed448Key, dsaKey); + rsaKey, eccKey, ed25519Key, ed448Key, dsaKey, falconKey, + dilithiumKey, sphincsKey); } if ((ret >= 0 && derBuffer != NULL) && (!dataASN[CERTREQBODYASN_IDX_EXT_BODY].noOut)) { @@ -31486,6 +31621,7 @@ int wc_SignCert(int requestSz, int sType, byte* buf, word32 buffSz, NULL, NULL, NULL, rng); } + WOLFSSL_ABI int wc_MakeSelfCert(Cert* cert, byte* buf, word32 buffSz, RsaKey* key, WC_RNG* rng) diff --git a/wolfcrypt/src/dilithium.c b/wolfcrypt/src/dilithium.c index f8968c561..ed45579c8 100644 --- a/wolfcrypt/src/dilithium.c +++ b/wolfcrypt/src/dilithium.c @@ -395,7 +395,7 @@ int wc_dilithium_export_public(dilithium_key* key, return BAD_FUNC_ARG; } - if ((key->level != 1) && (key->level != 5)) { + if ((key->level != 2) && (key->level != 3) && (key->level != 5)) { return BAD_FUNC_ARG; } @@ -914,11 +914,11 @@ int wc_Dilithium_PrivateKeyDecode(const byte* input, word32* inOutIdx, pubKey, &pubKeyLen, keytype); if (ret == 0) { if (pubKeyLen == 0) { - ret = wc_dilithium_import_private_only(input, inSz, key); + ret = wc_dilithium_import_private_key(input, inSz, NULL, 0, key); } else { - ret = wc_dilithium_import_private_key(privKey, privKeyLen, - pubKey, pubKeyLen, key); + ret = wc_dilithium_import_private_key(input, inSz, pubKey, + pubKeyLen, key); } } return ret; @@ -983,7 +983,7 @@ int wc_Dilithium_PublicKeyToDer(dilithium_key* key, byte* output, word32 inLen, word32 pubKeyLen = (word32)sizeof(pubKey); int keytype = 0; - if (key == NULL || output == NULL) { + if (key == NULL) { return BAD_FUNC_ARG; } diff --git a/wolfcrypt/src/falcon.c b/wolfcrypt/src/falcon.c index 2645db639..f01288971 100644 --- a/wolfcrypt/src/falcon.c +++ b/wolfcrypt/src/falcon.c @@ -846,11 +846,11 @@ int wc_Falcon_PrivateKeyDecode(const byte* input, word32* inOutIdx, pubKey, &pubKeyLen, keytype); if (ret == 0) { if (pubKeyLen == 0) { - ret = wc_falcon_import_private_only(input, inSz, key); + ret = wc_falcon_import_private_key(input, inSz, NULL, 0, key); } else { - ret = wc_falcon_import_private_key(privKey, privKeyLen, - pubKey, pubKeyLen, key); + ret = wc_falcon_import_private_key(input, inSz, pubKey, + pubKeyLen, key); } } return ret; @@ -912,7 +912,7 @@ int wc_Falcon_PublicKeyToDer(falcon_key* key, byte* output, word32 inLen, word32 pubKeyLen = (word32)sizeof(pubKey); int keytype = 0; - if (key == NULL || output == NULL) { + if (key == NULL) { return BAD_FUNC_ARG; } diff --git a/wolfcrypt/src/pkcs12.c b/wolfcrypt/src/pkcs12.c index 123b2e9db..e76f1b1a8 100644 --- a/wolfcrypt/src/pkcs12.c +++ b/wolfcrypt/src/pkcs12.c @@ -1120,7 +1120,7 @@ static WARN_UNUSED_RESULT int freeDecCertList(WC_DerCertList** list, InitDecodedCert(DeCert, current->buffer, current->bufferSz, heap); if (ParseCertRelative(DeCert, CERT_TYPE, NO_VERIFY, NULL) == 0) { - if (wc_CheckPrivateKeyCert(*pkey, *pkeySz, DeCert) == 1) { + if (wc_CheckPrivateKeyCert(*pkey, *pkeySz, DeCert, 0) == 1) { WOLFSSL_MSG("Key Pair found"); *cert = current->buffer; *certSz = current->bufferSz; diff --git a/wolfcrypt/src/sphincs.c b/wolfcrypt/src/sphincs.c index a0196ce39..6556fdb5d 100644 --- a/wolfcrypt/src/sphincs.c +++ b/wolfcrypt/src/sphincs.c @@ -952,7 +952,7 @@ int wc_Sphincs_PublicKeyToDer(sphincs_key* key, byte* output, word32 inLen, word32 pubKeyLen = (word32)sizeof(pubKey); int keytype = 0; - if (key == NULL || output == NULL) { + if (key == NULL) { return BAD_FUNC_ARG; } diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 258cb034e..a13f86580 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -1915,10 +1915,10 @@ enum Misc { #ifdef HAVE_PQC #ifndef MIN_FALCONKEY_SZ - #define MIN_FALCONKEY_SZ 897 + #define MIN_FALCONKEY_SZ 1281 #endif #ifndef MIN_DILITHIUMKEY_SZ - #define MIN_DILITHIUMKEY_SZ 1312 + #define MIN_DILITHIUMKEY_SZ 2528 #endif #endif @@ -3583,8 +3583,11 @@ struct WOLFSSL_CTX { #ifdef WOLFSSL_DUAL_ALG_CERTS DerBuffer* altPrivateKey; - byte altPrivateKeyType; + byte altPrivateKeyType:6; + byte altPrivateKeyId:1; + byte altPrivateKeyLabel:1; int altPrivateKeySz; + int altPrivateKeyDevId; #endif /* WOLFSSL_DUAL_ALG_CERTS */ #ifdef OPENSSL_ALL WOLFSSL_EVP_PKEY* privateKeyPKey; @@ -4548,15 +4551,18 @@ typedef struct Buffers { #ifndef NO_CERTS DerBuffer* certificate; /* WOLFSSL_CTX owns, unless we own */ DerBuffer* key; /* WOLFSSL_CTX owns, unless we own */ - byte keyType:6; /* Type of key: RSA, ECC, Ed25519 */ + byte keyType:6; /* Type of key */ byte keyId:1; /* Key data is an id not data */ byte keyLabel:1; /* Key data is a label not data */ int keySz; /* Size of RSA key */ int keyDevId; /* Device Id for key */ #ifdef WOLFSSL_DUAL_ALG_CERTS DerBuffer* altKey; /* WOLFSSL_CTX owns, unless we own */ - byte altKeyType; /* Type of key: dilithium, falcon */ - int altKeySz; /* Size of key */ + byte altKeyType:6; /* Type of alt key */ + byte altKeyId:1; /* Key data is an id not data */ + byte altKeyLabel:1; /* Key data is a label not data */ + int altKeySz; /* Size of alt key */ + int altKeyDevId; /* Device Id for alt key */ #endif DerBuffer* certChain; /* WOLFSSL_CTX owns, unless we own */ /* chain after self, in DER, with leading size for each cert */ diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 804ec44bb..cb36864cd 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -3096,6 +3096,17 @@ WOLFSSL_API int wolfSSL_make_eap_keys(WOLFSSL* ssl, void* key, unsigned int len, const unsigned char* in, long sz, int format); WOLFSSL_API int wolfSSL_CTX_use_certificate_chain_buffer(WOLFSSL_CTX* ctx, const unsigned char* in, long sz); +#ifdef WOLFSSL_DUAL_ALG_CERTS + WOLFSSL_API int wolfSSL_CTX_use_AltPrivateKey_buffer(WOLFSSL_CTX* ctx, + const unsigned char* in, long sz, int format); + WOLFSSL_API int wolfSSL_CTX_use_AltPrivateKey_id(WOLFSSL_CTX* ctx, + const unsigned char* id, long sz, + int devId, long keySz); + WOLFSSL_API int wolfSSL_CTX_use_AltPrivateKey_Id(WOLFSSL_CTX* ctx, + const unsigned char* id, long sz, int devId); + WOLFSSL_API int wolfSSL_CTX_use_AltPrivateKey_Label(WOLFSSL_CTX* ctx, + const char* label, int devId); +#endif /* SSL versions */ WOLFSSL_API int wolfSSL_use_certificate_buffer(WOLFSSL* ssl, const unsigned char* in, @@ -3114,6 +3125,17 @@ WOLFSSL_API int wolfSSL_make_eap_keys(WOLFSSL* ssl, void* key, unsigned int len, WOLFSSL_API int wolfSSL_use_certificate_chain_buffer(WOLFSSL* ssl, const unsigned char* in, long sz); WOLFSSL_API int wolfSSL_UnloadCertsKeys(WOLFSSL* ssl); +#ifdef WOLFSSL_DUAL_ALG_CERTS + WOLFSSL_API int wolfSSL_use_AltPrivateKey_buffer(WOLFSSL* ssl, + const unsigned char* in, long sz, int format); + WOLFSSL_API int wolfSSL_use_AltPrivateKey_id(WOLFSSL* ssl, + const unsigned char* id, long sz, + int devId, long keySz); + WOLFSSL_API int wolfSSL_use_AltPrivateKey_Id(WOLFSSL* ssl, + const unsigned char* id, long sz, int devId); + WOLFSSL_API int wolfSSL_use_AltPrivateKey_Label(WOLFSSL* ssl, + const char* label, int devId); +#endif #if (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) && \ defined(KEEP_OUR_CERT) diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index 01eb03c20..e8a6f99dd 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -969,6 +969,9 @@ enum Misc_ASN { MAX_DSA_PRIVKEY_SZ = (DSA_INTS * MAX_DSA_INT_SZ) + MAX_SEQ_SZ + MAX_VERSION_SZ, /* Maximum size of a DSA Private key taken from DsaKeyIntsToDer. */ +#if defined(HAVE_PQC) + MAX_PQC_PUBLIC_KEY_SZ = 2592, /* Maximum size of a Dilithium public key. */ +#endif MAX_RSA_E_SZ = 16, /* Max RSA public e size */ MAX_CA_SZ = 32, /* Max encoded CA basic constraint length */ MAX_SN_SZ = 35, /* Max encoded serial number (INT) length */ @@ -1015,7 +1018,11 @@ enum Misc_ASN { OCSP_NONCE_EXT_SZ = 35, /* OCSP Nonce Extension size */ MAX_OCSP_EXT_SZ = 58, /* Max OCSP Extension length */ MAX_OCSP_NONCE_SZ = 16, /* OCSP Nonce size */ +#if defined(HAVE_PQC) + MAX_PUBLIC_KEY_SZ = MAX_PQC_PUBLIC_KEY_SZ + MAX_ALGO_SZ + MAX_SEQ_SZ * 2, +#else MAX_PUBLIC_KEY_SZ = MAX_DSA_PUBKEY_SZ + MAX_ALGO_SZ + MAX_SEQ_SZ * 2, +#endif #ifdef WOLFSSL_ENCRYPTED_KEYS HEADER_ENCRYPTED_KEY_SIZE = 88,/* Extra header size for encrypted key */ #else @@ -2017,10 +2024,9 @@ struct Signer { word32 cm_idx; #endif #ifdef WOLFSSL_DUAL_ALG_CERTS - /* The Subject Alternative Public Key Info (SAPKI) will NOT be cached. - * Caching of it is NOT SUPPORTED yet. */ - byte *sapkiDer; - int sapkiLen; + word32 sapkiOID; /* key type */ + byte* sapkiDer; + int sapkiLen; #endif /* WOLFSSL_DUAL_ALG_CERTS */ byte type; @@ -2308,7 +2314,8 @@ WOLFSSL_LOCAL int GetNameHash(const byte* source, word32* idx, byte* hash, int maxIdx); WOLFSSL_LOCAL int GetNameHash_ex(const byte* source, word32* idx, byte* hash, int maxIdx, word32 sigOID); -WOLFSSL_LOCAL int wc_CheckPrivateKeyCert(const byte* key, word32 keySz, DecodedCert* der); +WOLFSSL_LOCAL int wc_CheckPrivateKeyCert(const byte* key, word32 keySz, + DecodedCert* der, int checkAlt); WOLFSSL_LOCAL int wc_CheckPrivateKey(const byte* privKey, word32 privKeySz, const byte* pubKey, word32 pubKeySz, enum Key_Sum ks); WOLFSSL_LOCAL int StoreDHparams(byte* out, word32* outLen, mp_int* p, mp_int* g); diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index bc544c70b..5f301cb7a 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -2008,6 +2008,7 @@ extern void uITRON4_free(void *p) ; #define WOLFSSL_DH_CONST #define WOLFSSL_HAVE_MAX #define NO_WRITEV + #define NO_STDLIB_ISASCII #define USE_FLAT_BENCHMARK_H #define USE_FLAT_TEST_H