Files
wolfssl/src/pk_rsa.c
T
Juliusz Sosinowicz a010825bb0 Address review comments on Fenrir zeroization fixes
Two follow-ups raised by Copilot review on PR #10247:

src/pk_rsa.c: Make derAllocSz a word32 instead of int and only assign
it after a successful XMALLOC, so the cleanup path can never call
ForceZero with a wrapped-around size derived from a negative derSz.

src/pk.c: Capture allocSz at the XMALLOC call site (and clear it back
to 0 on allocation failure) so the relationship between the buffer
allocation and the recorded size is explicit and cannot drift if the
surrounding control flow changes.
2026-04-20 16:12:30 +00:00

3954 lines
116 KiB
C

/* 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. */
if (der != NULL) {
ForceZero(der, (word32)derLen);
}
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;
word32 derAllocSz = 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;
}
else {
derAllocSz = (word32)derSz;
}
}
}
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. */
if ((derBuf != NULL) && (publicKey == 0) && (derAllocSz > 0)) {
ForceZero(derBuf, derAllocSz);
}
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 */