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