From 97f54e8e0a74f3638ef3f7057f18a90359f449bb Mon Sep 17 00:00:00 2001 From: Tesfa Mael Date: Tue, 3 May 2022 22:57:47 -0700 Subject: [PATCH 1/5] Support RSA OAEP with no malloc --- wolfcrypt/src/rsa.c | 51 ++++++++++++++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 14 deletions(-) diff --git a/wolfcrypt/src/rsa.c b/wolfcrypt/src/rsa.c index e12883c28..f94bf857b 100644 --- a/wolfcrypt/src/rsa.c +++ b/wolfcrypt/src/rsa.c @@ -853,11 +853,15 @@ int wc_CheckRsaKey(RsaKey* key) static int RsaMGF1(enum wc_HashType hType, byte* seed, word32 seedSz, byte* out, word32 outSz, void* heap) { - byte* tmp; +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + byte* tmp = NULL; +#else + byte tmp[RSA_MAX_SIZE/8] = {0}; +#endif /* needs to be large enough for seed size plus counter(4) */ - byte tmpA[WC_MAX_DIGEST_SIZE + 4]; - byte tmpF; /* 1 if dynamic memory needs freed */ - word32 tmpSz; + byte tmpA[WC_MAX_DIGEST_SIZE + 4]= {0}; + byte tmpF = 0; /* 1 if dynamic memory needs freed */ + word32 tmpSz = 0; int hLen; int ret; word32 counter; @@ -881,18 +885,22 @@ static int RsaMGF1(enum wc_HashType hType, byte* seed, word32 seedSz, /* find largest amount of memory needed which will be the max of * hLen and (seedSz + 4) since tmp is used to store the hash digest */ tmpSz = ((seedSz + 4) > (word32)hLen)? seedSz + 4: (word32)hLen; +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) tmp = (byte*)XMALLOC(tmpSz, heap, DYNAMIC_TYPE_RSA_BUFFER); if (tmp == NULL) { return MEMORY_E; } tmpF = 1; /* make sure to free memory when done */ +#endif } else { /* use array on the stack */ #ifndef WOLFSSL_SMALL_STACK_CACHE tmpSz = sizeof(tmpA); #endif +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) tmp = tmpA; + #endif tmpF = 0; /* no need to free memory at end */ } @@ -935,9 +943,11 @@ static int RsaMGF1(enum wc_HashType hType, byte* seed, word32 seedSz, #endif if (ret != 0) { /* check for if dynamic memory was needed, then free */ +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) if (tmpF) { XFREE(tmp, heap, DYNAMIC_TYPE_RSA_BUFFER); } +#endif return ret; } @@ -1038,15 +1048,15 @@ static int RsaPad_OAEP(const byte* input, word32 inputLen, byte* pkcsBlock, int i; word32 idx; - byte* dbMask; - #ifdef WOLFSSL_SMALL_STACK + byte* dbMask = NULL; byte* lHash = NULL; byte* seed = NULL; #else /* must be large enough to contain largest hash */ - byte lHash[WC_MAX_DIGEST_SIZE]; - byte seed[ WC_MAX_DIGEST_SIZE]; + byte lHash[WC_MAX_DIGEST_SIZE] = {0}; + byte seed[WC_MAX_DIGEST_SIZE]= {0}; + byte dbMask[RSA_MAX_SIZE/8 + RSA_PSS_PAD_SZ] = {0}; #endif /* no label is allowed, but catch if no label provided and length > 0 */ @@ -1143,21 +1153,21 @@ static int RsaPad_OAEP(const byte* input, word32 inputLen, byte* pkcsBlock, return ret; } +#ifdef WOLFSSL_SMALL_STACK /* create maskedDB from dbMask */ dbMask = (byte*)XMALLOC(pkcsBlockLen - hLen - 1, heap, DYNAMIC_TYPE_RSA); if (dbMask == NULL) { - #ifdef WOLFSSL_SMALL_STACK + XFREE(lHash, heap, DYNAMIC_TYPE_RSA_BUFFER); XFREE(seed, heap, DYNAMIC_TYPE_RSA_BUFFER); - #endif return MEMORY_E; } +#endif XMEMSET(dbMask, 0, pkcsBlockLen - hLen - 1); /* help static analyzer */ - ret = RsaMGF(mgf, seed, hLen, dbMask, pkcsBlockLen - hLen - 1, heap); if (ret != 0) { - XFREE(dbMask, heap, DYNAMIC_TYPE_RSA); #ifdef WOLFSSL_SMALL_STACK + XFREE(dbMask, heap, DYNAMIC_TYPE_RSA); XFREE(lHash, heap, DYNAMIC_TYPE_RSA_BUFFER); XFREE(seed, heap, DYNAMIC_TYPE_RSA_BUFFER); #endif @@ -1170,8 +1180,9 @@ static int RsaPad_OAEP(const byte* input, word32 inputLen, byte* pkcsBlock, pkcsBlock[idx] = dbMask[i++] ^ pkcsBlock[idx]; idx++; } +#ifdef WOLFSSL_SMALL_STACK XFREE(dbMask, heap, DYNAMIC_TYPE_RSA); - +#endif /* create maskedSeed from seedMask */ idx = 0; @@ -1513,9 +1524,13 @@ static int RsaUnPad_OAEP(byte *pkcsBlock, unsigned int pkcsBlockLen, int hLen; int ret; byte h[WC_MAX_DIGEST_SIZE]; /* max digest size */ - byte* tmp; word32 idx; +#ifdef WOLFSSL_SMALL_STACK + byte* tmp = NULL; +#else + byte tmp[RSA_MAX_SIZE/8 + RSA_PSS_PAD_SZ] = {0}; +#endif /* no label is allowed, but catch if no label provided and length > 0 */ if (optLabel == NULL && labelLen > 0) { return BUFFER_E; @@ -1526,16 +1541,20 @@ static int RsaUnPad_OAEP(byte *pkcsBlock, unsigned int pkcsBlockLen, return BAD_FUNC_ARG; } +#ifdef WOLFSSL_SMALL_STACK tmp = (byte*)XMALLOC(pkcsBlockLen, heap, DYNAMIC_TYPE_RSA_BUFFER); if (tmp == NULL) { return MEMORY_E; } +#endif XMEMSET(tmp, 0, pkcsBlockLen); /* find seedMask value */ if ((ret = RsaMGF(mgf, (byte*)(pkcsBlock + (hLen + 1)), pkcsBlockLen - hLen - 1, tmp, hLen, heap)) != 0) { +#ifdef WOLFSSL_SMALL_STACK XFREE(tmp, heap, DYNAMIC_TYPE_RSA_BUFFER); +#endif return ret; } @@ -1547,7 +1566,9 @@ static int RsaUnPad_OAEP(byte *pkcsBlock, unsigned int pkcsBlockLen, /* get dbMask value */ if ((ret = RsaMGF(mgf, tmp, hLen, tmp + hLen, pkcsBlockLen - hLen - 1, heap)) != 0) { +#ifdef WOLFSSL_SMALL_STACK XFREE(tmp, NULL, DYNAMIC_TYPE_RSA_BUFFER); +#endif return ret; } @@ -1556,8 +1577,10 @@ static int RsaUnPad_OAEP(byte *pkcsBlock, unsigned int pkcsBlockLen, pkcsBlock[hLen + 1 + idx] = pkcsBlock[hLen + 1 + idx] ^ tmp[idx + hLen]; } +#ifdef WOLFSSL_SMALL_STACK /* done with use of tmp buffer */ XFREE(tmp, heap, DYNAMIC_TYPE_RSA_BUFFER); +#endif /* advance idx to index of PS and msg separator, account for PS size of 0*/ idx = hLen + 1 + hLen; From bdd6072edec8103cfd264a5c92911ded8eceb72d Mon Sep 17 00:00:00 2001 From: Tesfa Mael Date: Wed, 4 May 2022 09:33:38 -0700 Subject: [PATCH 2/5] Check nomalloc with verify inline --- wolfcrypt/src/rsa.c | 19 ++++++++++++------- wolfssl/wolfcrypt/rsa.h | 3 ++- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/wolfcrypt/src/rsa.c b/wolfcrypt/src/rsa.c index f94bf857b..cc664884f 100644 --- a/wolfcrypt/src/rsa.c +++ b/wolfcrypt/src/rsa.c @@ -239,7 +239,7 @@ enum { static void wc_RsaCleanup(RsaKey* key) { -#ifndef WOLFSSL_RSA_VERIFY_INLINE +#if !defined(WOLFSSL_RSA_VERIFY_INLINE) && !defined(WOLFSSL_NO_MALLOC) if (key && key->data) { /* make sure any allocated memory is free'd */ if (key->dataIsAlloc) { @@ -273,7 +273,7 @@ int wc_InitRsaKey_ex(RsaKey* key, void* heap, int devId) key->type = RSA_TYPE_UNKNOWN; key->state = RSA_STATE_NONE; key->heap = heap; -#ifndef WOLFSSL_RSA_VERIFY_INLINE +#if !defined(WOLFSSL_RSA_VERIFY_INLINE) && !defined(WOLFSSL_NO_MALLOC) key->dataIsAlloc = 0; key->data = NULL; #endif @@ -3284,7 +3284,8 @@ static int RsaPrivateDecryptEx(const byte* in, word32 inLen, byte* out, #endif /* WOLFSSL_CRYPTOCELL */ -#if !defined(WOLFSSL_RSA_VERIFY_ONLY) && !defined(WOLFSSL_RSA_VERIFY_INLINE) +#if !defined(WOLFSSL_RSA_VERIFY_ONLY) && !defined(WOLFSSL_RSA_VERIFY_INLINE) && \ + !defined(WOLFSSL_NO_MALLOC) /* verify the tmp ptr is NULL, otherwise indicates bad state */ if (key->data != NULL) { ret = BAD_STATE_E; @@ -3312,7 +3313,8 @@ static int RsaPrivateDecryptEx(const byte* in, word32 inLen, byte* out, FALL_THROUGH; case RSA_STATE_DECRYPT_EXPTMOD: -#if !defined(WOLFSSL_RSA_VERIFY_ONLY) && !defined(WOLFSSL_RSA_VERIFY_INLINE) +#if !defined(WOLFSSL_RSA_VERIFY_ONLY) && !defined(WOLFSSL_RSA_VERIFY_INLINE) && \ + !defined(WOLFSSL_NO_MALLOC) ret = wc_RsaFunction_ex(key->data, inLen, key->data, &key->dataLen, rsa_type, key, rng, pad_type != WC_RSA_OAEP_PAD); @@ -3331,7 +3333,8 @@ static int RsaPrivateDecryptEx(const byte* in, word32 inLen, byte* out, FALL_THROUGH; case RSA_STATE_DECRYPT_UNPAD: -#if !defined(WOLFSSL_RSA_VERIFY_ONLY) && !defined(WOLFSSL_RSA_VERIFY_INLINE) +#if !defined(WOLFSSL_RSA_VERIFY_ONLY) && !defined(WOLFSSL_RSA_VERIFY_INLINE) && \ + !defined(WOLFSSL_NO_MALLOC) ret = wc_RsaUnPad_ex(key->data, key->dataLen, &pad, pad_value, pad_type, hash, mgf, label, labelSz, saltLen, mp_count_bits(&key->n), key->heap); @@ -3343,13 +3346,15 @@ static int RsaPrivateDecryptEx(const byte* in, word32 inLen, byte* out, if (rsa_type == RSA_PUBLIC_DECRYPT && ret > (int)outLen) ret = RSA_BUFFER_E; else if (ret >= 0 && pad != NULL) { -#if !defined(WOLFSSL_RSA_VERIFY_ONLY) && !defined(WOLFSSL_RSA_VERIFY_INLINE) +#if !defined(WOLFSSL_RSA_VERIFY_ONLY) && !defined(WOLFSSL_RSA_VERIFY_INLINE) && \ + !defined(WOLFSSL_NO_MALLOC) signed char c; #endif /* only copy output if not inline */ if (outPtr == NULL) { -#if !defined(WOLFSSL_RSA_VERIFY_ONLY) && !defined(WOLFSSL_RSA_VERIFY_INLINE) +#if !defined(WOLFSSL_RSA_VERIFY_ONLY) && !defined(WOLFSSL_RSA_VERIFY_INLINE) && \ + !defined(WOLFSSL_NO_MALLOC) if (rsa_type == RSA_PRIVATE_DECRYPT) { word32 i = 0; word32 j; diff --git a/wolfssl/wolfcrypt/rsa.h b/wolfssl/wolfcrypt/rsa.h index 2b2e373c0..bc845b8d7 100644 --- a/wolfssl/wolfcrypt/rsa.h +++ b/wolfssl/wolfcrypt/rsa.h @@ -205,7 +205,8 @@ struct RsaKey { char label[RSA_MAX_LABEL_LEN]; int labelLen; #endif -#if defined(WOLFSSL_ASYNC_CRYPT) || !defined(WOLFSSL_RSA_VERIFY_INLINE) +#if defined(WOLFSSL_ASYNC_CRYPT) || !defined(WOLFSSL_RSA_VERIFY_INLINE) && \ + !defined(WOLFSSL_NO_MALLOC) byte dataIsAlloc; #endif #ifdef WC_RSA_NONBLOCK From ad2119b2f8ed200faa0334d88b415398a2342391 Mon Sep 17 00:00:00 2001 From: Tesfa Mael Date: Fri, 6 May 2022 12:00:32 -0700 Subject: [PATCH 3/5] Review comments --- wolfcrypt/src/rsa.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/wolfcrypt/src/rsa.c b/wolfcrypt/src/rsa.c index cc664884f..6011b363b 100644 --- a/wolfcrypt/src/rsa.c +++ b/wolfcrypt/src/rsa.c @@ -856,10 +856,10 @@ static int RsaMGF1(enum wc_HashType hType, byte* seed, word32 seedSz, #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) byte* tmp = NULL; #else - byte tmp[RSA_MAX_SIZE/8] = {0}; + byte tmp[RSA_MAX_SIZE/8]; #endif /* needs to be large enough for seed size plus counter(4) */ - byte tmpA[WC_MAX_DIGEST_SIZE + 4]= {0}; + byte tmpA[WC_MAX_DIGEST_SIZE + 4]; byte tmpF = 0; /* 1 if dynamic memory needs freed */ word32 tmpSz = 0; int hLen; @@ -875,6 +875,7 @@ static int RsaMGF1(enum wc_HashType hType, byte* seed, word32 seedSz, (void)heap; + XMEMSET(tmpA, 0, sizeof(tmpA)); /* check error return of wc_HashGetDigestSize */ if (hLen < 0) { return hLen; @@ -885,6 +886,8 @@ static int RsaMGF1(enum wc_HashType hType, byte* seed, word32 seedSz, /* find largest amount of memory needed which will be the max of * hLen and (seedSz + 4) since tmp is used to store the hash digest */ tmpSz = ((seedSz + 4) > (word32)hLen)? seedSz + 4: (word32)hLen; + if (tmpSz > RSA_MAX_SIZE/8) + return BAD_FUNC_ARG; #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) tmp = (byte*)XMALLOC(tmpSz, heap, DYNAMIC_TYPE_RSA_BUFFER); if (tmp == NULL) { @@ -900,7 +903,7 @@ static int RsaMGF1(enum wc_HashType hType, byte* seed, word32 seedSz, #endif #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) tmp = tmpA; - #endif +#endif tmpF = 0; /* no need to free memory at end */ } @@ -1048,15 +1051,15 @@ static int RsaPad_OAEP(const byte* input, word32 inputLen, byte* pkcsBlock, int i; word32 idx; - #ifdef WOLFSSL_SMALL_STACK + #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) byte* dbMask = NULL; byte* lHash = NULL; byte* seed = NULL; #else + byte dbMask[RSA_MAX_SIZE/8 + RSA_PSS_PAD_SZ]; /* must be large enough to contain largest hash */ - byte lHash[WC_MAX_DIGEST_SIZE] = {0}; - byte seed[WC_MAX_DIGEST_SIZE]= {0}; - byte dbMask[RSA_MAX_SIZE/8 + RSA_PSS_PAD_SZ] = {0}; + byte lHash[WC_MAX_DIGEST_SIZE]; + byte seed[WC_MAX_DIGEST_SIZE]; #endif /* no label is allowed, but catch if no label provided and length > 0 */ @@ -1070,7 +1073,7 @@ static int RsaPad_OAEP(const byte* input, word32 inputLen, byte* pkcsBlock, return hLen; } - #ifdef WOLFSSL_SMALL_STACK + #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) lHash = (byte*)XMALLOC(hLen, heap, DYNAMIC_TYPE_RSA_BUFFER); if (lHash == NULL) { return MEMORY_E; @@ -1153,7 +1156,7 @@ static int RsaPad_OAEP(const byte* input, word32 inputLen, byte* pkcsBlock, return ret; } -#ifdef WOLFSSL_SMALL_STACK +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) /* create maskedDB from dbMask */ dbMask = (byte*)XMALLOC(pkcsBlockLen - hLen - 1, heap, DYNAMIC_TYPE_RSA); if (dbMask == NULL) { @@ -1526,10 +1529,11 @@ static int RsaUnPad_OAEP(byte *pkcsBlock, unsigned int pkcsBlockLen, byte h[WC_MAX_DIGEST_SIZE]; /* max digest size */ word32 idx; -#ifdef WOLFSSL_SMALL_STACK +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) byte* tmp = NULL; #else - byte tmp[RSA_MAX_SIZE/8 + RSA_PSS_PAD_SZ] = {0}; + byte tmp[RSA_MAX_SIZE/8 + RSA_PSS_PAD_SZ]; + XMEMSET(tmp, 0, RSA_MAX_SIZE/8 + RSA_PSS_PAD_SZ); #endif /* no label is allowed, but catch if no label provided and length > 0 */ if (optLabel == NULL && labelLen > 0) { @@ -1541,7 +1545,7 @@ static int RsaUnPad_OAEP(byte *pkcsBlock, unsigned int pkcsBlockLen, return BAD_FUNC_ARG; } -#ifdef WOLFSSL_SMALL_STACK +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) tmp = (byte*)XMALLOC(pkcsBlockLen, heap, DYNAMIC_TYPE_RSA_BUFFER); if (tmp == NULL) { return MEMORY_E; From 74b3df4f6cf37c94831963f5bf38ed10a0e0f089 Mon Sep 17 00:00:00 2001 From: Tesfa Mael Date: Fri, 6 May 2022 16:14:47 -0700 Subject: [PATCH 4/5] Refactor tmpF in RsaMGF1 --- wolfcrypt/src/rsa.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/wolfcrypt/src/rsa.c b/wolfcrypt/src/rsa.c index 6011b363b..58ee2b28e 100644 --- a/wolfcrypt/src/rsa.c +++ b/wolfcrypt/src/rsa.c @@ -855,12 +855,12 @@ static int RsaMGF1(enum wc_HashType hType, byte* seed, word32 seedSz, { #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) byte* tmp = NULL; + byte tmpF = 0; /* 1 if dynamic memory needs freed */ #else byte tmp[RSA_MAX_SIZE/8]; #endif /* needs to be large enough for seed size plus counter(4) */ byte tmpA[WC_MAX_DIGEST_SIZE + 4]; - byte tmpF = 0; /* 1 if dynamic memory needs freed */ word32 tmpSz = 0; int hLen; int ret; @@ -903,8 +903,8 @@ static int RsaMGF1(enum wc_HashType hType, byte* seed, word32 seedSz, #endif #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) tmp = tmpA; -#endif tmpF = 0; /* no need to free memory at end */ +#endif } #ifdef WOLFSSL_SMALL_STACK_CACHE @@ -959,11 +959,12 @@ static int RsaMGF1(enum wc_HashType hType, byte* seed, word32 seedSz, } counter++; } while (idx < outSz); - +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) /* check for if dynamic memory was needed, then free */ if (tmpF) { XFREE(tmp, heap, DYNAMIC_TYPE_RSA_BUFFER); } +#endif #ifdef WOLFSSL_SMALL_STACK_CACHE wc_HashFree(hash, hType); XFREE(hash, heap, DYNAMIC_TYPE_DIGEST); From d6935ed3be8ea4c710d1fb87056b26cf2b58ac13 Mon Sep 17 00:00:00 2001 From: Tesfa Mael Date: Tue, 17 May 2022 09:21:20 -0700 Subject: [PATCH 5/5] Review comments --- wolfcrypt/src/rsa.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/wolfcrypt/src/rsa.c b/wolfcrypt/src/rsa.c index 58ee2b28e..b6a445005 100644 --- a/wolfcrypt/src/rsa.c +++ b/wolfcrypt/src/rsa.c @@ -886,14 +886,15 @@ static int RsaMGF1(enum wc_HashType hType, byte* seed, word32 seedSz, /* find largest amount of memory needed which will be the max of * hLen and (seedSz + 4) since tmp is used to store the hash digest */ tmpSz = ((seedSz + 4) > (word32)hLen)? seedSz + 4: (word32)hLen; - if (tmpSz > RSA_MAX_SIZE/8) - return BAD_FUNC_ARG; #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) tmp = (byte*)XMALLOC(tmpSz, heap, DYNAMIC_TYPE_RSA_BUFFER); if (tmp == NULL) { return MEMORY_E; } tmpF = 1; /* make sure to free memory when done */ +#else + if (tmpSz > RSA_MAX_SIZE/8) + return BAD_FUNC_ARG; #endif } else {