Compile options for larger salt lengths in RSA-PSS

Salt length larger than the hash size allowed in RSA-PSS.
Passing -2 to PSS pad function uses maximum salt length.
Passing -2 to PSS un-pad function makes it discover salt length.
pull/2547/head
Sean Parkinson 2019-11-01 16:08:02 +10:00
parent 9e852b3867
commit 35ec2bc6d4
5 changed files with 253 additions and 61 deletions

View File

@ -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);

View File

@ -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";

View File

@ -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;
}

View File

@ -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);

View File

@ -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