/* pk_rsa.c
 *
 * Copyright (C) 2006-2026 wolfSSL Inc.
 *
 * This file is part of wolfSSL.
 *
 * wolfSSL is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * wolfSSL is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
 */

#include <wolfssl/wolfcrypt/libwolfssl_sources.h>

#include <wolfssl/internal.h>
#ifndef WC_NO_RNG
    #include <wolfssl/wolfcrypt/random.h>
#endif

#if !defined(WOLFSSL_PK_RSA_INCLUDED)
    #ifndef WOLFSSL_IGNORE_FILE_WARN
        #warning pk_rsa.c does not need to be compiled separately from ssl.c
    #endif
#else

#ifndef NO_RSA
    #include <wolfssl/wolfcrypt/rsa.h>
#endif

/*******************************************************************************
 * START OF RSA API
 ******************************************************************************/

#ifndef NO_RSA

/*
 * RSA METHOD
 * Could be used to hold function pointers to implementations of RSA operations.
 */

#if defined(OPENSSL_EXTRA)
/* Return a blank RSA method and set the name and flags.
 *
 * Only one implementation of RSA operations.
 * name is duplicated.
 *
 * @param [in] name   Name to use in method.
 * @param [in] flags  Flags to set into method.
 * @return  Newly allocated RSA method on success.
 * @return  NULL on failure.
 */
WOLFSSL_RSA_METHOD *wolfSSL_RSA_meth_new(const char *name, int flags)
{
    WOLFSSL_RSA_METHOD* meth = NULL;
    int name_len = 0;
    int err;

    /* Validate name is not NULL. */
    if (name == NULL)
        return NULL;
    /* Allocate an RSA METHOD to return. */
    meth = (WOLFSSL_RSA_METHOD*)XMALLOC(sizeof(WOLFSSL_RSA_METHOD), NULL,
                                        DYNAMIC_TYPE_OPENSSL);
    if (meth == NULL)
        return NULL;

    XMEMSET(meth, 0, sizeof(*meth));
    meth->flags = flags;
    meth->dynamic = 1;

    name_len = (int)XSTRLEN(name);
    meth->name = (char*)XMALLOC((size_t)(name_len + 1), NULL,
        DYNAMIC_TYPE_OPENSSL);
    err = (meth->name == NULL);

    if (!err) {
        XMEMCPY(meth->name, name, (size_t)(name_len + 1));
    }

    if (err) {
        /* meth->name won't be allocated on error. */
        XFREE(meth, NULL, DYNAMIC_TYPE_OPENSSL);
        meth = NULL;
    }
    return meth;
}

/* Default RSA method is one with wolfSSL name and no flags.
 *
 * @return  Newly allocated wolfSSL RSA method on success.
 * @return  NULL on failure.
 */
const WOLFSSL_RSA_METHOD* wolfSSL_RSA_get_default_method(void)
{
    static const WOLFSSL_RSA_METHOD wolfssl_rsa_meth = {
        0, /* No flags. */
        (char*)"wolfSSL RSA",
        0  /* Static definition. */
    };
    return &wolfssl_rsa_meth;
}

/* Dispose of RSA method and allocated data.
 *
 * @param [in] meth  RSA method to free.
 */
void wolfSSL_RSA_meth_free(WOLFSSL_RSA_METHOD *meth)
{
    /* Free method if available and dynamically allocated. */
    if ((meth != NULL) && meth->dynamic) {
        /* Name was duplicated and must be freed. */
        XFREE(meth->name, NULL, DYNAMIC_TYPE_OPENSSL);
        /* Dispose of RSA method. */
        XFREE(meth, NULL, DYNAMIC_TYPE_OPENSSL);
    }
}

#ifndef NO_WOLFSSL_STUB
/* Stub function for any RSA method setting function.
 *
 * Nothing is stored - not even flags or name.
 *
 * @param [in] meth  RSA method.
 * @param [in] p     A pointer.
 * @return  1 to indicate success.
 */
int wolfSSL_RSA_meth_set(WOLFSSL_RSA_METHOD *meth, void* p)
{
    WOLFSSL_STUB("RSA_METHOD is not implemented.");

    (void)meth;
    (void)p;

    return 1;
}
#endif /* !NO_WOLFSSL_STUB */
#endif /* OPENSSL_EXTRA */

/*
 * RSA constructor/deconstructor APIs
 */

#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
/* Dispose of RSA key and allocated data.
 *
 * Cannot use rsa after this call.
 *
 * @param [in] rsa  RSA key to free.
 */
void wolfSSL_RSA_free(WOLFSSL_RSA* rsa)
{
    int doFree = 1;

    WOLFSSL_ENTER("wolfSSL_RSA_free");

    /* Validate parameter. */
    if (rsa == NULL) {
        doFree = 0;
    }
    if (doFree) {
        int err;

        /* Decrement reference count. */
        wolfSSL_RefDec(&rsa->ref, &doFree, &err);
    #ifndef WOLFSSL_REFCNT_ERROR_RETURN
        (void)err;
    #endif
    }
    if (doFree) {
        void* heap = rsa->heap;

        /* Dispose of allocated reference counting data. */
        wolfSSL_RefFree(&rsa->ref);

    #ifdef HAVE_EX_DATA_CLEANUP_HOOKS
        wolfSSL_CRYPTO_cleanup_ex_data(&rsa->ex_data);
    #endif

        if (rsa->internal != NULL) {
        #if !defined(HAVE_FIPS) && defined(WC_RSA_BLINDING)
            /* Check if RNG is owned before freeing it. */
            if (rsa->ownRng) {
                WC_RNG* rng = ((RsaKey*)(rsa->internal))->rng;
                if ((rng != NULL) && (rng != wolfssl_get_global_rng())) {
                    wc_FreeRng(rng);
                    XFREE(rng, heap, DYNAMIC_TYPE_RNG);
                }
                /* RNG isn't freed by wolfCrypt RSA free. */
            }
        #endif
            /* Dispose of allocated data in wolfCrypt RSA key. */
            wc_FreeRsaKey((RsaKey*)rsa->internal);
            /* Dispose of memory for wolfCrypt RSA key. */
            XFREE(rsa->internal, heap, DYNAMIC_TYPE_RSA);
        }

        /* Dispose of external representation of RSA values. */
        wolfSSL_BN_clear_free(rsa->iqmp);
        wolfSSL_BN_clear_free(rsa->dmq1);
        wolfSSL_BN_clear_free(rsa->dmp1);
        wolfSSL_BN_clear_free(rsa->q);
        wolfSSL_BN_clear_free(rsa->p);
        wolfSSL_BN_clear_free(rsa->d);
        wolfSSL_BN_free(rsa->e);
        wolfSSL_BN_free(rsa->n);

    #if defined(OPENSSL_EXTRA)
        if (rsa->meth) {
            wolfSSL_RSA_meth_free((WOLFSSL_RSA_METHOD*)rsa->meth);
        }
    #endif

        /* Set back to NULLs for safety. */
        ForceZero(rsa, sizeof(*rsa));

        XFREE(rsa, heap, DYNAMIC_TYPE_RSA);
        (void)heap;
    }
}

/* Allocate and initialize a new RSA key.
 *
 * Not OpenSSL API.
 *
 * @param [in] heap   Heap hint for dynamic memory allocation.
 * @param [in] devId  Device identifier value.
 * @return  RSA key on success.
 * @return  NULL on failure.
 */
WOLFSSL_RSA* wolfSSL_RSA_new_ex(void* heap, int devId)
{
    WOLFSSL_RSA* rsa = NULL;
    RsaKey* key = NULL;
    int err = 0;
    int rsaKeyInited = 0;

    WOLFSSL_ENTER("wolfSSL_RSA_new");

    /* Allocate memory for new wolfCrypt RSA key. */
    key = (RsaKey*)XMALLOC(sizeof(RsaKey), heap, DYNAMIC_TYPE_RSA);
    if (key == NULL) {
        WOLFSSL_ERROR_MSG("wolfSSL_RSA_new malloc RsaKey failure");
        err = 1;
    }
    if (!err) {
        /* Allocate memory for new RSA key. */
        rsa = (WOLFSSL_RSA*)XMALLOC(sizeof(WOLFSSL_RSA), heap,
            DYNAMIC_TYPE_RSA);
        if (rsa == NULL) {
            WOLFSSL_ERROR_MSG("wolfSSL_RSA_new malloc WOLFSSL_RSA failure");
            err = 1;
        }
    }
    if (!err) {
        /* Clear all fields of RSA key. */
        XMEMSET(rsa, 0, sizeof(WOLFSSL_RSA));
        /* Cache heap to use for all allocations. */
        rsa->heap = heap;
    #ifdef OPENSSL_EXTRA
        /* Always have a method set. */
        rsa->meth = wolfSSL_RSA_get_default_method();
    #endif

        /* Initialize reference counting. */
        wolfSSL_RefInit(&rsa->ref, &err);
#ifdef WOLFSSL_REFCNT_ERROR_RETURN
    }
    if (!err) {
#endif
        /* Initialize wolfCrypt RSA key. */
        if (wc_InitRsaKey_ex(key, heap, devId) != 0) {
            WOLFSSL_ERROR_MSG("InitRsaKey WOLFSSL_RSA failure");
            err = 1;
        }
        else {
            rsaKeyInited = 1;
        }
    }
    #if !defined(HAVE_FIPS) && defined(WC_RSA_BLINDING)
    if (!err) {
        WC_RNG* rng;

        /* Create a local RNG. */
        rng = (WC_RNG*)XMALLOC(sizeof(WC_RNG), heap, DYNAMIC_TYPE_RNG);
        if ((rng != NULL) && (wc_InitRng_ex(rng, heap, devId) != 0)) {
            WOLFSSL_MSG("InitRng failure, attempting to use global RNG");
            XFREE(rng, heap, DYNAMIC_TYPE_RNG);
            rng = NULL;
        }

        rsa->ownRng = 1;
        if (rng == NULL) {
            /* Get the wolfSSL global RNG - not thread safe. */
            rng = wolfssl_get_global_rng();
            rsa->ownRng = 0;
        }
        if (rng == NULL) {
            /* Couldn't create global either. */
            WOLFSSL_ERROR_MSG("wolfSSL_RSA_new no WC_RNG for blinding");
            err = 1;
        }
        else {
            /* Set the local or global RNG into the wolfCrypt RSA key. */
            (void)wc_RsaSetRNG(key, rng);
            /* Won't fail as key and rng are not NULL. */
        }
    }
    #endif /* !HAVE_FIPS && WC_RSA_BLINDING */
    if (!err) {
        /* Set wolfCrypt RSA key into RSA key. */
        rsa->internal = key;
        /* Data from external RSA key has not been set into internal one. */
        rsa->inSet = 0;
    }

    if (err) {
        /* Dispose of any allocated data on error. */
        /* No failure after RNG allocation - no need to free RNG. */
        if (rsaKeyInited) {
            wc_FreeRsaKey(key);
        }
        XFREE(key, heap, DYNAMIC_TYPE_RSA);
        XFREE(rsa, heap, DYNAMIC_TYPE_RSA);
        /* Return NULL. */
        rsa = NULL;
    }
    return rsa;
}

/* Allocate and initialize a new RSA key.
 *
 * @return  RSA key on success.
 * @return  NULL on failure.
 */
WOLFSSL_RSA* wolfSSL_RSA_new(void)
{
    /* Call wolfSSL API to do work. */
    return wolfSSL_RSA_new_ex(NULL, INVALID_DEVID);
}

/* Increments ref count of RSA key.
 *
 * @param [in, out] rsa  RSA key.
 * @return  1 on success
 * @return  0 on error
 */
int wolfSSL_RSA_up_ref(WOLFSSL_RSA* rsa)
{
    int err = 0;
    if (rsa != NULL) {
        wolfSSL_RefInc(&rsa->ref, &err);
    }
    return !err;
}

#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */

#ifdef OPENSSL_EXTRA

#if defined(WOLFSSL_KEY_GEN)

/* Allocate a new RSA key and make it a copy.
 *
 * Encodes to and from DER to copy.
 *
 * @param [in] rsa  RSA key to duplicate.
 * @return  RSA key on success.
 * @return  NULL on error.
 */
WOLFSSL_RSA* wolfSSL_RSAPublicKey_dup(WOLFSSL_RSA *rsa)
{
    WOLFSSL_RSA* ret = NULL;
    int derSz = 0;
    byte* derBuf = NULL;
    int err;

    WOLFSSL_ENTER("wolfSSL_RSAPublicKey_dup");

    err = (rsa == NULL);
    if (!err) {
        /* Create a new RSA key to return. */
        ret = wolfSSL_RSA_new();
        if (ret == NULL) {
            WOLFSSL_ERROR_MSG("Error creating a new WOLFSSL_RSA structure");
            err = 1;
        }
    }
    if (!err) {
        /* Encode RSA public key to copy to DER - allocates DER buffer. */
        if ((derSz = wolfSSL_RSA_To_Der(rsa, &derBuf, 1, rsa->heap)) < 0) {
            WOLFSSL_ERROR_MSG("wolfSSL_RSA_To_Der failed");
            err = 1;
        }
    }
    if (!err) {
        /* Decode DER of the RSA public key into new key. */
        if (wolfSSL_RSA_LoadDer_ex(ret, derBuf, derSz,
                WOLFSSL_RSA_LOAD_PUBLIC) != 1) {
            WOLFSSL_ERROR_MSG("wolfSSL_RSA_LoadDer_ex failed");
            err = 1;
        }
    }

    /* Dispose of any allocated DER buffer. */
    XFREE(derBuf, rsa ? rsa->heap : NULL, DYNAMIC_TYPE_ASN1);
    if (err) {
        /* Disposes of any created RSA key - on error. */
        wolfSSL_RSA_free(ret);
        ret = NULL;
    }
    return ret;
}

/* wolfSSL_RSAPrivateKey_dup not supported */

#endif /* WOLFSSL_KEY_GEN */

static int wolfSSL_RSA_To_Der_ex(WOLFSSL_RSA* rsa, byte** outBuf, int publicKey,
    void* heap);

/*
 * RSA to/from bin APIs
 */

/* Convert RSA public key data to internal.
 *
 * Creates new RSA key from the DER encoded RSA public key.
 *
 * @param [out]     out      Pointer to RSA key to return through. May be NULL.
 * @param [in, out] derBuf   Pointer to start of DER encoded data.
 * @param [in]      derSz    Length of the data in the DER buffer.
 * @return  RSA key on success.
 * @return  NULL on failure.
 */
WOLFSSL_RSA *wolfSSL_d2i_RSAPublicKey(WOLFSSL_RSA **out,
    const unsigned char **derBuf, long derSz)
{
    WOLFSSL_RSA *rsa = NULL;
    int err = 0;

    WOLFSSL_ENTER("wolfSSL_d2i_RSAPublicKey");

    /* Validate parameters. */
    if (derBuf == NULL) {
        WOLFSSL_ERROR_MSG("Bad argument");
        err = 1;
    }
    /* Create a new RSA key to return. */
    if ((!err) && ((rsa = wolfSSL_RSA_new()) == NULL)) {
        WOLFSSL_ERROR_MSG("RSA_new failed");
        err = 1;
    }
    /* Decode RSA key from DER. */
    if ((!err) && (wolfSSL_RSA_LoadDer_ex(rsa, *derBuf, (int)derSz,
            WOLFSSL_RSA_LOAD_PUBLIC) != 1)) {
        WOLFSSL_ERROR_MSG("RSA_LoadDer failed");
        err = 1;
    }
    if ((!err) && (out != NULL)) {
        /* Return through parameter too. */
        *out = rsa;
        /* Move buffer on by the used amount. */
        *derBuf += wolfssl_der_length(*derBuf, (int)derSz);
    }

    if (err) {
        /* Dispose of any created RSA key. */
        wolfSSL_RSA_free(rsa);
        rsa = NULL;
    }
    return rsa;
}

/* Convert RSA private key data to internal.
 *
 * Create a new RSA key from the DER encoded RSA private key.
 *
 * @param [out]     out      Pointer to RSA key to return through. May be NULL.
 * @param [in, out] derBuf   Pointer to start of DER encoded data.
 * @param [in]      derSz    Length of the data in the DER buffer.
 * @return  RSA key on success.
 * @return  NULL on failure.
 */
WOLFSSL_RSA *wolfSSL_d2i_RSAPrivateKey(WOLFSSL_RSA **out,
    const unsigned char **derBuf, long derSz)
{
    WOLFSSL_RSA *rsa = NULL;
    int err = 0;

    WOLFSSL_ENTER("wolfSSL_d2i_RSAPublicKey");

    /* Validate parameters. */
    if (derBuf == NULL) {
        WOLFSSL_ERROR_MSG("Bad argument");
        err = 1;
    }
    /* Create a new RSA key to return. */
    if ((!err) && ((rsa = wolfSSL_RSA_new()) == NULL)) {
        WOLFSSL_ERROR_MSG("RSA_new failed");
        err = 1;
    }
    /* Decode RSA key from DER. */
    if ((!err) && (wolfSSL_RSA_LoadDer_ex(rsa, *derBuf, (int)derSz,
            WOLFSSL_RSA_LOAD_PRIVATE) != 1)) {
        WOLFSSL_ERROR_MSG("RSA_LoadDer failed");
        err = 1;
    }
    if ((!err) && (out != NULL)) {
        /* Return through parameter too. */
        *out = rsa;
        /* Move buffer on by the used amount. */
        *derBuf += wolfssl_der_length(*derBuf, (int)derSz);
    }

    if (err) {
        /* Dispose of any created RSA key. */
        wolfSSL_RSA_free(rsa);
        rsa = NULL;
    }
    return rsa;
}

/* Converts an internal RSA structure to DER format for the private key.
 *
 * If "pp" is null then buffer size only is returned.
 * If "*pp" is null then a created buffer is set in *pp and the caller is
 *  responsible for free'ing it.
 *
 * @param [in]      rsa  RSA key.
 * @param [in, out] pp   On in, pointer to allocated buffer or NULL.
 *                       May be NULL.
 *                       On out, newly allocated buffer or pointer to byte after
 *                       encoding in passed in buffer.
 *
 * @return  Size of DER encoding on success
 * @return  BAD_FUNC_ARG when rsa is NULL.
 * @return  0 on failure.
 */
int wolfSSL_i2d_RSAPrivateKey(WOLFSSL_RSA *rsa, unsigned char **pp)
{
    int ret;

    WOLFSSL_ENTER("wolfSSL_i2d_RSAPrivateKey");

    /* Validate parameters. */
    if (rsa == NULL) {
        WOLFSSL_ERROR_MSG("Bad Function Arguments");
        ret = BAD_FUNC_ARG;
    }
    /* Encode the RSA key as a DER. Call allocates buffer into pp.
     * No heap hint as this gets returned to the user */
    else if ((ret = wolfSSL_RSA_To_Der_ex(rsa, pp, 0, NULL)) < 0) {
        WOLFSSL_ERROR_MSG("wolfSSL_RSA_To_Der failed");
        ret = 0;
    }

    /* Size of DER encoding. */
    return ret;
}

/* Converts an internal RSA structure to DER format for the public key.
 *
 * If "pp" is null then buffer size only is returned.
 * If "*pp" is null then a created buffer is set in *pp and the caller is
 *  responsible for free'ing it.
 *
 * @param [in]      rsa  RSA key.
 * @param [in, out] pp   On in, pointer to allocated buffer or NULL.
 *                       May be NULL.
 *                       On out, newly allocated buffer or pointer to byte after
 *                       encoding in passed in buffer.
 * @return  Size of DER encoding on success
 * @return  BAD_FUNC_ARG when rsa is NULL.
 * @return  0 on failure.
 */
int wolfSSL_i2d_RSAPublicKey(WOLFSSL_RSA *rsa, unsigned char **pp)
{
    int ret;

    WOLFSSL_ENTER("wolfSSL_i2d_RSAPublicKey");

    /* check for bad functions arguments */
    if (rsa == NULL) {
        WOLFSSL_ERROR_MSG("Bad Function Arguments");
        ret = BAD_FUNC_ARG;
    }
    /* Encode the RSA key as a DER. Call allocates buffer into pp.
     * No heap hint as this gets returned to the user */
    else if ((ret = wolfSSL_RSA_To_Der_ex(rsa, pp, 1, NULL)) < 0) {
        WOLFSSL_ERROR_MSG("wolfSSL_RSA_To_Der failed");
        ret = 0;
    }

    return ret;
}

#endif /* OPENSSL_EXTRA */

/*
 * RSA to/from BIO APIs
 */

/* wolfSSL_d2i_RSAPublicKey_bio not supported */

#if defined(OPENSSL_ALL) || defined(WOLFSSL_ASIO) || defined(WOLFSSL_HAPROXY) \
    || defined(WOLFSSL_NGINX) || defined(WOLFSSL_QT)

#if defined(WOLFSSL_KEY_GEN) && !defined(NO_BIO)

/* Read DER data from a BIO.
 *
 * DER structures start with a constructed sequence. Use this to calculate the
 * total length of the DER data.
 *
 * @param [in]  bio   BIO object to read from.
 * @param [out] out   Buffer holding DER encoding.
 * @return  Number of bytes to DER encoding on success.
 * @return  0 on failure.
 */
static int wolfssl_read_der_bio(WOLFSSL_BIO* bio, unsigned char** out)
{
    int err = 0;
    unsigned char seq[MAX_SEQ_SZ];
    unsigned char* der = NULL;
    int derLen = 0;

    /* Read in a minimal amount to get a SEQUENCE header of any size. */
    if (wolfSSL_BIO_read(bio, seq, sizeof(seq)) != sizeof(seq)) {
        WOLFSSL_ERROR_MSG("wolfSSL_BIO_read() of sequence failure");
        err = 1;
    }
    /* Calculate complete DER encoding length. */
    if ((!err) && ((derLen = wolfssl_der_length(seq, sizeof(seq))) <= 0)) {
        WOLFSSL_ERROR_MSG("DER SEQUENCE decode failed");
        err = 1;
    }
    /* Allocate a buffer to read DER data into. */
    if ((!err) && ((der = (unsigned char*)XMALLOC((size_t)derLen, bio->heap,
            DYNAMIC_TYPE_TMP_BUFFER)) == NULL)) {
        WOLFSSL_ERROR_MSG("Malloc failure");
        err = 1;
    }
    if ((!err) && (derLen <= (int)sizeof(seq))) {
        /* Copy the previously read data into the buffer. */
        XMEMCPY(der, seq, derLen);
    }
    else if (!err) {
        /* Calculate the unread amount. */
        int len = derLen - (int)sizeof(seq);
        /* Copy the previously read data into the buffer. */
        XMEMCPY(der, seq, sizeof(seq));
        /* Read rest of DER data from BIO. */
        if (wolfSSL_BIO_read(bio, der + sizeof(seq), len) != len) {
            WOLFSSL_ERROR_MSG("wolfSSL_BIO_read() failure");
            err = 1;
        }
    }
    if (!err) {
        /* Return buffer through parameter. */
        *out = der;
    }

    if (err) {
        /* Dispose of any allocated buffer on error. */
        XFREE(der, bio->heap, DYNAMIC_TYPE_TMP_BUFFER);
        derLen = 0;
    }
    return derLen;
}

/* Reads the RSA private key data from a BIO to the internal form.
 *
 * Creates new RSA key from the DER encoded RSA private key read from the BIO.
 *
 * @param [in]  bio  BIO object to read from.
 * @param [out] out  Pointer to RSA key to return through. May be NULL.
 * @return  RSA key on success.
 * @return  NULL on failure.
 */
WOLFSSL_RSA* wolfSSL_d2i_RSAPrivateKey_bio(WOLFSSL_BIO *bio, WOLFSSL_RSA **out)
{
    WOLFSSL_RSA* key = NULL;
    unsigned char* der = NULL;
    int derLen = 0;
    int err;

    WOLFSSL_ENTER("wolfSSL_d2i_RSAPrivateKey_bio");

    /* Validate parameters. */
    err = (bio == NULL);
    /* Read just DER encoding from BIO - buffer allocated in call. */
    if ((!err) && ((derLen = wolfssl_read_der_bio(bio, &der)) == 0)) {
        err = 1;
    }
    if (!err) {
        /* Keep der for call to deallocate. */
        const unsigned char* cder = der;
        /* Create an RSA key from the data from the BIO. */
        key = wolfSSL_d2i_RSAPrivateKey(NULL, &cder, derLen);
        err = (key == NULL);
    }
    if ((!err) && (out != NULL)) {
        /* Return the created RSA key through the parameter. */
        *out = key;
    }

    if (err) {
        /* Dispose of created key on error. */
        wolfSSL_RSA_free(key);
        key = NULL;
    }
    /* Dispose of allocated data. */
    XFREE(der, bio ? bio->heap : NULL, DYNAMIC_TYPE_TMP_BUFFER);
    return key;
}
#endif /* defined(WOLFSSL_KEY_GEN) && !NO_BIO */

#endif /* OPENSSL_ALL || WOLFSSL_ASIO || WOLFSSL_HAPROXY || WOLFSSL_QT */

/*
 * RSA DER APIs
 */

#ifdef OPENSSL_EXTRA

/* Create a DER encoding of key.
 *
 * Not OpenSSL API.
 *
 * @param [in]  rsa        RSA key.
 * @param [out] outBuf     Allocated buffer containing DER encoding.
 *                         May be NULL.
 * @param [in]  publicKey  Whether to encode as public key.
 * @param [in]  heap       Heap hint.
 * @return  Encoding size on success.
 * @return  Negative on failure.
 */
int wolfSSL_RSA_To_Der(WOLFSSL_RSA* rsa, byte** outBuf, int publicKey,
    void* heap)
{
    byte* p = NULL;
    int ret;

    if (outBuf != NULL) {
        p = *outBuf;
    }
    ret = wolfSSL_RSA_To_Der_ex(rsa, outBuf, publicKey, heap);
    if ((ret > 0) && (p != NULL)) {
        *outBuf = p;
    }
    return ret;
}

/* Create a DER encoding of key.
 *
 * Buffer allocated with heap and DYNAMIC_TYPE_TMP_BUFFER.
 *
 * @param [in]      rsa        RSA key.
 * @param [in, out] outBuf     On in, pointer to allocated buffer or NULL.
 *                             May be NULL.
 *                             On out, newly allocated buffer or pointer to byte
 *                             after encoding in passed in buffer.
 * @param [in]      publicKey  Whether to encode as public key.
 * @param [in]      heap       Heap hint.
 * @return  Encoding size on success.
 * @return  Negative on failure.
 */
static int wolfSSL_RSA_To_Der_ex(WOLFSSL_RSA* rsa, byte** outBuf, int publicKey,
    void* heap)
{
    int ret = 1;
    int derSz = 0;
    byte* derBuf = NULL;

    WOLFSSL_ENTER("wolfSSL_RSA_To_Der");

    /* Unused if memory is disabled. */
    (void)heap;

    /* Validate parameters. */
    if ((rsa == NULL) || ((publicKey != 0) && (publicKey != 1))) {
        WOLFSSL_LEAVE("wolfSSL_RSA_To_Der", BAD_FUNC_ARG);
        ret = BAD_FUNC_ARG;
    }
    /* Push external RSA data into internal RSA key if not set. */
    if ((ret == 1) && (!rsa->inSet)) {
        ret = SetRsaInternal(rsa);
    }
    /* wc_RsaKeyToPublicDer encode regardless of values. */
    if ((ret == 1) && publicKey && (mp_iszero(&((RsaKey*)rsa->internal)->n) ||
            mp_iszero(&((RsaKey*)rsa->internal)->e))) {
        ret = BAD_FUNC_ARG;
    }

    if (ret == 1) {
        if (publicKey) {
            /* Calculate length of DER encoded RSA public key. */
            derSz = wc_RsaPublicKeyDerSize((RsaKey*)rsa->internal, 1);
            if (derSz < 0) {
                WOLFSSL_ERROR_MSG("wc_RsaPublicKeyDerSize failed");
                ret = derSz;
            }
        }
        else {
            /* Calculate length of DER encoded RSA private key. */
            derSz = wc_RsaKeyToDer((RsaKey*)rsa->internal, NULL, 0);
            if (derSz < 0) {
                WOLFSSL_ERROR_MSG("wc_RsaKeyToDer failed");
                ret = derSz;
            }
        }
    }

    if ((ret == 1) && (outBuf != NULL)) {
        derBuf = *outBuf;
        if (derBuf == NULL) {
            /* Allocate buffer to hold DER encoded RSA key. */
            derBuf = (byte*)XMALLOC((size_t)derSz, heap,
                DYNAMIC_TYPE_TMP_BUFFER);
            if (derBuf == NULL) {
                WOLFSSL_ERROR_MSG("Memory allocation failed");
                ret = MEMORY_ERROR;
            }
        }
    }
    if ((ret == 1) && (outBuf != NULL)) {
        if (publicKey > 0) {
            /* RSA public key to DER. */
            derSz = wc_RsaKeyToPublicDer((RsaKey*)rsa->internal, derBuf,
                (word32)derSz);
        }
        else {
            /* RSA private key to DER. */
            derSz = wc_RsaKeyToDer((RsaKey*)rsa->internal, derBuf,
                (word32)derSz);
        }
        if (derSz < 0) {
            WOLFSSL_ERROR_MSG("RSA key encoding failed");
            ret = derSz;
        }
        else if ((*outBuf) != NULL) {
            derBuf = NULL;
            *outBuf += derSz;
        }
        else {
            /* Return allocated buffer. */
            *outBuf = derBuf;
        }
    }
    if (ret == 1) {
        /* Success - return DER encoding size. */
        ret = derSz;
    }

    if ((outBuf != NULL) && (*outBuf != derBuf)) {
        /* Not returning buffer, needs to be disposed of. */
        XFREE(derBuf, heap, DYNAMIC_TYPE_TMP_BUFFER);
    }
    WOLFSSL_LEAVE("wolfSSL_RSA_To_Der", ret);
    return ret;
}

#endif /* OPENSSL_EXTRA */

#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
/* Load the DER encoded private RSA key.
 *
 * Not OpenSSL API.
 *
 * @param [in] rsa     RSA key.
 * @param [in] derBuf  Buffer holding DER encoding.
 * @param [in] derSz   Length of DER encoding.
 * @return  1 on success.
 * @return  -1 on failure.
 */
int wolfSSL_RSA_LoadDer(WOLFSSL_RSA* rsa, const unsigned char* derBuf,
    int derSz)
{
    /* Call implementation that handles both private and public keys. */
    return wolfSSL_RSA_LoadDer_ex(rsa, derBuf, derSz, WOLFSSL_RSA_LOAD_PRIVATE);
}

/* Load the DER encoded public or private RSA key.
 *
 * Not OpenSSL API.
 *
 * @param [in] rsa     RSA key.
 * @param [in] derBuf  Buffer holding DER encoding.
 * @param [in] derSz   Length of DER encoding.
 * @param [in] opt     Indicates public or private key.
 *                     (WOLFSSL_RSA_LOAD_PUBLIC or WOLFSSL_RSA_LOAD_PRIVATE)
 * @return  1 on success.
 * @return  -1 on failure.
 */
int wolfSSL_RSA_LoadDer_ex(WOLFSSL_RSA* rsa, const unsigned char* derBuf,
    int derSz, int opt)
{
    int ret = 1;
    int res;
    word32 idx = 0;
    word32 algId;

    WOLFSSL_ENTER("wolfSSL_RSA_LoadDer");

    /* Validate parameters. */
    if ((rsa == NULL) || (rsa->internal == NULL) || (derBuf == NULL) ||
            (derSz <= 0)) {
        WOLFSSL_ERROR_MSG("Bad function arguments");
        ret = WOLFSSL_FATAL_ERROR;
    }

    if (ret == 1) {
        rsa->pkcs8HeaderSz = 0;
        /* Check if input buffer has PKCS8 header. In the case that it does not
         * have a PKCS8 header then do not error out. */
        res = ToTraditionalInline_ex((const byte*)derBuf, &idx, (word32)derSz,
            &algId);
        if (res >= 0) {
            /* Store size of PKCS#8 header for encoding. */
            WOLFSSL_MSG("Found PKCS8 header");
            rsa->pkcs8HeaderSz = (word16)idx;
        }
        /* When decoding and not PKCS#8, return will be ASN_PARSE_E. */
        else if (res != WC_NO_ERR_TRACE(ASN_PARSE_E)) {
            /* Something went wrong while decoding. */
            WOLFSSL_ERROR_MSG("Unexpected error with trying to remove PKCS#8 "
                              "header");
            ret = WOLFSSL_FATAL_ERROR;
        }
    }
    if (ret == 1) {
        /* Decode private or public key data. */
        if (opt == WOLFSSL_RSA_LOAD_PRIVATE) {
            res = wc_RsaPrivateKeyDecode(derBuf, &idx, (RsaKey*)rsa->internal,
                (word32)derSz);
        }
        else {
            res = wc_RsaPublicKeyDecode(derBuf, &idx, (RsaKey*)rsa->internal,
                (word32)derSz);
        }
        /* Check for error. */
        if (res < 0) {
            if (opt == WOLFSSL_RSA_LOAD_PRIVATE) {
                 WOLFSSL_ERROR_MSG("RsaPrivateKeyDecode failed");
            }
            else {
                 WOLFSSL_ERROR_MSG("RsaPublicKeyDecode failed");
            }
            WOLFSSL_ERROR_VERBOSE(res);
            ret = WOLFSSL_FATAL_ERROR;
        }
    }
    if (ret == 1) {
        /* Set external RSA key data from wolfCrypt key. */
        if (SetRsaExternal(rsa) != 1) {
            ret = WOLFSSL_FATAL_ERROR;
        }
        else {
            rsa->inSet = 1;
        }
    }

    return ret;
}

#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */

#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL)

#if !defined(NO_BIO) || !defined(NO_FILESYSTEM)
/* Load DER encoded data into WOLFSSL_RSA object.
 *
 * Creates a new WOLFSSL_RSA object if one is not passed in.
 *
 * @param [in, out] rsa   WOLFSSL_RSA object to load into.
 *                        When rsa or *rsa is NULL a new object is created.
 *                        When not NULL and *rsa is NULL then new object
 *                        returned through pointer.
 * @param [in]      in    DER encoded RSA key data.
 * @param [in]      inSz  Size of DER encoded data in bytes.
 * @param [in]      opt   Public or private key encoded in data. Valid values:
 *                        WOLFSSL_RSA_LOAD_PRIVATE, WOLFSSL_RSA_LOAD_PUBLIC.
 * @return  NULL on failure.
 * @return  WOLFSSL_RSA object on success.
 */
static WOLFSSL_RSA* wolfssl_rsa_d2i(WOLFSSL_RSA** rsa, const unsigned char* in,
    long inSz, int opt)
{
    WOLFSSL_RSA* ret = NULL;

    if ((rsa != NULL) && (*rsa != NULL)) {
        ret = *rsa;
    }
    else {
        ret = wolfSSL_RSA_new();
    }
    if ((ret != NULL) && (wolfSSL_RSA_LoadDer_ex(ret, in, (int)inSz, opt)
            != 1)) {
        if ((rsa == NULL) || (ret != *rsa)) {
            wolfSSL_RSA_free(ret);
        }
        ret = NULL;
    }

    if ((rsa != NULL) && (*rsa == NULL)) {
        *rsa = ret;
    }
    return ret;
}
#endif

#endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */

/*
 * RSA PEM APIs
 */

#ifdef OPENSSL_EXTRA

#ifndef NO_BIO
#if defined(WOLFSSL_KEY_GEN)
/* Writes PEM encoding of an RSA public key to a BIO.
 *
 * @param [in] bio  BIO object to write to.
 * @param [in] rsa  RSA key to write.
 * @return  1 on success.
 * @return  0 on failure.
 */
int wolfSSL_PEM_write_bio_RSA_PUBKEY(WOLFSSL_BIO* bio, WOLFSSL_RSA* rsa)
{
    int ret = 1;
    int derSz = 0;
    byte* derBuf = NULL;

    WOLFSSL_ENTER("wolfSSL_PEM_write_bio_RSA_PUBKEY");

    /* Validate parameters. */
    if ((bio == NULL) || (rsa == NULL)) {
        WOLFSSL_ERROR_MSG("Bad Function Arguments");
        return 0;
    }

    if ((derSz = wolfSSL_RSA_To_Der(rsa, &derBuf, 1, bio->heap)) < 0) {
        WOLFSSL_ERROR_MSG("wolfSSL_RSA_To_Der failed");
        ret = 0;
    }
    if (derBuf == NULL) {
        WOLFSSL_ERROR_MSG("wolfSSL_RSA_To_Der failed to get buffer");
        ret = 0;
    }
    if ((ret == 1) && (der_write_to_bio_as_pem(derBuf, derSz, bio,
            PUBLICKEY_TYPE) != 1)) {
        ret = 0;
    }

    /* Dispose of DER buffer. */
    XFREE(derBuf, bio->heap, DYNAMIC_TYPE_TMP_BUFFER);
    return ret;
}

#endif /* WOLFSSL_KEY_GEN */
#endif /* !NO_BIO */

#if defined(WOLFSSL_KEY_GEN)
#ifndef NO_FILESYSTEM

/* Writes PEM encoding of an RSA public key to a file pointer.
 *
 * @param [in] fp    File pointer to write to.
 * @param [in] rsa   RSA key to write.
 * @param [in] type  PEM type to write out.
 * @return  1 on success.
 * @return  0 on failure.
 */
static int wolfssl_pem_write_rsa_public_key(XFILE fp, WOLFSSL_RSA* rsa,
    int type)
{
    int ret = 1;
    int derSz;
    byte* derBuf = NULL;

    /* Validate parameters. */
    if ((fp == XBADFILE) || (rsa == NULL)) {
        WOLFSSL_ERROR_MSG("Bad Function Arguments");
        return 0;
    }

    if ((derSz = wolfSSL_RSA_To_Der(rsa, &derBuf, 1, rsa->heap)) < 0) {
        WOLFSSL_ERROR_MSG("wolfSSL_RSA_To_Der failed");
        ret = 0;
    }
    if (derBuf == NULL) {
        WOLFSSL_ERROR_MSG("wolfSSL_RSA_To_Der failed to get buffer");
        ret = 0;
    }
    if ((ret == 1) && (der_write_to_file_as_pem(derBuf, derSz, fp, type,
            rsa->heap) != 1)) {
        ret = 0;
    }

    /* Dispose of DER buffer. */
    XFREE(derBuf, rsa->heap, DYNAMIC_TYPE_TMP_BUFFER);

    return ret;
}

/* Writes PEM encoding of an RSA public key to a file pointer.
 *
 * Header/footer will contain: PUBLIC KEY
 *
 * @param [in] fp   File pointer to write to.
 * @param [in] rsa  RSA key to write.
 * @return  1 on success.
 * @return  0 on failure.
 */
int wolfSSL_PEM_write_RSA_PUBKEY(XFILE fp, WOLFSSL_RSA* rsa)
{
    return wolfssl_pem_write_rsa_public_key(fp, rsa, PUBLICKEY_TYPE);
}

/* Writes PEM encoding of an RSA public key to a file pointer.
 *
 * Header/footer will contain: RSA PUBLIC KEY
 *
 * @param [in] fp   File pointer to write to.
 * @param [in] rsa  RSA key to write.
 * @return  1 on success.
 * @return  0 on failure.
 */
int wolfSSL_PEM_write_RSAPublicKey(XFILE fp, WOLFSSL_RSA* rsa)
{
    return wolfssl_pem_write_rsa_public_key(fp, rsa, RSA_PUBLICKEY_TYPE);
}
#endif /* !NO_FILESYSTEM */
#endif /* WOLFSSL_KEY_GEN */

#ifndef NO_BIO
/* Create an RSA public key by reading the PEM encoded data from the BIO.
 *
 * @param [in]  bio   BIO object to read from.
 * @param [out] out   RSA key created.
 * @param [in]  cb    Password callback when PEM encrypted.
 * @param [in]  pass  NUL terminated string for passphrase when PEM encrypted.
 * @return  RSA key on success.
 * @return  NULL on failure.
 */
WOLFSSL_RSA *wolfSSL_PEM_read_bio_RSA_PUBKEY(WOLFSSL_BIO* bio,
    WOLFSSL_RSA** out, wc_pem_password_cb* cb, void *pass)
{
    WOLFSSL_RSA* rsa = NULL;
    DerBuffer*   der = NULL;
    int          keyFormat = 0;

    WOLFSSL_ENTER("wolfSSL_PEM_read_bio_RSA_PUBKEY");

    if ((bio != NULL) && (pem_read_bio_key(bio, cb, pass, PUBLICKEY_TYPE,
            &keyFormat, &der) >= 0)) {
        rsa = wolfssl_rsa_d2i(out, der->buffer, der->length,
            WOLFSSL_RSA_LOAD_PUBLIC);
        if (rsa == NULL) {
            WOLFSSL_ERROR_MSG("Error loading DER buffer into WOLFSSL_RSA");
        }
    }

    FreeDer(&der);
    if ((out != NULL) && (rsa != NULL)) {
        *out = rsa;
    }
    return rsa;
}

WOLFSSL_RSA *wolfSSL_d2i_RSA_PUBKEY_bio(WOLFSSL_BIO *bio, WOLFSSL_RSA **out)
{
    char* data = NULL;
    int dataSz = 0;
    int memAlloced = 0;
    WOLFSSL_RSA* rsa = NULL;

    WOLFSSL_ENTER("wolfSSL_d2i_RSA_PUBKEY_bio");

    if (bio == NULL)
        return NULL;

    if (wolfssl_read_bio(bio, &data, &dataSz, &memAlloced) != 0) {
        if (memAlloced)
            XFREE(data, NULL, DYNAMIC_TYPE_TMP_BUFFER);
        return NULL;
    }

    rsa = wolfssl_rsa_d2i(out, (const unsigned char*)data, dataSz,
            WOLFSSL_RSA_LOAD_PUBLIC);
    if (memAlloced)
        XFREE(data, NULL, DYNAMIC_TYPE_TMP_BUFFER);

    return rsa;
}
#endif /* !NO_BIO */

#ifndef NO_FILESYSTEM
/* Create an RSA public key by reading the PEM encoded data from the BIO.
 *
 * Header/footer should contain: PUBLIC KEY
 * PEM decoder supports either 'RSA PUBLIC KEY' or 'PUBLIC KEY'.
 *
 * @param [in]  fp    File pointer to read from.
 * @param [out] out   RSA key created.
 * @param [in]  cb    Password callback when PEM encrypted.
 * @param [in]  pass  NUL terminated string for passphrase when PEM encrypted.
 * @return  RSA key on success.
 * @return  NULL on failure.
 */
WOLFSSL_RSA *wolfSSL_PEM_read_RSA_PUBKEY(XFILE fp,
    WOLFSSL_RSA** out, wc_pem_password_cb* cb, void *pass)
{
    WOLFSSL_RSA* rsa = NULL;
    DerBuffer*   der = NULL;
    int          keyFormat = 0;

    WOLFSSL_ENTER("wolfSSL_PEM_read_RSA_PUBKEY");

    if ((fp != XBADFILE) && (pem_read_file_key(fp, cb, pass, PUBLICKEY_TYPE,
            &keyFormat, &der) >= 0)) {
        rsa = wolfssl_rsa_d2i(out, der->buffer, der->length,
            WOLFSSL_RSA_LOAD_PUBLIC);
        if (rsa == NULL) {
            WOLFSSL_ERROR_MSG("Error loading DER buffer into WOLFSSL_RSA");
        }
    }

    FreeDer(&der);
    if ((out != NULL) && (rsa != NULL)) {
        *out = rsa;
    }
    return rsa;
}

/* Create an RSA public key by reading the PEM encoded data from the BIO.
 *
 * Header/footer should contain: RSA PUBLIC KEY
 * PEM decoder supports either 'RSA PUBLIC KEY' or 'PUBLIC KEY'.
 *
 * @param [in]  fp    File pointer to read from.
 * @param [out] rsa   RSA key created.
 * @param [in]  cb    Password callback when PEM encrypted. May be NULL.
 * @param [in]  pass  NUL terminated string for passphrase when PEM encrypted.
 *                    May be NULL.
 * @return  RSA key on success.
 * @return  NULL on failure.
 */
WOLFSSL_RSA* wolfSSL_PEM_read_RSAPublicKey(XFILE fp, WOLFSSL_RSA** rsa,
    wc_pem_password_cb* cb, void* pass)
{
    return wolfSSL_PEM_read_RSA_PUBKEY(fp, rsa, cb, pass);
}

#endif /* NO_FILESYSTEM */

#if defined(WOLFSSL_KEY_GEN) && \
    (defined(WOLFSSL_PEM_TO_DER) || defined(WOLFSSL_DER_TO_PEM))

/* Writes PEM encoding of an RSA private key to newly allocated buffer.
 *
 * Buffer returned was allocated with: DYNAMIC_TYPE_KEY.
 *
 * @param [in]  rsa       RSA key to write.
 * @param [in]  cipher    Cipher to use when PEM encrypted. May be NULL.
 * @param [in]  passwd    Password string when PEM encrypted. May be NULL.
 * @param [in]  passwdSz  Length of password string when PEM encrypted.
 * @param [out] pem       Allocated buffer with PEM encoding.
 * @param [out] pLen      Length of PEM encoding.
 * @return  1 on success.
 * @return  0 on failure.
 */
int wolfSSL_PEM_write_mem_RSAPrivateKey(WOLFSSL_RSA* rsa,
    const WOLFSSL_EVP_CIPHER* cipher, unsigned char* passwd, int passwdSz,
    unsigned char **pem, int *pLen)
{
    int ret = 1;
    byte* derBuf = NULL;
    int  derSz = 0;

    WOLFSSL_ENTER("wolfSSL_PEM_write_mem_RSAPrivateKey");

    /* Validate parameters. */
    if ((pem == NULL) || (pLen == NULL) || (rsa == NULL) ||
            (rsa->internal == NULL)) {
        WOLFSSL_ERROR_MSG("Bad function arguments");
        ret = 0;
    }

    /* Set the RSA key data into the wolfCrypt RSA key if not done so. */
    if ((ret == 1) && (!rsa->inSet) && (SetRsaInternal(rsa) != 1)) {
        ret = 0;
    }

    /* Encode wolfCrypt RSA key to DER - derBuf allocated in call. */
    if ((ret == 1) && ((derSz = wolfSSL_RSA_To_Der(rsa, &derBuf, 0,
            rsa->heap)) < 0)) {
        WOLFSSL_ERROR_MSG("wolfSSL_RSA_To_Der failed");
        ret = 0;
    }

    if ((ret == 1) && (der_to_enc_pem_alloc(derBuf, derSz, cipher, passwd,
            passwdSz, PRIVATEKEY_TYPE, NULL, pem, pLen) != 1)) {
        WOLFSSL_ERROR_MSG("der_to_enc_pem_alloc failed");
        ret = 0;
    }

    return ret;
}

#ifndef NO_BIO
/* Writes PEM encoding of an RSA private key to a BIO.
 *
 * @param [in] bio     BIO object to write to.
 * @param [in] rsa     RSA key to write.
 * @param [in] cipher  Cipher to use when PEM encrypted.
 * @param [in] passwd  Password string when PEM encrypted.
 * @param [in] len     Length of password string when PEM encrypted.
 * @param [in] cb      Password callback to use when PEM encrypted.
 * @param [in] arg     NUL terminated string for passphrase when PEM encrypted.
 * @return  1 on success.
 * @return  0 on failure.
 */
int wolfSSL_PEM_write_bio_RSAPrivateKey(WOLFSSL_BIO* bio, WOLFSSL_RSA* rsa,
    const WOLFSSL_EVP_CIPHER* cipher, unsigned char* passwd, int len,
    wc_pem_password_cb* cb, void* arg)
{
    int ret = 1;
    byte* pem = NULL;
    int pLen = 0;

    (void)cb;
    (void)arg;

    WOLFSSL_ENTER("wolfSSL_PEM_write_bio_RSAPrivateKey");

    /* Validate parameters. */
    if ((bio == NULL) || (rsa == NULL) || (rsa->internal == NULL)) {
        WOLFSSL_ERROR_MSG("Bad function arguments");
        ret = 0;
    }

    if (ret == 1) {
        /* Write PEM to buffer that is allocated in the call. */
        ret = wolfSSL_PEM_write_mem_RSAPrivateKey(rsa, cipher, passwd, len,
            &pem, &pLen);
        if (ret != 1) {
            WOLFSSL_ERROR_MSG("wolfSSL_PEM_write_mem_RSAPrivateKey failed");
        }
    }
    /* Write PEM to BIO. */
    if ((ret == 1) && (wolfSSL_BIO_write(bio, pem, pLen) <= 0)) {
        WOLFSSL_ERROR_MSG("RSA private key BIO write failed");
        ret = 0;
    }

    /* Dispose of any allocated PEM buffer. */
    XFREE(pem, NULL, DYNAMIC_TYPE_KEY);
    return ret;
}
#endif /* !NO_BIO */

#ifndef NO_FILESYSTEM
/* Writes PEM encoding of an RSA private key to a file pointer.
 *
 * TODO: Support use of the password callback and callback context.
 *
 * @param [in] fp        File pointer to write to.
 * @param [in] rsa       RSA key to write.
 * @param [in] cipher    Cipher to use when PEM encrypted. May be NULL.
 * @param [in] passwd    Password string when PEM encrypted. May be NULL.
 * @param [in] passwdSz  Length of password string when PEM encrypted.
 * @param [in] cb        Password callback to use when PEM encrypted. Unused.
 * @param [in] arg       NUL terminated string for passphrase when PEM
 *                       encrypted. Unused.
 * @return  1 on success.
 * @return  0 on failure.
 */
int wolfSSL_PEM_write_RSAPrivateKey(XFILE fp, WOLFSSL_RSA *rsa,
    const WOLFSSL_EVP_CIPHER *cipher, unsigned char *passwd, int passwdSz,
    wc_pem_password_cb *cb, void *arg)
{
    int ret = 1;
    byte* pem = NULL;
    int pLen = 0;

    (void)cb;
    (void)arg;

    WOLFSSL_ENTER("wolfSSL_PEM_write_RSAPrivateKey");

    /* Validate parameters. */
    if ((fp == XBADFILE) || (rsa == NULL) || (rsa->internal == NULL)) {
        WOLFSSL_ERROR_MSG("Bad function arguments");
        ret = 0;
    }

    if (ret == 1) {
        /* Write PEM to buffer that is allocated in the call. */
        ret = wolfSSL_PEM_write_mem_RSAPrivateKey(rsa, cipher, passwd, passwdSz,
            &pem, &pLen);
        if (ret != 1) {
            WOLFSSL_ERROR_MSG("wolfSSL_PEM_write_mem_RSAPrivateKey failed");
        }
    }
    /* Write PEM to file pointer. */
    if ((ret == 1) && ((int)XFWRITE(pem, 1, (size_t)pLen, fp) != pLen)) {
        WOLFSSL_ERROR_MSG("RSA private key file write failed");
        ret = 0;
    }

    /* Dispose of any allocated PEM buffer. */
    XFREE(pem, NULL, DYNAMIC_TYPE_KEY);
    return ret;
}
#endif /* NO_FILESYSTEM */
#endif /* WOLFSSL_KEY_GEN && WOLFSSL_PEM_TO_DER */

#ifndef NO_BIO
/* Create an RSA private key by reading the PEM encoded data from the BIO.
 *
 * @param [in]  bio   BIO object to read from.
 * @param [out] out   RSA key created.
 * @param [in]  cb    Password callback when PEM encrypted.
 * @param [in]  pass  NUL terminated string for passphrase when PEM encrypted.
 * @return  RSA key on success.
 * @return  NULL on failure.
 */
WOLFSSL_RSA* wolfSSL_PEM_read_bio_RSAPrivateKey(WOLFSSL_BIO* bio,
    WOLFSSL_RSA** out, wc_pem_password_cb* cb, void* pass)
{
    WOLFSSL_RSA* rsa = NULL;
    DerBuffer*   der = NULL;
    int          keyFormat = 0;

    WOLFSSL_ENTER("wolfSSL_PEM_read_bio_RSAPrivateKey");

    if ((bio != NULL) && (pem_read_bio_key(bio, cb, pass, PRIVATEKEY_TYPE,
            &keyFormat, &der) >= 0)) {
        rsa = wolfssl_rsa_d2i(out, der->buffer, der->length,
            WOLFSSL_RSA_LOAD_PRIVATE);
        if (rsa == NULL) {
            WOLFSSL_ERROR_MSG("Error loading DER buffer into WOLFSSL_RSA");
        }
    }

    FreeDer(&der);
    if ((out != NULL) && (rsa != NULL)) {
        *out = rsa;
    }
    return rsa;
}
#endif /* !NO_BIO */

/* Create an RSA private key by reading the PEM encoded data from the file
 * pointer.
 *
 * @param [in]  fp    File pointer to read from.
 * @param [out] out   RSA key created.
 * @param [in]  cb    Password callback when PEM encrypted.
 * @param [in]  pass  NUL terminated string for passphrase when PEM encrypted.
 * @return  RSA key on success.
 * @return  NULL on failure.
 */
#ifndef NO_FILESYSTEM
WOLFSSL_RSA* wolfSSL_PEM_read_RSAPrivateKey(XFILE fp, WOLFSSL_RSA** out,
    wc_pem_password_cb* cb, void* pass)
{
    WOLFSSL_RSA* rsa = NULL;
    DerBuffer*   der = NULL;
    int          keyFormat = 0;

    WOLFSSL_ENTER("wolfSSL_PEM_read_RSAPrivateKey");

    if ((fp != XBADFILE) && (pem_read_file_key(fp, cb, pass, PRIVATEKEY_TYPE,
            &keyFormat, &der) >= 0)) {
        rsa = wolfssl_rsa_d2i(out, der->buffer, der->length,
            WOLFSSL_RSA_LOAD_PRIVATE);
        if (rsa == NULL) {
            WOLFSSL_ERROR_MSG("Error loading DER buffer into WOLFSSL_RSA");
        }
    }

    FreeDer(&der);
    if ((out != NULL) && (rsa != NULL)) {
        *out = rsa;
    }
    return rsa;
}
#endif /* !NO_FILESYSTEM */

/*
 * RSA print APIs
 */

#if defined(XFPRINTF) && !defined(NO_FILESYSTEM) && \
    !defined(NO_STDIO_FILESYSTEM)
/* Print an RSA key to a file pointer.
 *
 * @param [in] fp      File pointer to write to.
 * @param [in] rsa     RSA key to write.
 * @param [in] indent  Number of spaces to prepend to each line.
 * @return  1 on success.
 * @return  0 on failure.
 */
int wolfSSL_RSA_print_fp(XFILE fp, WOLFSSL_RSA* rsa, int indent)
{
    int ret = 1;

    WOLFSSL_ENTER("wolfSSL_RSA_print_fp");

    /* Validate parameters. */
    if ((fp == XBADFILE) || (rsa == NULL)) {
        ret = 0;
    }

    /* Set the external data from the wolfCrypt RSA key if not done. */
    if ((ret == 1) && (!rsa->exSet)) {
        ret = SetRsaExternal(rsa);
    }

    /* Get the key size from modulus if available. */
    if ((ret == 1) && (rsa->n != NULL)) {
        int keySize = wolfSSL_BN_num_bits(rsa->n);
        if (keySize == 0) {
            ret = 0;
        }
        else {
            if (XFPRINTF(fp, "%*s", indent, "") < 0)
                ret = 0;
            else if (XFPRINTF(fp, "RSA Private-Key: (%d bit, 2 primes)\n",
                              keySize) < 0)
                ret = 0;
        }
    }
    /* Print out any components available. */
    if ((ret == 1) && (rsa->n != NULL)) {
        ret = pk_bn_field_print_fp(fp, indent, "modulus", rsa->n);
    }
    if ((ret == 1) && (rsa->d != NULL)) {
        ret = pk_bn_field_print_fp(fp, indent, "privateExponent", rsa->d);
    }
    if ((ret == 1) && (rsa->p != NULL)) {
        ret = pk_bn_field_print_fp(fp, indent, "prime1", rsa->p);
    }
    if ((ret == 1) && (rsa->q != NULL)) {
        ret = pk_bn_field_print_fp(fp, indent, "prime2", rsa->q);
    }
    if ((ret == 1) && (rsa->dmp1 != NULL)) {
        ret = pk_bn_field_print_fp(fp, indent, "exponent1", rsa->dmp1);
    }
    if ((ret == 1) && (rsa->dmq1 != NULL)) {
        ret = pk_bn_field_print_fp(fp, indent, "exponent2", rsa->dmq1);
    }
    if ((ret == 1) && (rsa->iqmp != NULL)) {
        ret = pk_bn_field_print_fp(fp, indent, "coefficient", rsa->iqmp);
    }

    WOLFSSL_LEAVE("wolfSSL_RSA_print_fp", ret);

    return ret;
}
#endif /* XFPRINTF && !NO_FILESYSTEM && !NO_STDIO_FILESYSTEM */

#if defined(XSNPRINTF) && !defined(NO_BIO)
/* snprintf() must be available */

/* Maximum size of a header line. */
#define RSA_PRINT_MAX_HEADER_LINE   PRINT_NUM_MAX_INDENT

/* Writes the human readable form of RSA to a BIO.
 *
 * @param [in] bio     BIO object to write to.
 * @param [in] rsa     RSA key to write.
 * @param [in] indent  Number of spaces before each line.
 * @return  1 on success.
 * @return  0 on failure.
 */
int wolfSSL_RSA_print(WOLFSSL_BIO* bio, WOLFSSL_RSA* rsa, int indent)
{
    int ret = 1;
    int sz = 0;
    RsaKey* key = NULL;
    char line[RSA_PRINT_MAX_HEADER_LINE];
    int i = 0;
    mp_int *num = NULL;
    /* Header strings. */
    const char *name[] = {
        "Modulus:", "Exponent:", "PrivateExponent:", "Prime1:", "Prime2:",
        "Exponent1:", "Exponent2:", "Coefficient:"
    };

    WOLFSSL_ENTER("wolfSSL_RSA_print");

    /* Validate parameters. */
    if ((bio == NULL) || (rsa == NULL) || (indent > PRINT_NUM_MAX_INDENT)) {
        ret = WOLFSSL_FATAL_ERROR;
    }

    if (ret == 1) {
        key = (RsaKey*)rsa->internal;

        /* Get size in bits of key for printing out. */
        sz = wolfSSL_RSA_bits(rsa);
        if (sz <= 0) {
            WOLFSSL_ERROR_MSG("Error getting RSA key size");
            ret = 0;
        }
    }
    if (ret == 1) {
        /* Print any indent spaces. */
        ret = wolfssl_print_indent(bio, line, sizeof(line), indent);
    }
    if (ret == 1) {
        /* Print header line. */
        int len = XSNPRINTF(line, sizeof(line), "\nRSA %s: (%d bit)\n",
            (!mp_iszero(&key->d)) ? "Private-Key" : "Public-Key", sz);
        if (len >= (int)sizeof(line)) {
            WOLFSSL_ERROR_MSG("Buffer overflow while formatting key preamble");
            ret = 0;
        }
        else {
            if (wolfSSL_BIO_write(bio, line, len) <= 0) {
                ret = 0;
            }
        }
    }

    for (i = 0; (ret == 1) && (i < RSA_INTS); i++) {
        /* Get mp_int for index. */
        switch (i) {
            case 0:
                /* Print out modulus */
                num = &key->n;
                break;
            case 1:
                num = &key->e;
                break;
            case 2:
                num = &key->d;
                break;
            case 3:
                num = &key->p;
                break;
            case 4:
                num = &key->q;
                break;
            case 5:
                num = &key->dP;
                break;
            case 6:
                num = &key->dQ;
                break;
            case 7:
                num = &key->u;
                break;
            default:
                WOLFSSL_ERROR_MSG("Bad index value");
        }

        if (i == 1) {
            /* Print exponent as a 32-bit value. */
            ret = wolfssl_print_value(bio, num, name[i], indent);
        }
        else if (!mp_iszero(num)) {
            /* Print name and MP integer. */
            ret = wolfssl_print_number(bio, num, name[i], indent);
        }
    }

    return ret;
}
#endif /* XSNPRINTF && !NO_BIO */

#endif /* OPENSSL_EXTRA */

/*
 * RSA get/set/test APIs
 */

#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
/* Set RSA key data (external) from wolfCrypt RSA key (internal).
 *
 * @param [in, out] rsa  RSA key.
 * @return  1 on success.
 * @return  0 on failure.
 */
int SetRsaExternal(WOLFSSL_RSA* rsa)
{
    int ret = 1;

    WOLFSSL_ENTER("SetRsaExternal");

    /* Validate parameters. */
    if ((rsa == NULL) || (rsa->internal == NULL)) {
        WOLFSSL_ERROR_MSG("rsa key NULL error");
        ret = WOLFSSL_FATAL_ERROR;
    }

    if (ret == 1) {
        RsaKey* key = (RsaKey*)rsa->internal;

        /* Copy modulus. */
        ret = wolfssl_bn_set_value(&rsa->n, &key->n);
        if (ret != 1) {
            WOLFSSL_ERROR_MSG("rsa n error");
        }
        if (ret == 1) {
            /* Copy public exponent. */
            ret = wolfssl_bn_set_value(&rsa->e, &key->e);
            if (ret != 1) {
                WOLFSSL_ERROR_MSG("rsa e error");
            }
        }

        if (key->type == RSA_PRIVATE) {
    #ifndef WOLFSSL_RSA_PUBLIC_ONLY
            if (ret == 1) {
                /* Copy private exponent. */
                ret = wolfssl_bn_set_value(&rsa->d, &key->d);
                if (ret != 1) {
                    WOLFSSL_ERROR_MSG("rsa d error");
                }
            }
            if (ret == 1) {
                /* Copy first prime. */
                ret = wolfssl_bn_set_value(&rsa->p, &key->p);
                if (ret != 1) {
                    WOLFSSL_ERROR_MSG("rsa p error");
                }
            }
            if (ret == 1) {
                /* Copy second prime. */
                ret = wolfssl_bn_set_value(&rsa->q, &key->q);
                if (ret != 1) {
                    WOLFSSL_ERROR_MSG("rsa q error");
                }
            }
        #if defined(WOLFSSL_KEY_GEN) || defined(OPENSSL_EXTRA) || \
            !defined(RSA_LOW_MEM)
            if (ret == 1) {
                /* Copy d mod p-1. */
                ret = wolfssl_bn_set_value(&rsa->dmp1, &key->dP);
                if (ret != 1) {
                    WOLFSSL_ERROR_MSG("rsa dP error");
                }
            }
            if (ret == 1) {
                /* Copy d mod q-1. */
                ret = wolfssl_bn_set_value(&rsa->dmq1, &key->dQ);
                if (ret != 1) {
                    WOLFSSL_ERROR_MSG("rsa dq error");
                }
            }
            if (ret == 1) {
                /* Copy 1/q mod p. */
                ret = wolfssl_bn_set_value(&rsa->iqmp, &key->u);
                if (ret != 1) {
                    WOLFSSL_ERROR_MSG("rsa u error");
                }
            }
        #endif
    #else
            WOLFSSL_ERROR_MSG("rsa private key not compiled in ");
            ret = 0;
    #endif /* !WOLFSSL_RSA_PUBLIC_ONLY */
        }
    }
    if (ret == 1) {
        /* External values set. */
        rsa->exSet = 1;
    }
    else {
        /* Return 0 on failure. */
        ret = 0;
    }

    return ret;
}
#endif /* (OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL) */

#ifdef OPENSSL_EXTRA

/* Set wolfCrypt RSA key data (internal) from RSA key (external).
 *
 * @param [in, out] rsa  RSA key.
 * @return  1 on success.
 * @return  0 on failure.
 */
int SetRsaInternal(WOLFSSL_RSA* rsa)
{
    int ret = 1;

    WOLFSSL_ENTER("SetRsaInternal");

    /* Validate parameters. */
    if ((rsa == NULL) || (rsa->internal == NULL)) {
        WOLFSSL_ERROR_MSG("rsa key NULL error");
        ret = WOLFSSL_FATAL_ERROR;
    }

    if (ret == 1) {
        RsaKey* key = (RsaKey*)rsa->internal;

        /* Copy down modulus if available. */
        if ((rsa->n != NULL) && (wolfssl_bn_get_value(rsa->n, &key->n) != 1)) {
            WOLFSSL_ERROR_MSG("rsa n key error");
            ret = WOLFSSL_FATAL_ERROR;
        }

        /* Copy down public exponent if available. */
        if ((ret == 1) && (rsa->e != NULL) &&
                (wolfssl_bn_get_value(rsa->e, &key->e) != 1)) {
            WOLFSSL_ERROR_MSG("rsa e key error");
            ret = WOLFSSL_FATAL_ERROR;
        }

        /* Enough numbers for public key */
        key->type = RSA_PUBLIC;

#ifndef WOLFSSL_RSA_PUBLIC_ONLY
        /* Copy down private exponent if available. */
        if ((ret == 1) && (rsa->d != NULL)) {
            if (wolfssl_bn_get_value(rsa->d, &key->d) != 1) {
                WOLFSSL_ERROR_MSG("rsa d key error");
                ret = WOLFSSL_FATAL_ERROR;
            }
            else {
                /* Enough numbers for private key */
                key->type = RSA_PRIVATE;
           }
        }

        /* Copy down first prime if available. */
        if ((ret == 1) && (rsa->p != NULL) &&
                (wolfssl_bn_get_value(rsa->p, &key->p) != 1)) {
            WOLFSSL_ERROR_MSG("rsa p key error");
            ret = WOLFSSL_FATAL_ERROR;
        }

        /* Copy down second prime if available. */
        if ((ret == 1) && (rsa->q != NULL) &&
                (wolfssl_bn_get_value(rsa->q, &key->q) != 1)) {
            WOLFSSL_ERROR_MSG("rsa q key error");
            ret = WOLFSSL_FATAL_ERROR;
        }

#if defined(WOLFSSL_KEY_GEN) || defined(OPENSSL_EXTRA) || !defined(RSA_LOW_MEM)
        /* Copy down d mod p-1 if available. */
        if ((ret == 1) && (rsa->dmp1 != NULL) &&
                (wolfssl_bn_get_value(rsa->dmp1, &key->dP) != 1)) {
            WOLFSSL_ERROR_MSG("rsa dP key error");
            ret = WOLFSSL_FATAL_ERROR;
        }

        /* Copy down d mod q-1 if available. */
        if ((ret == 1) && (rsa->dmq1 != NULL) &&
                (wolfssl_bn_get_value(rsa->dmq1, &key->dQ) != 1)) {
            WOLFSSL_ERROR_MSG("rsa dQ key error");
            ret = WOLFSSL_FATAL_ERROR;
        }

        /* Copy down 1/q mod p if available. */
        if ((ret == 1) && (rsa->iqmp != NULL) &&
                (wolfssl_bn_get_value(rsa->iqmp, &key->u) != 1)) {
            WOLFSSL_ERROR_MSG("rsa u key error");
            ret = WOLFSSL_FATAL_ERROR;
        }
#endif
#endif

        if (ret == 1) {
            /* All available numbers have been set down. */
            rsa->inSet = 1;
        }
    }

    return ret;
}

/* Set the RSA method into object.
 *
 * @param [in, out] rsa   RSA key.
 * @param [in]      meth  RSA method.
 * @return  1 always.
 */
int wolfSSL_RSA_set_method(WOLFSSL_RSA *rsa, WOLFSSL_RSA_METHOD *meth)
{
    if (rsa != NULL) {
        /* Store the method into object. */
        rsa->meth = meth;
        /* Copy over flags. */
        rsa->flags = meth->flags;
    }
    /* OpenSSL always assumes it will work. */
    return 1;
}

/* Get the RSA method from the RSA object.
 *
 * @param [in] rsa  RSA key.
 * @return  RSA method on success.
 * @return  NULL when RSA is NULL or no method set.
 */
const WOLFSSL_RSA_METHOD* wolfSSL_RSA_get_method(const WOLFSSL_RSA *rsa)
{
    return (rsa != NULL) ? rsa->meth : NULL;
}

/* Get the size in bytes of the RSA key.
 *
 * Return compliant with OpenSSL
 *
 * @param [in] rsa  RSA key.
 * @return  RSA modulus size in bytes.
 * @return  0 on error.
 */
int wolfSSL_RSA_size(const WOLFSSL_RSA* rsa)
{
    int ret = 0;

    WOLFSSL_ENTER("wolfSSL_RSA_size");

    if (rsa != NULL) {
        /* Make sure we have set the RSA values into wolfCrypt RSA key. */
        if (rsa->inSet || (SetRsaInternal((WOLFSSL_RSA*)rsa) == 1)) {
            /* Get key size in bytes using wolfCrypt RSA key. */
            ret = wc_RsaEncryptSize((RsaKey*)rsa->internal);
        }
    }

    return ret;
}

/* Get the size in bits of the RSA key.
 *
 * Uses external modulus field.
 *
 * @param [in] rsa  RSA key.
 * @return  RSA modulus size in bits.
 * @return  0 on error.
 */
int wolfSSL_RSA_bits(const WOLFSSL_RSA* rsa)
{
    int ret = 0;

    WOLFSSL_ENTER("wolfSSL_RSA_bits");

    if (rsa != NULL) {
        /* Get number of bits in external modulus. */
        ret = wolfSSL_BN_num_bits(rsa->n);
    }

    return ret;
}

/* Get the BN objects that are the Chinese-Remainder Theorem (CRT) parameters.
 *
 * Only for those that are not NULL parameters.
 *
 * @param [in]  rsa   RSA key.
 * @param [out] dmp1  BN that is d mod (p - 1). May be NULL.
 * @param [out] dmq1  BN that is d mod (q - 1). May be NULL.
 * @param [out] iqmp  BN that is 1/q mod p. May be NULL.
 */
void wolfSSL_RSA_get0_crt_params(const WOLFSSL_RSA *rsa,
    const WOLFSSL_BIGNUM **dmp1, const WOLFSSL_BIGNUM **dmq1,
    const WOLFSSL_BIGNUM **iqmp)
{
    WOLFSSL_ENTER("wolfSSL_RSA_get0_crt_params");

    /* For any parameters not NULL, return the BN from the key or NULL. */
    if (dmp1 != NULL) {
        *dmp1 = (rsa != NULL) ? rsa->dmp1 : NULL;
    }
    if (dmq1 != NULL) {
        *dmq1 = (rsa != NULL) ? rsa->dmq1 : NULL;
    }
    if (iqmp != NULL) {
        *iqmp = (rsa != NULL) ? rsa->iqmp : NULL;
    }
}

/* Set the BN objects that are the Chinese-Remainder Theorem (CRT) parameters
 * into RSA key.
 *
 * If CRT parameter is NULL then there must be one in the RSA key already.
 *
 * @param [in, out] rsa   RSA key.
 * @param [in]      dmp1  BN that is d mod (p - 1). May be NULL.
 * @param [in]      dmq1  BN that is d mod (q - 1). May be NULL.
 * @param [in]      iqmp  BN that is 1/q mod p. May be NULL.
 * @return  1 on success.
 * @return  0 on failure.
 */
int wolfSSL_RSA_set0_crt_params(WOLFSSL_RSA *rsa, WOLFSSL_BIGNUM *dmp1,
                                WOLFSSL_BIGNUM *dmq1, WOLFSSL_BIGNUM *iqmp)
{
    int ret = 1;

    WOLFSSL_ENTER("wolfSSL_RSA_set0_crt_params");

    /* If a param is NULL in rsa then it must be non-NULL in the
     * corresponding user input. */
    if ((rsa == NULL) || ((rsa->dmp1 == NULL) && (dmp1 == NULL)) ||
            ((rsa->dmq1 == NULL) && (dmq1 == NULL)) ||
            ((rsa->iqmp == NULL) && (iqmp == NULL))) {
        WOLFSSL_ERROR_MSG("Bad parameters");
        ret = 0;
    }
    if (ret == 1) {
        /* Replace the BNs. */
        if (dmp1 != NULL) {
            wolfSSL_BN_clear_free(rsa->dmp1);
            rsa->dmp1 = dmp1;
        }
        if (dmq1 != NULL) {
            wolfSSL_BN_clear_free(rsa->dmq1);
            rsa->dmq1 = dmq1;
        }
        if (iqmp != NULL) {
            wolfSSL_BN_clear_free(rsa->iqmp);
            rsa->iqmp = iqmp;
        }

        /* Set the values into the wolfCrypt RSA key. */
        if (SetRsaInternal(rsa) != 1) {
            if (dmp1 != NULL) {
                rsa->dmp1 = NULL;
            }
            if (dmq1 != NULL) {
                rsa->dmq1 = NULL;
            }
            if (iqmp != NULL) {
                rsa->iqmp = NULL;
            }
            ret = 0;
        }
    }

    return ret;
}

/* Get the BN objects that are the factors of the RSA key (two primes p and q).
 *
 * @param [in]  rsa  RSA key.
 * @param [out] p    BN that is first prime. May be NULL.
 * @param [out] q    BN that is second prime. May be NULL.
 */
void wolfSSL_RSA_get0_factors(const WOLFSSL_RSA *rsa, const WOLFSSL_BIGNUM **p,
                              const WOLFSSL_BIGNUM **q)
{
    WOLFSSL_ENTER("wolfSSL_RSA_get0_factors");

    /* For any primes not NULL, return the BN from the key or NULL. */
    if (p != NULL) {
        *p = (rsa != NULL) ? rsa->p : NULL;
    }
    if (q != NULL) {
        *q = (rsa != NULL) ? rsa->q : NULL;
    }
}

/* Set the BN objects that are the factors of the RSA key (two primes p and q).
 *
 * If factor parameter is NULL then there must be one in the RSA key already.
 *
 * @param [in, out] rsa  RSA key.
 * @param [in]      p    BN that is first prime. May be NULL.
 * @param [in]      q    BN that is second prime. May be NULL.
 * @return  1 on success.
 * @return  0 on failure.
 */
int wolfSSL_RSA_set0_factors(WOLFSSL_RSA *rsa, WOLFSSL_BIGNUM *p,
    WOLFSSL_BIGNUM *q)
{
    int ret = 1;

    WOLFSSL_ENTER("wolfSSL_RSA_set0_factors");

    /* If a param is null in r then it must be non-null in the
     * corresponding user input. */
    if (rsa == NULL || ((rsa->p == NULL) && (p == NULL)) ||
            ((rsa->q == NULL) && (q == NULL))) {
        WOLFSSL_ERROR_MSG("Bad parameters");
        ret = 0;
    }
    if (ret == 1) {
        /* Replace the BNs. */
        if (p != NULL) {
            wolfSSL_BN_clear_free(rsa->p);
            rsa->p = p;
        }
        if (q != NULL) {
            wolfSSL_BN_clear_free(rsa->q);
            rsa->q = q;
        }

        /* Set the values into the wolfCrypt RSA key. */
        if (SetRsaInternal(rsa) != 1) {
             if (p != NULL) {
                 rsa->p = NULL;
             }
             if (q != NULL) {
                 rsa->q = NULL;
             }
             ret = 0;
        }
    }

    return ret;
}

/* Get the BN objects for the basic key numbers of the RSA key (modulus, public
 * exponent, private exponent).
 *
 * @param [in]  rsa  RSA key.
 * @param [out] n    BN that is the modulus. May be NULL.
 * @param [out] e    BN that is the public exponent. May be NULL.
 * @param [out] d    BN that is the private exponent. May be NULL.
 */
void wolfSSL_RSA_get0_key(const WOLFSSL_RSA *rsa, const WOLFSSL_BIGNUM **n,
    const WOLFSSL_BIGNUM **e, const WOLFSSL_BIGNUM **d)
{
    WOLFSSL_ENTER("wolfSSL_RSA_get0_key");

    /* For any parameters not NULL, return the BN from the key or NULL. */
    if (n != NULL) {
        *n = (rsa != NULL) ? rsa->n : NULL;
    }
    if (e != NULL) {
        *e = (rsa != NULL) ? rsa->e : NULL;
    }
    if (d != NULL) {
        *d = (rsa != NULL) ? rsa->d : NULL;
    }
}

/* Set the BN objects for the basic key numbers into the RSA key (modulus,
 * public exponent, private exponent).
 *
 * If BN parameter is NULL then there must be one in the RSA key already.
 *
 * @param [in,out]  rsa  RSA key.
 * @param [in]      n    BN that is the modulus. May be NULL.
 * @param [in]      e    BN that is the public exponent. May be NULL.
 * @param [in]      d    BN that is the private exponent. May be NULL.
 * @return  1 on success.
 * @return  0 on failure.
 */
int wolfSSL_RSA_set0_key(WOLFSSL_RSA *rsa, WOLFSSL_BIGNUM *n, WOLFSSL_BIGNUM *e,
     WOLFSSL_BIGNUM *d)
{
    int ret = 1;

    /* If the fields n and e in r are NULL, the corresponding input
     * parameters MUST be non-NULL for n and e.  d may be
     * left NULL (in case only the public key is used).
     */
    if ((rsa == NULL) || ((rsa->n == NULL) && (n == NULL)) ||
            ((rsa->e == NULL) && (e == NULL))) {
        ret = 0;
    }
    if (ret == 1) {
        /* Replace the BNs. */
        if (n != NULL) {
            wolfSSL_BN_free(rsa->n);
            rsa->n = n;
        }
        if (e != NULL) {
            wolfSSL_BN_free(rsa->e);
            rsa->e = e;
        }
        if (d != NULL) {
            /* Private key is sensitive data. */
            wolfSSL_BN_clear_free(rsa->d);
            rsa->d = d;
        }

        /* Set the values into the wolfCrypt RSA key. */
        if (SetRsaInternal(rsa) != 1) {
            if (n != NULL) {
                rsa->n = NULL;
            }
            if (e != NULL) {
                rsa->e = NULL;
            }
            if (d != NULL) {
                rsa->d = NULL;
            }
            ret = 0;
        }
    }

    return ret;
}

/* Get the flags of the RSA key.
 *
 * @param [in] rsa  RSA key.
 * @return  Flags set in RSA key on success.
 * @return  0 when RSA key is NULL.
 */
int wolfSSL_RSA_flags(const WOLFSSL_RSA *rsa)
{
    int ret = 0;

    /* Get flags from the RSA key if available. */
    if (rsa != NULL) {
        ret = rsa->flags;
    }

    return ret;
}

/* Set the flags into the RSA key.
 *
 * @param [in, out] rsa    RSA key.
 * @param [in]      flags  Flags to set.
 */
void wolfSSL_RSA_set_flags(WOLFSSL_RSA *rsa, int flags)
{
    /* Add the flags into RSA key if available. */
    if (rsa != NULL) {
        rsa->flags |= flags;
    }
}

/* Clear the flags in the RSA key.
 *
 * @param [in, out] rsa    RSA key.
 * @param [in]      flags  Flags to clear.
 */
void wolfSSL_RSA_clear_flags(WOLFSSL_RSA *rsa, int flags)
{
    /* Clear the flags passed in that are on the RSA key if available. */
    if (rsa != NULL) {
        rsa->flags &= ~flags;
    }
}

/* Test the flags in the RSA key.
 *
 * @param [in] rsa  RSA key.
 * @return  Matching flags of RSA key on success.
 * @return  0 when RSA key is NULL.
 */
int wolfSSL_RSA_test_flags(const WOLFSSL_RSA *rsa, int flags)
{
    /* Return the flags passed in that are set on the RSA key if available. */
    return (rsa != NULL) ?  (rsa->flags & flags) : 0;
}

/* Get the extra data, by index, associated with the RSA key.
 *
 * @param [in] rsa  RSA key.
 * @param [in] idx  Index of extra data.
 * @return  Extra data (anonymous type) on success.
 * @return  NULL on failure.
 */
void* wolfSSL_RSA_get_ex_data(const WOLFSSL_RSA *rsa, int idx)
{
    WOLFSSL_ENTER("wolfSSL_RSA_get_ex_data");

#ifdef HAVE_EX_DATA
    return (rsa == NULL) ? NULL :
        wolfSSL_CRYPTO_get_ex_data(&rsa->ex_data, idx);
#else
    (void)rsa;
    (void)idx;

    return NULL;
#endif
}

/* Set extra data against the RSA key at an index.
 *
 * @param [in, out] rsa   RSA key.
 * @param [in]      idx   Index set set extra data at.
 * @param [in]      data  Extra data of anonymous type.
 * @return 1 on success.
 * @return 0 on failure.
 */
int wolfSSL_RSA_set_ex_data(WOLFSSL_RSA *rsa, int idx, void *data)
{
    WOLFSSL_ENTER("wolfSSL_RSA_set_ex_data");

#ifdef HAVE_EX_DATA
    return (rsa == NULL) ? 0 :
        wolfSSL_CRYPTO_set_ex_data(&rsa->ex_data, idx, data);
#else
    (void)rsa;
    (void)idx;
    (void)data;

    return 0;
#endif
}

#ifdef HAVE_EX_DATA_CLEANUP_HOOKS
/* Set the extra data and cleanup callback against the RSA key at an index.
 *
 * Not OpenSSL API.
 *
 * @param [in, out] rsa     RSA key.
 * @param [in]      idx     Index set set extra data at.
 * @param [in]      data    Extra data of anonymous type.
 * @param [in]      freeCb  Callback function to free extra data.
 * @return 1 on success.
 * @return 0 on failure.
 */
int wolfSSL_RSA_set_ex_data_with_cleanup(WOLFSSL_RSA *rsa, int idx, void *data,
    wolfSSL_ex_data_cleanup_routine_t freeCb)
{
    WOLFSSL_ENTER("wolfSSL_RSA_set_ex_data_with_cleanup");

    return (rsa == NULL) ? 0 :
        wolfSSL_CRYPTO_set_ex_data_with_cleanup(&rsa->ex_data, idx, data,
            freeCb);
}
#endif /* HAVE_EX_DATA_CLEANUP_HOOKS */

/*
 * RSA check key APIs
 */

#ifdef WOLFSSL_RSA_KEY_CHECK
/* Check that the RSA key is valid using wolfCrypt.
 *
 * @param [in] rsa  RSA key.
 * @return  1 on success.
 * @return  0 on failure.
 */
int wolfSSL_RSA_check_key(const WOLFSSL_RSA* rsa)
{
    int ret = 1;

    WOLFSSL_ENTER("wolfSSL_RSA_check_key");

    /* Validate parameters. */
    if ((rsa == NULL) || (rsa->internal == NULL)) {
        ret = 0;
    }

    /* Constant RSA - assume internal data has been set. */

    /* Check wolfCrypt RSA key. */
    if ((ret == 1) && (wc_CheckRsaKey((RsaKey*)rsa->internal) != 0)) {
        ret = 0;
    }

    WOLFSSL_LEAVE("wolfSSL_RSA_check_key", ret);

    return ret;
}
#endif /* WOLFSSL_RSA_KEY_CHECK */

/*
 * RSA generate APIs
 */

/* Get a random number generator associated with the RSA key.
 *
 * If not able, then get the global if possible.
 * *tmpRng must not be an initialized RNG.
 * *tmpRng is allocated when WOLFSSL_SMALL_STACK is defined and an RNG isn't
 * associated with the wolfCrypt RSA key.
 *
 * @param [in]  rsa         RSA key.
 * @param [out] tmpRng      Temporary random number generator.
 * @param [out] initTmpRng  Temporary random number generator was initialized.
 *
 * @return  A wolfCrypt RNG to use on success.
 * @return  NULL on error.
 */
WC_RNG* WOLFSSL_RSA_GetRNG(WOLFSSL_RSA* rsa, WC_RNG** tmpRng, int* initTmpRng)
{
    WC_RNG* rng = NULL;
    int err = 0;

    /* Check validity of parameters. */
    if ((rsa == NULL) || (initTmpRng == NULL)) {
        err = 1;
    }
    if (!err) {
        /* Haven't initialized any RNG passed through tmpRng. */
        *initTmpRng = 0;

    #if !defined(HAVE_FIPS) && defined(WC_RSA_BLINDING)
        /* Use wolfCrypt RSA key's RNG if available/set. */
        rng = ((RsaKey*)rsa->internal)->rng;
    #endif
    }
    if ((!err) && (rng == NULL) && (tmpRng != NULL)) {
        /* Make an RNG with tmpRng or get global. */
        rng = wolfssl_make_rng(*tmpRng, initTmpRng);
        if ((rng != NULL) && *initTmpRng) {
            *tmpRng = rng;
        }
    }

    return rng;
}

/* Use the wolfCrypt RSA APIs to generate a new RSA key.
 *
 * @param [in, out] rsa   RSA key.
 * @param [in]      bits  Number of bits that the modulus must have.
 * @param [in]      e     A BN object holding the public exponent to use.
 * @param [in]      cb    Status callback. Unused.
 * @return 0 on success.
 * @return wolfSSL native error code on error.
 */
static int wolfssl_rsa_generate_key_native(WOLFSSL_RSA* rsa, int bits,
    WOLFSSL_BIGNUM* e, void* cb)
{
#ifdef WOLFSSL_KEY_GEN
    int ret = 0;
#ifdef WOLFSSL_SMALL_STACK
    WC_RNG* tmpRng = NULL;
#else
    WC_RNG  _tmpRng[1];
    WC_RNG* tmpRng = _tmpRng;
#endif
    int initTmpRng = 0;
    WC_RNG* rng = NULL;
    long en = 0;
#endif

    (void)cb;

    WOLFSSL_ENTER("wolfssl_rsa_generate_key_native");

#ifdef WOLFSSL_KEY_GEN
    /* Get RNG in wolfCrypt RSA key or initialize a new one (or global). */
    rng = WOLFSSL_RSA_GetRNG(rsa, (WC_RNG**)&tmpRng, &initTmpRng);
    if (rng == NULL) {
        /* Something went wrong so return memory error. */
        ret = MEMORY_E;
    }
    if ((ret == 0) && ((en = (long)wolfSSL_BN_get_word(e)) <= 0)) {
        ret = BAD_FUNC_ARG;
    }
    if (ret == 0) {
        /* Generate an RSA key. */
        ret = wc_MakeRsaKey((RsaKey*)rsa->internal, bits, en, rng);
        if (ret != MP_OKAY) {
            WOLFSSL_ERROR_MSG("wc_MakeRsaKey failed");
        }
    }
    if (ret == 0) {
        /* Get the values from wolfCrypt RSA key into external RSA key. */
        ret = SetRsaExternal(rsa);
        if (ret == 1) {
            /* Internal matches external. */
            rsa->inSet = 1;
            /* Return success. */
            ret = 0;
        }
        else {
            /* Something went wrong so return memory error. */
            ret = MEMORY_E;
        }
    }

    /* Finalize RNG if initialized in WOLFSSL_RSA_GetRNG(). */
    if (initTmpRng) {
        wc_FreeRng(tmpRng);
    }
    WC_FREE_VAR_EX(tmpRng, NULL, DYNAMIC_TYPE_RNG);

    return ret;
#else
    WOLFSSL_ERROR_MSG("No Key Gen built in");

    (void)rsa;
    (void)e;
    (void)bits;

    return NOT_COMPILED_IN;
#endif
}

/* Generate an RSA key that has the specified modulus size and public exponent.
 *
 * Note: Because of wc_MakeRsaKey an RSA key size generated can be rounded
 *       down to nearest multiple of 8. For example generating a key of size
 *       2999 bits will make a key of size 374 bytes instead of 375 bytes.
 *
 * @param [in]      bits  Number of bits that the modulus must have i.e. 2048.
 * @param [in]      e     Public exponent to use i.e. 65537.
 * @param [in]      cb    Status callback. Unused.
 * @param [in]      data  Data to pass to status callback. Unused.
 * @return  A new RSA key on success.
 * @return  NULL on failure.
 */
WOLFSSL_RSA* wolfSSL_RSA_generate_key(int bits, unsigned long e,
    void(*cb)(int, int, void*), void* data)
{
    WOLFSSL_RSA*    rsa = NULL;
    WOLFSSL_BIGNUM* bn  = NULL;
    int             err = 0;

    WOLFSSL_ENTER("wolfSSL_RSA_generate_key");

    (void)cb;
    (void)data;

    /* Validate bits. */
    if (bits < 0) {
        WOLFSSL_ERROR_MSG("Bad argument: bits was less than 0");
        err = 1;
    }
    /* Create a new BN to hold public exponent - for when wolfCrypt supports
     * longer values. */
    if ((!err) && ((bn = wolfSSL_BN_new()) == NULL)) {
        WOLFSSL_ERROR_MSG("Error creating big number");
        err = 1;
    }
    /* Set public exponent. */
    if ((!err) && (wolfSSL_BN_set_word(bn, e) != 1)) {
        WOLFSSL_ERROR_MSG("Error using e value");
        err = 1;
    }

    /* Create an RSA key object to hold generated key. */
    if ((!err) && ((rsa = wolfSSL_RSA_new()) == NULL)) {
        WOLFSSL_ERROR_MSG("memory error");
        err = 1;
    }
    while (!err) {
        int ret;

        /* Use wolfCrypt to generate RSA key. */
        ret = wolfssl_rsa_generate_key_native(rsa, bits, bn, NULL);
    #ifdef HAVE_FIPS
        /* Keep trying if failed to find a prime. */
        if (ret == WC_NO_ERR_TRACE(PRIME_GEN_E)) {
            continue;
        }
    #endif
        if (ret != WOLFSSL_ERROR_NONE) {
            /* Unrecoverable error in generation. */
            err = 1;
        }
        /* Done generating - unrecoverable error or success. */
        break;
    }
    if (err) {
        /* Dispose of RSA key object if generation didn't work. */
        wolfSSL_RSA_free(rsa);
        /* Returning NULL on error. */
        rsa = NULL;
    }
    /* Dispose of the temporary BN used for the public exponent. */
    wolfSSL_BN_free(bn);

    return rsa;
}

/* Generate an RSA key that has the specified modulus size and public exponent.
 *
 * Note: Because of wc_MakeRsaKey an RSA key size generated can be rounded
 *       down to nearest multiple of 8. For example generating a key of size
 *       2999 bits will make a key of size 374 bytes instead of 375 bytes.
 *
 * @param [in]      bits  Number of bits that the modulus must have i.e. 2048.
 * @param [in]      e     Public exponent to use, i.e. 65537, as a BN.
 * @param [in]      cb    Status callback. Unused.
 * @return 1 on success.
 * @return 0 on failure.
 */
int wolfSSL_RSA_generate_key_ex(WOLFSSL_RSA* rsa, int bits, WOLFSSL_BIGNUM* e,
    void* cb)
{
    int ret = 1;

    /* Validate parameters. */
    if ((rsa == NULL) || (rsa->internal == NULL)) {
        WOLFSSL_ERROR_MSG("bad arguments");
        ret = 0;
    }
    else {
        for (;;) {
            /* Use wolfCrypt to generate RSA key. */
            int gen_ret = wolfssl_rsa_generate_key_native(rsa, bits, e, cb);
        #ifdef HAVE_FIPS
            /* Keep trying again if public key value didn't work. */
            if (gen_ret == WC_NO_ERR_TRACE(PRIME_GEN_E)) {
                continue;
            }
        #endif
            if (gen_ret != WOLFSSL_ERROR_NONE) {
                /* Unrecoverable error in generation. */
                ret = 0;
            }
            /* Done generating - unrecoverable error or success. */
            break;
        }
    }

    return ret;
}

#endif /* OPENSSL_EXTRA */

/*
 * RSA padding APIs
 */

#ifdef WC_RSA_PSS

#if defined(OPENSSL_EXTRA) && !defined(HAVE_SELFTEST) && \
    (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0))
static int rsa_pss_calc_salt(int saltLen, int hashLen, int emLen)
{
    /* Calculate the salt length to use for special cases. */
    switch (saltLen) {
        /* Negative saltLen values are treated differently. */
        case WC_RSA_PSS_SALTLEN_DIGEST:
            saltLen = hashLen;
            break;
        case WC_RSA_PSS_SALTLEN_MAX_SIGN:
        case WC_RSA_PSS_SALTLEN_MAX:
        #ifdef WOLFSSL_PSS_LONG_SALT
            saltLen = emLen - hashLen - 2;
        #else
            saltLen = hashLen;
            (void)emLen;
        #endif
            break;
        default:
            break;
    }
    if (saltLen < 0) {
        /* log invalid salt, let wolfCrypt handle error */
        WOLFSSL_ERROR_MSG("invalid saltLen");
        saltLen = -3; /* for wolfCrypt to produce error must be < -2 */
    }
    return saltLen;
}
#endif /* OPENSSL_EXTRA && !HAVE_SELFTEST */

#if (defined(OPENSSL_ALL) || defined(WOLFSSL_ASIO) || \
     defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_NGINX)) && \
    (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0))

/* Add PKCS#1 PSS padding to hash.
 *
 *
 *                                +-----------+
 *                                |     M     |
 *                                +-----------+
 *                                      |
 *                                      V
 *                                    Hash
 *                                      |
 *                                      V
 *                        +--------+----------+----------+
 *                   M' = |Padding1|  mHash   |   salt   |
 *                        +--------+----------+----------+
 *                                       |
 *             +--------+----------+     V
 *       DB =  |Padding2|maskedseed|   Hash
 *             +--------+----------+     |
 *                       |               |
 *                       V               |    +--+
 *                      xor <--- MGF <---|    |bc|
 *                       |               |    +--+
 *                       |               |      |
 *                       V               V      V
 *             +-------------------+----------+--+
 *       EM =  |    maskedDB       |maskedseed|bc|
 *             +-------------------+----------+--+
 * Diagram taken from https://tools.ietf.org/html/rfc3447#section-9.1
 *
 * @param [in]  rsa      RSA key.
 * @param [out] em       Encoded message.
 * @param [in[  mHash    Message hash.
 * @param [in]  hashAlg  Hash algorithm.
 * @param [in]  mgf1Hash MGF algorithm.
 * @param [in]  saltLen  Length of salt to generate.
 * @return  1 on success.
 * @return  0 on failure.
 */

int wolfSSL_RSA_padding_add_PKCS1_PSS_mgf1(WOLFSSL_RSA *rsa, unsigned char *em,
        const unsigned char *mHash, const WOLFSSL_EVP_MD *hashAlg,
        const WOLFSSL_EVP_MD *mgf1Hash, int saltLen)
{
    int ret = 1;
    enum wc_HashType hashType = WC_HASH_TYPE_NONE;
    int hashLen = 0;
    int emLen = 0;
    int mgf = 0;
    int initTmpRng = 0;
    WC_RNG *rng = NULL;
#ifdef WOLFSSL_SMALL_STACK
    WC_RNG* tmpRng = NULL;
#else
    WC_RNG  _tmpRng[1];
    WC_RNG* tmpRng = _tmpRng;
#endif

    WOLFSSL_ENTER("wolfSSL_RSA_padding_add_PKCS1_PSS");

    /* Validate parameters. */
    if ((rsa == NULL) || (em == NULL) || (mHash == NULL) || (hashAlg == NULL)) {
        ret = 0;
    }

    if (mgf1Hash == NULL)
        mgf1Hash = hashAlg;

    if (ret == 1) {
        /* Get/create an RNG. */
        rng = WOLFSSL_RSA_GetRNG(rsa, (WC_RNG**)&tmpRng, &initTmpRng);
        if (rng == NULL) {
            WOLFSSL_ERROR_MSG("WOLFSSL_RSA_GetRNG error");
            ret = 0;
        }
    }

    /* TODO: use wolfCrypt RSA key to get emLen and bits? */
    /* Set the external data from the wolfCrypt RSA key if not done. */
    if ((ret == 1) && (!rsa->exSet)) {
        ret = SetRsaExternal(rsa);
    }

    if (ret == 1) {
        /* Get the wolfCrypt hash algorithm type. */
        hashType = EvpMd2MacType(hashAlg);
        if (hashType > WC_HASH_TYPE_MAX) {
            WOLFSSL_ERROR_MSG("EvpMd2MacType error");
            ret = 0;
        }
    }
    if (ret == 1) {
        /* Get the wolfCrypt MGF algorithm from hash algorithm. */
        mgf = wc_hash2mgf(EvpMd2MacType(mgf1Hash));
        if (mgf == WC_MGF1NONE) {
            WOLFSSL_ERROR_MSG("wc_hash2mgf error");
            ret = 0;
        }
    }
    if (ret == 1) {
        /* Get the length of the hash output. */
        hashLen = wolfSSL_EVP_MD_size(hashAlg);
        if (hashLen < 0) {
            WOLFSSL_ERROR_MSG("wolfSSL_EVP_MD_size error");
            ret = 0;
        }
    }

    if (ret == 1) {
        /* Get length of RSA key - encrypted message length. */
        emLen = wolfSSL_RSA_size(rsa);
        if (emLen <= 0) {
            WOLFSSL_ERROR_MSG("wolfSSL_RSA_size error");
            ret = 0;
        }
    }

    if (ret == 1) {
        saltLen = rsa_pss_calc_salt(saltLen, hashLen, emLen);
    }

    if (ret == 1) {
        /* Generate RSA PKCS#1 PSS padding for hash using wolfCrypt. */
        if (wc_RsaPad_ex(mHash, (word32)hashLen, em, (word32)emLen,
                RSA_BLOCK_TYPE_1, rng, WC_RSA_PSS_PAD, hashType, mgf, NULL, 0,
                saltLen, wolfSSL_BN_num_bits(rsa->n), NULL) != MP_OKAY) {
            WOLFSSL_ERROR_MSG("wc_RsaPad_ex error");
            ret = 0;
        }
    }

    /* Finalize RNG if initialized in WOLFSSL_RSA_GetRNG(). */
    if (initTmpRng) {
        wc_FreeRng(tmpRng);
    }
    WC_FREE_VAR_EX(tmpRng, NULL, DYNAMIC_TYPE_RNG);

    return ret;
}

int wolfSSL_RSA_padding_add_PKCS1_PSS(WOLFSSL_RSA *rsa, unsigned char *em,
    const unsigned char *mHash, const WOLFSSL_EVP_MD *hashAlg, int saltLen)
{
    return wolfSSL_RSA_padding_add_PKCS1_PSS_mgf1(rsa, em, mHash, hashAlg, NULL,
            saltLen);
}

/* Checks that the hash is valid for the RSA PKCS#1 PSS encoded message.
 *
 * Refer to wolfSSL_RSA_padding_add_PKCS1_PSS for a diagram.
 *
 * @param [in]  rsa      RSA key.
 * @param [in[  mHash    Message hash.
 * @param [in]  hashAlg  Hash algorithm.
 * @param [in]  mgf1Hash MGF algorithm.
 * @param [in]  em       Encoded message.
 * @param [in]  saltLen  Length of salt to generate.
 * @return  1 on success.
 * @return  0 on failure.
 */
int wolfSSL_RSA_verify_PKCS1_PSS_mgf1(WOLFSSL_RSA *rsa,
        const unsigned char *mHash, const WOLFSSL_EVP_MD *hashAlg,
        const WOLFSSL_EVP_MD *mgf1Hash, const unsigned char *em, int saltLen)
{
    int ret = 1;
    int hashLen = 0;
    int mgf = 0;
    int emLen = 0;
    int mPrimeLen = 0;
    enum wc_HashType hashType = WC_HASH_TYPE_NONE;
    byte *mPrime = NULL;
    byte *buf = NULL;

    WOLFSSL_ENTER("wolfSSL_RSA_verify_PKCS1_PSS");

    /* Validate parameters. */
    if ((rsa == NULL) || (mHash == NULL) || (hashAlg == NULL) || (em == NULL)) {
        ret = 0;
    }

    if (mgf1Hash == NULL)
        mgf1Hash = hashAlg;

    /* TODO: use wolfCrypt RSA key to get emLen and bits? */
    /* Set the external data from the wolfCrypt RSA key if not done. */
    if ((ret == 1) && (!rsa->exSet)) {
        ret = SetRsaExternal(rsa);
    }

    if (ret == 1) {
        /* Get hash length for hash algorithm. */
        hashLen = wolfSSL_EVP_MD_size(hashAlg);
        if (hashLen < 0) {
            ret = 0;
        }
    }

    if (ret == 1) {
        /* Get length of RSA key - encrypted message length. */
        emLen = wolfSSL_RSA_size(rsa);
        if (emLen <= 0) {
            WOLFSSL_ERROR_MSG("wolfSSL_RSA_size error");
            ret = 0;
        }
    }

    if (ret == 1) {
        saltLen = rsa_pss_calc_salt(saltLen, hashLen, emLen);
    }

    if (ret == 1) {
        /* Get the wolfCrypt hash algorithm type. */
        hashType = EvpMd2MacType(hashAlg);
        if (hashType > WC_HASH_TYPE_MAX) {
            WOLFSSL_ERROR_MSG("EvpMd2MacType error");
            ret = 0;
        }
    }

    if (ret == 1) {
        /* Get the wolfCrypt MGF algorithm from hash algorithm. */
        if ((mgf = wc_hash2mgf(EvpMd2MacType(mgf1Hash))) == WC_MGF1NONE) {
            WOLFSSL_ERROR_MSG("wc_hash2mgf error");
            ret = 0;
        }
    }

    if (ret == 1) {
        /* Allocate buffer to unpad inline with. */
        buf = (byte*)XMALLOC((size_t)emLen, NULL, DYNAMIC_TYPE_TMP_BUFFER);
        if (buf == NULL) {
            WOLFSSL_ERROR_MSG("malloc error");
            ret = 0;
        }
    }

    if (ret == 1) {
        /* Copy encrypted message to temp for inline unpadding. */
        XMEMCPY(buf, em, (size_t)emLen);

        /* Remove and verify the PSS padding. */
        mPrimeLen = wc_RsaUnPad_ex(buf, (word32)emLen, &mPrime,
            RSA_BLOCK_TYPE_1, WC_RSA_PSS_PAD, hashType, mgf, NULL, 0, saltLen,
            wolfSSL_BN_num_bits(rsa->n), NULL);
        if (mPrimeLen < 0) {
            WOLFSSL_ERROR_MSG("wc_RsaPad_ex error");
            ret = 0;
        }
    }

    if (ret == 1) {
        /* Verify the hash is correct. */
        if (wc_RsaPSS_CheckPadding_ex(mHash, (word32)hashLen, mPrime,
                (word32)mPrimeLen, hashType, saltLen,
                wolfSSL_BN_num_bits(rsa->n)) != MP_OKAY) {
            WOLFSSL_ERROR_MSG("wc_RsaPSS_CheckPadding_ex error");
            ret = 0;
        }
    }

    /* Dispose of any allocated buffer. */
    XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    return ret;
}

int wolfSSL_RSA_verify_PKCS1_PSS(WOLFSSL_RSA *rsa, const unsigned char *mHash,
                                 const WOLFSSL_EVP_MD *hashAlg,
                                 const unsigned char *em, int saltLen)
{
    return wolfSSL_RSA_verify_PKCS1_PSS_mgf1(rsa, mHash, hashAlg, NULL, em,
            saltLen);
}
#endif /* (!HAVE_FIPS || FIPS_VERSION_GT(2,0)) && \
          (OPENSSL_ALL || WOLFSSL_ASIO || WOLFSSL_HAPROXY || WOLFSSL_NGINX) */
#endif /* WC_RSA_PSS */

/*
 * RSA sign/verify APIs
 */

#if defined(WC_RSA_PSS) && !defined(HAVE_SELFTEST) && \
    (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5,1))
    #ifndef WOLFSSL_PSS_SALT_LEN_DISCOVER
        #define DEF_PSS_SALT_LEN    RSA_PSS_SALT_LEN_DEFAULT
    #else
        #define DEF_PSS_SALT_LEN    RSA_PSS_SALT_LEN_DISCOVER
    #endif
#else
    #define DEF_PSS_SALT_LEN 0 /* not used */
#endif

#if defined(OPENSSL_EXTRA)

/* Encode the message hash.
 *
 * Used by signing and verification.
 *
 * @param [in]  hashAlg   Hash algorithm OID.
 * @param [in]  hash      Hash of message to encode for signing.
 * @param [in]  hLen      Length of hash of message.
 * @param [out] enc       Encoded message hash.
 * @param [out] encLen    Length of encoded message hash.
 * @param [in]  padding   Which padding scheme is being used.
 * @return  1 on success.
 * @return  0 on failure.
 */
static int wolfssl_rsa_sig_encode(int hashAlg, const unsigned char* hash,
    unsigned int hLen, unsigned char* enc, unsigned int* encLen, int padding)
{
    int ret = 1;
    int hType = WC_HASH_TYPE_NONE;

    /* Validate parameters. */
    if ((hash == NULL) || (enc == NULL) || (encLen == NULL)) {
        ret = 0;
    }

    if ((ret == 1) && (hashAlg != WC_NID_undef) &&
            (padding == WC_RSA_PKCS1_PADDING)) {
        /* Convert hash algorithm to hash type for PKCS#1.5 padding. */
        hType = (int)nid2oid(hashAlg, oidHashType);
        if (hType == -1) {
            ret = 0;
        }
    }
    if ((ret == 1) && (padding == WC_RSA_PKCS1_PADDING)) {
        /* PKCS#1.5 encoding. */
        word32 encSz = wc_EncodeSignature(enc, hash, hLen, hType);
        if (encSz == 0) {
            WOLFSSL_ERROR_MSG("Bad Encode Signature");
            ret = 0;
        }
        else  {
            *encLen = (unsigned int)encSz;
        }
    }
    /* Other padding schemes require the hash as is. */
    if ((ret == 1) && (padding != WC_RSA_PKCS1_PADDING)) {
        XMEMCPY(enc, hash, hLen);
        *encLen = hLen;
    }

    return ret;
}

/* Sign the message hash using hash algorithm and RSA key.
 *
 * @param [in]  hashAlg   Hash algorithm OID.
 * @param [in]  hash      Hash of message to encode for signing.
 * @param [in]  hLen      Length of hash of message.
 * @param [out] enc       Encoded message hash.
 * @param [out] encLen    Length of encoded message hash.
 * @param [in]  rsa       RSA key.
 * @return  1 on success.
 * @return  0 on failure.
 */
int wolfSSL_RSA_sign(int hashAlg, const unsigned char* hash, unsigned int hLen,
    unsigned char* sigRet, unsigned int* sigLen, WOLFSSL_RSA* rsa)
{
    if (sigLen != NULL) {
        /* No size checking in this API */
        *sigLen = RSA_MAX_SIZE / CHAR_BIT;
    }
    /* flag is 1: output complete signature. */
    return wolfSSL_RSA_sign_generic_padding(hashAlg, hash, hLen, sigRet,
        sigLen, rsa, 1, WC_RSA_PKCS1_PADDING);
}

/* Sign the message hash using hash algorithm and RSA key.
 *
 * Not OpenSSL API.
 *
 * @param [in]  hashAlg   Hash algorithm NID.
 * @param [in]  hash      Hash of message to encode for signing.
 * @param [in]  hLen      Length of hash of message.
 * @param [out] enc       Encoded message hash.
 * @param [out] encLen    Length of encoded message hash.
 * @param [in]  rsa       RSA key.
 * @param [in]  flag      When 1: Output encrypted signature.
 *                        When 0: Output encoded hash.
 * @return  1 on success.
 * @return  0 on failure.
 */
int wolfSSL_RSA_sign_ex(int hashAlg, const unsigned char* hash,
    unsigned int hLen, unsigned char* sigRet, unsigned int* sigLen,
    WOLFSSL_RSA* rsa, int flag)
{
    int ret = 0;

    if ((flag == 0) || (flag == 1)) {
        if (sigLen != NULL) {
            /* No size checking in this API */
            *sigLen = RSA_MAX_SIZE / CHAR_BIT;
        }
        ret = wolfSSL_RSA_sign_generic_padding(hashAlg, hash, hLen, sigRet,
            sigLen, rsa, flag, WC_RSA_PKCS1_PADDING);
    }

    return ret;
}

int wolfSSL_RSA_sign_generic_padding(int hashAlg, const unsigned char* hash,
    unsigned int hLen, unsigned char* sigRet, unsigned int* sigLen,
    WOLFSSL_RSA* rsa, int flag, int padding)
{
    return wolfSSL_RSA_sign_mgf(hashAlg, hash, hLen, sigRet, sigLen, rsa, flag,
        padding, hashAlg, DEF_PSS_SALT_LEN);
}

/**
 * Sign a message hash with the chosen message digest, padding, and RSA key.
 *
 * Not OpenSSL API.
 *
 * @param [in]      hashAlg  Hash NID
 * @param [in]      hash     Message hash to sign.
 * @param [in]      mLen     Length of message hash to sign.
 * @param [out]     sigRet   Output buffer.
 * @param [in, out] sigLen   On Input: length of sigRet buffer.
 *                           On Output: length of data written to sigRet.
 * @param [in]      rsa      RSA key used to sign the input.
 * @param [in]      flag     1: Output the signature.
 *                           0: Output the value that the unpadded signature
 *                              should be compared to.
 * @param [in]      padding  Padding to use. Only RSA_PKCS1_PSS_PADDING and
 *                           WC_RSA_PKCS1_PADDING are currently supported for
 *                           signing.
 * @param [in]      mgf1Hash MGF1 Hash NID
 * @param [in]      saltLen  Length of RSA PSS salt
 * @return  1 on success.
 * @return  0 on failure.
 */
int wolfSSL_RSA_sign_mgf(int hashAlg, const unsigned char* hash,
    unsigned int hLen, unsigned char* sigRet, unsigned int* sigLen,
    WOLFSSL_RSA* rsa, int flag, int padding, int mgf1Hash, int saltLen)
{
    int     ret        = 1;
    word32  outLen     = 0;
    int     signSz     = 0;
    WC_RNG* rng        = NULL;
    int     initTmpRng = 0;
#ifdef WOLFSSL_SMALL_STACK
    WC_RNG* tmpRng     = NULL;
    byte*   encodedSig = NULL;
#else
    WC_RNG  _tmpRng[1];
    WC_RNG* tmpRng = _tmpRng;
    byte    encodedSig[MAX_ENCODED_SIG_SZ];
#endif
    unsigned int encSz = 0;

    WOLFSSL_ENTER("wolfSSL_RSA_sign_mgf");

    if (flag == 0) {
        /* Only encode message. */
        return wolfssl_rsa_sig_encode(hashAlg, hash, hLen, sigRet, sigLen,
            padding);
    }

    /* Validate parameters. */
    if ((hash == NULL) || (sigRet == NULL) || sigLen == NULL || rsa == NULL) {
        WOLFSSL_ERROR_MSG("Bad function arguments");
        ret = 0;
    }

    /* Set wolfCrypt RSA key data from external if not already done. */
    if ((ret == 1) && (!rsa->inSet) && (SetRsaInternal(rsa) != 1)) {
        ret = 0;
    }

    if (ret == 1) {
        /* Get the maximum signature length. */
        outLen = (word32)wolfSSL_BN_num_bytes(rsa->n);
        /* Check not an error return. */
        if (outLen == 0) {
            WOLFSSL_ERROR_MSG("Bad RSA size");
            ret = 0;
        }
        /* Check signature buffer is big enough. */
        else if (outLen > *sigLen) {
            WOLFSSL_ERROR_MSG("Output buffer too small");
            ret = 0;
        }
    }

#ifdef WOLFSSL_SMALL_STACK
    if (ret == 1) {
        /* Allocate encoded signature buffer if doing PKCS#1 padding. */
        encodedSig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, NULL,
            DYNAMIC_TYPE_SIGNATURE);
        if (encodedSig == NULL) {
            ret = 0;
        }
    }
#endif

    if (ret == 1) {
        /* Get/create an RNG. */
        rng = WOLFSSL_RSA_GetRNG(rsa, (WC_RNG**)&tmpRng, &initTmpRng);
        if (rng == NULL) {
            WOLFSSL_ERROR_MSG("WOLFSSL_RSA_GetRNG error");
            ret = 0;
        }
    }

    /* Either encodes with PKCS#1.5 or copies hash into encodedSig. */
    if ((ret == 1) && (wolfssl_rsa_sig_encode(hashAlg, hash, hLen, encodedSig,
            &encSz, padding) == 0)) {
        WOLFSSL_ERROR_MSG("Bad Encode Signature");
        ret = 0;
    }

    if (ret == 1) {
        switch (padding) {
    #if defined(WC_RSA_NO_PADDING) || defined(WC_RSA_DIRECT)
        case WC_RSA_NO_PAD:
            if ((signSz = wc_RsaDirect(encodedSig, encSz, sigRet, &outLen,
                (RsaKey*)rsa->internal, RSA_PRIVATE_ENCRYPT, rng)) <= 0) {
                WOLFSSL_ERROR_MSG("Bad RSA Sign no pad");
                ret = 0;
            }
            break;
    #endif
    #if defined(WC_RSA_PSS) && !defined(HAVE_SELFTEST) && \
        (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5,1))
        case WC_RSA_PKCS1_PSS_PADDING:
        {
            RsaKey* key = (RsaKey*)rsa->internal;
            enum wc_HashType mgf1, hType;
            hType = wc_OidGetHash((int)nid2oid(hashAlg, oidHashType));
            if (mgf1Hash == WC_NID_undef)
                mgf1Hash = hashAlg;
            mgf1 = wc_OidGetHash((int)nid2oid(mgf1Hash, oidHashType));
            /* handle compat layer salt special cases */
            saltLen = rsa_pss_calc_salt(saltLen, wc_HashGetDigestSize(hType),
                wolfSSL_RSA_size(rsa));

            /* Create RSA PSS signature. */
            if ((signSz = wc_RsaPSS_Sign_ex(encodedSig, encSz, sigRet, outLen,
                hType, wc_hash2mgf(mgf1), saltLen, key, rng)) <= 0) {
                WOLFSSL_ERROR_MSG("Bad RSA PSS Sign");
                ret = 0;
            }
            break;
        }
    #endif
    #ifndef WC_NO_RSA_OAEP
        case WC_RSA_PKCS1_OAEP_PADDING:
            /* Not a signature padding scheme. */
            WOLFSSL_ERROR_MSG("RSA_PKCS1_OAEP_PADDING not supported for "
                              "signing");
            ret = 0;
            break;
    #endif
        case WC_RSA_PKCS1_PADDING:
        {
            /* Sign (private encrypt) PKCS#1 encoded signature. */
            if ((signSz = wc_RsaSSL_Sign(encodedSig, encSz, sigRet, outLen,
                    (RsaKey*)rsa->internal, rng)) <= 0) {
                WOLFSSL_ERROR_MSG("Bad PKCS1 RSA Sign");
                ret = 0;
            }
            break;
        }
        default:
            WOLFSSL_ERROR_MSG("Unsupported padding");
            (void)mgf1Hash;
            (void)saltLen;
            ret = 0;
            break;
        }
    }

    if (ret == 1) {
        /* Return the size of signature generated. */
        *sigLen = (unsigned int)signSz;
    }

    /* Finalize RNG if initialized in WOLFSSL_RSA_GetRNG(). */
    if (initTmpRng) {
        wc_FreeRng(tmpRng);
    }
    WC_FREE_VAR_EX(tmpRng, NULL, DYNAMIC_TYPE_RNG);
    WC_FREE_VAR_EX(encodedSig, NULL, DYNAMIC_TYPE_SIGNATURE);

    WOLFSSL_LEAVE("wolfSSL_RSA_sign_mgf", ret);
    return ret;
}

/**
 * Verify a message hash with the chosen message digest, padding, and RSA key.
 *
 * @param [in]  hashAlg  Hash NID
 * @param [in]  hash     Message hash.
 * @param [in]  mLen     Length of message hash.
 * @param [in]  sigRet   Signature data.
 * @param [in]  sigLen   Length of signature data.
 * @param [in]  rsa      RSA key used to sign the input
 * @return  1 on success.
 * @return  0 on failure.
 */
int wolfSSL_RSA_verify(int hashAlg, const unsigned char* hash,
    unsigned int hLen, const unsigned char* sig, unsigned int sigLen,
    WOLFSSL_RSA* rsa)
{
    return wolfSSL_RSA_verify_ex(hashAlg, hash, hLen, sig, sigLen, rsa,
        WC_RSA_PKCS1_PADDING);
}

int wolfSSL_RSA_verify_ex(int hashAlg, const unsigned char* hash,
    unsigned int hLen, const unsigned char* sig, unsigned int sigLen,
    WOLFSSL_RSA* rsa, int padding)
{
    return wolfSSL_RSA_verify_mgf(hashAlg, hash, hLen, sig, sigLen, rsa,
        padding, hashAlg, DEF_PSS_SALT_LEN);
}

/**
 * Verify a message hash with the chosen message digest, padding, and RSA key.
 *
 * Not OpenSSL API.
 *
 * @param [in]  hashAlg  Hash NID
 * @param [in]  hash     Message hash.
 * @param [in]  mLen     Length of message hash.
 * @param [in]  sigRet   Signature data.
 * @param [in]  sigLen   Length of signature data.
 * @param [in]  rsa      RSA key used to sign the input
 * @param [in]  padding  Padding to use. Only RSA_PKCS1_PSS_PADDING and
 *                       WC_RSA_PKCS1_PADDING are currently supported for
 *                       signing.
 * @param [in]  mgf1Hash MGF1 Hash NID
 * @param [in]  saltLen  Length of RSA PSS salt
 * @return  1 on success.
 * @return  0 on failure.
 */
int wolfSSL_RSA_verify_mgf(int hashAlg, const unsigned char* hash,
    unsigned int hLen, const unsigned char* sig, unsigned int sigLen,
    WOLFSSL_RSA* rsa, int padding, int mgf1Hash, int saltLen)
{
    int              ret    = 1;
#ifdef WOLFSSL_SMALL_STACK
    unsigned char*   encodedSig = NULL;
#else
    unsigned char    encodedSig[MAX_ENCODED_SIG_SZ];
#endif
    unsigned char*   sigDec = NULL;
    unsigned int     len    = MAX_ENCODED_SIG_SZ;
    int              verLen = 0;
#if (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5, 1)) && !defined(HAVE_SELFTEST)
    enum wc_HashType hType = WC_HASH_TYPE_NONE;
#endif

    WOLFSSL_ENTER("wolfSSL_RSA_verify_mgf");

    /* Validate parameters. */
    if ((hash == NULL) || (sig == NULL) || (rsa == NULL)) {
        WOLFSSL_ERROR_MSG("Bad function arguments");
        ret = 0;
    }

    if (ret == 1) {
        /* Allocate memory for decrypted signature. */
        sigDec = (unsigned char *)XMALLOC(sigLen, NULL,
            DYNAMIC_TYPE_TMP_BUFFER);
        if (sigDec == NULL) {
            WOLFSSL_ERROR_MSG("Memory allocation failure");
            ret = 0;
        }
    }
    if (ret == 1 && padding == WC_RSA_PKCS1_PSS_PADDING) {
        #if defined(WC_RSA_PSS) && !defined(HAVE_SELFTEST) && \
        (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5,1))
        RsaKey* key = (RsaKey*)rsa->internal;
        enum wc_HashType mgf1;
        hType = wc_OidGetHash((int)nid2oid(hashAlg, oidHashType));
        if (mgf1Hash == WC_NID_undef)
            mgf1Hash = hashAlg;
        mgf1 = wc_OidGetHash((int)nid2oid(mgf1Hash, oidHashType));

        /* handle compat layer salt special cases */
        saltLen = rsa_pss_calc_salt(saltLen, wc_HashGetDigestSize(hType),
            wolfSSL_RSA_size(rsa));

        verLen = wc_RsaPSS_Verify_ex((byte*)sig, sigLen, sigDec, sigLen,
            hType, wc_hash2mgf(mgf1), saltLen, key);
        if (verLen > 0) {
            /* Check PSS padding is valid. */
            if (wc_RsaPSS_CheckPadding_ex(hash, hLen, sigDec, (word32)verLen,
                hType, saltLen, mp_count_bits(&key->n)) != 0) {
                WOLFSSL_ERROR_MSG("wc_RsaPSS_CheckPadding_ex error");
                ret = WOLFSSL_FAILURE;
            }
            else {
                /* Success! Free resources and return early */
                XFREE(sigDec, NULL, DYNAMIC_TYPE_TMP_BUFFER);
                return WOLFSSL_SUCCESS;
            }
        }
        else {
            WOLFSSL_ERROR_MSG("wc_RsaPSS_Verify_ex failed!");
            ret = WOLFSSL_FAILURE;
        }
    #else
        (void)mgf1Hash;
        (void)saltLen;
        WOLFSSL_ERROR_MSG("RSA PSS not compiled in!");
        ret = WOLFSSL_FAILURE;
    #endif
    }

#ifdef WOLFSSL_SMALL_STACK
    if (ret == 1) {
        /* Allocate memory for encoded signature. */
        encodedSig = (unsigned char *)XMALLOC(len, NULL,
            DYNAMIC_TYPE_TMP_BUFFER);
        if (encodedSig == NULL) {
            WOLFSSL_ERROR_MSG("Memory allocation failure");
            ret = 0;
        }
    }
#endif
    if (ret == 1) {
        /* Make encoded signature to compare with decrypted signature. */
        if (wolfssl_rsa_sig_encode(hashAlg, hash, hLen, encodedSig, &len,
                padding) <= 0) {
            WOLFSSL_ERROR_MSG("Message Digest Error");
            ret = 0;
        }
    }
    if (ret == 1) {
        /* Decrypt signature */
    #if (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5, 1)) && \
        !defined(HAVE_SELFTEST)
        hType = wc_OidGetHash((int)nid2oid(hashAlg, oidHashType));
        if ((verLen = wc_RsaSSL_Verify_ex2(sig, sigLen, (unsigned char *)sigDec,
                sigLen, (RsaKey*)rsa->internal, padding, hType)) <= 0) {
            WOLFSSL_ERROR_MSG("RSA Decrypt error");
            ret = 0;
        }
    #else
        verLen = wc_RsaSSL_Verify(sig, sigLen, (unsigned char *)sigDec, sigLen,
            (RsaKey*)rsa->internal);
        if (verLen < 0) {
            ret = 0;
        }
    #endif
    }
    if (ret == 1) {
        /* Compare decrypted signature to encoded signature. */
        if (((int)len != verLen) ||
                (XMEMCMP(encodedSig, sigDec, (size_t)verLen) != 0)) {
            WOLFSSL_ERROR_MSG("wolfSSL_RSA_verify_ex failed");
            ret = 0;
        }
    }

    /* Dispose of any allocated data. */
    WC_FREE_VAR_EX(encodedSig, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    XFREE(sigDec, NULL, DYNAMIC_TYPE_TMP_BUFFER);

    WOLFSSL_LEAVE("wolfSSL_RSA_verify_mgf", ret);
    return ret;
}

/*
 * RSA public/private encrypt/decrypt APIs
 */

/* Encrypt with the RSA public key.
 *
 * Return compliant with OpenSSL.
 *
 * @param [in]  len      Length of data to encrypt.
 * @param [in]  from     Data to encrypt.
 * @param [out] to       Encrypted data.
 * @param [in]  rsa      RSA key.
 * @param [in]  padding  Type of padding to place around plaintext.
 * @return  Size of encrypted data on success.
 * @return  -1 on failure.
 */
int wolfSSL_RSA_public_encrypt(int len, const unsigned char* from,
    unsigned char* to, WOLFSSL_RSA* rsa, int padding)
{
    int ret = 0;
    int initTmpRng = 0;
    WC_RNG *rng = NULL;
#ifdef WOLFSSL_SMALL_STACK
    WC_RNG* tmpRng = NULL;
#else
    WC_RNG  _tmpRng[1];
    WC_RNG* tmpRng = _tmpRng;
#endif
#if !defined(HAVE_FIPS)
    int  mgf = WC_MGF1NONE;
    enum wc_HashType hash = WC_HASH_TYPE_NONE;
    int pad_type = WC_RSA_NO_PAD;
#endif
    int outLen = 0;

    WOLFSSL_ENTER("wolfSSL_RSA_public_encrypt");

    /* Validate parameters. */
    if ((len < 0) || (rsa == NULL) || (rsa->internal == NULL) ||
            (from == NULL)) {
        WOLFSSL_ERROR_MSG("Bad function arguments");
        ret = WOLFSSL_FATAL_ERROR;
    }

    if (ret == 0) {
    #if !defined(HAVE_FIPS)
        /* Convert to wolfCrypt padding, hash and MGF. */
        switch (padding) {
        case WC_RSA_PKCS1_PADDING:
            pad_type = WC_RSA_PKCSV15_PAD;
            break;
        case WC_RSA_PKCS1_OAEP_PADDING:
            pad_type = WC_RSA_OAEP_PAD;
            hash = WC_HASH_TYPE_SHA;
            mgf = WC_MGF1SHA1;
            break;
        case WC_RSA_NO_PAD:
            pad_type = WC_RSA_NO_PAD;
            break;
        default:
            WOLFSSL_ERROR_MSG("RSA_public_encrypt doesn't support padding "
                              "scheme");
            ret = WOLFSSL_FATAL_ERROR;
        }
    #else
        /* Check for supported padding schemes in FIPS. */
        /* TODO: Do we support more schemes in later versions of FIPS? */
        if (padding != WC_RSA_PKCS1_PADDING) {
            WOLFSSL_ERROR_MSG("RSA_public_encrypt pad type not supported in "
                              "FIPS");
            ret = WOLFSSL_FATAL_ERROR;
        }
    #endif
    }

    /* Set wolfCrypt RSA key data from external if not already done. */
    if ((ret == 0) && (!rsa->inSet) && (SetRsaInternal(rsa) != 1)) {
        ret = WOLFSSL_FATAL_ERROR;
    }

    if (ret == 0) {
        /* Calculate maximum length of encrypted data. */
        outLen = wolfSSL_RSA_size(rsa);
        if (outLen == 0) {
            WOLFSSL_ERROR_MSG("Bad RSA size");
            ret = WOLFSSL_FATAL_ERROR;
        }
    }

    if (ret == 0) {
        /* Get an RNG. */
        rng = WOLFSSL_RSA_GetRNG(rsa, (WC_RNG**)&tmpRng, &initTmpRng);
        if (rng == NULL) {
            ret = WOLFSSL_FATAL_ERROR;
        }
    }

    if (ret == 0) {
        /* Use wolfCrypt to public-encrypt with RSA key. */
    #if !defined(HAVE_FIPS)
        ret = wc_RsaPublicEncrypt_ex(from, (word32)len, to, (word32)outLen,
            (RsaKey*)rsa->internal, rng, pad_type, hash, mgf, NULL, 0);
    #else
        ret = wc_RsaPublicEncrypt(from, (word32)len, to, (word32)outLen,
            (RsaKey*)rsa->internal, rng);
    #endif
    }

    /* Finalize RNG if initialized in WOLFSSL_RSA_GetRNG(). */
    if (initTmpRng) {
        wc_FreeRng(tmpRng);
    }
    WC_FREE_VAR_EX(tmpRng, NULL, DYNAMIC_TYPE_RNG);

    /* wolfCrypt error means return -1. */
    if (ret <= 0) {
        ret = WOLFSSL_FATAL_ERROR;
    }
    WOLFSSL_LEAVE("wolfSSL_RSA_public_encrypt", ret);
    return ret;
}

/* Decrypt with the RSA public key.
 *
 * Return compliant with OpenSSL.
 *
 * @param [in]  len      Length of encrypted data.
 * @param [in]  from     Encrypted data.
 * @param [out] to       Decrypted data.
 * @param [in]  rsa      RSA key.
 * @param [in]  padding  Type of padding to around plaintext to remove.
 * @return  Size of decrypted data on success.
 * @return  -1 on failure.
 */
int wolfSSL_RSA_private_decrypt(int len, const unsigned char* from,
    unsigned char* to, WOLFSSL_RSA* rsa, int padding)
{
    int ret = 0;
#if !defined(HAVE_FIPS)
    int mgf = WC_MGF1NONE;
    enum wc_HashType hash = WC_HASH_TYPE_NONE;
    int pad_type = WC_RSA_NO_PAD;
#endif
    int outLen = 0;

    WOLFSSL_ENTER("wolfSSL_RSA_private_decrypt");

    /* Validate parameters. */
    if ((len < 0) || (rsa == NULL) || (rsa->internal == NULL) ||
            (from == NULL)) {
        WOLFSSL_ERROR_MSG("Bad function arguments");
        ret = WOLFSSL_FATAL_ERROR;
    }

    if (ret == 0) {
    #if !defined(HAVE_FIPS)
        switch (padding) {
        case WC_RSA_PKCS1_PADDING:
            pad_type = WC_RSA_PKCSV15_PAD;
            break;
        case WC_RSA_PKCS1_OAEP_PADDING:
            pad_type = WC_RSA_OAEP_PAD;
            hash = WC_HASH_TYPE_SHA;
            mgf = WC_MGF1SHA1;
            break;
        case WC_RSA_NO_PAD:
            pad_type = WC_RSA_NO_PAD;
            break;
        default:
            WOLFSSL_ERROR_MSG("RSA_private_decrypt unsupported padding");
            ret = WOLFSSL_FATAL_ERROR;
        }
    #else
        /* Check for supported padding schemes in FIPS. */
        /* TODO: Do we support more schemes in later versions of FIPS? */
        if (padding != WC_RSA_PKCS1_PADDING) {
            WOLFSSL_ERROR_MSG("RSA_public_encrypt pad type not supported in "
                              "FIPS");
            ret = WOLFSSL_FATAL_ERROR;
        }
    #endif
    }

    /* Set wolfCrypt RSA key data from external if not already done. */
    if ((ret == 0) && (!rsa->inSet) && (SetRsaInternal(rsa) != 1)) {
        ret = WOLFSSL_FATAL_ERROR;
    }

    if (ret == 0) {
        /* Calculate maximum length of decrypted data. */
        outLen = wolfSSL_RSA_size(rsa);
        if (outLen == 0) {
            WOLFSSL_ERROR_MSG("Bad RSA size");
            ret = WOLFSSL_FATAL_ERROR;
        }
    }

    if (ret == 0) {
        /* Use wolfCrypt to private-decrypt with RSA key.
         * Size of 'to' buffer must be size of RSA key */
    #if !defined(HAVE_FIPS)
        ret = wc_RsaPrivateDecrypt_ex(from, (word32)len, to, (word32)outLen,
            (RsaKey*)rsa->internal, pad_type, hash, mgf, NULL, 0);
    #else
        ret = wc_RsaPrivateDecrypt(from, (word32)len, to, (word32)outLen,
            (RsaKey*)rsa->internal);
    #endif
    }

    /* wolfCrypt error means return -1. */
    if (ret <= 0) {
        ret = WOLFSSL_FATAL_ERROR;
    }
    WOLFSSL_LEAVE("wolfSSL_RSA_private_decrypt", ret);
    return ret;
}

/* Decrypt with the RSA public key.
 *
 * @param [in]  len      Length of encrypted data.
 * @param [in]  from     Encrypted data.
 * @param [out] to       Decrypted data.
 * @param [in]  rsa      RSA key.
 * @param [in]  padding  Type of padding to around plaintext to remove.
 * @return  Size of decrypted data on success.
 * @return  -1 on failure.
 */
int wolfSSL_RSA_public_decrypt(int len, const unsigned char* from,
    unsigned char* to, WOLFSSL_RSA* rsa, int padding)
{
    int ret = 0;
#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0))
    int pad_type = WC_RSA_NO_PAD;
#endif
    int outLen = 0;

    WOLFSSL_ENTER("wolfSSL_RSA_public_decrypt");

    /* Validate parameters. */
    if ((len < 0) || (rsa == NULL) || (rsa->internal == NULL) ||
            (from == NULL)) {
        WOLFSSL_ERROR_MSG("Bad function arguments");
        ret = WOLFSSL_FATAL_ERROR;
    }

    if (ret == 0) {
    #if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0))
        switch (padding) {
        case WC_RSA_PKCS1_PADDING:
            pad_type = WC_RSA_PKCSV15_PAD;
            break;
        case WC_RSA_NO_PAD:
            pad_type = WC_RSA_NO_PAD;
            break;
        /* TODO: RSA_X931_PADDING not supported */
        default:
            WOLFSSL_ERROR_MSG("RSA_public_decrypt unsupported padding");
            ret = WOLFSSL_FATAL_ERROR;
        }
    #else
        if (padding != WC_RSA_PKCS1_PADDING) {
            WOLFSSL_ERROR_MSG("RSA_public_decrypt pad type not supported in "
                              "FIPS");
            ret = WOLFSSL_FATAL_ERROR;
        }
    #endif
    }

    /* Set wolfCrypt RSA key data from external if not already done. */
    if ((ret == 0) && (!rsa->inSet) && (SetRsaInternal(rsa) != 1)) {
        ret = WOLFSSL_FATAL_ERROR;
    }

    if (ret == 0) {
        /* Calculate maximum length of encrypted data. */
        outLen = wolfSSL_RSA_size(rsa);
        if (outLen == 0) {
            WOLFSSL_ERROR_MSG("Bad RSA size");
            ret = WOLFSSL_FATAL_ERROR;
        }
    }

    if (ret == 0) {
        /* Use wolfCrypt to public-decrypt with RSA key. */
    #if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0))
        /* Size of 'to' buffer must be size of RSA key. */
        ret = wc_RsaSSL_Verify_ex(from, (word32)len, to, (word32)outLen,
            (RsaKey*)rsa->internal, pad_type);
    #else
        /* For FIPS v1/v2 only PKCSV15 padding is supported */
        ret = wc_RsaSSL_Verify(from, (word32)len, to, (word32)outLen,
            (RsaKey*)rsa->internal);
    #endif
    }

    /* wolfCrypt error means return -1. */
    if (ret <= 0) {
        ret = WOLFSSL_FATAL_ERROR;
    }
    WOLFSSL_LEAVE("wolfSSL_RSA_public_decrypt", ret);
    return ret;
}

/* Encrypt with the RSA private key.
 *
 * Calls wc_RsaSSL_Sign.
 *
 * @param [in]  len      Length of data to encrypt.
 * @param [in]  from     Data to encrypt.
 * @param [out] to       Encrypted data.
 * @param [in]  rsa      RSA key.
 * @param [in]  padding  Type of padding to place around plaintext.
 * @return  Size of encrypted data on success.
 * @return  -1 on failure.
 */
int wolfSSL_RSA_private_encrypt(int len, const unsigned char* from,
    unsigned char* to, WOLFSSL_RSA* rsa, int padding)
{
    int ret = 0;
    int initTmpRng = 0;
    WC_RNG *rng = NULL;
#ifdef WOLFSSL_SMALL_STACK
    WC_RNG* tmpRng = NULL;
#else
    WC_RNG  _tmpRng[1];
    WC_RNG* tmpRng = _tmpRng;
#endif

    WOLFSSL_ENTER("wolfSSL_RSA_private_encrypt");

    /* Validate parameters. */
    if ((len < 0) || (rsa == NULL) || (rsa->internal == NULL) ||
            (from == NULL)) {
        WOLFSSL_ERROR_MSG("Bad function arguments");
        ret = WOLFSSL_FATAL_ERROR;
    }

    if (ret == 0) {
        switch (padding) {
        case WC_RSA_PKCS1_PADDING:
    #ifdef WC_RSA_NO_PADDING
        case WC_RSA_NO_PAD:
    #endif
            break;
        /* TODO: RSA_X931_PADDING not supported */
        default:
            WOLFSSL_ERROR_MSG("RSA_private_encrypt unsupported padding");
            ret = WOLFSSL_FATAL_ERROR;
        }
    }

    /* Set wolfCrypt RSA key data from external if not already done. */
    if ((ret == 0) && (!rsa->inSet) && (SetRsaInternal(rsa) != 1)) {
        ret = WOLFSSL_FATAL_ERROR;
    }

    if (ret == 0) {
        /* Get an RNG. */
        rng = WOLFSSL_RSA_GetRNG(rsa, (WC_RNG**)&tmpRng, &initTmpRng);
        if (rng == NULL) {
            ret = WOLFSSL_FATAL_ERROR;
        }
    }

    if (ret == 0) {
        /* Use wolfCrypt to private-encrypt with RSA key.
         * Size of output buffer must be size of RSA key. */
        if (padding == WC_RSA_PKCS1_PADDING) {
            ret = wc_RsaSSL_Sign(from, (word32)len, to,
                (word32)wolfSSL_RSA_size(rsa), (RsaKey*)rsa->internal, rng);
        }
    #ifdef WC_RSA_NO_PADDING
        else if (padding == WC_RSA_NO_PAD) {
            word32 outLen = (word32)wolfSSL_RSA_size(rsa);
            ret = wc_RsaFunction(from, (word32)len, to, &outLen,
                    RSA_PRIVATE_ENCRYPT, (RsaKey*)rsa->internal, rng);
            if (ret == 0)
                ret = (int)outLen;
        }
    #endif
    }

    /* Finalize RNG if initialized in WOLFSSL_RSA_GetRNG(). */
    if (initTmpRng) {
        wc_FreeRng(tmpRng);
    }
    WC_FREE_VAR_EX(tmpRng, NULL, DYNAMIC_TYPE_RNG);

    /* wolfCrypt error means return -1. */
    if (ret <= 0) {
        ret = WOLFSSL_FATAL_ERROR;
    }
    WOLFSSL_LEAVE("wolfSSL_RSA_private_encrypt", ret);
    return ret;
}

/*
 * RSA misc operation APIs
 */

/* Calculate d mod p-1 and q-1 into BNs.
 *
 * Not OpenSSL API.
 *
 * @param [in, out] rsa  RSA key.
 * @return 1 on success.
 * @return -1 on failure.
 */
int wolfSSL_RSA_GenAdd(WOLFSSL_RSA* rsa)
{
    int     ret = 1;
    int     err;
    mp_int* t = NULL;
    WC_DECLARE_VAR(tmp, mp_int, 1, 0);

    WOLFSSL_ENTER("wolfSSL_RsaGenAdd");

    /* Validate parameters. */
    if ((rsa == NULL) || (rsa->p == NULL) || (rsa->q == NULL) ||
            (rsa->d == NULL) || (rsa->dmp1 == NULL) || (rsa->dmq1 == NULL)) {
        WOLFSSL_ERROR_MSG("rsa no init error");
        ret = WOLFSSL_FATAL_ERROR;
    }

#ifdef WOLFSSL_SMALL_STACK
    if (ret == 1) {
        tmp = (mp_int *)XMALLOC(sizeof(*tmp), rsa->heap,
                                     DYNAMIC_TYPE_TMP_BUFFER);
        if (tmp == NULL) {
            WOLFSSL_ERROR_MSG("Memory allocation failure");
            ret = WOLFSSL_FATAL_ERROR;
        }
    }
#endif

    if (ret == 1) {
        /* Initialize temp MP integer. */
        if (mp_init(tmp) != MP_OKAY) {
            WOLFSSL_ERROR_MSG("mp_init error");
            ret = WOLFSSL_FATAL_ERROR;
        }
    }

    if (ret == 1) {
        t = tmp;

        /* Sub 1 from p into temp. */
        err = mp_sub_d((mp_int*)rsa->p->internal, 1, tmp);
        if (err != MP_OKAY) {
            WOLFSSL_ERROR_MSG("mp_sub_d error");
            ret = WOLFSSL_FATAL_ERROR;
        }
    }
    if (ret == 1) {
        /* Calculate d mod (p - 1) into dmp1 MP integer of BN. */
        err = mp_mod((mp_int*)rsa->d->internal, tmp,
            (mp_int*)rsa->dmp1->internal);
        if (err != MP_OKAY) {
            WOLFSSL_ERROR_MSG("mp_mod error");
            ret = WOLFSSL_FATAL_ERROR;
        }
    }
    if (ret == 1) {
        /* Sub 1 from q into temp. */
        err = mp_sub_d((mp_int*)rsa->q->internal, 1, tmp);
        if (err != MP_OKAY) {
            WOLFSSL_ERROR_MSG("mp_sub_d error");
            ret = WOLFSSL_FATAL_ERROR;
        }
    }
    if (ret == 1) {
        /* Calculate d mod (q - 1) into dmq1 MP integer of BN. */
        err = mp_mod((mp_int*)rsa->d->internal, tmp,
            (mp_int*)rsa->dmq1->internal);
        if (err != MP_OKAY) {
            WOLFSSL_ERROR_MSG("mp_mod error");
            ret = WOLFSSL_FATAL_ERROR;
        }
    }

    mp_forcezero(t);

#ifdef WOLFSSL_SMALL_STACK
    if (rsa != NULL) {
        XFREE(tmp, rsa->heap, DYNAMIC_TYPE_TMP_BUFFER);
    }
#endif

    return ret;
}


#ifndef NO_WOLFSSL_STUB
/* Enable blinding for RSA key operations.
 *
 * Blinding is a compile time option in wolfCrypt.
 *
 * @param [in] rsa    RSA key. Unused.
 * @param [in] bnCtx  BN context to use for blinding. Unused.
 * @return 1 always.
 */
int wolfSSL_RSA_blinding_on(WOLFSSL_RSA* rsa, WOLFSSL_BN_CTX* bnCtx)
{
    WOLFSSL_STUB("RSA_blinding_on");
    WOLFSSL_ENTER("wolfSSL_RSA_blinding_on");

    (void)rsa;
    (void)bnCtx;

    return 1;  /* on by default */
}
#endif

#endif /* OPENSSL_EXTRA */

#endif /* !NO_RSA */

/*******************************************************************************
 * END OF RSA API
 ******************************************************************************/

#endif /* !WOLFSSL_PK_RSA_INCLUDED */
