Index: asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/rsa.c
===================================================================
--- asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/rsa.c	(revision 337)
+++ asp3_tinet_ecnl_rx/trunk/wolfssl-3.12.2/wolfcrypt/src/rsa.c	(revision 372)
@@ -30,4 +30,16 @@
 #ifndef NO_RSA
 
+#if defined(HAVE_FIPS) && \
+    defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2)
+
+    /* set NO_WRAPPERS before headers, use direct internal f()s not wrappers */
+    #define FIPS_NO_WRAPPERS
+
+       #ifdef USE_WINDOWS_API
+               #pragma code_seg(".fipsA$e")
+               #pragma const_seg(".fipsB$e")
+       #endif
+#endif
+
 #include <wolfssl/wolfcrypt/rsa.h>
 
@@ -44,5 +56,7 @@
  * RSA_LOW_MEM:         NON CRT Private Operations, less memory     default: off
  * WC_NO_RSA_OAEP:      Disables RSA OAEP padding                   default: on (not defined)
-
+ * WC_RSA_NONBLOCK:     Enables support for RSA non-blocking        default: off
+ * WC_RSA_NONBLOCK_TIME:Enables support for time based blocking     default: off
+ *                      time calculation.
 */
 
@@ -55,5 +69,8 @@
 
 
-#ifdef HAVE_FIPS
+/* If building for old FIPS. */
+#if defined(HAVE_FIPS) && \
+    (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))
+
 int  wc_InitRsaKey(RsaKey* key, void* ptr)
 {
@@ -64,4 +81,5 @@
     return InitRsaKey_fips(key, ptr);
 }
+
 
 int  wc_InitRsaKey_ex(RsaKey* key, void* ptr, int devId)
@@ -74,4 +92,5 @@
 }
 
+
 int  wc_FreeRsaKey(RsaKey* key)
 {
@@ -80,4 +99,5 @@
 
 
+#ifndef WOLFSSL_RSA_VERIFY_ONLY
 int  wc_RsaPublicEncrypt(const byte* in, word32 inLen, byte* out,
                                  word32 outLen, RsaKey* key, WC_RNG* rng)
@@ -88,6 +108,8 @@
     return RsaPublicEncrypt_fips(in, inLen, out, outLen, key, rng);
 }
-
-
+#endif
+
+
+#ifndef WOLFSSL_RSA_PUBLIC_ONLY
 int  wc_RsaPrivateDecryptInline(byte* in, word32 inLen, byte** out,
                                         RsaKey* key)
@@ -118,4 +140,5 @@
     return RsaSSL_Sign_fips(in, inLen, out, outLen, key, rng);
 }
+#endif
 
 
@@ -148,4 +171,5 @@
 
 
+#ifndef WOLFSSL_RSA_VERIFY_ONLY
 int wc_RsaFlattenPublicKey(RsaKey* key, byte* a, word32* aSz, byte* b,
                            word32* bSz)
@@ -155,4 +179,7 @@
     return RsaFlattenPublicKey(key, a, aSz, b, bSz);
 }
+#endif
+
+
 #ifdef WOLFSSL_KEY_GEN
     int wc_MakeRsaKey(RsaKey* key, int size, long e, WC_RNG* rng)
@@ -168,8 +195,11 @@
 */
 
-#else /* else build without fips */
+#else /* else build without fips, or for new fips */
 
 #include <wolfssl/wolfcrypt/random.h>
 #include <wolfssl/wolfcrypt/logging.h>
+#ifdef WOLF_CRYPTO_DEV
+    #include <wolfssl/wolfcrypt/cryptodev.h>
+#endif
 #ifdef NO_INLINE
     #include <wolfssl/wolfcrypt/misc.h>
@@ -179,6 +209,4 @@
 #endif
 
-#define ERROR_OUT(x) { ret = (x); goto done;}
-
 
 enum {
@@ -196,11 +224,14 @@
 static void wc_RsaCleanup(RsaKey* key)
 {
+#ifndef WOLFSSL_RSA_VERIFY_INLINE
     if (key && key->data) {
         /* make sure any allocated memory is free'd */
         if (key->dataIsAlloc) {
+        #ifndef WOLFSSL_RSA_PUBLIC_ONLY
             if (key->type == RSA_PRIVATE_DECRYPT ||
                 key->type == RSA_PRIVATE_ENCRYPT) {
                 ForceZero(key->data, key->dataLen);
             }
+        #endif
             XFREE(key->data, key->heap, DYNAMIC_TYPE_WOLF_BIGINT);
             key->dataIsAlloc = 0;
@@ -209,4 +240,7 @@
         key->dataLen = 0;
     }
+#else
+    (void)key;
+#endif
 }
 
@@ -218,13 +252,23 @@
         return BAD_FUNC_ARG;
     }
+
+    XMEMSET(key, 0, sizeof(RsaKey));
 
     key->type = RSA_TYPE_UNKNOWN;
     key->state = RSA_STATE_NONE;
     key->heap = heap;
+#ifndef WOLFSSL_RSA_VERIFY_INLINE
+    key->dataIsAlloc = 0;
     key->data = NULL;
+#endif
     key->dataLen = 0;
-    key->dataIsAlloc = 0;
 #ifdef WC_RSA_BLINDING
     key->rng = NULL;
+#endif
+
+#ifdef WOLF_CRYPTO_DEV
+    key->devId = devId;
+#else
+    (void)devId;
 #endif
 
@@ -241,13 +285,16 @@
             return ret;
     #endif /* WC_ASYNC_ENABLE_RSA */
-#else
-    (void)devId;
 #endif /* WOLFSSL_ASYNC_CRYPT */
 
+#ifndef WOLFSSL_RSA_PUBLIC_ONLY
     ret = mp_init_multi(&key->n, &key->e, NULL, NULL, NULL, NULL);
     if (ret != MP_OKAY)
         return ret;
 
+#if !defined(WOLFSSL_KEY_GEN) && !defined(OPENSSL_EXTRA) && defined(RSA_LOW_MEM)
+    ret = mp_init_multi(&key->d, &key->p, &key->q, NULL, NULL, NULL);
+#else
     ret = mp_init_multi(&key->d, &key->p, &key->q, &key->dP, &key->dQ, &key->u);
+#endif
     if (ret != MP_OKAY) {
         mp_clear(&key->n);
@@ -255,4 +302,14 @@
         return ret;
     }
+#else
+    ret = mp_init(&key->n);
+    if (ret != MP_OKAY)
+        return ret;
+    ret = mp_init(&key->e);
+    if (ret != MP_OKAY) {
+        mp_clear(&key->n);
+        return ret;
+    }
+#endif
 
 #ifdef WOLFSSL_XILINX_CRYPT
@@ -268,4 +325,27 @@
     return wc_InitRsaKey_ex(key, heap, INVALID_DEVID);
 }
+
+#ifdef HAVE_PKCS11
+int wc_InitRsaKey_Id(RsaKey* key, unsigned char* id, int len, void* heap,
+                     int devId)
+{
+    int ret = 0;
+
+    if (key == NULL)
+        ret = BAD_FUNC_ARG;
+    if (ret == 0 && (len < 0 || len > RSA_MAX_ID_LEN))
+        ret = BUFFER_E;
+
+    if (ret == 0)
+        ret = wc_InitRsaKey_ex(key, heap, devId);
+
+    if (ret == 0 && id != NULL && len != 0) {
+        XMEMCPY(key->id, id, len);
+        key->idLen = len;
+    }
+
+    return ret;
+}
+#endif
 
 
@@ -359,8 +439,11 @@
 #endif
 
+#ifndef WOLFSSL_RSA_PUBLIC_ONLY
     if (key->type == RSA_PRIVATE) {
+#if defined(WOLFSSL_KEY_GEN) || defined(OPENSSL_EXTRA) || !defined(RSA_LOW_MEM)
         mp_forcezero(&key->u);
         mp_forcezero(&key->dQ);
         mp_forcezero(&key->dP);
+#endif
         mp_forcezero(&key->q);
         mp_forcezero(&key->p);
@@ -368,10 +451,13 @@
     }
     /* private part */
+#if defined(WOLFSSL_KEY_GEN) || defined(OPENSSL_EXTRA) || !defined(RSA_LOW_MEM)
     mp_clear(&key->u);
     mp_clear(&key->dQ);
     mp_clear(&key->dP);
+#endif
     mp_clear(&key->q);
     mp_clear(&key->p);
     mp_clear(&key->d);
+#endif /* WOLFSSL_RSA_PUBLIC_ONLY */
 
     /* public part */
@@ -386,4 +472,95 @@
     return ret;
 }
+
+#ifndef WOLFSSL_RSA_PUBLIC_ONLY
+/* Check the pair-wise consistency of the RSA key.
+ * From NIST SP 800-56B, section 6.4.1.1.
+ * Verify that k = (k^e)^d, for some k: 1 < k < n-1. */
+int wc_CheckRsaKey(RsaKey* key)
+{
+#ifdef WOLFSSL_SMALL_STACK
+    mp_int *k = NULL, *tmp = NULL;
+#else
+    mp_int k[1], tmp[1];
+#endif
+    int ret = 0;
+
+#ifdef WOLFSSL_SMALL_STACK
+    k = (mp_int*)XMALLOC(sizeof(mp_int) * 2, NULL, DYNAMIC_TYPE_RSA);
+    if (k == NULL)
+        return MEMORY_E;
+    tmp = k + 1;
+#endif
+
+    if (mp_init_multi(k, tmp, NULL, NULL, NULL, NULL) != MP_OKAY)
+        ret = MP_INIT_E;
+
+    if (ret == 0) {
+        if (key == NULL)
+            ret = BAD_FUNC_ARG;
+    }
+
+    if (ret == 0) {
+        if (mp_set_int(k, 0x2342) != MP_OKAY)
+            ret = MP_READ_E;
+    }
+
+#ifdef WOLFSSL_SP_RSA
+#ifndef WOLFSSL_SP_NO_2048
+    if (mp_count_bits(&key->n) == 2048) {
+        ret = sp_ModExp_2048(k, &key->e, &key->n, tmp);
+        if (ret != 0)
+            ret = MP_EXPTMOD_E;
+        ret = sp_ModExp_2048(tmp, &key->d, &key->n, tmp);
+        if (ret != 0)
+            ret = MP_EXPTMOD_E;
+    }
+    else
+#endif
+#ifndef WOLFSSL_SP_NO_3072
+    if (mp_count_bits(&key->n) == 3072) {
+        ret = sp_ModExp_3072(k, &key->e, &key->n, tmp);
+        if (ret != 0)
+            ret = MP_EXPTMOD_E;
+        ret = sp_ModExp_3072(tmp, &key->d, &key->n, tmp);
+        if (ret != 0)
+            ret = MP_EXPTMOD_E;
+    }
+    else
+#endif
+#endif
+#ifdef WOLFSSL_SP_MATH
+    {
+        ret = WC_KEY_SIZE_E;
+    }
+#else
+    {
+        if (ret == 0) {
+            if (mp_exptmod(k, &key->e, &key->n, tmp) != MP_OKAY)
+                ret = MP_EXPTMOD_E;
+        }
+
+        if (ret == 0) {
+            if (mp_exptmod(tmp, &key->d, &key->n, tmp) != MP_OKAY)
+                ret = MP_EXPTMOD_E;
+        }
+    }
+#endif
+
+    if (ret == 0) {
+        if (mp_cmp(k, tmp) != MP_EQ)
+            ret = RSA_KEY_PAIR_E;
+    }
+
+    mp_forcezero(tmp);
+    mp_clear(tmp);
+    mp_clear(k);
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(k, NULL, DYNAMIC_TYPE_RSA);
+#endif
+
+    return ret;
+}
+#endif
 
 
@@ -494,5 +671,4 @@
             break;
     #endif
-    #ifdef WOLFSSL_SHA512
     #ifdef WOLFSSL_SHA384
         case WC_MGF1SHA384:
@@ -500,4 +676,5 @@
             break;
     #endif
+    #ifdef WOLFSSL_SHA512
         case WC_MGF1SHA512:
             ret = RsaMGF1(WC_HASH_TYPE_SHA512, seed, seedSz, out, outSz, heap);
@@ -522,4 +699,6 @@
 
 /* Padding */
+#ifndef WOLFSSL_RSA_VERIFY_ONLY
+#ifndef WC_NO_RNG
 #ifndef WC_NO_RSA_OAEP
 static int RsaPad_OAEP(const byte* input, word32 inputLen, byte* pkcsBlock,
@@ -700,11 +879,25 @@
 
 #ifdef WC_RSA_PSS
+
 /* 0x00 .. 0x00 0x01 | Salt | Gen Hash | 0xbc
  * XOR MGF over all bytes down to end of Salt
  * Gen Hash = HASH(8 * 0x00 | Message Hash | Salt)
+ *
+ * input         Digest of the message.
+ * inputLen      Length of digest.
+ * pkcsBlock     Buffer to write to.
+ * pkcsBlockLen  Length of buffer to write to.
+ * rng           Random number generator (for salt).
+ * htype         Hash function to use.
+ * mgf           Mask generation function.
+ * saltLen       Length of salt to put in padding.
+ * bits          Length of key in bits.
+ * heap          Used for dynamic memory allocation.
+ * returns 0 on success, PSS_SALTLEN_E when the salt length is invalid
+ * and other negative values on error.
  */
 static int RsaPad_PSS(const byte* input, word32 inputLen, byte* pkcsBlock,
         word32 pkcsBlockLen, WC_RNG* rng, enum wc_HashType hType, int mgf,
-        int bits, void* heap)
+        int saltLen, int bits, void* heap)
 {
     int   ret;
@@ -719,18 +912,31 @@
         return hLen;
 
+    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)
+                saltLen = RSA_PSS_SALT_MAX_SZ;
+        #endif
+    }
+    else if (saltLen > hLen || saltLen < -1)
+        return PSS_SALTLEN_E;
+    if ((int)pkcsBlockLen - hLen < saltLen + 2)
+        return PSS_SALTLEN_E;
+
     s = m = pkcsBlock;
-    XMEMSET(m, 0, 8);
-    m += 8;
+    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, hLen)) != 0)
+    if ((ret = wc_RNG_GenerateBlock(rng, salt, saltLen)) != 0)
         return ret;
-    XMEMCPY(m, salt, hLen);
-    m += hLen;
+    XMEMCPY(m, salt, saltLen);
+    m += saltLen;
 
     h = pkcsBlock + pkcsBlockLen - 1 - hLen;
     if ((ret = wc_Hash(hType, s, (word32)(m - s), h, hLen)) != 0)
         return ret;
-    pkcsBlock[pkcsBlockLen - 1] = 0xbc;
+    pkcsBlock[pkcsBlockLen - 1] = RSA_PSS_PAD_TERM;
 
     ret = RsaMGF(mgf, h, hLen, pkcsBlock, pkcsBlockLen - hLen - 1, heap);
@@ -739,12 +945,12 @@
     pkcsBlock[0] &= (1 << ((bits - 1) & 0x7)) - 1;
 
-    m = pkcsBlock + pkcsBlockLen - 1 - hLen - hLen - 1;
+    m = pkcsBlock + pkcsBlockLen - 1 - saltLen - hLen - 1;
     *(m++) ^= 0x01;
-    for (i = 0; i < hLen; i++)
+    for (i = 0; i < saltLen; i++)
         m[i] ^= salt[i];
 
     return 0;
 }
-#endif
+#endif /* WC_RSA_PSS */
 
 static int RsaPad(const byte* input, word32 inputLen, byte* pkcsBlock,
@@ -770,4 +976,5 @@
     }
     else {
+#ifndef WOLFSSL_RSA_VERIFY_ONLY
         /* pad with non-zero random bytes */
         word32 padLen, i;
@@ -789,4 +996,8 @@
             if (pkcsBlock[i] == 0) pkcsBlock[i] = 0x01;
         }
+#else
+        (void)rng;
+        return RSA_WRONG_TYPE_E;
+#endif
     }
 
@@ -796,10 +1007,11 @@
     return 0;
 }
+#endif /* !WC_NO_RNG */
 
 /* helper function to direct which padding is used */
 static int wc_RsaPad_ex(const byte* input, word32 inputLen, byte* pkcsBlock,
     word32 pkcsBlockLen, byte padValue, WC_RNG* rng, int padType,
-    enum wc_HashType hType, int mgf, byte* optLabel, word32 labelLen, int bits,
-    void* heap)
+    enum wc_HashType hType, int mgf, byte* optLabel, word32 labelLen,
+    int saltLen, int bits, void* heap)
 {
     int ret;
@@ -807,4 +1019,5 @@
     switch (padType)
     {
+#ifndef WC_NO_RNG
         case WC_RSA_PKCSV15_PAD:
             /*WOLFSSL_MSG("wolfSSL Using RSA PKCSV15 padding");*/
@@ -825,5 +1038,23 @@
             WOLFSSL_MSG("wolfSSL Using RSA PSS padding");
             ret = RsaPad_PSS(input, inputLen, pkcsBlock, pkcsBlockLen, rng,
-                                                        hType, mgf, bits, heap);
+                                               hType, mgf, saltLen, bits, heap);
+            break;
+    #endif
+#endif /* !WC_NO_RNG */
+
+    #ifdef WC_RSA_NO_PADDING
+        case WC_RSA_NO_PAD:
+            WOLFSSL_MSG("wolfSSL Using NO padding");
+
+            /* In the case of no padding being used check that input is exactly
+             * the RSA key length */
+            if (bits <= 0 || inputLen != ((word32)bits/WOLFSSL_BIT_SIZE)) {
+                WOLFSSL_MSG("Bad input size");
+                ret = RSA_PAD_E;
+            }
+            else {
+                XMEMCPY(pkcsBlock, input, inputLen);
+                ret = 0;
+            }
             break;
     #endif
@@ -835,8 +1066,16 @@
 
     /* silence warning if not used with padding scheme */
+    (void)input;
+    (void)inputLen;
+    (void)pkcsBlock;
+    (void)pkcsBlockLen;
+    (void)padValue;
+    (void)rng;
+    (void)padType;
     (void)hType;
     (void)mgf;
     (void)optLabel;
     (void)labelLen;
+    (void)saltLen;
     (void)bits;
     (void)heap;
@@ -844,4 +1083,5 @@
     return ret;
 }
+#endif /* WOLFSSL_RSA_VERIFY_ONLY */
 
 
@@ -923,8 +1163,6 @@
     ret += pkcsBlock[0]     ^ 0x00; /* Y, the first value, should be 0 */
 
-    if (ret != 0) {
-        WOLFSSL_MSG("RsaUnPad_OAEP: Padding Error");
-        return BAD_PADDING_E;
-    }
+    /* Return 0 data length on error. */
+    idx = ctMaskSelInt(ctMaskEq(ret, 0), idx, pkcsBlockLen);
 
     /* adjust pointer to correct location in array and return size of M */
@@ -935,7 +1173,21 @@
 
 #ifdef WC_RSA_PSS
+/* 0x00 .. 0x00 0x01 | Salt | Gen Hash | 0xbc
+ * MGF over all bytes down to end of Salt
+ *
+ * pkcsBlock     Buffer holding decrypted data.
+ * pkcsBlockLen  Length of buffer.
+ * htype         Hash function to use.
+ * mgf           Mask generation function.
+ * saltLen       Length of salt to put in padding.
+ * bits          Length of key in bits.
+ * heap          Used for dynamic memory allocation.
+ * returns 0 on success, PSS_SALTLEN_E when the salt length is invalid,
+ * BAD_PADDING_E when the padding is not valid, MEMORY_E when allocation fails
+ * and other negative values on error.
+ */
 static int RsaUnPad_PSS(byte *pkcsBlock, unsigned int pkcsBlockLen,
                         byte **output, enum wc_HashType hType, int mgf,
-                        int bits, void* heap)
+                        int saltLen, int bits, void* heap)
 {
     int   ret;
@@ -947,13 +1199,25 @@
         return hLen;
 
-    if (pkcsBlock[pkcsBlockLen - 1] != 0xbc) {
-        WOLFSSL_MSG("RsaUnPad_PSS: Padding Error 0xBC");
+    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)
+                saltLen = RSA_PSS_SALT_MAX_SZ;
+        #endif
+    }
+    else if (saltLen > hLen || saltLen < -1)
+        return PSS_SALTLEN_E;
+    if ((int)pkcsBlockLen - hLen < saltLen + 2)
+        return PSS_SALTLEN_E;
+
+    if (pkcsBlock[pkcsBlockLen - 1] != RSA_PSS_PAD_TERM) {
+        WOLFSSL_MSG("RsaUnPad_PSS: Padding Term Error");
         return BAD_PADDING_E;
     }
 
     tmp = (byte*)XMALLOC(pkcsBlockLen, heap, DYNAMIC_TYPE_RSA_BUFFER);
-    if (tmp == NULL) {
+    if (tmp == NULL)
         return MEMORY_E;
-    }
 
     if ((ret = RsaMGF(mgf, pkcsBlock + pkcsBlockLen - 1 - hLen, hLen,
@@ -964,5 +1228,5 @@
 
     tmp[0] &= (1 << ((bits - 1) & 0x7)) - 1;
-    for (i = 0; i < (int)(pkcsBlockLen - 1 - hLen - hLen - 1); i++) {
+    for (i = 0; i < (int)(pkcsBlockLen - 1 - saltLen - hLen - 1); i++) {
         if (tmp[i] != pkcsBlock[i]) {
             XFREE(tmp, heap, DYNAMIC_TYPE_RSA_BUFFER);
@@ -981,9 +1245,6 @@
     XFREE(tmp, heap, DYNAMIC_TYPE_RSA_BUFFER);
 
-    i = pkcsBlockLen - (RSA_PSS_PAD_SZ + 3 * hLen + 1);
-    XMEMSET(pkcsBlock + i, 0, RSA_PSS_PAD_SZ);
-
-    *output = pkcsBlock + i;
-    return RSA_PSS_PAD_SZ + 3 * hLen;
+    *output = pkcsBlock + pkcsBlockLen - (hLen + saltLen + 1);
+    return saltLen + hLen;
 }
 #endif
@@ -994,8 +1255,9 @@
                                                byte **output, byte padValue)
 {
-    word32 maxOutputLen = (pkcsBlockLen > 10) ? (pkcsBlockLen - 10) : 0;
-    word32 invalid = 0;
-    word32 i = 1;
-    word32 outputLen;
+    int    ret = BAD_FUNC_ARG;
+    word32 i;
+#ifndef WOLFSSL_RSA_VERIFY_ONLY
+    byte   invalid = 0;
+#endif
 
     if (output == NULL || pkcsBlockLen == 0) {
@@ -1003,42 +1265,60 @@
     }
 
-    if (pkcsBlock[0] != 0x0) { /* skip past zero */
-        invalid = 1;
-    }
-    pkcsBlock++; pkcsBlockLen--;
-
-    /* Require block type padValue */
-    invalid = (pkcsBlock[0] != padValue) || invalid;
-
-    /* verify the padding until we find the separator */
     if (padValue == RSA_BLOCK_TYPE_1) {
-        while (i<pkcsBlockLen && pkcsBlock[i++] == 0xFF) {/* Null body */}
-    }
-    else {
-        while (i<pkcsBlockLen && pkcsBlock[i++]) {/* Null body */}
-    }
-
-    if (!(i==pkcsBlockLen || pkcsBlock[i-1]==0)) {
+        /* First byte must be 0x00 and Second byte, block type, 0x01 */
+        if (pkcsBlock[0] != 0 || pkcsBlock[1] != RSA_BLOCK_TYPE_1) {
+            WOLFSSL_MSG("RsaUnPad error, invalid formatting");
+            return RSA_PAD_E;
+    }
+
+        /* check the padding until we find the separator */
+        for (i = 2; i < pkcsBlockLen && pkcsBlock[i++] == 0xFF; ) { }
+
+        /* Minimum of 11 bytes of pre-message data and must have separator. */
+        if (i < RSA_MIN_PAD_SZ || pkcsBlock[i-1] != 0) {
         WOLFSSL_MSG("RsaUnPad error, bad formatting");
         return RSA_PAD_E;
     }
 
-    outputLen = pkcsBlockLen - i;
-    invalid = (outputLen > maxOutputLen) || invalid;
-
-    if (invalid) {
-        WOLFSSL_MSG("RsaUnPad error, invalid formatting");
-        return RSA_PAD_E;
-    }
+        *output = (byte *)(pkcsBlock + i);
+        ret = pkcsBlockLen - i;
+    }
+#ifndef WOLFSSL_RSA_VERIFY_ONLY
+    else {
+        word32 j;
+        byte   pastSep = 0;
+
+        /* Decrypted with private key - unpad must be constant time. */
+        for (i = 0, j = 2; j < pkcsBlockLen; j++) {
+           /* Update i if not passed the separator and at separator. */
+           i |= (~pastSep) & ctMaskEq(pkcsBlock[j], 0x00) & (j + 1);
+           pastSep |= ctMaskEq(pkcsBlock[j], 0x00);
+        }
+
+        /* Minimum of 11 bytes of pre-message data - including leading 0x00. */
+        invalid |= ctMaskLT(i, RSA_MIN_PAD_SZ);
+        /* Must have seen separator. */
+        invalid |= ~pastSep;
+        /* First byte must be 0x00. */
+        invalid |= ctMaskNotEq(pkcsBlock[0], 0x00);
+        /* Check against expected block type: padValue */
+        invalid |= ctMaskNotEq(pkcsBlock[1], padValue);
 
     *output = (byte *)(pkcsBlock + i);
-    return outputLen;
-}
-
-/* helper function to direct unpadding */
+        ret = ((int)~invalid) & (pkcsBlockLen - i);
+    }
+#endif
+
+    return ret;
+}
+
+/* helper function to direct unpadding
+ *
+ * bits is the key modulus size in bits
+ */
 static int wc_RsaUnPad_ex(byte* pkcsBlock, word32 pkcsBlockLen, byte** out,
                           byte padValue, int padType, enum wc_HashType hType,
-                          int mgf, byte* optLabel, word32 labelLen, int bits,
-                          void* heap)
+                          int mgf, byte* optLabel, word32 labelLen, int saltLen,
+                          int bits, void* heap)
 {
     int ret;
@@ -1062,7 +1342,26 @@
             WOLFSSL_MSG("wolfSSL Using RSA PSS un-padding");
             ret = RsaUnPad_PSS((byte*)pkcsBlock, pkcsBlockLen, out, hType, mgf,
-                                                                    bits, heap);
+                                                           saltLen, bits, heap);
             break;
     #endif
+
+    #ifdef WC_RSA_NO_PADDING
+        case WC_RSA_NO_PAD:
+            WOLFSSL_MSG("wolfSSL Using NO un-padding");
+
+            /* 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)) {
+                WOLFSSL_MSG("Bad input size");
+                ret = RSA_PAD_E;
+            }
+            else {
+                if (out != NULL) {
+                    *out = pkcsBlock;
+                }
+                ret = pkcsBlockLen;
+            }
+            break;
+    #endif /* WC_RSA_NO_PADDING */
 
         default:
@@ -1076,4 +1375,5 @@
     (void)optLabel;
     (void)labelLen;
+    (void)saltLen;
     (void)bits;
     (void)heap;
@@ -1131,13 +1431,101 @@
 #endif /* WOLFSSL_XILINX_CRYPT */
 
+#ifdef WC_RSA_NONBLOCK
+static int wc_RsaFunctionNonBlock(const byte* in, word32 inLen, byte* out,
+                          word32* outLen, int type, RsaKey* key)
+{
+    int    ret = 0;
+    word32 keyLen, len;
+
+    if (key == NULL || key->nb == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
+    if (key->nb->exptmod.state == TFM_EXPTMOD_NB_INIT) {
+        if (mp_init(&key->nb->tmp) != MP_OKAY) {
+            ret = MP_INIT_E;
+        }
+
+        if (ret == 0) {
+            if (mp_read_unsigned_bin(&key->nb->tmp, (byte*)in, inLen) != MP_OKAY) {
+                ret = MP_READ_E;
+            }
+        }
+    }
+
+    if (ret == 0) {
+        switch(type) {
+        case RSA_PRIVATE_DECRYPT:
+        case RSA_PRIVATE_ENCRYPT:
+            ret = fp_exptmod_nb(&key->nb->exptmod, &key->nb->tmp, &key->d,
+                &key->n, &key->nb->tmp);
+            if (ret == FP_WOULDBLOCK)
+                return ret;
+            if (ret != MP_OKAY)
+                ret = MP_EXPTMOD_E;
+            break;
+
+        case RSA_PUBLIC_ENCRYPT:
+        case RSA_PUBLIC_DECRYPT:
+            ret = fp_exptmod_nb(&key->nb->exptmod, &key->nb->tmp, &key->e,
+                &key->n, &key->nb->tmp);
+            if (ret == FP_WOULDBLOCK)
+                return ret;
+            if (ret != MP_OKAY)
+                ret = MP_EXPTMOD_E;
+            break;
+        default:
+            ret = RSA_WRONG_TYPE_E;
+            break;
+        }
+    }
+
+    if (ret == 0) {
+        keyLen = wc_RsaEncryptSize(key);
+        if (keyLen > *outLen)
+            ret = RSA_BUFFER_E;
+    }
+    if (ret == 0) {
+        len = mp_unsigned_bin_size(&key->nb->tmp);
+
+        /* pad front w/ zeros to match key length */
+        while (len < keyLen) {
+            *out++ = 0x00;
+            len++;
+        }
+
+        *outLen = keyLen;
+
+        /* convert */
+        if (mp_to_unsigned_bin(&key->nb->tmp, out) != MP_OKAY) {
+             ret = MP_TO_E;
+        }
+    }
+
+    mp_clear(&key->nb->tmp);
+
+    return ret;
+}
+#endif /* WC_RSA_NONBLOCK */
+
 static int wc_RsaFunctionSync(const byte* in, word32 inLen, byte* out,
                           word32* outLen, int type, RsaKey* key, WC_RNG* rng)
 {
-    mp_int tmp;
+#ifndef WOLFSSL_SP_MATH
+#ifdef WOLFSSL_SMALL_STACK
+    mp_int* tmp = NULL;
 #ifdef WC_RSA_BLINDING
-    mp_int rnd, rndi;
+    mp_int* rnd = NULL;
+    mp_int* rndi = NULL;
+#endif
+#else
+    mp_int tmp[1];
+#ifdef WC_RSA_BLINDING
+    mp_int rnd[1], rndi[1];
+#endif
 #endif
     int    ret = 0;
-    word32 keyLen, len;
+    word32 keyLen = 0;
+#endif
 
 #ifdef WOLFSSL_HAVE_SP_RSA
@@ -1145,4 +1533,5 @@
     if (mp_count_bits(&key->n) == 2048) {
         switch(type) {
+#ifndef WOLFSSL_RSA_PUBLIC_ONLY
         case RSA_PRIVATE_DECRYPT:
         case RSA_PRIVATE_ENCRYPT:
@@ -1151,7 +1540,13 @@
                 return MISSING_RNG_E;
     #endif
+    #ifndef RSA_LOW_MEM
             return sp_RsaPrivate_2048(in, inLen, &key->d, &key->p, &key->q,
                                       &key->dP, &key->dQ, &key->u, &key->n,
                                       out, outLen);
+    #else
+            return sp_RsaPrivate_2048(in, inLen, &key->d, &key->p, &key->q,
+                                      NULL, NULL, NULL, &key->n, out, outLen);
+    #endif
+#endif
         case RSA_PUBLIC_ENCRYPT:
         case RSA_PUBLIC_DECRYPT:
@@ -1163,4 +1558,5 @@
     if (mp_count_bits(&key->n) == 3072) {
         switch(type) {
+#ifndef WOLFSSL_RSA_PUBLIC_ONLY
         case RSA_PRIVATE_DECRYPT:
         case RSA_PRIVATE_ENCRYPT:
@@ -1169,7 +1565,13 @@
                 return MISSING_RNG_E;
     #endif
+    #ifndef RSA_LOW_MEM
             return sp_RsaPrivate_3072(in, inLen, &key->d, &key->p, &key->q,
                                       &key->dP, &key->dQ, &key->u, &key->n,
                                       out, outLen);
+    #else
+            return sp_RsaPrivate_3072(in, inLen, &key->d, &key->p, &key->q,
+                                      NULL, NULL, NULL, &key->n, out, outLen);
+    #endif
+#endif
         case RSA_PUBLIC_ENCRYPT:
         case RSA_PUBLIC_DECRYPT:
@@ -1180,98 +1582,137 @@
 #endif /* WOLFSSL_HAVE_SP_RSA */
 
+#ifdef WOLFSSL_SP_MATH
     (void)rng;
-
-    if (mp_init(&tmp) != MP_OKAY)
-        return MP_INIT_E;
-
+    return WC_KEY_SIZE_E;
+#else
+    (void)rng;
+
+#ifdef WOLFSSL_SMALL_STACK
+    tmp = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_RSA);
+    if (tmp == NULL)
+        return MEMORY_E;
 #ifdef WC_RSA_BLINDING
+    rnd = (mp_int*)XMALLOC(sizeof(mp_int) * 2, key->heap, DYNAMIC_TYPE_RSA);
+    if (rnd == NULL) {
+        XFREE(tmp, key->heap, DYNAMIC_TYPE_RSA);
+        return MEMORY_E;
+    }
+    rndi = rnd + 1;
+#endif /* WC_RSA_BLINDING */
+#endif /* WOLFSSL_SMALL_STACK */
+
+    if (mp_init(tmp) != MP_OKAY)
+        ret = MP_INIT_E;
+
+#ifdef WC_RSA_BLINDING
+    if (ret == 0) {
     if (type == RSA_PRIVATE_DECRYPT || type == RSA_PRIVATE_ENCRYPT) {
-        if (mp_init_multi(&rnd, &rndi, NULL, NULL, NULL, NULL) != MP_OKAY) {
-            mp_clear(&tmp);
-            return MP_INIT_E;
-        }
-    }
-#endif
-
-    if (mp_read_unsigned_bin(&tmp, (byte*)in, inLen) != MP_OKAY)
-        ERROR_OUT(MP_READ_E);
-
+            if (mp_init_multi(rnd, rndi, NULL, NULL, NULL, NULL) != MP_OKAY) {
+                mp_clear(tmp);
+                ret = MP_INIT_E;
+            }
+        }
+    }
+#endif
+
+#ifndef TEST_UNPAD_CONSTANT_TIME
+    if (ret == 0 && mp_read_unsigned_bin(tmp, (byte*)in, inLen) != MP_OKAY)
+        ret = MP_READ_E;
+
+    if (ret == 0) {
     switch(type) {
+    #ifndef WOLFSSL_RSA_PUBLIC_ONLY
     case RSA_PRIVATE_DECRYPT:
     case RSA_PRIVATE_ENCRYPT:
     {
-    #ifdef WC_RSA_BLINDING
+        #if defined(WC_RSA_BLINDING) && !defined(WC_NO_RNG)
         /* blind */
-        ret = mp_rand(&rnd, get_digit_count(&key->n), rng);
-        if (ret != MP_OKAY)
-            goto done;
+            ret = mp_rand(rnd, get_digit_count(&key->n), rng);
 
         /* rndi = 1/rnd mod n */
-        if (mp_invmod(&rnd, &key->n, &rndi) != MP_OKAY)
-            ERROR_OUT(MP_INVMOD_E);
+            if (ret == 0 && mp_invmod(rnd, &key->n, rndi) != MP_OKAY)
+                ret = MP_INVMOD_E;
 
         /* rnd = rnd^e */
-        if (mp_exptmod(&rnd, &key->e, &key->n, &rnd) != MP_OKAY)
-            ERROR_OUT(MP_EXPTMOD_E);
+            if (ret == 0 && mp_exptmod(rnd, &key->e, &key->n, rnd) != MP_OKAY)
+                ret = MP_EXPTMOD_E;
 
         /* tmp = tmp*rnd mod n */
-        if (mp_mulmod(&tmp, &rnd, &key->n, &tmp) != MP_OKAY)
-            ERROR_OUT(MP_MULMOD_E);
-    #endif /* WC_RSA_BLINGING */
+            if (ret == 0 && mp_mulmod(tmp, rnd, &key->n, tmp) != MP_OKAY)
+                ret = MP_MULMOD_E;
+        #endif /* WC_RSA_BLINDING && !WC_NO_RNG */
 
     #ifdef RSA_LOW_MEM      /* half as much memory but twice as slow */
-        if (mp_exptmod(&tmp, &key->d, &key->n, &tmp) != MP_OKAY)
-            ERROR_OUT(MP_EXPTMOD_E);
+            if (ret == 0 && mp_exptmod(tmp, &key->d, &key->n, tmp) != MP_OKAY)
+                ret = MP_EXPTMOD_E;
     #else
-        /* Return 0 when cond is false and n when cond is true. */
-        #define COND_N(cond, n)    ((0 - (cond)) & (n))
-        /* If ret has an error value return it otherwise if r is OK then return
-         * 0 otherwise return e.
-         */
-        #define RET_ERR(ret, r, e) \
-            ((ret) | (COND_N((ret) == 0, COND_N((r) != MP_OKAY, (e)))))
-
-        { /* tmpa/b scope */
-        mp_int tmpa, tmpb;
-        int r;
-
-        if (mp_init(&tmpa) != MP_OKAY)
-            ERROR_OUT(MP_INIT_E);
-
-        if (mp_init(&tmpb) != MP_OKAY) {
-            mp_clear(&tmpa);
-            ERROR_OUT(MP_INIT_E);
+            if (ret == 0) {
+            #ifdef WOLFSSL_SMALL_STACK
+                mp_int* tmpa = NULL;
+                mp_int* tmpb = NULL;
+            #else
+                mp_int tmpa[1], tmpb[1];
+            #endif
+                int cleara = 0, clearb = 0;
+
+            #ifdef WOLFSSL_SMALL_STACK
+                tmpa = XMALLOC(sizeof(mp_int) * 2, key->heap, DYNAMIC_TYPE_RSA);
+                if (tmpa != NULL)
+                    tmpb = tmpa + 1;
+                else
+                    ret = MEMORY_E;
+            #endif
+
+                if (ret == 0) {
+                    if (mp_init(tmpa) != MP_OKAY)
+                        ret = MP_INIT_E;
+                    else
+                        cleara = 1;
+                }
+
+                if (ret == 0) {
+                    if (mp_init(tmpb) != MP_OKAY)
+                        ret = MP_INIT_E;
+                    else
+                        clearb = 1;
         }
 
         /* tmpa = tmp^dP mod p */
-        r = mp_exptmod(&tmp, &key->dP, &key->p, &tmpa);
-        ret = RET_ERR(ret, r, MP_EXPTMOD_E);
+                if (ret == 0 && mp_exptmod(tmp, &key->dP, &key->p,
+                                                               tmpa) != MP_OKAY)
+                    ret = MP_EXPTMOD_E;
 
         /* tmpb = tmp^dQ mod q */
-        r = mp_exptmod(&tmp, &key->dQ, &key->q, &tmpb);
-        ret = RET_ERR(ret, r, MP_EXPTMOD_E);
+                if (ret == 0 && mp_exptmod(tmp, &key->dQ, &key->q,
+                                                               tmpb) != MP_OKAY)
+                    ret = MP_EXPTMOD_E;
 
         /* tmp = (tmpa - tmpb) * qInv (mod p) */
-        r = mp_sub(&tmpa, &tmpb, &tmp);
-        ret = RET_ERR(ret, r, MP_SUB_E);
-
-        r = mp_mulmod(&tmp, &key->u, &key->p, &tmp);
-        ret = RET_ERR(ret, r, MP_MULMOD_E);
+                if (ret == 0 && mp_sub(tmpa, tmpb, tmp) != MP_OKAY)
+                    ret = MP_SUB_E;
+
+                if (ret == 0 && mp_mulmod(tmp, &key->u, &key->p,
+                                                                tmp) != MP_OKAY)
+                    ret = MP_MULMOD_E;
 
         /* tmp = tmpb + q * tmp */
-        r = mp_mul(&tmp, &key->q, &tmp);
-        ret = RET_ERR(ret, r, MP_MUL_E);
-
-        r = mp_add(&tmp, &tmpb, &tmp);
-        ret = RET_ERR(ret, r, MP_ADD_E);
-
-        mp_clear(&tmpa);
-        mp_clear(&tmpb);
-
-        if (ret != 0) {
-            goto done;
-        }
-        #undef RET_ERR
-        #undef COND_N
+                if (ret == 0 && mp_mul(tmp, &key->q, tmp) != MP_OKAY)
+                    ret = MP_MUL_E;
+
+                if (ret == 0 && mp_add(tmp, tmpb, tmp) != MP_OKAY)
+                    ret = MP_ADD_E;
+
+            #ifdef WOLFSSL_SMALL_STACK
+                if (tmpa != NULL)
+            #endif
+                {
+                    if (cleara)
+                        mp_clear(tmpa);
+                    if (clearb)
+                        mp_clear(tmpb);
+            #ifdef WOLFSSL_SMALL_STACK
+                    XFREE(tmpa, key->heap, DYNAMIC_TYPE_RSA);
+            #endif
+        }
         } /* tmpa/b scope */
     #endif   /* RSA_LOW_MEM */
@@ -1279,52 +1720,59 @@
     #ifdef WC_RSA_BLINDING
         /* unblind */
-        if (mp_mulmod(&tmp, &rndi, &key->n, &tmp) != MP_OKAY)
-            ERROR_OUT(MP_MULMOD_E);
+            if (ret == 0 && mp_mulmod(tmp, rndi, &key->n, tmp) != MP_OKAY)
+                ret = MP_MULMOD_E;
     #endif   /* WC_RSA_BLINDING */
 
         break;
     }
+    #endif
     case RSA_PUBLIC_ENCRYPT:
     case RSA_PUBLIC_DECRYPT:
     #ifdef WOLFSSL_XILINX_CRYPT
         ret = wc_RsaFunctionXil(in, inLen, out, outLen, type, key, rng);
-        goto done;
     #else
-        if (mp_exptmod(&tmp, &key->e, &key->n, &tmp) != MP_OKAY)
-            ERROR_OUT(MP_EXPTMOD_E);
+            if (mp_exptmod(tmp, &key->e, &key->n, tmp) != MP_OKAY)
+                ret = MP_EXPTMOD_E;
         break;
     #endif
     default:
-        ERROR_OUT(RSA_WRONG_TYPE_E);
-    }
-
-    keyLen = wc_RsaEncryptSize(key);
-    if (keyLen > *outLen) {
-        ERROR_OUT(RSA_BUFFER_E);
-    }
-
-    len = mp_unsigned_bin_size(&tmp);
-
-    /* pad front w/ zeros to match key length */
-    while (len < keyLen) {
-        *out++ = 0x00;
-        len++;
-    }
-
+            ret = RSA_WRONG_TYPE_E;
+            break;
+    }
+    }
+
+    if (ret == 0) {
+        keyLen = wc_RsaEncryptSize(key);
+        if (keyLen > *outLen)
+            ret = RSA_BUFFER_E;
+    }
+    if (ret == 0) {
     *outLen = keyLen;
-
-    /* convert */
-    if (mp_to_unsigned_bin(&tmp, out) != MP_OKAY)
-        ERROR_OUT(MP_TO_E);
-
-done:
-    mp_clear(&tmp);
+        if (mp_to_unsigned_bin_len(tmp, out, keyLen) != MP_OKAY)
+             ret = MP_TO_E;
+    }
+#else
+    (void)type;
+    (void)key;
+    (void)keyLen;
+    XMEMCPY(out, in, inLen);
+    *outLen = inLen;
+#endif
+
+    mp_clear(tmp);
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(tmp, key->heap, DYNAMIC_TYPE_RSA);
+#endif
 #ifdef WC_RSA_BLINDING
     if (type == RSA_PRIVATE_DECRYPT || type == RSA_PRIVATE_ENCRYPT) {
-        mp_clear(&rndi);
-        mp_clear(&rnd);
-    }
-#endif
+        mp_clear(rndi);
+        mp_clear(rnd);
+    }
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(rnd, key->heap, DYNAMIC_TYPE_RSA);
+#endif
+#endif /* WC_RSA_BLINDING */
     return ret;
+#endif /* WOLFSSL_SP_MATH */
 }
 
@@ -1352,7 +1800,9 @@
 
     switch(type) {
+#ifndef WOLFSSL_RSA_PUBLIC_ONLY
     case RSA_PRIVATE_DECRYPT:
     case RSA_PRIVATE_ENCRYPT:
     #ifdef HAVE_CAVIUM
+        key->dataLen = key->n.raw.len;
         ret = NitroxRsaExptMod(in, inLen,
                                key->d.raw.buf, key->d.raw.len,
@@ -1375,8 +1825,10 @@
     #endif
         break;
+#endif
 
     case RSA_PUBLIC_ENCRYPT:
     case RSA_PUBLIC_DECRYPT:
     #ifdef HAVE_CAVIUM
+        key->dataLen = key->n.raw.len;
         ret = NitroxRsaExptMod(in, inLen,
                                key->e.raw.buf, key->e.raw.len,
@@ -1400,8 +1852,109 @@
 #endif /* WOLFSSL_ASYNC_CRYPT && WC_ASYNC_ENABLE_RSA */
 
+#if defined(WC_RSA_DIRECT) || defined(WC_RSA_NO_PADDING)
+/* Function that does the RSA operation directly with no padding.
+ *
+ * in       buffer to do operation on
+ * inLen    length of input buffer
+ * out      buffer to hold results
+ * outSz    gets set to size of result buffer. Should be passed in as length
+ *          of out buffer. If the pointer "out" is null then outSz gets set to
+ *          the expected buffer size needed and LENGTH_ONLY_E gets returned.
+ * key      RSA key to use for encrypt/decrypt
+ * type     if using private or public key {RSA_PUBLIC_ENCRYPT,
+ *          RSA_PUBLIC_DECRYPT, RSA_PRIVATE_ENCRYPT, RSA_PRIVATE_DECRYPT}
+ * rng      wolfSSL RNG to use if needed
+ *
+ * returns size of result on success
+ */
+int wc_RsaDirect(byte* in, word32 inLen, byte* out, word32* outSz,
+        RsaKey* key, int type, WC_RNG* rng)
+{
+    int ret;
+
+    if (in == NULL || outSz == NULL || key == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
+    /* sanity check on type of RSA operation */
+    switch (type) {
+        case RSA_PUBLIC_ENCRYPT:
+        case RSA_PUBLIC_DECRYPT:
+        case RSA_PRIVATE_ENCRYPT:
+        case RSA_PRIVATE_DECRYPT:
+            break;
+        default:
+            WOLFSSL_MSG("Bad RSA type");
+            return BAD_FUNC_ARG;
+    }
+
+    if ((ret = wc_RsaEncryptSize(key)) < 0) {
+        return BAD_FUNC_ARG;
+    }
+
+    if (inLen != (word32)ret) {
+        WOLFSSL_MSG("Bad input length. Should be RSA key size");
+        return BAD_FUNC_ARG;
+    }
+
+    if (out == NULL) {
+        *outSz = inLen;
+        return LENGTH_ONLY_E;
+    }
+
+    switch (key->state) {
+        case RSA_STATE_NONE:
+        case RSA_STATE_ENCRYPT_PAD:
+        case RSA_STATE_ENCRYPT_EXPTMOD:
+        case RSA_STATE_DECRYPT_EXPTMOD:
+        case RSA_STATE_DECRYPT_UNPAD:
+            key->state = (type == RSA_PRIVATE_ENCRYPT ||
+                    type == RSA_PUBLIC_ENCRYPT) ? RSA_STATE_ENCRYPT_EXPTMOD:
+                                                  RSA_STATE_DECRYPT_EXPTMOD;
+
+            key->dataLen = *outSz;
+
+            ret = wc_RsaFunction(in, inLen, out, &key->dataLen, type, key, rng);
+            if (ret >= 0 || ret == WC_PENDING_E) {
+                key->state = (type == RSA_PRIVATE_ENCRYPT ||
+                    type == RSA_PUBLIC_ENCRYPT) ? RSA_STATE_ENCRYPT_RES:
+                                                  RSA_STATE_DECRYPT_RES;
+            }
+            if (ret < 0) {
+                break;
+            }
+
+            FALL_THROUGH;
+
+        case RSA_STATE_ENCRYPT_RES:
+        case RSA_STATE_DECRYPT_RES:
+            ret = key->dataLen;
+            break;
+
+        default:
+            ret = BAD_STATE_E;
+    }
+
+    /* if async pending then skip cleanup*/
+    if (ret == WC_PENDING_E
+    #ifdef WC_RSA_NONBLOCK
+        || ret == FP_WOULDBLOCK
+    #endif
+    ) {
+        return ret;
+    }
+
+    key->state = RSA_STATE_NONE;
+    wc_RsaCleanup(key);
+
+    return ret;
+}
+#endif /* WC_RSA_DIRECT || WC_RSA_NO_PADDING */
+
+
 int wc_RsaFunction(const byte* in, word32 inLen, byte* out,
                           word32* outLen, int type, RsaKey* key, WC_RNG* rng)
 {
-    int ret;
+    int ret = 0;
 
     if (key == NULL || in == NULL || inLen == 0 || out == NULL ||
@@ -1409,4 +1962,64 @@
         return BAD_FUNC_ARG;
     }
+
+#ifdef WOLF_CRYPTO_DEV
+    if (key->devId != INVALID_DEVID) {
+        ret = wc_CryptoDev_Rsa(in, inLen, out, outLen, type, key, rng);
+        if (ret != NOT_COMPILED_IN)
+            return ret;
+        ret = 0; /* reset error code and try using software */
+    }
+#endif
+
+#ifndef TEST_UNPAD_CONSTANT_TIME
+#ifndef NO_RSA_BOUNDS_CHECK
+    if (type == RSA_PRIVATE_DECRYPT &&
+        key->state == RSA_STATE_DECRYPT_EXPTMOD) {
+
+        /* Check that 1 < in < n-1. (Requirement of 800-56B.) */
+#ifdef WOLFSSL_SMALL_STACK
+        mp_int* c = NULL;
+#else
+        mp_int c[1];
+#endif
+
+#ifdef WOLFSSL_SMALL_STACK
+        c = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_RSA);
+        if (c == NULL)
+            ret = MEMORY_E;
+#endif
+
+        if (mp_init(c) != MP_OKAY)
+            ret = MEMORY_E;
+        if (ret == 0) {
+            if (mp_read_unsigned_bin(c, in, inLen) != 0)
+                ret = MP_READ_E;
+        }
+        if (ret == 0) {
+            /* check c > 1 */
+            if (mp_cmp_d(c, 1) != MP_GT)
+                ret = RSA_OUT_OF_RANGE_E;
+        }
+        if (ret == 0) {
+            /* add c+1 */
+            if (mp_add_d(c, 1, c) != MP_OKAY)
+                ret = MP_ADD_E;
+        }
+        if (ret == 0) {
+            /* check c+1 < n */
+            if (mp_cmp(c, &key->n) != MP_LT)
+                ret = RSA_OUT_OF_RANGE_E;
+        }
+        mp_clear(c);
+
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(c, key->heap, DYNAMIC_TYPE_RSA);
+#endif
+
+        if (ret != 0)
+            return ret;
+    }
+#endif /* NO_RSA_BOUNDS_CHECK */
+#endif
 
 #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_RSA)
@@ -1417,4 +2030,10 @@
     else
 #endif
+#ifdef WC_RSA_NONBLOCK
+    if (key->nb) {
+        ret = wc_RsaFunctionNonBlock(in, inLen, out, outLen, type, key);
+    }
+    else
+#endif
     {
         ret = wc_RsaFunctionSync(in, inLen, out, outLen, type, key, rng);
@@ -1422,5 +2041,9 @@
 
     /* handle error */
-    if (ret < 0 && ret != WC_PENDING_E) {
+    if (ret < 0 && ret != WC_PENDING_E
+    #ifdef WC_RSA_NONBLOCK
+        && ret != FP_WOULDBLOCK
+    #endif
+    ) {
         if (ret == MP_EXPTMOD_E) {
             /* This can happen due to incorrectly set FP_MAX_BITS or missing XREALLOC */
@@ -1436,4 +2059,5 @@
 
 
+#ifndef WOLFSSL_RSA_VERIFY_ONLY
 /* Internal Wrappers */
 /* Gives the option of choosing padding type
@@ -1447,15 +2071,18 @@
         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, WC_RSA_OAEP_PAD or
-        WC_RSA_PSS_PAD
+   pad_type  : type of padding: WC_RSA_PKCSV15_PAD, WC_RSA_OAEP_PAD,
+        WC_RSA_NO_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
-   labelSz : size of optional label buffer */
+   labelSz : size of optional label buffer
+   saltLen : Length of salt used in PSS
+   rng : random number generator */
 static int RsaPublicEncryptEx(const byte* in, word32 inLen, byte* out,
                             word32 outLen, RsaKey* key, int rsa_type,
                             byte pad_value, int pad_type,
                             enum wc_HashType hash, int mgf,
-                            byte* label, word32 labelSz, WC_RNG* rng)
+                            byte* label, word32 labelSz, int saltLen,
+                            WC_RNG* rng)
 {
     int ret, sz;
@@ -1475,4 +2102,9 @@
 
     if (inLen > (word32)(sz - RSA_MIN_PAD_SZ)) {
+#ifdef WC_RSA_NO_PADDING
+        /* In the case that no padding is used the input length can and should
+         * be the same size as the RSA key. */
+        if (pad_type != WC_RSA_NO_PAD)
+#endif
         return RSA_BUFFER_E;
     }
@@ -1481,9 +2113,8 @@
     case RSA_STATE_NONE:
     case RSA_STATE_ENCRYPT_PAD:
-        key->state = RSA_STATE_ENCRYPT_PAD;
-
     #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_RSA) && \
             defined(HAVE_CAVIUM)
-        if (key->asyncDev.marker == WOLFSSL_ASYNC_MARKER_RSA && key->n.raw.buf) {
+        if (key->asyncDev.marker == WOLFSSL_ASYNC_MARKER_RSA &&
+                                 pad_type != WC_RSA_PSS_PAD && key->n.raw.buf) {
             /* Async operations that include padding */
             if (rsa_type == RSA_PUBLIC_ENCRYPT &&
@@ -1502,6 +2133,7 @@
     #endif
 
+        key->state = RSA_STATE_ENCRYPT_PAD;
         ret = wc_RsaPad_ex(in, inLen, out, sz, pad_value, rng, pad_type, hash,
-                           mgf, label, labelSz, mp_count_bits(&key->n),
+                           mgf, label, labelSz, saltLen, mp_count_bits(&key->n),
                            key->heap);
         if (ret < 0) {
@@ -1510,5 +2142,4 @@
 
         key->state = RSA_STATE_ENCRYPT_EXPTMOD;
-
         FALL_THROUGH;
 
@@ -1537,5 +2168,9 @@
 
     /* if async pending then return and skip done cleanup below */
-    if (ret == WC_PENDING_E) {
+    if (ret == WC_PENDING_E
+    #ifdef WC_RSA_NONBLOCK
+        || ret == FP_WOULDBLOCK
+    #endif
+    ) {
         return ret;
     }
@@ -1546,4 +2181,5 @@
     return ret;
 }
+#endif
 
 /* Gives the option of choosing padding type
@@ -1557,15 +2193,18 @@
         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, WC_RSA_OAEP_PAD
-        WC_RSA_PSS_PAD
+   pad_type  : type of padding: WC_RSA_PKCSV15_PAD, WC_RSA_OAEP_PAD,
+        WC_RSA_NO_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
-   labelSz : size of optional label buffer */
+   labelSz : size of optional label buffer
+   saltLen : Length of salt used in PSS
+   rng : random number generator */
 static int RsaPrivateDecryptEx(byte* in, word32 inLen, byte* out,
                             word32 outLen, byte** outPtr, RsaKey* key,
                             int rsa_type, byte pad_value, int pad_type,
                             enum wc_HashType hash, int mgf,
-                            byte* label, word32 labelSz, WC_RNG* rng)
+                            byte* label, word32 labelSz, int saltLen,
+                            WC_RNG* rng)
 {
     int ret = RSA_WRONG_TYPE_E;
@@ -1577,6 +2216,4 @@
     switch (key->state) {
     case RSA_STATE_NONE:
-    case RSA_STATE_DECRYPT_EXPTMOD:
-        key->state = RSA_STATE_DECRYPT_EXPTMOD;
         key->dataLen = inLen;
 
@@ -1584,12 +2221,14 @@
             defined(HAVE_CAVIUM)
         /* Async operations that include padding */
-        if (key->asyncDev.marker == WOLFSSL_ASYNC_MARKER_RSA) {
+        if (key->asyncDev.marker == WOLFSSL_ASYNC_MARKER_RSA &&
+                                                   pad_type != WC_RSA_PSS_PAD) {
+#ifndef WOLFSSL_RSA_PUBLIC_ONLY
             if (rsa_type == RSA_PRIVATE_DECRYPT &&
                                                 pad_value == RSA_BLOCK_TYPE_2) {
                 key->state = RSA_STATE_DECRYPT_RES;
                 key->data = NULL;
-                if (outPtr)
-                    *outPtr = in;
-                return NitroxRsaPrivateDecrypt(in, inLen, out, &key->dataLen, key);
+                return NitroxRsaPrivateDecrypt(in, inLen, out, &key->dataLen,
+                                               key);
+#endif
             }
             else if (rsa_type == RSA_PUBLIC_DECRYPT &&
@@ -1602,4 +2241,5 @@
     #endif
 
+#if !defined(WOLFSSL_RSA_VERIFY_ONLY) && !defined(WOLFSSL_RSA_VERIFY_INLINE)
         /* verify the tmp ptr is NULL, otherwise indicates bad state */
         if (key->data != NULL) {
@@ -1610,5 +2250,6 @@
         /* if not doing this inline then allocate a buffer for it */
         if (outPtr == NULL) {
-            key->data = (byte*)XMALLOC(inLen, key->heap, DYNAMIC_TYPE_WOLF_BIGINT);
+            key->data = (byte*)XMALLOC(inLen, key->heap,
+                                                      DYNAMIC_TYPE_WOLF_BIGINT);
             key->dataIsAlloc = 1;
             if (key->data == NULL) {
@@ -1621,6 +2262,17 @@
             key->data = out;
         }
-        ret = wc_RsaFunction(key->data, inLen, key->data, &key->dataLen, rsa_type,
-                                                                      key, rng);
+#endif
+
+        key->state = RSA_STATE_DECRYPT_EXPTMOD;
+        FALL_THROUGH;
+
+    case RSA_STATE_DECRYPT_EXPTMOD:
+#if !defined(WOLFSSL_RSA_VERIFY_ONLY) && !defined(WOLFSSL_RSA_VERIFY_INLINE)
+        ret = wc_RsaFunction(key->data, inLen, key->data, &key->dataLen,
+                                                            rsa_type, key, rng);
+#else
+        ret = wc_RsaFunction(out, inLen, out, &key->dataLen, rsa_type, key,
+                                                                           rng);
+#endif
 
         if (ret >= 0 || ret == WC_PENDING_E) {
@@ -1636,21 +2288,47 @@
     {
         byte* pad = NULL;
+#if !defined(WOLFSSL_RSA_VERIFY_ONLY) && !defined(WOLFSSL_RSA_VERIFY_INLINE)
         ret = wc_RsaUnPad_ex(key->data, key->dataLen, &pad, pad_value, pad_type,
-                             hash, mgf, label, labelSz, mp_count_bits(&key->n),
-                             key->heap);
-        if (ret > 0 && ret <= (int)outLen && pad != NULL) {
+                             hash, mgf, label, labelSz, saltLen,
+                             mp_count_bits(&key->n), key->heap);
+#else
+        ret = wc_RsaUnPad_ex(out, key->dataLen, &pad, pad_value, pad_type, hash,
+                             mgf, label, labelSz, saltLen,
+                             mp_count_bits(&key->n), key->heap);
+#endif
+        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)
+            signed char c;
+#endif
+
             /* only copy output if not inline */
             if (outPtr == NULL) {
+#if !defined(WOLFSSL_RSA_VERIFY_ONLY)
+                word32 i, j;
+                int start = (int)((size_t)pad - (size_t)key->data);
+
+                for (i = 0, j = 0; j < key->dataLen; j++) {
+                    out[i] = key->data[j];
+                    c  = ctMaskGTE(j, start);
+                    c &= ctMaskLT(i, outLen);
+                    /* 0 - no add, -1 add */
+                    i += -c;
+                }
+#else
                 XMEMCPY(out, pad, ret);
+#endif
             }
-            else {
+            else
                 *outPtr = pad;
-            }
-        }
-        else if (ret >= 0) {
+
+#if !defined(WOLFSSL_RSA_VERIFY_ONLY)
+            ret = ctMaskSelInt(ctMaskLTE(ret, outLen), ret, RSA_BUFFER_E);
+            ret = ctMaskSelInt(ctMaskNotEq(ret, 0), ret, RSA_BUFFER_E);
+#else
+            if (outLen < (word32)ret)
             ret = RSA_BUFFER_E;
-        }
-        if (ret < 0) {
-            break;
+#endif
         }
 
@@ -1662,11 +2340,13 @@
     #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_RSA) && \
             defined(HAVE_CAVIUM)
-        if (key->asyncDev.marker == WOLFSSL_ASYNC_MARKER_RSA) {
-            /* return event ret */
-            ret = key->asyncDev.event.ret;
-            if (ret == 0) {
+        if (key->asyncDev.marker == WOLFSSL_ASYNC_MARKER_RSA &&
+                                                   pad_type != WC_RSA_PSS_PAD) {
+            if (ret > 0) {
                 /* convert result */
                 byte* dataLen = (byte*)&key->dataLen;
                 ret = (dataLen[0] << 8) | (dataLen[1]);
+
+                if (outPtr)
+                    *outPtr = in;
             }
         }
@@ -1680,5 +2360,9 @@
 
     /* if async pending then return and skip done cleanup below */
-    if (ret == WC_PENDING_E) {
+    if (ret == WC_PENDING_E
+    #ifdef WC_RSA_NONBLOCK
+        || ret == FP_WOULDBLOCK
+    #endif
+    ) {
         return ret;
     }
@@ -1691,4 +2375,5 @@
 
 
+#ifndef WOLFSSL_RSA_VERIFY_ONLY
 /* Public RSA Functions */
 int wc_RsaPublicEncrypt(const byte* in, word32 inLen, byte* out, word32 outLen,
@@ -1697,9 +2382,9 @@
     return RsaPublicEncryptEx(in, inLen, out, outLen, key,
         RSA_PUBLIC_ENCRYPT, RSA_BLOCK_TYPE_2, WC_RSA_PKCSV15_PAD,
-        WC_HASH_TYPE_NONE, WC_MGF1NONE, NULL, 0, rng);
-}
-
-
-#ifndef WC_NO_RSA_OAEP
+        WC_HASH_TYPE_NONE, WC_MGF1NONE, NULL, 0, 0, rng);
+}
+
+
+#if !defined(WC_NO_RSA_OAEP) || defined(WC_RSA_NO_PADDING)
 int wc_RsaPublicEncrypt_ex(const byte* in, word32 inLen, byte* out,
                     word32 outLen, RsaKey* key, WC_RNG* rng, int type,
@@ -1708,9 +2393,11 @@
 {
     return RsaPublicEncryptEx(in, inLen, out, outLen, key, RSA_PUBLIC_ENCRYPT,
-        RSA_BLOCK_TYPE_2, type, hash, mgf, label, labelSz, rng);
+        RSA_BLOCK_TYPE_2, type, hash, mgf, label, labelSz, 0, rng);
 }
 #endif /* WC_NO_RSA_OAEP */
-
-
+#endif
+
+
+#ifndef WOLFSSL_RSA_PUBLIC_ONLY
 int wc_RsaPrivateDecryptInline(byte* in, word32 inLen, byte** out, RsaKey* key)
 {
@@ -1721,5 +2408,5 @@
     return RsaPrivateDecryptEx(in, inLen, in, inLen, out, key,
         RSA_PRIVATE_DECRYPT, RSA_BLOCK_TYPE_2, WC_RSA_PKCSV15_PAD,
-        WC_HASH_TYPE_NONE, WC_MGF1NONE, NULL, 0, rng);
+        WC_HASH_TYPE_NONE, WC_MGF1NONE, NULL, 0, 0, rng);
 }
 
@@ -1736,5 +2423,5 @@
     return RsaPrivateDecryptEx(in, inLen, in, inLen, out, key,
         RSA_PRIVATE_DECRYPT, RSA_BLOCK_TYPE_2, type, hash,
-        mgf, label, labelSz, rng);
+        mgf, label, labelSz, 0, rng);
 }
 #endif /* WC_NO_RSA_OAEP */
@@ -1750,8 +2437,8 @@
     return RsaPrivateDecryptEx((byte*)in, inLen, out, outLen, NULL, key,
         RSA_PRIVATE_DECRYPT, RSA_BLOCK_TYPE_2, WC_RSA_PKCSV15_PAD,
-        WC_HASH_TYPE_NONE, WC_MGF1NONE, NULL, 0, rng);
-}
-
-#ifndef WC_NO_RSA_OAEP
+        WC_HASH_TYPE_NONE, WC_MGF1NONE, NULL, 0, 0, rng);
+}
+
+#if !defined(WC_NO_RSA_OAEP) || defined(WC_RSA_NO_PADDING)
 int wc_RsaPrivateDecrypt_ex(const byte* in, word32 inLen, byte* out,
                             word32 outLen, RsaKey* key, int type,
@@ -1765,7 +2452,8 @@
     return RsaPrivateDecryptEx((byte*)in, inLen, out, outLen, NULL, key,
         RSA_PRIVATE_DECRYPT, RSA_BLOCK_TYPE_2, type, hash, mgf, label,
-        labelSz, rng);
-}
-#endif /* WC_NO_RSA_OAEP */
+        labelSz, 0, rng);
+}
+#endif /* WC_NO_RSA_OAEP || WC_RSA_NO_PADDING */
+#endif /* WOLFSSL_RSA_PUBLIC_ONLY */
 
 
@@ -1778,7 +2466,8 @@
     return RsaPrivateDecryptEx(in, inLen, in, inLen, out, key,
         RSA_PUBLIC_DECRYPT, RSA_BLOCK_TYPE_1, WC_RSA_PKCSV15_PAD,
-        WC_HASH_TYPE_NONE, WC_MGF1NONE, NULL, 0, rng);
-}
-
+        WC_HASH_TYPE_NONE, WC_MGF1NONE, NULL, 0, 0, rng);
+}
+
+#ifndef WOLFSSL_RSA_VERIFY_ONLY
 int wc_RsaSSL_Verify(const byte* in, word32 inLen, byte* out, word32 outLen,
                                                                  RsaKey* key)
@@ -1796,10 +2485,43 @@
     return RsaPrivateDecryptEx((byte*)in, inLen, out, outLen, NULL, key,
         RSA_PUBLIC_DECRYPT, RSA_BLOCK_TYPE_1, WC_RSA_PKCSV15_PAD,
-        WC_HASH_TYPE_NONE, WC_MGF1NONE, NULL, 0, rng);
-}
+        WC_HASH_TYPE_NONE, WC_MGF1NONE, NULL, 0, 0, rng);
+}
+#endif
 
 #ifdef WC_RSA_PSS
+/* Verify the message signed with RSA-PSS.
+ * The input buffer is reused for the ouput buffer.
+ * Salt length is equal to hash length.
+ *
+ * in     Buffer holding encrypted data.
+ * inLen  Length of data in buffer.
+ * out    Pointer to address containing the PSS data.
+ * hash   Hash algorithm.
+ * mgf    Mask generation function.
+ * key    Public RSA key.
+ * returns the length of the PSS data on success and negative indicates failure.
+ */
 int wc_RsaPSS_VerifyInline(byte* in, word32 inLen, byte** out,
                            enum wc_HashType hash, int mgf, RsaKey* key)
+{
+    return wc_RsaPSS_VerifyInline_ex(in, inLen, out, hash, mgf, -1, key);
+}
+
+/* Verify the message signed with RSA-PSS.
+ * The input buffer is reused for the ouput buffer.
+ *
+ * in       Buffer holding encrypted data.
+ * inLen    Length of data in buffer.
+ * out      Pointer to address containing the PSS data.
+ * hash     Hash algorithm.
+ * mgf      Mask generation function.
+ * key      Public RSA key.
+ * saltLen  Length of salt used. -1 indicates salt length is the same as the
+ *          hash length.
+ * returns the length of the PSS data on success and negative indicates failure.
+ */
+int wc_RsaPSS_VerifyInline_ex(byte* in, word32 inLen, byte** out,
+                              enum wc_HashType hash, int mgf, int saltLen,
+                              RsaKey* key)
 {
     WC_RNG* rng = NULL;
@@ -1809,36 +2531,226 @@
     return RsaPrivateDecryptEx(in, inLen, in, inLen, out, key,
         RSA_PUBLIC_DECRYPT, RSA_BLOCK_TYPE_1, WC_RSA_PSS_PAD,
-        hash, mgf, NULL, 0, rng);
-}
-
-/* Sig = 8 * 0x00 | Space for Message Hash | Salt | Exp Hash
- * Exp Hash = HASH(8 * 0x00 | Message Hash | Salt)
+        hash, mgf, NULL, 0, saltLen, rng);
+}
+
+/* Verify the message signed with RSA-PSS.
+ * Salt length is equal to hash length.
+ *
+ * in     Buffer holding encrypted data.
+ * inLen  Length of data in buffer.
+ * out    Pointer to address containing the PSS data.
+ * hash   Hash algorithm.
+ * mgf    Mask generation function.
+ * key    Public RSA key.
+ * returns the length of the PSS data on success and negative indicates failure.
+ */
+int wc_RsaPSS_Verify(byte* in, word32 inLen, byte* out, word32 outLen,
+                     enum wc_HashType hash, int mgf, RsaKey* key)
+{
+    return wc_RsaPSS_Verify_ex(in, inLen, out, outLen, hash, mgf, -1, key);
+}
+
+/* Verify the message signed with RSA-PSS.
+ *
+ * in       Buffer holding encrypted data.
+ * inLen    Length of data in buffer.
+ * out      Pointer to address containing the PSS data.
+ * hash     Hash algorithm.
+ * mgf      Mask generation function.
+ * key      Public RSA key.
+ * saltLen  Length of salt used. -1 indicates salt length is the same as the
+ *          hash length.
+ * returns the length of the PSS data on success and negative indicates failure.
+ */
+int wc_RsaPSS_Verify_ex(byte* in, word32 inLen, byte* out, word32 outLen,
+                        enum wc_HashType hash, int mgf, int saltLen,
+                        RsaKey* key)
+{
+    WC_RNG* rng = NULL;
+#ifdef WC_RSA_BLINDING
+    rng = key->rng;
+#endif
+    return RsaPrivateDecryptEx(in, inLen, out, outLen, NULL, key,
+        RSA_PUBLIC_DECRYPT, RSA_BLOCK_TYPE_1, WC_RSA_PSS_PAD,
+        hash, mgf, NULL, 0, saltLen, rng);
+}
+
+
+/* Checks the PSS data to ensure that the signature matches.
+ * Salt length is equal to hash length.
+ *
+ * in        Hash of the data that is being verified.
+ * inSz      Length of hash.
+ * sig       Buffer holding PSS data.
+ * sigSz     Size of PSS data.
+ * hashType  Hash algorithm.
+ * returns BAD_PADDING_E when the PSS data is invalid, BAD_FUNC_ARG when
+ * NULL is passed in to in or sig or inSz is not the same as the hash
+ * algorithm length and 0 on success.
  */
 int wc_RsaPSS_CheckPadding(const byte* in, word32 inSz, byte* sig,
                            word32 sigSz, enum wc_HashType hashType)
 {
-    int ret;
+    return wc_RsaPSS_CheckPadding_ex(in, inSz, sig, sigSz, hashType, inSz, 0);
+}
+
+/* Checks the PSS data to ensure that the signature matches.
+ *
+ * in        Hash of the data that is being verified.
+ * inSz      Length of hash.
+ * sig       Buffer holding PSS data.
+ * sigSz     Size of PSS data.
+ * hashType  Hash algorithm.
+ * saltLen   Length of salt used. -1 indicates salt length is the same as the
+ *           hash length.
+ * returns BAD_PADDING_E when the PSS data is invalid, BAD_FUNC_ARG when
+ * NULL is passed in to in or sig or inSz is not the same as the hash
+ * algorithm length and 0 on success.
+ */
+int wc_RsaPSS_CheckPadding_ex(const byte* in, word32 inSz, byte* sig,
+                              word32 sigSz, enum wc_HashType hashType,
+                              int saltLen, int bits)
+{
+    int ret = 0;
+    byte sigCheck[WC_MAX_DIGEST_SIZE*2 + RSA_PSS_PAD_SZ];
+
+    (void)bits;
 
     if (in == NULL || sig == NULL ||
-                      inSz != (word32)wc_HashGetDigestSize(hashType) ||
-                      sigSz != RSA_PSS_PAD_SZ + inSz * 3)
+                      inSz != (word32)wc_HashGetDigestSize(hashType))
         ret = BAD_FUNC_ARG;
-    else {
-        XMEMCPY(sig + RSA_PSS_PAD_SZ, in, inSz);
-        ret = wc_Hash(hashType, sig, RSA_PSS_PAD_SZ + inSz * 2, sig, inSz);
-        if (ret != 0)
-            return ret;
-        if (XMEMCMP(sig, sig + RSA_PSS_PAD_SZ + inSz * 2, inSz) != 0) {
+
+    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)
+                    saltLen = RSA_PSS_SALT_MAX_SZ;
+            #endif
+        }
+        else if (saltLen < -1 || (word32)saltLen > inSz)
+            ret = PSS_SALTLEN_E;
+    }
+
+    /* Sig = Salt | Exp Hash */
+    if (ret == 0) {
+        if (sigSz != inSz + saltLen)
+            ret = BAD_PADDING_E;
+    }
+
+    /* Exp Hash = HASH(8 * 0x00 | Message Hash | Salt) */
+    if (ret == 0) {
+        XMEMSET(sigCheck, 0, RSA_PSS_PAD_SZ);
+        XMEMCPY(sigCheck + RSA_PSS_PAD_SZ, in, inSz);
+        XMEMCPY(sigCheck + RSA_PSS_PAD_SZ + inSz, sig, saltLen);
+        ret = wc_Hash(hashType, sigCheck, RSA_PSS_PAD_SZ + inSz + saltLen,
+                      sigCheck, inSz);
+    }
+    if (ret == 0) {
+        if (XMEMCMP(sigCheck, sig + saltLen, inSz) != 0) {
             WOLFSSL_MSG("RsaPSS_CheckPadding: Padding Error");
             ret = BAD_PADDING_E;
         }
-        else
-            ret = 0;
     }
 
     return ret;
 }
-#endif
-
+
+
+/* Verify the message signed with RSA-PSS.
+ * The input buffer is reused for the ouput buffer.
+ * Salt length is equal to hash length.
+ *
+ * in     Buffer holding encrypted data.
+ * inLen  Length of data in buffer.
+ * out    Pointer to address containing the PSS data.
+ * digest Hash of the data that is being verified.
+ * digestLen Length of hash.
+ * hash   Hash algorithm.
+ * mgf    Mask generation function.
+ * key    Public RSA key.
+ * returns the length of the PSS data on success and negative indicates failure.
+ */
+int wc_RsaPSS_VerifyCheckInline(byte* in, word32 inLen, byte** out,
+                           const byte* digest, word32 digestLen,
+                           enum wc_HashType hash, int mgf, RsaKey* key)
+{
+    int ret = 0, verify, saltLen, hLen, bits = 0;
+
+    hLen = wc_HashGetDigestSize(hash);
+    if (hLen < 0)
+        return hLen;
+    if ((word32)hLen != digestLen)
+        return BAD_FUNC_ARG;
+
+    saltLen = hLen;
+    #ifdef WOLFSSL_SHA512
+        /* See FIPS 186-4 section 5.5 item (e). */
+        bits = mp_count_bits(&key->n);
+        if (bits == 1024 && hLen == WC_SHA512_DIGEST_SIZE)
+            saltLen = RSA_PSS_SALT_MAX_SZ;
+    #endif
+
+    verify = wc_RsaPSS_VerifyInline_ex(in, inLen, out, hash, mgf, saltLen, key);
+    if (verify > 0)
+        ret = wc_RsaPSS_CheckPadding_ex(digest, digestLen, *out, verify,
+                                        hash, saltLen, bits);
+    if (ret == 0)
+        ret = verify;
+
+    return ret;
+}
+
+
+/* Verify the message signed with RSA-PSS.
+ * Salt length is equal to hash length.
+ *
+ * in     Buffer holding encrypted data.
+ * inLen  Length of data in buffer.
+ * out    Pointer to address containing the PSS data.
+ * outLen Length of the output.
+ * digest Hash of the data that is being verified.
+ * digestLen Length of hash.
+ * hash   Hash algorithm.
+ * mgf    Mask generation function.
+ * key    Public RSA key.
+ * returns the length of the PSS data on success and negative indicates failure.
+ */
+int wc_RsaPSS_VerifyCheck(byte* in, word32 inLen, byte* out, word32 outLen,
+                          const byte* digest, word32 digestLen,
+                          enum wc_HashType hash, int mgf,
+                          RsaKey* key)
+{
+    int ret = 0, verify, saltLen, hLen, bits = 0;
+
+    hLen = wc_HashGetDigestSize(hash);
+    if (hLen < 0)
+        return hLen;
+    if ((word32)hLen != digestLen)
+        return BAD_FUNC_ARG;
+
+    saltLen = hLen;
+    #ifdef WOLFSSL_SHA512
+        /* See FIPS 186-4 section 5.5 item (e). */
+        bits = mp_count_bits(&key->n);
+        if (bits == 1024 && hLen == WC_SHA512_DIGEST_SIZE)
+            saltLen = RSA_PSS_SALT_MAX_SZ;
+    #endif
+
+    verify = wc_RsaPSS_Verify_ex(in, inLen, out, outLen, hash,
+                                 mgf, saltLen, key);
+    if (verify > 0)
+        ret = wc_RsaPSS_CheckPadding_ex(digest, digestLen, out, verify,
+                                        hash, saltLen, bits);
+    if (ret == 0)
+        ret = verify;
+
+    return ret;
+}
+
+#endif
+
+#ifndef WOLFSSL_RSA_PUBLIC_ONLY
 int wc_RsaSSL_Sign(const byte* in, word32 inLen, byte* out, word32 outLen,
                                                    RsaKey* key, WC_RNG* rng)
@@ -1846,26 +2758,76 @@
     return RsaPublicEncryptEx(in, inLen, out, outLen, key,
         RSA_PRIVATE_ENCRYPT, RSA_BLOCK_TYPE_1, WC_RSA_PKCSV15_PAD,
-        WC_HASH_TYPE_NONE, WC_MGF1NONE, NULL, 0, rng);
+        WC_HASH_TYPE_NONE, WC_MGF1NONE, NULL, 0, 0, rng);
 }
 
 #ifdef WC_RSA_PSS
+/* Sign the hash of a message using RSA-PSS.
+ * Salt length is equal to hash length.
+ *
+ * in      Buffer holding hash of message.
+ * inLen   Length of data in buffer (hash length).
+ * out     Buffer to write encrypted signature into.
+ * outLen  Size of buffer to write to.
+ * hash    Hash algorithm.
+ * mgf     Mask generation function.
+ * key     Public RSA key.
+ * rng     Random number generator.
+ * returns the length of the encrypted signature on success, a negative value
+ * indicates failure.
+ */
 int wc_RsaPSS_Sign(const byte* in, word32 inLen, byte* out, word32 outLen,
                        enum wc_HashType hash, int mgf, RsaKey* key, WC_RNG* rng)
 {
+    return wc_RsaPSS_Sign_ex(in, inLen, out, outLen, hash, mgf, -1, key, rng);
+}
+
+/* Sign the hash of a message using RSA-PSS.
+ *
+ * in       Buffer holding hash of message.
+ * inLen    Length of data in buffer (hash length).
+ * out      Buffer to write encrypted signature into.
+ * outLen   Size of buffer to write to.
+ * hash     Hash algorithm.
+ * mgf      Mask generation function.
+ * saltLen  Length of salt used. -1 indicates salt length is the same as the
+ *          hash length.
+ * key      Public RSA key.
+ * rng      Random number generator.
+ * returns the length of the encrypted signature on success, a negative value
+ * indicates failure.
+ */
+int wc_RsaPSS_Sign_ex(const byte* in, word32 inLen, byte* out, word32 outLen,
+                      enum wc_HashType hash, int mgf, int saltLen, RsaKey* key,
+                      WC_RNG* rng)
+{
     return RsaPublicEncryptEx(in, inLen, out, outLen, key,
         RSA_PRIVATE_ENCRYPT, RSA_BLOCK_TYPE_1, WC_RSA_PSS_PAD,
-        hash, mgf, NULL, 0, rng);
-}
-#endif
-
+        hash, mgf, NULL, 0, saltLen, rng);
+}
+#endif
+#endif
+
+#if !defined(WOLFSSL_RSA_PUBLIC_ONLY) || !defined(WOLFSSL_SP_MATH)
 int wc_RsaEncryptSize(RsaKey* key)
 {
+    int ret;
+
     if (key == NULL) {
         return BAD_FUNC_ARG;
     }
-    return mp_unsigned_bin_size(&key->n);
-}
-
-
+
+    ret = mp_unsigned_bin_size(&key->n);
+
+#ifdef WOLF_CRYPTO_DEV
+    if (ret == 0 && key->devId != INVALID_DEVID) {
+        ret = 2048/8; /* hardware handles, use 2048-bit as default */
+}
+#endif
+
+    return ret;
+}
+#endif
+
+#ifndef WOLFSSL_RSA_VERIFY_ONLY
 /* flatten RsaKey structure into individual elements (e, n) */
 int wc_RsaFlattenPublicKey(RsaKey* key, byte* e, word32* eSz, byte* n,
@@ -1896,16 +2858,312 @@
     return 0;
 }
+#endif
+
+#endif /* HAVE_FIPS */
+
+
+#ifndef WOLFSSL_RSA_VERIFY_ONLY
+static int RsaGetValue(mp_int* in, byte* out, word32* outSz)
+{
+    word32 sz;
+    int ret = 0;
+
+    /* Parameters ensured by calling function. */
+
+    sz = (word32)mp_unsigned_bin_size(in);
+    if (sz > *outSz)
+        ret = RSA_BUFFER_E;
+
+    if (ret == 0)
+        ret = mp_to_unsigned_bin(in, out);
+
+    if (ret == MP_OKAY)
+        *outSz = sz;
+
+    return ret;
+}
+
+
+int wc_RsaExportKey(RsaKey* key,
+                    byte* e, word32* eSz, byte* n, word32* nSz,
+                    byte* d, word32* dSz, byte* p, word32* pSz,
+                    byte* q, word32* qSz)
+{
+    int ret = BAD_FUNC_ARG;
+
+    if (key && e && eSz && n && nSz && d && dSz && p && pSz && q && qSz)
+        ret = 0;
+
+    if (ret == 0)
+        ret = RsaGetValue(&key->e, e, eSz);
+    if (ret == 0)
+        ret = RsaGetValue(&key->n, n, nSz);
+#ifndef WOLFSSL_RSA_PUBLIC_ONLY
+    if (ret == 0)
+        ret = RsaGetValue(&key->d, d, dSz);
+    if (ret == 0)
+        ret = RsaGetValue(&key->p, p, pSz);
+    if (ret == 0)
+        ret = RsaGetValue(&key->q, q, qSz);
+#else
+    /* no private parts to key */
+    if (d == NULL || p == NULL || q == NULL || dSz == NULL || pSz == NULL
+            || qSz == NULL) {
+        ret = BAD_FUNC_ARG;
+    }
+    else {
+        *dSz = 0;
+        *pSz = 0;
+        *qSz = 0;
+    }
+#endif /* WOLFSSL_RSA_PUBLIC_ONLY */
+
+    return ret;
+}
+#endif
+
 
 #ifdef WOLFSSL_KEY_GEN
+
+/* Check that |p-q| > 2^((size/2)-100) */
+static int wc_CompareDiffPQ(mp_int* p, mp_int* q, int size)
+{
+    mp_int c, d;
+    int ret;
+
+    if (p == NULL || q == NULL)
+        return BAD_FUNC_ARG;
+
+    ret = mp_init_multi(&c, &d, NULL, NULL, NULL, NULL);
+
+    /* c = 2^((size/2)-100) */
+    if (ret == 0)
+        ret = mp_2expt(&c, (size/2)-100);
+
+    /* d = |p-q| */
+    if (ret == 0)
+        ret = mp_sub(p, q, &d);
+
+    if (ret == 0)
+        ret = mp_abs(&d, &d);
+
+    /* compare */
+    if (ret == 0)
+        ret = mp_cmp(&d, &c);
+
+    if (ret == MP_GT)
+        ret = MP_OKAY;
+
+    mp_clear(&d);
+    mp_clear(&c);
+
+    return ret;
+}
+
+
+/* The lower_bound value is floor(2^(0.5) * 2^((nlen/2)-1)) where nlen is 4096.
+ * This number was calculated using a small test tool written with a common
+ * large number math library. Other values of nlen may be checked with a subset
+ * of lower_bound. */
+static const byte lower_bound[] = {
+    0xB5, 0x04, 0xF3, 0x33, 0xF9, 0xDE, 0x64, 0x84,
+    0x59, 0x7D, 0x89, 0xB3, 0x75, 0x4A, 0xBE, 0x9F,
+    0x1D, 0x6F, 0x60, 0xBA, 0x89, 0x3B, 0xA8, 0x4C,
+    0xED, 0x17, 0xAC, 0x85, 0x83, 0x33, 0x99, 0x15,
+/* 512 */
+    0x4A, 0xFC, 0x83, 0x04, 0x3A, 0xB8, 0xA2, 0xC3,
+    0xA8, 0xB1, 0xFE, 0x6F, 0xDC, 0x83, 0xDB, 0x39,
+    0x0F, 0x74, 0xA8, 0x5E, 0x43, 0x9C, 0x7B, 0x4A,
+    0x78, 0x04, 0x87, 0x36, 0x3D, 0xFA, 0x27, 0x68,
+/* 1024 */
+    0xD2, 0x20, 0x2E, 0x87, 0x42, 0xAF, 0x1F, 0x4E,
+    0x53, 0x05, 0x9C, 0x60, 0x11, 0xBC, 0x33, 0x7B,
+    0xCA, 0xB1, 0xBC, 0x91, 0x16, 0x88, 0x45, 0x8A,
+    0x46, 0x0A, 0xBC, 0x72, 0x2F, 0x7C, 0x4E, 0x33,
+    0xC6, 0xD5, 0xA8, 0xA3, 0x8B, 0xB7, 0xE9, 0xDC,
+    0xCB, 0x2A, 0x63, 0x43, 0x31, 0xF3, 0xC8, 0x4D,
+    0xF5, 0x2F, 0x12, 0x0F, 0x83, 0x6E, 0x58, 0x2E,
+    0xEA, 0xA4, 0xA0, 0x89, 0x90, 0x40, 0xCA, 0x4A,
+/* 2048 */
+    0x81, 0x39, 0x4A, 0xB6, 0xD8, 0xFD, 0x0E, 0xFD,
+    0xF4, 0xD3, 0xA0, 0x2C, 0xEB, 0xC9, 0x3E, 0x0C,
+    0x42, 0x64, 0xDA, 0xBC, 0xD5, 0x28, 0xB6, 0x51,
+    0xB8, 0xCF, 0x34, 0x1B, 0x6F, 0x82, 0x36, 0xC7,
+    0x01, 0x04, 0xDC, 0x01, 0xFE, 0x32, 0x35, 0x2F,
+    0x33, 0x2A, 0x5E, 0x9F, 0x7B, 0xDA, 0x1E, 0xBF,
+    0xF6, 0xA1, 0xBE, 0x3F, 0xCA, 0x22, 0x13, 0x07,
+    0xDE, 0xA0, 0x62, 0x41, 0xF7, 0xAA, 0x81, 0xC2,
+/* 3072 */
+    0xC1, 0xFC, 0xBD, 0xDE, 0xA2, 0xF7, 0xDC, 0x33,
+    0x18, 0x83, 0x8A, 0x2E, 0xAF, 0xF5, 0xF3, 0xB2,
+    0xD2, 0x4F, 0x4A, 0x76, 0x3F, 0xAC, 0xB8, 0x82,
+    0xFD, 0xFE, 0x17, 0x0F, 0xD3, 0xB1, 0xF7, 0x80,
+    0xF9, 0xAC, 0xCE, 0x41, 0x79, 0x7F, 0x28, 0x05,
+    0xC2, 0x46, 0x78, 0x5E, 0x92, 0x95, 0x70, 0x23,
+    0x5F, 0xCF, 0x8F, 0x7B, 0xCA, 0x3E, 0xA3, 0x3B,
+    0x4D, 0x7C, 0x60, 0xA5, 0xE6, 0x33, 0xE3, 0xE1
+/* 4096 */
+};
+
+
+/* returns 1 on key size ok and 0 if not ok */
+static WC_INLINE int RsaSizeCheck(int size)
+{
+    if (size < RSA_MIN_SIZE || size > RSA_MAX_SIZE) {
+        return 0;
+    }
+
+#ifdef HAVE_FIPS
+    /* Key size requirements for CAVP */
+    switch (size) {
+        case 1024:
+        case 2048:
+        case 3072:
+        case 4096:
+            return 1;
+    }
+
+    return 0;
+#else
+    return 1; /* allow unusual key sizes in non FIPS mode */
+#endif /* HAVE_FIPS */
+}
+
+
+static int _CheckProbablePrime(mp_int* p, mp_int* q, mp_int* e, int nlen,
+                                    int* isPrime, WC_RNG* rng)
+{
+    int ret;
+    mp_int tmp1, tmp2;
+    mp_int* prime;
+
+    if (p == NULL || e == NULL || isPrime == NULL)
+        return BAD_FUNC_ARG;
+
+    if (!RsaSizeCheck(nlen))
+        return BAD_FUNC_ARG;
+
+    *isPrime = MP_NO;
+
+    if (q != NULL) {
+        /* 5.4 - check that |p-q| <= (2^(1/2))(2^((nlen/2)-1)) */
+        ret = wc_CompareDiffPQ(p, q, nlen);
+        if (ret != MP_OKAY) goto notOkay;
+        prime = q;
+    }
+    else
+        prime = p;
+
+    ret = mp_init_multi(&tmp1, &tmp2, NULL, NULL, NULL, NULL);
+    if (ret != MP_OKAY) goto notOkay;
+
+    /* 4.4,5.5 - Check that prime >= (2^(1/2))(2^((nlen/2)-1))
+     *           This is a comparison against lowerBound */
+    ret = mp_read_unsigned_bin(&tmp1, lower_bound, nlen/16);
+    if (ret != MP_OKAY) goto notOkay;
+    ret = mp_cmp(prime, &tmp1);
+    if (ret == MP_LT) goto exit;
+
+    /* 4.5,5.6 - Check that GCD(p-1, e) == 1 */
+    ret = mp_sub_d(prime, 1, &tmp1);  /* tmp1 = prime-1 */
+    if (ret != MP_OKAY) goto notOkay;
+    ret = mp_gcd(&tmp1, e, &tmp2);  /* tmp2 = gcd(prime-1, e) */
+    if (ret != MP_OKAY) goto notOkay;
+    ret = mp_cmp_d(&tmp2, 1);
+    if (ret != MP_EQ) goto exit; /* e divides p-1 */
+
+    /* 4.5.1,5.6.1 - Check primality of p with 8 rounds of M-R.
+     * mp_prime_is_prime_ex() performs test divisions against the first 256
+     * prime numbers. After that it performs 8 rounds of M-R using random
+     * bases between 2 and n-2.
+     * mp_prime_is_prime() performs the same test divisions and then does
+     * M-R with the first 8 primes. Both functions set isPrime as a
+     * side-effect. */
+    if (rng != NULL)
+        ret = mp_prime_is_prime_ex(prime, 8, isPrime, rng);
+    else
+        ret = mp_prime_is_prime(prime, 8, isPrime);
+    if (ret != MP_OKAY) goto notOkay;
+
+exit:
+    ret = MP_OKAY;
+notOkay:
+    mp_clear(&tmp1);
+    mp_clear(&tmp2);
+    return ret;
+}
+
+
+int wc_CheckProbablePrime_ex(const byte* pRaw, word32 pRawSz,
+                          const byte* qRaw, word32 qRawSz,
+                          const byte* eRaw, word32 eRawSz,
+                          int nlen, int* isPrime, WC_RNG* rng)
+{
+    mp_int p, q, e;
+    mp_int* Q = NULL;
+    int ret;
+
+    if (pRaw == NULL || pRawSz == 0 ||
+        eRaw == NULL || eRawSz == 0 ||
+        isPrime == NULL) {
+
+        return BAD_FUNC_ARG;
+    }
+
+    if ((qRaw != NULL && qRawSz == 0) || (qRaw == NULL && qRawSz != 0))
+        return BAD_FUNC_ARG;
+
+    ret = mp_init_multi(&p, &q, &e, NULL, NULL, NULL);
+
+    if (ret == MP_OKAY)
+        ret = mp_read_unsigned_bin(&p, pRaw, pRawSz);
+
+    if (ret == MP_OKAY) {
+        if (qRaw != NULL) {
+            ret = mp_read_unsigned_bin(&q, qRaw, qRawSz);
+            if (ret == MP_OKAY)
+                Q = &q;
+        }
+    }
+
+    if (ret == MP_OKAY)
+        ret = mp_read_unsigned_bin(&e, eRaw, eRawSz);
+
+    if (ret == MP_OKAY)
+        ret = _CheckProbablePrime(&p, Q, &e, nlen, isPrime, rng);
+
+    ret = (ret == MP_OKAY) ? 0 : PRIME_GEN_E;
+
+    mp_clear(&p);
+    mp_clear(&q);
+    mp_clear(&e);
+
+    return ret;
+}
+
+
+int wc_CheckProbablePrime(const byte* pRaw, word32 pRawSz,
+                          const byte* qRaw, word32 qRawSz,
+                          const byte* eRaw, word32 eRawSz,
+                          int nlen, int* isPrime)
+{
+    return wc_CheckProbablePrime_ex(pRaw, pRawSz, qRaw, qRawSz,
+                          eRaw, eRawSz, nlen, isPrime, NULL);
+}
+
+#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS) && \
+        defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2))
 /* Make an RSA key for size bits, with e specified, 65537 is a good e */
 int wc_MakeRsaKey(RsaKey* key, int size, long e, WC_RNG* rng)
 {
+#ifndef WC_NO_RNG
     mp_int p, q, tmp1, tmp2, tmp3;
-    int    err;
+    int err, i, failCount, primeSz, isPrime = 0;
+    byte* buf = NULL;
 
     if (key == NULL || rng == NULL)
         return BAD_FUNC_ARG;
 
-    if (size < RSA_MIN_SIZE || size > RSA_MAX_SIZE)
+    if (!RsaSizeCheck(size))
         return BAD_FUNC_ARG;
 
@@ -1913,10 +3171,19 @@
         return BAD_FUNC_ARG;
 
-#if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_RSA)
+#ifdef WOLF_CRYPTO_DEV
+    if (key->devId != INVALID_DEVID) {
+        int ret = wc_CryptoDev_MakeRsaKey(key, size, e, rng);
+        if (ret != NOT_COMPILED_IN)
+            return ret;
+    }
+#endif
+
+#if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_RSA) && \
+    defined(WC_ASYNC_ENABLE_RSA_KEYGEN)
     if (key->asyncDev.marker == WOLFSSL_ASYNC_MARKER_RSA) {
     #ifdef HAVE_CAVIUM
         /* TODO: Not implemented */
     #elif defined(HAVE_INTEL_QA)
-        /* TODO: Not implemented */
+        return IntelQaRsaKeyGen(&key->asyncDev, key, size, e, rng);
     #else
         if (wc_AsyncTestInit(&key->asyncDev, ASYNC_TEST_RSA_MAKE)) {
@@ -1932,88 +3199,163 @@
 #endif
 
-    if ((err = mp_init_multi(&p, &q, &tmp1, &tmp2, &tmp3, NULL)) != MP_OKAY)
-        return err;
-
+    err = mp_init_multi(&p, &q, &tmp1, &tmp2, &tmp3, NULL);
+
+    if (err == MP_OKAY)
     err = mp_set_int(&tmp3, e);
+
+    /* The failCount value comes from NIST FIPS 186-4, section B.3.3,
+     * process steps 4.7 and 5.8. */
+    failCount = 5 * (size / 2);
+    primeSz = size / 16; /* size is the size of n in bits.
+                            primeSz is in bytes. */
+
+    /* allocate buffer to work with */
+    if (err == MP_OKAY) {
+        buf = (byte*)XMALLOC(primeSz, key->heap, DYNAMIC_TYPE_RSA);
+        if (buf == NULL)
+            err = MEMORY_E;
+    }
 
     /* make p */
     if (err == MP_OKAY) {
+        isPrime = 0;
+        i = 0;
         do {
-            err = mp_rand_prime(&p, size/16, rng, key->heap); /* size in bytes/2 */
+#ifdef SHOW_GEN
+            printf(".");
+            fflush(stdout);
+#endif
+            /* generate value */
+            err = wc_RNG_GenerateBlock(rng, buf, primeSz);
+            if (err == 0) {
+                /* prime lower bound has the MSB set, set it in candidate */
+                buf[0] |= 0x80;
+                /* make candidate odd */
+                buf[primeSz-1] |= 0x01;
+                /* load value */
+                err = mp_read_unsigned_bin(&p, buf, primeSz);
+            }
 
             if (err == MP_OKAY)
-                err = mp_sub_d(&p, 1, &tmp1);  /* tmp1 = p-1 */
-
-            if (err == MP_OKAY)
-                err = mp_gcd(&tmp1, &tmp3, &tmp2);  /* tmp2 = gcd(p-1, e) */
-        } while (err == MP_OKAY && mp_cmp_d(&tmp2, 1) != 0);  /* e divides p-1 */
-    }
+                err = _CheckProbablePrime(&p, NULL, &tmp3, size, &isPrime, rng);
+
+#ifdef WOLFSSL_FIPS
+            i++;
+#else
+            /* Keep the old retry behavior in non-FIPS build. */
+            (void)i;
+#endif
+        } while (err == MP_OKAY && !isPrime && i < failCount);
+    }
+
+    if (err == MP_OKAY && !isPrime)
+        err = PRIME_GEN_E;
 
     /* make q */
     if (err == MP_OKAY) {
+        isPrime = 0;
+        i = 0;
         do {
-            err = mp_rand_prime(&q, size/16, rng, key->heap); /* size in bytes/2 */
+#ifdef SHOW_GEN
+            printf(".");
+            fflush(stdout);
+#endif
+            /* generate value */
+            err = wc_RNG_GenerateBlock(rng, buf, primeSz);
+            if (err == 0) {
+                /* prime lower bound has the MSB set, set it in candidate */
+                buf[0] |= 0x80;
+                /* make candidate odd */
+                buf[primeSz-1] |= 0x01;
+                /* load value */
+                err = mp_read_unsigned_bin(&q, buf, primeSz);
+            }
 
             if (err == MP_OKAY)
-                err = mp_sub_d(&q, 1, &tmp1);  /* tmp1 = q-1 */
-
-            if (err == MP_OKAY)
-                err = mp_gcd(&tmp1, &tmp3, &tmp2);  /* tmp2 = gcd(q-1, e) */
-        } while (err == MP_OKAY && mp_cmp_d(&tmp2, 1) != 0);  /* e divides q-1 */
-    }
-
+                err = _CheckProbablePrime(&p, &q, &tmp3, size, &isPrime, rng);
+
+#ifdef WOLFSSL_FIPS
+            i++;
+#else
+            /* Keep the old retry behavior in non-FIPS build. */
+            (void)i;
+#endif
+        } while (err == MP_OKAY && !isPrime && i < failCount);
+    }
+
+    if (err == MP_OKAY && !isPrime)
+        err = PRIME_GEN_E;
+
+    if (buf) {
+        ForceZero(buf, primeSz);
+        XFREE(buf, key->heap, DYNAMIC_TYPE_RSA);
+    }
+
+
+    /* Setup RsaKey buffers */
     if (err == MP_OKAY)
         err = mp_init_multi(&key->n, &key->e, &key->d, &key->p, &key->q, NULL);
-
     if (err == MP_OKAY)
         err = mp_init_multi(&key->dP, &key->dQ, &key->u, NULL, NULL, NULL);
 
-    if (err == MP_OKAY)
-        err = mp_sub_d(&p, 1, &tmp2);  /* tmp2 = p-1 */
-
-    if (err == MP_OKAY)
-        err = mp_lcm(&tmp1, &tmp2, &tmp1);  /* tmp1 = lcm(p-1, q-1),last loop */
-
+    /* Software Key Calculation */
+    if (err == MP_OKAY)                /* tmp1 = p-1 */
+        err = mp_sub_d(&p, 1, &tmp1);
+    if (err == MP_OKAY)                /* tmp2 = q-1 */
+        err = mp_sub_d(&q, 1, &tmp2);
+    if (err == MP_OKAY)                /* tmp3 = lcm(p-1, q-1), last loop */
+        err = mp_lcm(&tmp1, &tmp2, &tmp3);
     /* make key */
-    if (err == MP_OKAY)
-        err = mp_set_int(&key->e, (mp_digit)e);  /* key->e = e */
-
+    if (err == MP_OKAY)                /* key->e = e */
+        err = mp_set_int(&key->e, (mp_digit)e);
     if (err == MP_OKAY)                /* key->d = 1/e mod lcm(p-1, q-1) */
-        err = mp_invmod(&key->e, &tmp1, &key->d);
-
-    if (err == MP_OKAY)
-        err = mp_mul(&p, &q, &key->n);  /* key->n = pq */
-
-    if (err == MP_OKAY)
-        err = mp_sub_d(&p, 1, &tmp1);
-
-    if (err == MP_OKAY)
-        err = mp_sub_d(&q, 1, &tmp2);
-
-    if (err == MP_OKAY)
+        err = mp_invmod(&key->e, &tmp3, &key->d);
+    if (err == MP_OKAY)                /* key->n = pq */
+        err = mp_mul(&p, &q, &key->n);
+    if (err == MP_OKAY)                /* key->dP = d mod(p-1) */
         err = mp_mod(&key->d, &tmp1, &key->dP);
-
-    if (err == MP_OKAY)
+    if (err == MP_OKAY)                /* key->dQ = d mod(q-1) */
         err = mp_mod(&key->d, &tmp2, &key->dQ);
-
-    if (err == MP_OKAY)
+    if (err == MP_OKAY)                /* key->u = 1/q mod p */
         err = mp_invmod(&q, &p, &key->u);
-
     if (err == MP_OKAY)
         err = mp_copy(&p, &key->p);
-
     if (err == MP_OKAY)
         err = mp_copy(&q, &key->q);
 
+#ifdef HAVE_WOLF_BIGINT
+    /* make sure raw unsigned bin version is available */
+    if (err == MP_OKAY)
+         err = wc_mp_to_bigint(&key->n, &key->n.raw);
+    if (err == MP_OKAY)
+         err = wc_mp_to_bigint(&key->e, &key->e.raw);
+    if (err == MP_OKAY)
+         err = wc_mp_to_bigint(&key->d, &key->d.raw);
+    if (err == MP_OKAY)
+         err = wc_mp_to_bigint(&key->p, &key->p.raw);
+    if (err == MP_OKAY)
+         err = wc_mp_to_bigint(&key->q, &key->q.raw);
+    if (err == MP_OKAY)
+         err = wc_mp_to_bigint(&key->dP, &key->dP.raw);
+    if (err == MP_OKAY)
+         err = wc_mp_to_bigint(&key->dQ, &key->dQ.raw);
+    if (err == MP_OKAY)
+         err = wc_mp_to_bigint(&key->u, &key->u.raw);
+#endif
+
     if (err == MP_OKAY)
         key->type = RSA_PRIVATE;
 
+    mp_clear(&tmp1);
+    mp_clear(&tmp2);
     mp_clear(&tmp3);
-    mp_clear(&tmp2);
-    mp_clear(&tmp1);
+    mp_clear(&p);
     mp_clear(&q);
-    mp_clear(&p);
-
-    if (err != MP_OKAY) {
+
+    /* Perform the pair-wise consistency test on the new key. */
+    if (err == 0)
+        err = wc_CheckRsaKey(key);
+
+    if (err != 0) {
         wc_FreeRsaKey(key);
         return err;
@@ -2025,12 +3367,14 @@
     }
 #endif
-
     return 0;
-}
+#else
+    return NOT_COMPILED_IN;
+#endif
+}
+#endif /* !FIPS || FIPS_VER >= 2 */
 #endif /* WOLFSSL_KEY_GEN */
 
 
 #ifdef WC_RSA_BLINDING
-
 int wc_RsaSetRNG(RsaKey* key, WC_RNG* rng)
 {
@@ -2042,10 +3386,35 @@
     return 0;
 }
-
 #endif /* WC_RSA_BLINDING */
 
-
-#undef ERROR_OUT
-
-#endif /* HAVE_FIPS */
+#ifdef WC_RSA_NONBLOCK
+int wc_RsaSetNonBlock(RsaKey* key, RsaNb* nb)
+{
+    if (key == NULL)
+        return BAD_FUNC_ARG;
+
+    if (nb) {
+        XMEMSET(nb, 0, sizeof(RsaNb));
+    }
+
+    /* Allow nb == NULL to clear non-block mode */
+    key->nb = nb;
+
+    return 0;
+}
+#ifdef WC_RSA_NONBLOCK_TIME
+int wc_RsaSetNonBlockTime(RsaKey* key, word32 maxBlockUs, word32 cpuMHz)
+{
+    if (key == NULL || key->nb == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
+    /* calculate maximum number of instructions to block */
+    key->nb->exptmod.maxBlockInst = cpuMHz * maxBlockUs;
+
+    return 0;
+}
+#endif /* WC_RSA_NONBLOCK_TIME */
+#endif /* WC_RSA_NONBLOCK */
+
 #endif /* NO_RSA */
