diff --git a/configure.ac b/configure.ac index 87eb28026..d20614d8f 100644 --- a/configure.ac +++ b/configure.ac @@ -243,6 +243,7 @@ AC_ARG_ENABLE([tls13], if test "$ENABLED_TLS13" = "yes" then AM_CFLAGS="-DWOLFSSL_TLS13 -DHAVE_TLS_EXTENSIONS -DHAVE_FFDHE_2048 $AM_CFLAGS" + AM_CFLAGS="-DWC_RSA_PSS $AM_CFLAGS" fi # check if TLS v1.3 was enabled for conditionally running tls13.test script diff --git a/src/internal.c b/src/internal.c index 25fa2ac48..a6db2d19d 100755 --- a/src/internal.c +++ b/src/internal.c @@ -2773,8 +2773,9 @@ int RsaSign(WOLFSSL* ssl, const byte* in, word32 inSz, byte* out, return ret; } -int RsaVerify(WOLFSSL* ssl, byte* in, word32 inSz, - byte** out, RsaKey* key, const byte* keyBuf, word32 keySz, void* ctx) +int RsaVerify(WOLFSSL* ssl, byte* in, word32 inSz, byte** out, int sigAlgo, + int hashAlgo, RsaKey* key, const byte* keyBuf, word32 keySz, + void* ctx) { int ret; @@ -2782,6 +2783,8 @@ int RsaVerify(WOLFSSL* ssl, byte* in, word32 inSz, (void)keyBuf; (void)keySz; (void)ctx; + (void)sigAlgo; + (void)hashAlgo; WOLFSSL_ENTER("RsaVerify"); @@ -2792,7 +2795,37 @@ int RsaVerify(WOLFSSL* ssl, byte* in, word32 inSz, else #endif /*HAVE_PK_CALLBACKS */ { - ret = wc_RsaSSL_VerifyInline(in, inSz, out, key); +#ifdef WOLFSSL_TLS13 + #ifdef WC_RSA_PSS + if (sigAlgo == rsa_pss_sa_algo) { + enum wc_HashType hashType = WC_HASH_TYPE_NONE; + int mgf = 0; + switch (hashAlgo) { + case sha512_mac: + #ifdef WOLFSSL_SHA512 + hashType = WC_HASH_TYPE_SHA512; + mgf = WC_MGF1SHA512; + #endif + break; + case sha384_mac: + #ifdef WOLFSSL_SHA384 + hashType = WC_HASH_TYPE_SHA384; + mgf = WC_MGF1SHA384; + #endif + break; + case sha256_mac: + #ifndef NO_SHA256 + hashType = WC_HASH_TYPE_SHA256; + mgf = WC_MGF1SHA256; + #endif + break; + } + ret = wc_RsaPSS_VerifyInline(in, inSz, out, hashType, mgf, key); + } + else + #endif +#endif + ret = wc_RsaSSL_VerifyInline(in, inSz, out, key); } /* Handle async pending response */ @@ -16323,6 +16356,7 @@ static int DoServerKeyExchange(WOLFSSL* ssl, const byte* input, ret = RsaVerify(ssl, args->verifySig, args->verifySigSz, &args->output, + rsa_sa_algo, no_mac, ssl->peerRsaKey, #ifdef HAVE_PK_CALLBACKS ssl->buffers.peerRsaKey.buffer, @@ -21091,6 +21125,7 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, input + args->idx, args->sz, &args->output, + rsa_sa_algo, no_mac, ssl->peerRsaKey, #ifdef HAVE_PK_CALLBACKS ssl->buffers.peerRsaKey.buffer, diff --git a/src/tls.c b/src/tls.c index 24943275f..796fc89fa 100755 --- a/src/tls.c +++ b/src/tls.c @@ -40,6 +40,10 @@ #include #endif +#ifdef HAVE_CURVE25519 + #include +#endif + #ifdef HAVE_NTRU #include "libntruencrypt/ntru_crypto.h" #include @@ -4304,9 +4308,9 @@ static word16 TLSX_SupportedVersions_Write(byte* data, byte* output) /* TODO: [TLS13] Remove code when TLS v1.3 becomes an RFC. */ if (pv.minor - i == TLSv1_3_MINOR) { /* The TLS draft major number. */ - *(output++) = 0x7f; + *(output++) = TLS_DRAFT_MAJOR; /* Version of draft supported. */ - *(output++) = 18; + *(output++) = TLS_DRAFT_MINOR; continue; } @@ -4347,7 +4351,8 @@ static int TLSX_SupportedVersions_Parse(WOLFSSL *ssl, byte* input, /* Find first match. */ for (i = 0; i < len; i += OPAQUE16_LEN) { /* TODO: [TLS13] Remove code when TLS v1.3 becomes an RFC. */ - if (input[i] == 0x7f && input[i + OPAQUE8_LEN] == 18) { + if (input[i] == TLS_DRAFT_MAJOR && + input[i + OPAQUE8_LEN] == TLS_DRAFT_MINOR) { ssl->version.minor = TLSv1_3_MINOR; ssl->options.tls1_3 = 1; TLSX_Push(&ssl->extensions, TLSX_SUPPORTED_VERSIONS, input, @@ -4411,6 +4416,199 @@ static int TLSX_SetSupportedVersions(TLSX** extensions, const void* data, #endif /* WOLFSSL_TLS13 */ +/******************************************************************************/ +/* Sugnature Algorithms */ +/******************************************************************************/ + +#ifdef WOLFSSL_TLS13 +/* Return the size of the SignatureAlgorithms extension's data. + * + * data Unused + * returns the length of data that will be in the extension. + */ +static word16 TLSX_SignatureAlgorithms_GetSize(byte* data) +{ + int cnt = 0; + + (void)data; + +#ifndef NO_RSA + #ifndef NO_SHA1 + cnt++; + #endif + #ifndef NO_SHA256 + cnt++; + #endif + #ifdef HAVE_SHA384 + cnt++; + #endif + #ifdef HAVE_SHA512 + cnt++; + #endif + #ifdef WC_RSA_PSS + #ifndef NO_SHA256 + cnt++; + #endif + #ifdef HAVE_SHA384 + cnt++; + #endif + #ifdef HAVE_SHA512 + cnt++; + #endif + #endif +#endif + +#ifdef HAVE_ECC + #if !defined(NO_ECC256) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + cnt++; + #endif + #endif + #if !defined(NO_ECC384) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + cnt++; + #endif + #endif + #if !defined(NO_ECC521) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + cnt++; + #endif + #endif +#endif + + return OPAQUE16_LEN + cnt * OPAQUE16_LEN; +} + +/* Writes the SignatureAlgorithms extension into the buffer. + * + * data Unused + * output The buffer to write the extension into. + * returns the length of data that was written. + */ +static word16 TLSX_SignatureAlgorithms_Write(byte* data, byte* output) +{ + int idx = OPAQUE16_LEN; + + (void)data; + +#ifndef NO_RSA + #ifndef NO_SHA1 + output[idx++] = 0x02; + output[idx++] = 0x01; + #endif + #ifndef NO_SHA256 + output[idx++] = 0x04; + output[idx++] = 0x01; + #endif + #ifdef HAVE_SHA384 + output[idx++] = 0x05; + output[idx++] = 0x01; + #endif + #ifdef HAVE_SHA512 + output[idx++] = 0x06; + output[idx++] = 0x01; + #endif + #ifdef WC_RSA_PSS + #ifndef NO_SHA256 + output[idx++] = 0x08; + output[idx++] = 0x04; + #endif + #ifdef HAVE_SHA384 + output[idx++] = 0x08; + output[idx++] = 0x05; + #endif + #ifdef HAVE_SHA512 + output[idx++] = 0x08; + output[idx++] = 0x06; + #endif + #endif +#endif + +#ifdef HAVE_ECC + #if !defined(NO_ECC256) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + output[idx++] = 0x04; + output[idx++] = 0x03; + #endif + #endif + #if !defined(NO_ECC384) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + output[idx++] = 0x05; + output[idx++] = 0x03; + #endif + #endif + #if !defined(NO_ECC521) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + output[idx++] = 0x06; + output[idx++] = 0x03; + #endif + #endif +#endif + + output[0] = (idx - OPAQUE16_LEN) >> 8; + output[1] = idx - OPAQUE16_LEN; + + return idx; +} + +/* Parse the SignatureAlgorithms extension. + * + * ssl The SSL/TLS object. + * input The buffer with the extension data. + * length The length of the extension data. + * returns 0 on success, otherwise failure. + */ +static int TLSX_SignatureAlgorithms_Parse(WOLFSSL *ssl, byte* input, + word16 length) +{ + int ret = 0; + word16 len; + + (void)ssl; + + /* Must contain a length and at least algorithm. */ + if (length < OPAQUE16_LEN + OPAQUE16_LEN || (length & 1) != 0) + return BUFFER_ERROR; + + ato16(input, &len); + + /* Algorithm array must fill rest of data. */ + if (length != OPAQUE16_LEN + len) + return BUFFER_ERROR; + + /* Ignore for now. */ + + return ret; +} + +/* Sets a new SupportedVersions extension into the extension list. + * + * extensions The list of extensions. + * data The extensions specific data. + * heap The heap used for allocation. + * returns 0 on success, otherwise failure. + */ +static int TLSX_SetSignatureAlgorithms(TLSX** extensions, const void* data, + void* heap) +{ + if (extensions == NULL) + return BAD_FUNC_ARG; + + return TLSX_Push(extensions, TLSX_SIGNATURE_ALGORITHMS, (void *)data, heap); +} + +#define SA_GET_SIZE TLSX_SignatureAlgorithms_GetSize +#define SA_WRITE TLSX_SignatureAlgorithms_Write +#define SA_PARSE TLSX_SignatureAlgorithms_Parse + +#else + +#define SA_GET_SIZE(a) 0 +#define SA_WRITE(a, b) 0 +#define SA_PARSE(a, b, c) 0 + +#endif + /******************************************************************************/ /* Key Share */ /******************************************************************************/ @@ -4588,9 +4786,52 @@ static int TLSX_KeyShare_GenEccKey(WOLFSSL *ssl, KeyShareEntry* kse) #endif #ifdef HAVE_CURVE25519 case WOLFSSL_ECC_X25519: - curveId = ECC_X25519; - dataSize = keySize = 32; - break; + { + curve25519_key* key; + /* Allocate an ECC key to hold private key. */ + key = (curve25519_key*)XMALLOC(sizeof(curve25519_key), + ssl->heap, DYNAMIC_TYPE_TLSX); + if (key == NULL) { + WOLFSSL_MSG("EccTempKey Memory error"); + return MEMORY_E; + } + + dataSize = keySize = 32; + + /* Make an ECC key. */ + ret = wc_curve25519_init(key); + if (ret != 0) + goto end; + ret = wc_curve25519_make_key(ssl->rng, keySize, key); + if (ret != 0) + goto end; + + /* Allocate space for the public key. */ + keyData = XMALLOC(dataSize, ssl->heap, DYNAMIC_TYPE_TLSX); + if (keyData == NULL) { + WOLFSSL_MSG("Key data Memory error"); + ret = MEMORY_E; + goto end; + } + + /* Export public key. */ + if (wc_curve25519_export_public_ex(key, keyData, &dataSize, + EC25519_LITTLE_ENDIAN) != 0) { + ret = ECC_EXPORT_ERROR; + goto end; + } + + kse->ke = keyData; + kse->keLen = dataSize; + kse->key = key; + +#ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG("Public ECC Key"); + WOLFSSL_BUFFER(keyData, dataSize); +#endif + + goto end; + } #endif #ifdef HAVE_X448 case WOLFSSL_ECC_X448: @@ -4922,8 +5163,42 @@ static int TLSX_KeyShare_ProcessEcc(WOLFSSL* ssl, KeyShareEntry* keyShareEntry) #endif #ifdef HAVE_CURVE25519 case WOLFSSL_ECC_X25519: - curveId = ECC_X25519; - break; + { + curve25519_key* key = (curve25519_key*)keyShareEntry->key; + curve25519_key* peerEccKey; + + if (ssl->peerEccKey != NULL) + wc_ecc_free(ssl->peerEccKey); + + peerEccKey = (curve25519_key*)XMALLOC(sizeof(curve25519_key), + ssl->heap, DYNAMIC_TYPE_TLSX); + if (peerEccKey == NULL) { + WOLFSSL_MSG("PeerEccKey Memory error"); + return MEMORY_ERROR; + } + ret = wc_curve25519_init(peerEccKey); + if (ret != 0) + return ret; +#ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG("Peer ECC Key"); + WOLFSSL_BUFFER(keyShareEntry->ke, keyShareEntry->keLen); +#endif + + /* Point is validated by import function. */ + if (wc_curve25519_import_public_ex(keyShareEntry->ke, + keyShareEntry->keLen, peerEccKey, + EC25519_LITTLE_ENDIAN) != 0) { + return ECC_PEERKEY_ERROR; + } + + ssl->arrays->preMasterSz = ENCRYPT_LEN; + ret = wc_curve25519_shared_secret_ex(key, peerEccKey, + ssl->arrays->preMasterSecret, &ssl->arrays->preMasterSz, + EC25519_LITTLE_ENDIAN); + wc_curve25519_free(peerEccKey); + XFREE(peerEccKey, ssl->heap, DYNAMIC_TYPE_TLSX); + return ret; + } #endif #ifdef HAVE_X448 case WOLFSSL_ECC_X448: @@ -6136,6 +6411,9 @@ void TLSX_FreeAll(TLSX* list, void* heap) ALPN_FREE_ALL((ALPN*)extension->data, heap); break; + case TLSX_SIGNATURE_ALGORITHMS: + break; + #ifdef WOLFSSL_TLS13 case TLSX_SUPPORTED_VERSIONS: break; @@ -6237,6 +6515,12 @@ static word16 TLSX_GetSize(TLSX* list, byte* semaphore, byte msgType) length += ALPN_GET_SIZE((ALPN*)extension->data); break; + case TLSX_SIGNATURE_ALGORITHMS: +#ifdef WOLFSSL_TLS13 + length += SA_GET_SIZE(extension->data); +#endif + break; + #ifdef WOLFSSL_TLS13 case TLSX_SUPPORTED_VERSIONS: length += SV_GET_SIZE(extension->data); @@ -6355,6 +6639,13 @@ static word16 TLSX_Write(TLSX* list, byte* output, byte* semaphore, offset += ALPN_WRITE((ALPN*)extension->data, output + offset); break; + case TLSX_SIGNATURE_ALGORITHMS: +#ifdef WOLFSSL_TLS13 + WOLFSSL_MSG("Signature Algorithms extension to write"); + offset += SA_WRITE(extension->data, output + offset); +#endif + break; + #ifdef WOLFSSL_TLS13 case TLSX_SUPPORTED_VERSIONS: WOLFSSL_MSG("Supported Versions extension to write"); @@ -6760,6 +7051,15 @@ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer) if (ret != SSL_SUCCESS) return ret; #endif #endif + #ifdef WOLFSSL_TLS13 + #if defined(HAVE_CURVE25519) + #ifndef NO_ECC_SECP + ret = TLSX_UseSupportedCurve(&ssl->extensions, + WOLFSSL_ECC_X25519, ssl->heap); + if (ret != SSL_SUCCESS) return ret; + #endif + #endif + #endif } #endif /* HAVE_ECC && HAVE_SUPPORTED_CURVES */ } /* is not server */ @@ -6771,6 +7071,11 @@ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer) if ((ret = TLSX_SetSupportedVersions(&ssl->extensions, ssl, ssl->heap)) != 0) return ret; + /* Add TLS v1.3 extension: signature algorithms */ + WOLFSSL_MSG("Adding signature algorithms extension"); + if ((ret = TLSX_SetSignatureAlgorithms(&ssl->extensions, NULL, + ssl->heap)) != 0) + return ret; /* Add FFDHE supported groups. */ #ifdef HAVE_FFDHE_2048 @@ -6898,6 +7203,7 @@ word16 TLSX_GetRequestSize(WOLFSSL* ssl) #if defined(WOLFSSL_TLS13) if (!IsAtLeastTLSv1_3(ssl->version)) { TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS)); + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SIGNATURE_ALGORITHMS)); TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE)); #ifndef NO_PSK TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY)); @@ -6914,9 +7220,11 @@ word16 TLSX_GetRequestSize(WOLFSSL* ssl) client_hello); } +#ifndef WOLFSSL_TLS13 if (IsAtLeastTLSv1_2(ssl) && ssl->suites->hashSigAlgoSz) - length += HELLO_EXT_SZ + HELLO_EXT_SIGALGO_SZ + length += HELLO_EXT_SZ + OPAQUE16_LEN + + ssl->suites->hashSigAlgoSz; +#endif #ifdef HAVE_EXTENDED_MASTER if (ssl->options.haveEMS) @@ -6946,6 +7254,7 @@ word16 TLSX_WriteRequest(WOLFSSL* ssl, byte* output) #if defined(WOLFSSL_TLS13) if (!IsAtLeastTLSv1_3(ssl->version)) { TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS)); + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SIGNATURE_ALGORITHMS)); TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE)); #ifndef NO_PSK TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PSK_KEY_EXCHANGE_MODES)); @@ -6964,10 +7273,11 @@ word16 TLSX_WriteRequest(WOLFSSL* ssl, byte* output) offset += TLSX_Write(ssl->ctx->extensions, output + offset, semaphore, client_hello); +#ifndef WOLFSSL_TLS13 if (IsAtLeastTLSv1_2(ssl) && ssl->suites->hashSigAlgoSz) { int i; /* extension type */ - c16toa(HELLO_EXT_SIG_ALGO, output + offset); + c16toa(TLSX_SIGNATURE_ALGORITHMS, output + offset); offset += HELLO_EXT_TYPE_SZ; /* extension data length */ @@ -6983,6 +7293,7 @@ word16 TLSX_WriteRequest(WOLFSSL* ssl, byte* output) for (i = 0; i < ssl->suites->hashSigAlgoSz; i++, offset++) output[offset] = ssl->suites->hashSigAlgo[i]; } +#endif #ifdef HAVE_EXTENDED_MASTER if (ssl->options.haveEMS) { @@ -7285,16 +7596,11 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte msgType, ret = ALPN_PARSE(ssl, input + offset, size, isRequest); break; - case HELLO_EXT_SIG_ALGO: +#ifndef WOLFSSL_TLS13 + case TLSX_SIGNATURE_ALGORITHMS: WOLFSSL_MSG("Extended signature algorithm extension received"); if (isRequest) { -#ifdef WOLFSSL_TLS13 - if (IsAtLeastTLSv1_3(ssl->version) && - msgType != client_hello) { - return EXT_NOT_ALLOWED; - } -#endif /* do not mess with offset inside the switch! */ if (IsAtLeastTLSv1_2(ssl)) { ato16(input + offset, &suites->hashSigAlgoSz); @@ -7312,6 +7618,7 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte msgType, } break; +#endif #ifdef WOLFSSL_TLS13 case TLSX_SUPPORTED_VERSIONS: @@ -7327,6 +7634,19 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte msgType, ret = SV_PARSE(ssl, input + offset, size); break; + case TLSX_SIGNATURE_ALGORITHMS: + WOLFSSL_MSG("Signature Algorithms extension received"); + + if (!IsAtLeastTLSv1_3(ssl->version)) + break; + + if (IsAtLeastTLSv1_3(ssl->version) && + msgType != client_hello) { + return EXT_NOT_ALLOWED; + } + ret = SA_PARSE(ssl, input + offset, size); + break; + case TLSX_KEY_SHARE: WOLFSSL_MSG("Key Share extension received"); diff --git a/src/tls13.c b/src/tls13.c index aa8d727c8..badf1d098 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -2851,12 +2851,18 @@ static INLINE void EncodeSigAlg(byte hashAlgo, byte hsType, byte* output) static INLINE void DecodeSigAlg(byte* input, byte* hashAlgo, byte* hsType) { switch (input[0]) { - /* PSS signatures: 0x080[4-6] */ + case 0x08: + /* PSS signatures: 0x080[4-6] */ + if (input[1] <= 0x06) { + *hsType = input[0]; + *hashAlgo = input[1]; + } + break; /* ED25519: 0x0807 */ /* ED448: 0x0808 */ default: *hashAlgo = input[0]; - *hsType = input[1]; + *hsType = input[1]; break; } } @@ -3048,13 +3054,14 @@ static int CreateECCEncodedSig(byte* sigData, int sigDataSz, int hashAlgo) * based on the digest of the signature data. * * ssl The SSL/TLS object. + * hashAlgo The signature algorithm used to generate signature. * hashAlgo The hash algorithm used to generate signature. * decSig The decrypted signature. * decSigSz The size of the decrypted signature. * returns 0 on success, otherwise failure. */ -static int CheckRSASignature(WOLFSSL* ssl, int hashAlgo, byte* decSig, - word32 decSigSz) +static int CheckRSASignature(WOLFSSL* ssl, int sigAlgo, int hashAlgo, + byte* decSig, word32 decSigSz) { int ret = 0; byte sigData[MAX_SIG_DATA_SZ]; @@ -3066,21 +3073,38 @@ static int CheckRSASignature(WOLFSSL* ssl, int hashAlgo, byte* decSig, #endif word32 sigSz; + if (sigAlgo == rsa_sa_algo) { #ifdef WOLFSSL_SMALL_STACK - encodedSig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, ssl->heap, - DYNAMIC_TYPE_TMP_BUFFER); - if (encodedSig == NULL) { - ret = MEMORY_E; - goto end; - } + encodedSig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, ssl->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (encodedSig == NULL) { + ret = MEMORY_E; + goto end; + } #endif - CreateSigData(ssl, sigData, &sigDataSz, 1); - sigSz = CreateRSAEncodedSig(encodedSig, sigData, sigDataSz, hashAlgo); - /* Check the encoded and decrypted signature data match. */ - if (decSigSz != sigSz || decSig == NULL || - XMEMCMP(decSig, encodedSig, sigSz) != 0) { - ret = VERIFY_CERT_ERROR; + CreateSigData(ssl, sigData, &sigDataSz, 1); + sigSz = CreateRSAEncodedSig(encodedSig, sigData, sigDataSz, hashAlgo); + /* Check the encoded and decrypted signature data match. */ + if (decSigSz != sigSz || decSig == NULL || + XMEMCMP(decSig, encodedSig, sigSz) != 0) { + ret = VERIFY_CERT_ERROR; + } + } + else { + CreateSigData(ssl, sigData, &sigDataSz, 1); + sigSz = CreateECCEncodedSig(sigData, sigDataSz, hashAlgo); + if (decSigSz != sigSz || decSig == NULL) + ret = VERIFY_CERT_ERROR; + else { + decSig -= 2 * decSigSz; + XMEMCPY(decSig, sigData, decSigSz); + decSig -= 8; + XMEMSET(decSig, 0, 8); + CreateECCEncodedSig(decSig, 8 + decSigSz * 2, hashAlgo); + if (XMEMCMP(decSig, decSig + 8 + decSigSz * 2, decSigSz) != 0) + ret = VERIFY_CERT_ERROR; + } } #ifdef WOLFSSL_SMALL_STACK @@ -3783,8 +3807,9 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, !ssl->peerEccDsaKeyPresent) { WOLFSSL_MSG("Oops, peer sent ECC key but not in verify"); } - if (args->sigAlgo == rsa_sa_algo && - (ssl->peerRsaKey == NULL || !ssl->peerRsaKeyPresent)) { + if ((args->sigAlgo == rsa_sa_algo || + args->sigAlgo == rsa_pss_sa_algo) && + (ssl->peerRsaKey == NULL || !ssl->peerRsaKeyPresent)) { WOLFSSL_MSG("Oops, peer sent RSA key but not in verify"); } @@ -3818,11 +3843,12 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, case TLS_ASYNC_DO: { #ifndef NO_RSA - if (ssl->peerRsaKey != NULL && ssl->peerRsaKeyPresent) { + if (args->sigAlgo == rsa_sa_algo || + args->sigAlgo == rsa_pss_sa_algo) { WOLFSSL_MSG("Doing RSA peer cert verify"); ret = RsaVerify(ssl, sig->buffer, sig->length, &args->output, - ssl->peerRsaKey, + args->sigAlgo, args->hashAlgo, ssl->peerRsaKey, #ifdef HAVE_PK_CALLBACKS ssl->buffers.peerRsaKey.buffer, ssl->buffers.peerRsaKey.length, @@ -3868,7 +3894,8 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, { #ifndef NO_RSA if (ssl->peerRsaKey != NULL && ssl->peerRsaKeyPresent != 0) { - ret = CheckRSASignature(ssl, args->hashAlgo, args->output, args->sendSz); + ret = CheckRSASignature(ssl, args->sigAlgo, args->hashAlgo, + args->output, args->sendSz); if (ret != 0) goto exit_dcv; } diff --git a/wolfcrypt/src/rsa.c b/wolfcrypt/src/rsa.c index afeec506d..e419d6bb6 100755 --- a/wolfcrypt/src/rsa.c +++ b/wolfcrypt/src/rsa.c @@ -261,7 +261,7 @@ int wc_FreeRsaKey(RsaKey* key) } -#ifndef WC_NO_RSA_OAEP +#if !defined(WC_NO_RSA_OAEP) || defined(WC_RSA_PSS) /* Uses MGF1 standard as a mask generation function hType: hash type used seed: seed to use for generating mask @@ -572,6 +572,50 @@ static int RsaPad_OAEP(const byte* input, word32 inputLen, byte* pkcsBlock, } #endif /* !WC_NO_RSA_OAEP */ +#ifdef WC_RSA_PSS +static int RsaPad_PSS(const byte* input, word32 inputLen, byte* pkcsBlock, + word32 pkcsBlockLen, WC_RNG* rng, enum wc_HashType hType, int mgf, + void* heap) +{ + int ret; + int hLen, i; + byte* s; + byte* m; + byte* h; + byte salt[WC_MAX_DIGEST_SIZE]; + + hLen = wc_HashGetDigestSize(hType); + if (hLen < 0) + return hLen; + + s = m = pkcsBlock; + XMEMSET(m, 0, 8); + m += 8; + XMEMCPY(m, input, inputLen); + m += inputLen; + if ((ret = wc_RNG_GenerateBlock(rng, salt, hLen)) != 0) + return ret; + XMEMCPY(m, salt, hLen); + m += hLen; + + h = pkcsBlock + pkcsBlockLen - 1 - hLen; + if ((ret = wc_Hash(hType, s, (word32)(m - s), h, hLen)) != 0) + return ret; + pkcsBlock[pkcsBlockLen - 1] = 0xbc; + + ret = RsaMGF(mgf, h, hLen, pkcsBlock, pkcsBlockLen - hLen - 1, heap); + if (ret != 0) + return ret; + pkcsBlock[0] &= 0x7f; + + m = pkcsBlock + pkcsBlockLen - 1 - hLen - hLen - 1; + *(m++) ^= 0x01; + for (i = 0; i < hLen; i++) + m[i] ^= salt[i]; + + return 0; +} +#endif static int RsaPad(const byte* input, word32 inputLen, byte* pkcsBlock, word32 pkcsBlockLen, byte padValue, WC_RNG* rng) @@ -635,16 +679,25 @@ static int wc_RsaPad_ex(const byte* input, word32 inputLen, byte* pkcsBlock, case WC_RSA_PKCSV15_PAD: /*WOLFSSL_MSG("wolfSSL Using RSA PKCSV15 padding");*/ ret = RsaPad(input, inputLen, pkcsBlock, pkcsBlockLen, - padValue, rng); + padValue, rng); break; #ifndef WC_NO_RSA_OAEP case WC_RSA_OAEP_PAD: WOLFSSL_MSG("wolfSSL Using RSA OAEP padding"); ret = RsaPad_OAEP(input, inputLen, pkcsBlock, pkcsBlockLen, - padValue, rng, hType, mgf, optLabel, labelLen, heap); + padValue, rng, hType, mgf, optLabel, labelLen, heap); break; #endif + + #ifdef WC_RSA_PSS + case WC_RSA_PSS_PAD: + WOLFSSL_MSG("wolfSSL Using RSA PSS padding"); + ret = RsaPad_PSS(input, inputLen, pkcsBlock, pkcsBlockLen, + rng, hType, mgf, heap); + break; + #endif + default: WOLFSSL_MSG("Unknown RSA Pad Type"); ret = RSA_PAD_E; @@ -748,6 +801,53 @@ static int RsaUnPad_OAEP(byte *pkcsBlock, unsigned int pkcsBlockLen, } #endif /* WC_NO_RSA_OAEP */ +#ifdef WC_RSA_PSS +static int RsaUnPad_PSS(byte *pkcsBlock, unsigned int pkcsBlockLen, + byte **output, enum wc_HashType hType, int mgf, + void* heap) +{ + int ret; + byte* tmp; + int hLen, i; + + hLen = wc_HashGetDigestSize(hType); + if (hLen < 0) + return hLen; + + if (pkcsBlock[pkcsBlockLen - 1] != 0xbc) + return BAD_PADDING_E; + + tmp = (byte*)XMALLOC(pkcsBlockLen, heap, DYNAMIC_TYPE_TMP_BUFFER); + if (tmp == NULL) { + return MEMORY_E; + } + + if ((ret = RsaMGF(mgf, pkcsBlock + pkcsBlockLen - 1 - hLen, hLen, + tmp, pkcsBlockLen - 1 - hLen, heap)) != 0) { + XFREE(tmp, heap, DYNAMIC_TYPE_TMP_BUFFER); + return ret; + } + + tmp[0] &= 0x7f; + for (i = 0; i < (int)(pkcsBlockLen - 1 - hLen - hLen - 1); i++) { + if (tmp[i] != pkcsBlock[i]) { + XFREE(tmp, heap, DYNAMIC_TYPE_TMP_BUFFER); + return BAD_PADDING_E; + } + } + if (tmp[i] != (pkcsBlock[i] ^ 0x01)) { + XFREE(tmp, heap, DYNAMIC_TYPE_TMP_BUFFER); + return BAD_PADDING_E; + } + for (i++; i < (int)(pkcsBlockLen - 1 - hLen); i++) + pkcsBlock[i] ^= tmp[i]; + + XFREE(tmp, heap, DYNAMIC_TYPE_TMP_BUFFER); + + *output = pkcsBlock + i; + return hLen; +} +#endif /* UnPad plaintext, set start to *output, return length of plaintext, * < 0 on error */ @@ -817,6 +917,14 @@ static int wc_RsaUnPad_ex(byte* pkcsBlock, word32 pkcsBlockLen, byte** out, break; #endif + #ifdef WC_RSA_PSS + case WC_RSA_PSS_PAD: + WOLFSSL_MSG("wolfSSL Using RSA PSS un-padding"); + ret = RsaUnPad_PSS((byte*)pkcsBlock, pkcsBlockLen, out, hType, mgf, + heap); + break; + #endif + default: WOLFSSL_MSG("Unknown RSA UnPad Type"); ret = RSA_PAD_E; @@ -1105,7 +1213,8 @@ int wc_RsaFunction(const byte* in, word32 inLen, byte* out, rsa_type : type of RSA: RSA_PUBLIC_ENCRYPT, RSA_PUBLIC_DECRYPT, RSA_PRIVATE_ENCRYPT or RSA_PRIVATE_DECRYPT pad_value: RSA_BLOCK_TYPE_1 or RSA_BLOCK_TYPE_2 - pad_type : type of padding: WC_RSA_PKCSV15_PAD or WC_RSA_OAEP_PAD + pad_type : type of padding: WC_RSA_PKCSV15_PAD, WC_RSA_OAEP_PAD or + WC_RSA_PSS_PAD hash : type of hash algorithm to use found in wolfssl/wolfcrypt/hash.h mgf : type of mask generation function to use label : optional label @@ -1212,7 +1321,8 @@ static int RsaPublicEncryptEx(const byte* in, word32 inLen, byte* out, rsa_type : type of RSA: RSA_PUBLIC_ENCRYPT, RSA_PUBLIC_DECRYPT, RSA_PRIVATE_ENCRYPT or RSA_PRIVATE_DECRYPT pad_value: RSA_BLOCK_TYPE_1 or RSA_BLOCK_TYPE_2 - pad_type : type of padding: WC_RSA_PKCSV15_PAD or WC_RSA_OAEP_PAD + pad_type : type of padding: WC_RSA_PKCSV15_PAD, WC_RSA_OAEP_PAD + WC_RSA_PSS_PAD hash : type of hash algorithm to use found in wolfssl/wolfcrypt/hash.h mgf : type of mask generation function to use label : optional label @@ -1446,6 +1556,19 @@ int wc_RsaSSL_Verify(const byte* in, word32 inLen, byte* out, word32 outLen, WC_HASH_TYPE_NONE, WC_MGF1NONE, NULL, 0, rng); } +#ifdef WC_RSA_PSS +int wc_RsaPSS_VerifyInline(byte* in, word32 inLen, byte** out, + enum wc_HashType hash, int mgf, RsaKey* key) +{ + WC_RNG* rng = NULL; +#ifdef WC_RSA_BLINDING + rng = key->rng; +#endif + return RsaPrivateDecryptEx(in, inLen, in, inLen, out, key, + RSA_PUBLIC_DECRYPT, RSA_BLOCK_TYPE_1, WC_RSA_PSS_PAD, + hash, mgf, NULL, 0, rng); +} +#endif int wc_RsaSSL_Sign(const byte* in, word32 inLen, byte* out, word32 outLen, RsaKey* key, WC_RNG* rng) diff --git a/wolfssl/internal.h b/wolfssl/internal.h index ae9c00b97..0c6c3ed57 100755 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -1747,6 +1747,7 @@ typedef enum { TLSX_TRUNCATED_HMAC = 0x0004, TLSX_STATUS_REQUEST = 0x0005, /* a.k.a. OCSP stapling */ TLSX_SUPPORTED_GROUPS = 0x000a, /* a.k.a. Supported Curves */ + TLSX_SIGNATURE_ALGORITHMS = 0x000d, TLSX_APPLICATION_LAYER_PROTOCOL = 0x0010, /* a.k.a. ALPN */ TLSX_STATUS_REQUEST_V2 = 0x0011, /* a.k.a. OCSP stapling v2 */ TLSX_QUANTUM_SAFE_HYBRID = 0x0018, /* a.k.a. QSH */ @@ -2344,10 +2345,11 @@ enum KeyExchangeAlgorithm { /* Supported Authentication Schemes */ enum SignatureAlgorithm { - anonymous_sa_algo, - rsa_sa_algo, - dsa_sa_algo, - ecc_dsa_sa_algo + anonymous_sa_algo = 0, + rsa_sa_algo = 1, + dsa_sa_algo = 2, + ecc_dsa_sa_algo = 4, + rsa_pss_sa_algo = 8 }; @@ -3406,7 +3408,8 @@ WOLFSSL_LOCAL int VerifyClientSuite(WOLFSSL* ssl); WOLFSSL_LOCAL int RsaSign(WOLFSSL* ssl, const byte* in, word32 inSz, byte* out, word32* outSz, RsaKey* key, const byte* keyBuf, word32 keySz, void* ctx); WOLFSSL_LOCAL int RsaVerify(WOLFSSL* ssl, byte* in, word32 inSz, - byte** out, RsaKey* key, const byte* keyBuf, word32 keySz, void* ctx); + byte** out, int sigAlgo, int hashAlgo, RsaKey* key, + const byte* keyBuf, word32 keySz, void* ctx); WOLFSSL_LOCAL int RsaDec(WOLFSSL* ssl, byte* in, word32 inSz, byte** out, word32* outSz, RsaKey* key, const byte* keyBuf, word32 keySz, void* ctx); WOLFSSL_LOCAL int RsaEnc(WOLFSSL* ssl, const byte* in, word32 inSz, byte* out, diff --git a/wolfssl/wolfcrypt/rsa.h b/wolfssl/wolfcrypt/rsa.h index a64eb8708..6905d1dd2 100644 --- a/wolfssl/wolfcrypt/rsa.h +++ b/wolfssl/wolfcrypt/rsa.h @@ -126,6 +126,9 @@ WOLFSSL_API int wc_RsaSSL_VerifyInline(byte* in, word32 inLen, byte** out, RsaKey* key); WOLFSSL_API int wc_RsaSSL_Verify(const byte* in, word32 inLen, byte* out, word32 outLen, RsaKey* key); +WOLFSSL_API int wc_RsaPSS_VerifyInline(byte* in, word32 inLen, byte** out, + enum wc_HashType hash, int mgf, + RsaKey* key); WOLFSSL_API int wc_RsaEncryptSize(RsaKey* key); #ifndef HAVE_FIPS /* to avoid asn duplicate symbols @wc_fips */ @@ -156,6 +159,7 @@ WOLFSSL_API int wc_RsaSetRNG(RsaKey* key, WC_RNG* rng); /* Padding types */ #define WC_RSA_PKCSV15_PAD 0 #define WC_RSA_OAEP_PAD 1 +#define WC_RSA_PSS_PAD 2 WOLFSSL_API int wc_RsaPublicEncrypt_ex(const byte* in, word32 inLen, byte* out, word32 outLen, RsaKey* key, WC_RNG* rng, int type,