diff --git a/tests/api.c b/tests/api.c index 5d05dd635..8d25bb6a6 100644 --- a/tests/api.c +++ b/tests/api.c @@ -22310,14 +22310,14 @@ static void test_wolfSSL_ERR_print_errors(void) AssertNotNull(bio = BIO_new(BIO_s_mem())); ERR_clear_error(); /* clear out any error nodes */ ERR_put_error(0,SYS_F_ACCEPT, -173, "ssl.c", 0); - ERR_put_error(0,SYS_F_BIND, -273, "asn.c", 100); + ERR_put_error(0,SYS_F_BIND, -283, "asn.c", 100); ERR_print_errors(bio); AssertIntEQ(BIO_gets(bio, buf, sizeof(buf)), 56); AssertIntEQ(XSTRNCMP("error:173:wolfSSL library:Bad function argument:ssl.c:0", buf, 55), 0); AssertIntEQ(BIO_gets(bio, buf, sizeof(buf)), 57); - AssertIntEQ(XSTRNCMP("error:273:wolfSSL library:unknown error number:asn.c:100", + AssertIntEQ(XSTRNCMP("error:283:wolfSSL library:unknown error number:asn.c:100", buf, 56), 0); AssertIntEQ(BIO_gets(bio, buf, sizeof(buf)), 0); AssertIntEQ(ERR_get_error_line(NULL, NULL), 0); diff --git a/wolfcrypt/src/error.c b/wolfcrypt/src/error.c index eed51ba35..14ad9cd82 100644 --- a/wolfcrypt/src/error.c +++ b/wolfcrypt/src/error.c @@ -509,6 +509,9 @@ const char* wc_GetErrorString(int error) case PKCS7_SIGNEEDS_CHECK: return "Signature found but no certificate to verify"; + case PSS_SALTLEN_RECOVER_E: + return "PSS - Salt length unable to be recovered"; + default: return "unknown error number"; diff --git a/wolfcrypt/src/rsa.c b/wolfcrypt/src/rsa.c index 878d7ff39..daee4fa00 100644 --- a/wolfcrypt/src/rsa.c +++ b/wolfcrypt/src/rsa.c @@ -1002,56 +1002,133 @@ static int RsaPad_PSS(const byte* input, word32 inputLen, byte* pkcsBlock, word32 pkcsBlockLen, WC_RNG* rng, enum wc_HashType hType, int mgf, int saltLen, int bits, void* heap) { - int ret; - int hLen, i; - byte* s; + int ret = 0; + int hLen, i, o, maskLen, hiBits; byte* m; - byte* h; - byte salt[WC_MAX_DIGEST_SIZE]; + byte* s; +#if defined(WOLFSSL_PSS_LONG_SALT) || defined(WOLFSSL_PSS_SALT_LEN_DISCOVER) + #if defined(WOLFSSL_NO_MALLOC) && !defined(WOLFSSL_STATIC_MEMORY) + byte salt[RSA_MAX_SIZE/8 + RSA_PSS_PAD_SZ]; + #else + byte* salt = NULL; + #endif +#else + byte salt[WC_MAX_DIGEST_SIZE]; +#endif + +#if defined(WOLFSSL_PSS_LONG_SALT) || defined(WOLFSSL_PSS_SALT_LEN_DISCOVER) + if (pkcsBlockLen > RSA_MAX_SIZE/8) { + return MEMORY_E; + } +#endif hLen = wc_HashGetDigestSize(hType); if (hLen < 0) return hLen; + hiBits = (bits - 1) & 0x7; + if (hiBits == 0) { + *(pkcsBlock++) = 0; + pkcsBlockLen--; + } + if (saltLen == -1) { saltLen = hLen; #ifdef WOLFSSL_SHA512 /* See FIPS 186-4 section 5.5 item (e). */ - if (bits == 1024 && hLen == WC_SHA512_DIGEST_SIZE) + if (bits == 1024 && hLen == WC_SHA512_DIGEST_SIZE) { saltLen = RSA_PSS_SALT_MAX_SZ; + } #endif } - else if (saltLen > hLen || saltLen < -1) +#ifndef WOLFSSL_PSS_LONG_SALT + else if (saltLen > hLen) { return PSS_SALTLEN_E; - if ((int)pkcsBlockLen - hLen < saltLen + 2) + } +#endif +#ifndef WOLFSSL_PSS_SALT_LEN_DISCOVER + else if (saltLen < -1) { return PSS_SALTLEN_E; + } +#else + else if (saltLen == -2) { + saltLen = (int)pkcsBlockLen - hLen - 2; + if (saltLen < 0) { + return PSS_SALTLEN_E; + } + } + else if (saltLen < -2) { + return PSS_SALTLEN_E; + } +#endif + if ((int)pkcsBlockLen - hLen < saltLen + 2) { + return PSS_SALTLEN_E; + } + maskLen = pkcsBlockLen - 1 - hLen; + +#if defined(WOLFSSL_PSS_LONG_SALT) || defined(WOLFSSL_PSS_SALT_LEN_DISCOVER) + #if !defined(WOLFSSL_NO_MALLOC) || defined(WOLFSSL_STATIC_MEMORY) + salt = (byte*)XMALLOC(RSA_PSS_PAD_SZ + inputLen + saltLen, heap, + DYNAMIC_TYPE_RSA_BUFFER); + if (salt == NULL) { + return MEMORY_E; + } + #endif + s = m = salt; + XMEMSET(m, 0, RSA_PSS_PAD_SZ); + m += RSA_PSS_PAD_SZ; + XMEMCPY(m, input, inputLen); + m += inputLen; + o = (int)(m - s); + if (saltLen > 0) { + ret = wc_RNG_GenerateBlock(rng, m, saltLen); + if (ret == 0) { + m += saltLen; + } + } +#else s = m = pkcsBlock; XMEMSET(m, 0, RSA_PSS_PAD_SZ); m += RSA_PSS_PAD_SZ; XMEMCPY(m, input, inputLen); m += inputLen; - if ((ret = wc_RNG_GenerateBlock(rng, salt, saltLen)) != 0) - return ret; - XMEMCPY(m, salt, saltLen); - m += saltLen; + o = 0; + if (saltLen > 0) { + ret = wc_RNG_GenerateBlock(rng, salt, saltLen); + if (ret == 0) { + XMEMCPY(m, salt, saltLen); + m += saltLen; + } + } +#endif + if (ret == 0) { + /* Put Hash at end of pkcsBlock - 1 */ + ret = wc_Hash(hType, s, (word32)(m - s), pkcsBlock + maskLen, hLen); + } + if (ret == 0) { + pkcsBlock[pkcsBlockLen - 1] = RSA_PSS_PAD_TERM; - h = pkcsBlock + pkcsBlockLen - 1 - hLen; - if ((ret = wc_Hash(hType, s, (word32)(m - s), h, hLen)) != 0) - return ret; - pkcsBlock[pkcsBlockLen - 1] = RSA_PSS_PAD_TERM; + ret = RsaMGF(mgf, pkcsBlock + maskLen, hLen, pkcsBlock, maskLen, heap); + } + if (ret == 0) { + pkcsBlock[0] &= (1 << hiBits) - 1; - ret = RsaMGF(mgf, h, hLen, pkcsBlock, pkcsBlockLen - hLen - 1, heap); - if (ret != 0) - return ret; - pkcsBlock[0] &= (1 << ((bits - 1) & 0x7)) - 1; + m = pkcsBlock + maskLen - saltLen - 1; + *(m++) ^= 0x01; + for (i = 0; i < saltLen; i++) { + m[i] ^= salt[o + i]; + } + } - m = pkcsBlock + pkcsBlockLen - 1 - saltLen - hLen - 1; - *(m++) ^= 0x01; - for (i = 0; i < saltLen; i++) - m[i] ^= salt[i]; - - return 0; +#if defined(WOLFSSL_PSS_LONG_SALT) || defined(WOLFSSL_PSS_SALT_LEN_DISCOVER) + #if !defined(WOLFSSL_NO_MALLOC) || defined(WOLFSSL_STATIC_MEMORY) + if (salt != NULL) { + XFREE(salt, heap, DYNAMIC_TYPE_RSA_BUFFER); + } + #endif +#endif + return ret; } #endif /* WC_RSA_PSS */ @@ -1294,7 +1371,7 @@ static int RsaUnPad_PSS(byte *pkcsBlock, unsigned int pkcsBlockLen, { int ret; byte* tmp; - int hLen, i; + int hLen, i, maskLen; #if defined(WOLFSSL_NO_MALLOC) && !defined(WOLFSSL_STATIC_MEMORY) byte tmp_buf[RSA_MAX_SIZE/8]; tmp = tmp_buf; @@ -1307,6 +1384,19 @@ static int RsaUnPad_PSS(byte *pkcsBlock, unsigned int pkcsBlockLen, hLen = wc_HashGetDigestSize(hType); if (hLen < 0) return hLen; + bits = (bits - 1) & 0x7; + if ((pkcsBlock[0] & (0xff << bits)) != 0) { + return BAD_PADDING_E; + } + if (bits == 0) { + pkcsBlock++; + pkcsBlockLen--; + } + maskLen = (int)pkcsBlockLen - 1 - hLen; + if (maskLen < 0) { + WOLFSSL_MSG("RsaUnPad_PSS: Hash too large"); + return WC_KEY_SIZE_E; + } if (saltLen == -1) { saltLen = hLen; @@ -1316,10 +1406,23 @@ static int RsaUnPad_PSS(byte *pkcsBlock, unsigned int pkcsBlockLen, saltLen = RSA_PSS_SALT_MAX_SZ; #endif } - else if (saltLen > hLen || saltLen < -1) +#ifndef WOLFSSL_PSS_LONG_SALT + else if (saltLen > hLen) return PSS_SALTLEN_E; - if ((int)pkcsBlockLen - hLen < saltLen + 2) +#endif +#ifndef WOLFSSL_PSS_SALT_LEN_DISCOVER + else if (saltLen < -1) return PSS_SALTLEN_E; + if (maskLen < saltLen + 1) { + return PSS_SALTLEN_E; + } +#else + else if (saltLen < -2) + return PSS_SALTLEN_E; + if (saltLen != -2 && maskLen < saltLen + 1) { + return WC_KEY_SIZE_E; + } +#endif if (pkcsBlock[pkcsBlockLen - 1] != RSA_PSS_PAD_TERM) { WOLFSSL_MSG("RsaUnPad_PSS: Padding Term Error"); @@ -1327,38 +1430,58 @@ static int RsaUnPad_PSS(byte *pkcsBlock, unsigned int pkcsBlockLen, } #if !defined(WOLFSSL_NO_MALLOC) || defined(WOLFSSL_STATIC_MEMORY) - tmp = (byte*)XMALLOC(pkcsBlockLen, heap, DYNAMIC_TYPE_RSA_BUFFER); - if (tmp == NULL) + tmp = (byte*)XMALLOC(maskLen, heap, DYNAMIC_TYPE_RSA_BUFFER); + if (tmp == NULL) { return MEMORY_E; + } #endif - if ((ret = RsaMGF(mgf, pkcsBlock + pkcsBlockLen - 1 - hLen, hLen, - tmp, pkcsBlockLen - 1 - hLen, heap)) != 0) { + if ((ret = RsaMGF(mgf, pkcsBlock + maskLen, hLen, tmp, maskLen, + heap)) != 0) { XFREE(tmp, heap, DYNAMIC_TYPE_RSA_BUFFER); return ret; } - tmp[0] &= (1 << ((bits - 1) & 0x7)) - 1; - for (i = 0; i < (int)(pkcsBlockLen - 1 - saltLen - hLen - 1); i++) { - if (tmp[i] != pkcsBlock[i]) { + tmp[0] &= (1 << bits) - 1; + pkcsBlock[0] &= (1 << bits) - 1; +#ifdef WOLFSSL_PSS_SALT_LEN_DISCOVER + if (saltLen == -2) { + for (i = 0; i < maskLen - 1; i++) { + if (tmp[i] != pkcsBlock[i]) { + break; + } + } + if (tmp[i] != (pkcsBlock[i] ^ 0x01)) { XFREE(tmp, heap, DYNAMIC_TYPE_RSA_BUFFER); WOLFSSL_MSG("RsaUnPad_PSS: Padding Error Match"); - return BAD_PADDING_E; + return PSS_SALTLEN_RECOVER_E; + } + saltLen = maskLen - (i + 1); + } + else +#endif + { + for (i = 0; i < maskLen - 1 - saltLen; i++) { + if (tmp[i] != pkcsBlock[i]) { + XFREE(tmp, heap, DYNAMIC_TYPE_RSA_BUFFER); + WOLFSSL_MSG("RsaUnPad_PSS: Padding Error Match"); + return PSS_SALTLEN_E; + } + } + if (tmp[i] != (pkcsBlock[i] ^ 0x01)) { + XFREE(tmp, heap, DYNAMIC_TYPE_RSA_BUFFER); + WOLFSSL_MSG("RsaUnPad_PSS: Padding Error End"); + return PSS_SALTLEN_E; } } - if (tmp[i] != (pkcsBlock[i] ^ 0x01)) { - XFREE(tmp, heap, DYNAMIC_TYPE_RSA_BUFFER); - WOLFSSL_MSG("RsaUnPad_PSS: Padding Error End"); - return BAD_PADDING_E; - } - for (i++; i < (int)(pkcsBlockLen - 1 - hLen); i++) + for (i++; i < maskLen; i++) pkcsBlock[i] ^= tmp[i]; #if !defined(WOLFSSL_NO_MALLOC) || defined(WOLFSSL_STATIC_MEMORY) XFREE(tmp, heap, DYNAMIC_TYPE_RSA_BUFFER); #endif - *output = pkcsBlock + pkcsBlockLen - (hLen + saltLen + 1); + *output = pkcsBlock + maskLen - saltLen; return saltLen + hLen; } #endif @@ -1465,7 +1588,8 @@ static int wc_RsaUnPad_ex(byte* pkcsBlock, word32 pkcsBlockLen, byte** out, /* In the case of no padding being used check that input is exactly * the RSA key length */ - if (bits <= 0 || pkcsBlockLen != ((word32)bits/WOLFSSL_BIT_SIZE)) { + if (bits <= 0 || pkcsBlockLen != + ((word32)(bits+WOLFSSL_BIT_SIZE-1)/WOLFSSL_BIT_SIZE)) { WOLFSSL_MSG("Bad input size"); ret = RSA_PAD_E; } @@ -2910,7 +3034,11 @@ int wc_RsaSSL_Verify(const byte* in, word32 inLen, byte* out, word32 outLen, int wc_RsaPSS_VerifyInline(byte* in, word32 inLen, byte** out, enum wc_HashType hash, int mgf, RsaKey* key) { +#ifndef WOLFSSL_PSS_SALT_LEN_DISCOVER return wc_RsaPSS_VerifyInline_ex(in, inLen, out, hash, mgf, -1, key); +#else + return wc_RsaPSS_VerifyInline_ex(in, inLen, out, hash, mgf, -2, key); +#endif } /* Verify the message signed with RSA-PSS. @@ -2953,7 +3081,11 @@ int wc_RsaPSS_VerifyInline_ex(byte* in, word32 inLen, byte** out, int wc_RsaPSS_Verify(byte* in, word32 inLen, byte* out, word32 outLen, enum wc_HashType hash, int mgf, RsaKey* key) { +#ifndef WOLFSSL_PSS_SALT_LEN_DISCOVER return wc_RsaPSS_Verify_ex(in, inLen, out, outLen, hash, mgf, -1, key); +#else + return wc_RsaPSS_Verify_ex(in, inLen, out, outLen, hash, mgf, -2, key); +#endif } /* Verify the message signed with RSA-PSS. @@ -3018,33 +3150,68 @@ int wc_RsaPSS_CheckPadding_ex(const byte* in, word32 inSz, byte* sig, int saltLen, int bits) { int ret = 0; +#ifndef WOLFSSL_PSS_LONG_SALT byte sigCheck[WC_MAX_DIGEST_SIZE*2 + RSA_PSS_PAD_SZ]; +#else + byte *sigCheck = NULL; +#endif (void)bits; if (in == NULL || sig == NULL || - inSz != (word32)wc_HashGetDigestSize(hashType)) + inSz != (word32)wc_HashGetDigestSize(hashType)) { ret = BAD_FUNC_ARG; + } if (ret == 0) { if (saltLen == -1) { saltLen = inSz; #ifdef WOLFSSL_SHA512 /* See FIPS 186-4 section 5.5 item (e). */ - if (bits == 1024 && inSz == WC_SHA512_DIGEST_SIZE) + if (bits == 1024 && inSz == WC_SHA512_DIGEST_SIZE) { saltLen = RSA_PSS_SALT_MAX_SZ; + } #endif } - else if (saltLen < -1 || (word32)saltLen > inSz) +#ifndef WOLFSSL_PSS_LONG_SALT + else if ((word32)saltLen > inSz) { ret = PSS_SALTLEN_E; + } +#endif +#ifndef WOLFSSL_PSS_SALT_LEN_DISCOVER + else if (saltLen < -1) { + ret = PSS_SALTLEN_E; + } +#else + else if (saltLen == -2) { + saltLen = sigSz - inSz; + if (saltLen < 0) { + ret = PSS_SALTLEN_E; + } + } + else if (saltLen < -2) { + ret = PSS_SALTLEN_E; + } +#endif } /* Sig = Salt | Exp Hash */ if (ret == 0) { - if (sigSz != inSz + saltLen) - ret = BAD_PADDING_E; + if (sigSz != inSz + saltLen) { + ret = PSS_SALTLEN_E; + } } +#ifdef WOLFSSL_PSS_LONG_SALT + if (ret == 0) { + sigCheck = (byte*)XMALLOC(RSA_PSS_PAD_SZ + inSz + saltLen, NULL, + DYNAMIC_TYPE_RSA_BUFFER); + if (sigCheck == NULL) { + ret = MEMORY_E; + } + } +#endif + /* Exp Hash = HASH(8 * 0x00 | Message Hash | Salt) */ if (ret == 0) { XMEMSET(sigCheck, 0, RSA_PSS_PAD_SZ); @@ -3060,6 +3227,11 @@ int wc_RsaPSS_CheckPadding_ex(const byte* in, word32 inSz, byte* sig, } } +#ifdef WOLFSSL_PSS_LONG_SALT + if (sigCheck != NULL) { + XFREE(sigCheck, NULL, DYNAMIC_TYPE_RSA_BUFFER); + } +#endif return ret; } diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 1f9bb52f0..10724066c 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -10526,6 +10526,7 @@ static int rsa_pss_test(WC_RNG* rng, RsaKey* key) #ifdef RSA_PSS_TEST_WRONG_PARAMS int k, l; #endif + int len; byte* plain; int mgf[] = { #ifndef NO_SHA @@ -10722,6 +10723,11 @@ static int rsa_pss_test(WC_RNG* rng, RsaKey* key) /* Test bad salt lengths in various APIs. */ digestSz = wc_HashGetDigestSize(hash[0]); outSz = RSA_TEST_BYTES; +#ifndef WOLFSSL_PSS_SALT_LEN_DISCOVER + len = -2; +#else + len = -3; +#endif do { #if defined(WOLFSSL_ASYNC_CRYPT) ret = wc_AsyncWait(ret, &key->asyncDev, @@ -10729,7 +10735,7 @@ static int rsa_pss_test(WC_RNG* rng, RsaKey* key) #endif if (ret >= 0) { ret = wc_RsaPSS_Sign_ex(digest, digestSz, out, outSz, hash[0], - mgf[0], -2, key, rng); + mgf[0], len, key, rng); } } while (ret == WC_PENDING_E); if (ret != PSS_SALTLEN_E) @@ -10777,21 +10783,31 @@ static int rsa_pss_test(WC_RNG* rng, RsaKey* key) ERROR_OUT(-6830, exit_rsa_pss); TEST_SLEEP(); +#ifndef WOLFSSL_PSS_SALT_LEN_DISCOVER + len = -2; +#else + len = -3; +#endif #ifdef HAVE_SELFTEST ret = wc_RsaPSS_CheckPadding_ex(digest, digestSz, plain, plainSz, hash[0], - -2); + len); #else ret = wc_RsaPSS_CheckPadding_ex(digest, digestSz, plain, plainSz, hash[0], - -2, 0); + len, 0); #endif if (ret != PSS_SALTLEN_E) ERROR_OUT(-6831, exit_rsa_pss); +#ifndef WOLFSSL_PSS_LONG_SALT + len = digestSz + 1; +#else + len = plainSz - digestSz - 1; +#endif #ifdef HAVE_SELFTEST ret = wc_RsaPSS_CheckPadding_ex(digest, digestSz, plain, plainSz, hash[0], - digestSz + 1); + len); #else ret = wc_RsaPSS_CheckPadding_ex(digest, digestSz, plain, plainSz, hash[0], - digestSz + 1, 0); + len, 0); #endif if (ret != PSS_SALTLEN_E) ERROR_OUT(-6832, exit_rsa_pss); diff --git a/wolfssl/wolfcrypt/error-crypt.h b/wolfssl/wolfcrypt/error-crypt.h index e91fe8fdf..a8b8e5786 100644 --- a/wolfssl/wolfcrypt/error-crypt.h +++ b/wolfssl/wolfcrypt/error-crypt.h @@ -199,7 +199,7 @@ enum { WC_HW_E = -248, /* Error with hardware crypto use */ WC_HW_WAIT_E = -249, /* Hardware waiting on resource */ - PSS_SALTLEN_E = -250, /* PSS length of salt is to long for hash */ + PSS_SALTLEN_E = -250, /* PSS length of salt is too long for hash */ PRIME_GEN_E = -251, /* Failure finding a prime. */ BER_INDEF_E = -252, /* Cannot decode indefinite length BER. */ RSA_OUT_OF_RANGE_E = -253, /* Ciphertext to decrypt out of range. */ @@ -224,10 +224,11 @@ enum { PKCS7_NO_SIGNER_E = -269, /* No signer in PKCS#7 signed data msg */ WC_PKCS7_WANT_READ_E= -270, /* PKCS7 operations wants more input */ - CRYPTOCB_UNAVAILABLE= -271, /* Crypto callback unavailable */ - PKCS7_SIGNEEDS_CHECK= -272, /* signature needs verified by caller */ + CRYPTOCB_UNAVAILABLE= -271, /* Crypto callback unavailable */ + PKCS7_SIGNEEDS_CHECK= -272, /* signature needs verified by caller */ + PSS_SALTLEN_RECOVER_E=-273, /* PSS slat length not recoverable */ - WC_LAST_E = -272, /* Update this to indicate last error */ + WC_LAST_E = -273, /* Update this to indicate last error */ MIN_CODE_E = -300 /* errors -101 - -299 */ /* add new companion error id strings for any new error codes