From ec6d8f48b8f18efd978abe144f459f21fd3f28ac Mon Sep 17 00:00:00 2001 From: Sean Parkinson Date: Wed, 10 May 2017 16:59:11 +1000 Subject: [PATCH] Add PSS for TLS v1.3 --- configure.ac | 1 + src/internal.c | 41 ++++++++++++- src/tls.c | 25 ++++++++ src/tls13.c | 69 ++++++++++++++------- wolfcrypt/src/rsa.c | 133 ++++++++++++++++++++++++++++++++++++++-- wolfssl/internal.h | 12 ++-- wolfssl/wolfcrypt/rsa.h | 4 ++ 7 files changed, 251 insertions(+), 34 deletions(-) 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 fb60eadae..796fc89fa 100755 --- a/src/tls.c +++ b/src/tls.c @@ -4445,6 +4445,17 @@ static word16 TLSX_SignatureAlgorithms_GetSize(byte* data) #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 @@ -4497,6 +4508,20 @@ static word16 TLSX_SignatureAlgorithms_Write(byte* data, byte* output) 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 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 9b490bddd..0c6c3ed57 100755 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -2345,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 }; @@ -3407,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,