2018-02-19 12:29:49 +01:00

2766 lines
76 KiB
C

/* rsa.c
*
* Copyright (C) 2006-2017 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 2 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
*/
#ifdef HAVE_CONFIG_H /* configure options when using autoconf */
#include <config.h>
#endif
#include <wolfssl/options.h>
#include <wolfssl/wolfcrypt/settings.h>
#ifndef NO_RSA
#define USER_CRYPTO_ERROR -101
#ifdef OPENSSL_EXTRA
#include <wolfssl/openssl/rsa.h> /* include for openssl compatibility */
#include <wolfssl/openssl/bn.h>
#endif
#include "user_rsa.h"
#ifdef DEBUG_WOLFSSL /* debug done without variadric to allow older compilers */
#include <stdio.h>
#define USER_DEBUG(x) printf x
#else
#define USER_DEBUG(x)
#endif
#define ASN_INTEGER 0x02
#define ASN_BIT_STRING 0x03
#define ASN_TAG_NULL 0x05
#define ASN_OBJECT_ID 0x06
/* Make sure compiler doesn't skip -- used from wolfSSL */
static inline void ForceZero(const void* mem, word32 len)
{
volatile byte* z = (volatile byte*)mem;
while (len--) *z++ = 0;
}
enum {
RSA_PUBLIC_ENCRYPT = 0,
RSA_PUBLIC_DECRYPT = 1,
RSA_PRIVATE_ENCRYPT = 2,
RSA_PRIVATE_DECRYPT = 3,
RSA_BLOCK_TYPE_1 = 1,
RSA_BLOCK_TYPE_2 = 2,
RSA_MIN_SIZE = 512,
RSA_MAX_SIZE = 4096, /* max allowed in IPP library */
RSA_MIN_PAD_SZ = 11 /* seperator + 0 + pad value + 8 pads */
};
int wc_InitRsaKey_ex(RsaKey* key, void* heap, int devId)
{
USER_DEBUG(("Entering wc_InitRsaKey\n"));
if (key == NULL)
return USER_CRYPTO_ERROR;
/* set full struct as 0 */
ForceZero(key, sizeof(RsaKey));
USER_DEBUG(("\tExit wc_InitRsaKey\n"));
(void)devId;
(void)heap;
return 0;
}
int wc_InitRsaKey(RsaKey* key, void* heap)
{
return wc_InitRsaKey_ex(key, heap, INVALID_DEVID);
}
/* three functions needed for cert and key gen */
#if defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_KEY_GEN)
/* return 1 if there is a leading bit*/
int wc_Rsa_leading_bit(void* bn)
{
int ret = 0;
int dataSz;
Ipp32u* data;
Ipp32u q;
int qSz = sizeof(Ipp32u);
if (ippsExtGet_BN(NULL, &dataSz, NULL, bn) != ippStsNoErr) {
USER_DEBUG(("ippsExtGet_BN Rsa leading bit error\n"));
return USER_CRYPTO_ERROR;
}
/* convert from size in binary to Ipp32u */
dataSz = dataSz / 32 + ((dataSz % 32)? 1 : 0);
data = (Ipp32u*)XMALLOC(dataSz * sizeof(Ipp32u), NULL,
DYNAMIC_TYPE_USER_CRYPTO);
if (data == NULL) {
USER_DEBUG(("Rsa leading bit memory error\n"));
return 0;
}
/* extract value from BN */
if (ippsExtGet_BN(NULL, NULL, data, bn) != ippStsNoErr) {
USER_DEBUG(("Rsa leading bit error\n"));
XFREE(data, NULL, DYNAMIC_TYPE_USER_CRYPTO);
return 0;
}
/* use method like what's used in wolfssl tfm.c */
q = data[dataSz - 1];
ret = 0;
while (qSz > 0) {
if (q != 0)
ret = (q & 0x80) != 0;
q >>= 8;
qSz--;
}
XFREE(data, NULL, DYNAMIC_TYPE_USER_CRYPTO);
return ret;
}
/* get the size in bytes of BN */
int wc_Rsa_unsigned_bin_size(void* bn)
{
int ret = 0;
if (ippsExtGet_BN(NULL, &ret, NULL, bn) != ippStsNoErr) {
USER_DEBUG(("Rsa unsigned bin size error\n"));
return USER_CRYPTO_ERROR;
}
return (ret / 8) + ((ret % 8)? 1: 0); /* size in bytes */
}
#ifndef MP_OKAY
#define MP_OKAY 0
#endif
/* extract the bn value to a unsigned byte array and return MP_OKAY on succes */
int wc_Rsa_to_unsigned_bin(void* bn, byte* in, int inLen)
{
if (ippsGetOctString_BN((Ipp8u*)in, inLen, bn) != ippStsNoErr) {
USER_DEBUG(("Rsa to unsigned bin error\n"));
return USER_CRYPTO_ERROR;
}
return MP_OKAY;
}
#endif /* WOLFSSL_CERT_GEN or WOLFSSL_KEY_GEN */
#ifdef OPENSSL_EXTRA /* functions needed for openssl compatibility layer */
static int SetIndividualExternal(WOLFSSL_BIGNUM** bn, IppsBigNumState* in)
{
IppStatus ret;
byte* data;
int sz;
USER_DEBUG(("Entering SetIndividualExternal\n"));
if (bn == NULL || in == NULL) {
USER_DEBUG(("inputs NULL error\n"));
return USER_CRYPTO_ERROR;
}
if (*bn == NULL) {
*bn = wolfSSL_BN_new();
if (*bn == NULL) {
USER_DEBUG(("SetIndividualExternal alloc failed\n"));
return USER_CRYPTO_ERROR;
}
}
/* get size of array needed and extract oct array of data */
ret = ippsGetSize_BN(in, &sz);
if (ret != ippStsNoErr)
return USER_CRYPTO_ERROR;
data = (byte*)XMALLOC(sz, NULL, DYNAMIC_TYPE_USER_CRYPTO);
if (data == NULL)
return USER_CRYPTO_ERROR;
ret = ippsGetOctString_BN(data, sz, in);
if (ret != ippStsNoErr) {
XFREE(data, NULL, DYNAMIC_TYPE_USER_CRYPTO);
return USER_CRYPTO_ERROR;
}
/* store the data into a wolfSSL Big Number */
*bn = wolfSSL_BN_bin2bn(data, sz, *bn);
XFREE(data, NULL, DYNAMIC_TYPE_USER_CRYPTO);
return 0;
}
static int SetIndividualInternal(WOLFSSL_BIGNUM* bn, IppsBigNumState** mpi)
{
int length, ctxSz, sz;
IppStatus ret;
Ipp8u* data;
USER_DEBUG(("Entering SetIndividualInternal\n"));
if (bn == NULL || bn->internal == NULL) {
USER_DEBUG(("bn NULL error\n"));
return USER_CRYPTO_ERROR;
}
length = wolfSSL_BN_num_bytes(bn);
/* if not IPP BN then create one */
if (*mpi == NULL) {
ret = ippsBigNumGetSize(length, &ctxSz);
if (ret != ippStsNoErr)
return USER_CRYPTO_ERROR;
*mpi = (IppsBigNumState*)XMALLOC(ctxSz, 0, DYNAMIC_TYPE_USER_CRYPTO);
if (*mpi == NULL)
return USER_CRYPTO_ERROR;
ret = ippsBigNumInit(length, *mpi);
if (ret != ippStsNoErr) {
XFREE(*mpi, NULL, DYNAMIC_TYPE_USER_CRYPTO);
return USER_CRYPTO_ERROR;
}
}
/* get the size of array needed and check IPP BigNum */
if (ippsGetSize_BN(*mpi, &sz) != ippStsNoErr)
return USER_CRYPTO_ERROR;
if (sz < length) {
USER_DEBUG(("big num size is too small\n"));
return USER_CRYPTO_ERROR;
}
data = (Ipp8u*)XMALLOC(length, NULL, DYNAMIC_TYPE_USER_CRYPTO);
if (data == NULL)
return USER_CRYPTO_ERROR;
/* extract the wolfSSL BigNum and store it into IPP BigNum */
if (wolfSSL_BN_bn2bin(bn, data) < 0) {
XFREE(data, NULL, DYNAMIC_TYPE_USER_CRYPTO);
USER_DEBUG(("error in getting bin from wolfssl bn\n"));
return USER_CRYPTO_ERROR;
}
ret = ippsSetOctString_BN(data, length, *mpi);
if (ret != ippStsNoErr) {
XFREE(data, NULL, DYNAMIC_TYPE_USER_CRYPTO);
return USER_CRYPTO_ERROR;
}
XFREE(data, NULL, DYNAMIC_TYPE_USER_CRYPTO);
return 0;
}
/* WolfSSL -> OpenSSL */
int SetRsaExternal(WOLFSSL_RSA* rsa)
{
RsaKey* key;
USER_DEBUG(("Entering SetRsaExternal\n"));
if (rsa == NULL || rsa->internal == NULL) {
USER_DEBUG(("rsa key NULL error\n"));
return USER_CRYPTO_ERROR;
}
key = (RsaKey*)rsa->internal;
if (SetIndividualExternal(&rsa->n, key->n) != 0) {
USER_DEBUG(("rsa n key error\n"));
return USER_CRYPTO_ERROR;
}
if (SetIndividualExternal(&rsa->e, key->e) != 0) {
USER_DEBUG(("rsa e key error\n"));
return USER_CRYPTO_ERROR;
}
if (SetIndividualExternal(&rsa->d, key->dipp) != 0) {
USER_DEBUG(("rsa d key error\n"));
return USER_CRYPTO_ERROR;
}
if (SetIndividualExternal(&rsa->p, key->pipp) != 0) {
USER_DEBUG(("rsa p key error\n"));
return USER_CRYPTO_ERROR;
}
if (SetIndividualExternal(&rsa->q, key->qipp) != 0) {
USER_DEBUG(("rsa q key error\n"));
return USER_CRYPTO_ERROR;
}
if (SetIndividualExternal(&rsa->dmp1, key->dPipp) != 0) {
USER_DEBUG(("rsa dP key error\n"));
return USER_CRYPTO_ERROR;
}
if (SetIndividualExternal(&rsa->dmq1, key->dQipp) != 0) {
USER_DEBUG(("rsa dQ key error\n"));
return USER_CRYPTO_ERROR;
}
if (SetIndividualExternal(&rsa->iqmp, key->uipp) != 0) {
USER_DEBUG(("rsa u key error\n"));
return USER_CRYPTO_ERROR;
}
rsa->exSet = 1;
/* SSL_SUCCESS */
return 1;
}
/* Openssl -> WolfSSL */
int SetRsaInternal(WOLFSSL_RSA* rsa)
{
int ctxSz, pSz, qSz;
IppStatus ret;
RsaKey* key;
USER_DEBUG(("Entering SetRsaInternal\n"));
if (rsa == NULL || rsa->internal == NULL) {
USER_DEBUG(("rsa key NULL error\n"));
return USER_CRYPTO_ERROR;
}
key = (RsaKey*)rsa->internal;
if (SetIndividualInternal(rsa->n, &key->n) != 0) {
USER_DEBUG(("rsa n key error\n"));
return USER_CRYPTO_ERROR;
}
if (SetIndividualInternal(rsa->e, &key->e) != 0) {
USER_DEBUG(("rsa e key error\n"));
return USER_CRYPTO_ERROR;
}
/* public key */
key->type = RSA_PUBLIC;
if (rsa->d != NULL) {
if (SetIndividualInternal(rsa->d, &key->dipp) != 0) {
USER_DEBUG(("rsa d key error\n"));
return USER_CRYPTO_ERROR;
}
/* private key */
key->type = RSA_PRIVATE;
}
if (rsa->p != NULL &&
SetIndividualInternal(rsa->p, &key->pipp) != 0) {
USER_DEBUG(("rsa p key error\n"));
return USER_CRYPTO_ERROR;
}
if (rsa->q != NULL &&
SetIndividualInternal(rsa->q, &key->qipp) != 0) {
USER_DEBUG(("rsa q key error\n"));
return USER_CRYPTO_ERROR;
}
if (rsa->dmp1 != NULL &&
SetIndividualInternal(rsa->dmp1, &key->dPipp) != 0) {
USER_DEBUG(("rsa dP key error\n"));
return USER_CRYPTO_ERROR;
}
if (rsa->dmq1 != NULL &&
SetIndividualInternal(rsa->dmq1, &key->dQipp) != 0) {
USER_DEBUG(("rsa dQ key error\n"));
return USER_CRYPTO_ERROR;
}
if (rsa->iqmp != NULL &&
SetIndividualInternal(rsa->iqmp, &key->uipp) != 0) {
USER_DEBUG(("rsa u key error\n"));
return USER_CRYPTO_ERROR;
}
rsa->inSet = 1;
/* get sizes of IPP BN key states created from input */
ret = ippsGetSize_BN(key->n, &key->nSz);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsGetSize_BN error %s\n", ippGetStatusString(ret)));
return USER_CRYPTO_ERROR;
}
ret = ippsGetSize_BN(key->e, &key->eSz);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsGetSize_BN error %s\n", ippGetStatusString(ret)));
return USER_CRYPTO_ERROR;
}
key->sz = key->nSz; /* set modulus size */
/* convert to size in bits */
key->nSz = key->nSz * 8;
key->eSz = key->eSz * 8;
/* set up public key state */
ret = ippsRSA_GetSizePublicKey(key->nSz, key->eSz, &ctxSz);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsRSA_GetSizePublicKey error %s\n",
ippGetStatusString(ret)));
return USER_CRYPTO_ERROR;
}
key->pPub = (IppsRSAPublicKeyState*)XMALLOC(ctxSz, NULL,
DYNAMIC_TYPE_USER_CRYPTO);
if (key->pPub == NULL)
return USER_CRYPTO_ERROR;
ret = ippsRSA_InitPublicKey(key->nSz, key->eSz, key->pPub, ctxSz);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsRSA_InitPublicKey error %s\n",
ippGetStatusString(ret)));
return USER_CRYPTO_ERROR;
}
ret = ippsRSA_SetPublicKey(key->n, key->e, key->pPub);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsRSA_SetPublicKey error %s\n", ippGetStatusString(ret)));
return USER_CRYPTO_ERROR;
}
if (key->pipp != NULL && key->qipp != NULL && key->dipp != NULL &&
key->dPipp != NULL && key->dQipp != NULL && key->uipp != NULL) {
/* get bn sizes needed for private key set up */
ret = ippsGetSize_BN(key->pipp, &pSz);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsGetSize_BN error %s\n", ippGetStatusString(ret)));
return USER_CRYPTO_ERROR;
}
ret = ippsGetSize_BN(key->qipp, &qSz);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsGetSize_BN error %s\n", ippGetStatusString(ret)));
return USER_CRYPTO_ERROR;
}
/* store sizes needed for creating tmp private keys */
ret = ippsGetSize_BN(key->dipp, &key->dSz);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsGetSize_BN error %s\n", ippGetStatusString(ret)));
return USER_CRYPTO_ERROR;
}
/* convert to size in bits */
key->dSz = key->dSz * 8;
pSz = pSz * 8;
qSz = qSz * 8;
/* set up private key state */
ret = ippsRSA_GetSizePrivateKeyType2(pSz, qSz, &ctxSz);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsRSA_GetSizePrivateKey error %s\n",
ippGetStatusString(ret)));
return USER_CRYPTO_ERROR;
}
key->prvSz = ctxSz;
key->pPrv = (IppsRSAPrivateKeyState*)XMALLOC(ctxSz, 0,
DYNAMIC_TYPE_USER_CRYPTO);
if (key->pPrv == NULL)
return USER_CRYPTO_ERROR;
ret = ippsRSA_InitPrivateKeyType2(pSz, qSz, key->pPrv, ctxSz);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsRSA_InitPrivateKey error %s\n",
ippGetStatusString(ret)));
return USER_CRYPTO_ERROR;
}
ret = ippsRSA_SetPrivateKeyType2(key->pipp, key->qipp, key->dPipp,
key->dQipp, key->uipp, key->pPrv);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsRSA_SetPrivateKey error %s\n", ippGetStatusString(ret)));
return USER_CRYPTO_ERROR;
}
}
/* SSL_SUCCESS */
return 1;
}
#endif /* OPENSSLEXTRA */
/* Padding scheme function used in wolfSSL for signing needed for matching
existing API signing scheme
input : the msg to be signed
inputLen : length of input msg
pkcsBlock : the outputed padded msg
pkcsBlockLen : length of outptued padded msg buffer
padValue : the padded value after first 00 , is either 01 or 02
rng : random number generator structure
*/
static int wc_RsaPad(const byte* input, word32 inputLen, byte* pkcsBlock,
word32 pkcsBlockLen, byte padValue, WC_RNG* rng)
{
if (inputLen == 0 || pkcsBlockLen == 0) {
return USER_CRYPTO_ERROR;
}
pkcsBlock[0] = 0x0; /* set first byte to zero and advance */
pkcsBlock++; pkcsBlockLen--;
pkcsBlock[0] = padValue; /* insert padValue */
if (padValue == RSA_BLOCK_TYPE_1) {
if (pkcsBlockLen < inputLen + 2) {
return USER_CRYPTO_ERROR;
}
/* pad with 0xff bytes */
XMEMSET(&pkcsBlock[1], 0xFF, pkcsBlockLen - inputLen - 2);
}
else {
/* pad with non-zero random bytes */
word32 padLen, i;
int ret;
if (pkcsBlockLen < inputLen + 1) {
return USER_CRYPTO_ERROR;
}
padLen = pkcsBlockLen - inputLen - 1;
ret = wc_RNG_GenerateBlock(rng, &pkcsBlock[1], padLen);
if (ret != 0)
return ret;
/* remove zeros */
for (i = 1; i < padLen; i++)
if (pkcsBlock[i] == 0) pkcsBlock[i] = 0x01;
}
pkcsBlock[pkcsBlockLen-inputLen-1] = 0; /* separator */
XMEMCPY(pkcsBlock+pkcsBlockLen-inputLen, input, inputLen);
return 0;
}
/* UnPad plaintext, set start to *output, return length of plaintext,
* < 0 on error */
static int RsaUnPad(const byte *pkcsBlock, unsigned int pkcsBlockLen,
byte **output, byte padValue)
{
word32 maxOutputLen = (pkcsBlockLen > 10) ? (pkcsBlockLen - 10) : 0,
invalid = 0,
i = 1,
outputLen;
if (pkcsBlockLen == 0) {
return USER_CRYPTO_ERROR;
}
if (pkcsBlock[0] != 0x0) /* skip past zero */
invalid = 1;
pkcsBlock++; pkcsBlockLen--;
/* Require block type padValue */
invalid = (pkcsBlock[0] != padValue) || invalid;
/* verify the padding until we find the separator */
if (padValue == RSA_BLOCK_TYPE_1) {
while (i<pkcsBlockLen && pkcsBlock[i++] == 0xFF) {/* Null body */}
}
else {
while (i<pkcsBlockLen && pkcsBlock[i++]) {/* Null body */}
}
if(!(i==pkcsBlockLen || pkcsBlock[i-1]==0)) {
USER_DEBUG(("RsaUnPad error, bad formatting\n"));
return USER_CRYPTO_ERROR;
}
outputLen = pkcsBlockLen - i;
invalid = (outputLen > maxOutputLen) || invalid;
if (invalid) {
USER_DEBUG(("RsaUnPad error, bad formatting\n"));
return USER_CRYPTO_ERROR;
}
*output = (byte *)(pkcsBlock + i);
return outputLen;
}
/* Set up memory and structure for a Big Number
* returns ippStsNoErr on success
*/
static IppStatus init_bn(IppsBigNumState** in, int sz)
{
int ctxSz;
IppStatus ret;
ret = ippsBigNumGetSize(sz, &ctxSz);
if (ret != ippStsNoErr) {
return ret;
}
*in = (IppsBigNumState*)XMALLOC(ctxSz, 0, DYNAMIC_TYPE_USER_CRYPTO);
if (*in == NULL) {
return ippStsNoMemErr;
}
ret = ippsBigNumInit(sz, *in);
if (ret != ippStsNoErr) {
XFREE(*in, NULL, DYNAMIC_TYPE_USER_CRYPTO);
*in = NULL;
return ret;
}
return ippStsNoErr;
}
/* Set up memory and structure for a Montgomery struct
* returns ippStsNoErr on success
*/
static IppStatus init_mont(IppsMontState** mont, int* ctxSz,
IppsBigNumState* modul)
{
int mSz;
Ipp32u* m;
IppStatus ret;
ret = ippsExtGet_BN(NULL, ctxSz, NULL, modul);
if (ret != ippStsNoErr) {
return ret;
}
/* convert bits to Ipp32u array size and round up
32 is number of bits in type */
mSz = (*ctxSz/32)+((*ctxSz % 32)? 1: 0);
m = (Ipp32u*)XMALLOC(mSz * sizeof(Ipp32u), 0, DYNAMIC_TYPE_USER_CRYPTO);
if (m == NULL) {
XFREE(m, NULL, DYNAMIC_TYPE_USER_CRYPTO);
return ippStsNoMemErr;
}
ret = ippsExtGet_BN(NULL, NULL, m, modul);
if (ret != ippStsNoErr) {
XFREE(m, NULL, DYNAMIC_TYPE_USER_CRYPTO);
return ret;
}
ret = ippsMontGetSize(IppsSlidingWindows, mSz, ctxSz);
if (ret != ippStsNoErr) {
XFREE(m, NULL, DYNAMIC_TYPE_USER_CRYPTO);
return ret;
}
/* 2. Allocate working buffer using malloc */
*mont = (IppsMontState*)XMALLOC(*ctxSz, 0, DYNAMIC_TYPE_USER_CRYPTO);
if (mont == NULL) {
XFREE(m, NULL, DYNAMIC_TYPE_USER_CRYPTO);
return ippStsNoMemErr;
}
ret = ippsMontInit(IppsSlidingWindows, mSz, *mont);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsMontInit error of %s\n", ippGetStatusString(ret)));
XFREE(m, NULL, DYNAMIC_TYPE_USER_CRYPTO);
XFREE(*mont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
*mont = NULL;
return ret;
}
/* 3. Call the function MontSet to set big number module */
ret = ippsMontSet(m, mSz, *mont);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsMontSet error of %s\n", ippGetStatusString(ret)));
XFREE(m, NULL, DYNAMIC_TYPE_USER_CRYPTO);
XFREE(*mont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
*mont = NULL;
return ret;
}
XFREE(m, NULL, DYNAMIC_TYPE_USER_CRYPTO);
return ippStsNoErr;
}
int wc_FreeRsaKey(RsaKey* key)
{
if (key == NULL)
return 0;
USER_DEBUG(("Entering wc_FreeRsaKey\n"));
if (key->pPub != NULL) {
XFREE(key->pPub, NULL, DYNAMIC_TYPE_USER_CRYPTO);
key->pPub = NULL;
}
if (key->pPrv != NULL) {
/* write over senstive information */
ForceZero(key->pPrv, key->prvSz);
XFREE(key->pPrv, NULL, DYNAMIC_TYPE_USER_CRYPTO);
key->pPrv = NULL;
}
if (key->n != NULL) {
XFREE(key->n, NULL, DYNAMIC_TYPE_USER_CRYPTO);
key->n = NULL;
}
if (key->e != NULL) {
XFREE(key->e, NULL, DYNAMIC_TYPE_USER_CRYPTO);
key->e = NULL;
}
if (key->dipp != NULL) {
XFREE(key->dipp, NULL, DYNAMIC_TYPE_USER_CRYPTO);
key->dipp = NULL;
}
if (key->pipp != NULL) {
XFREE(key->pipp, NULL, DYNAMIC_TYPE_USER_CRYPTO);
key->pipp = NULL;
}
if (key->qipp != NULL) {
XFREE(key->qipp, NULL, DYNAMIC_TYPE_USER_CRYPTO);
key->qipp = NULL;
}
if (key->dPipp != NULL) {
XFREE(key->dPipp, NULL, DYNAMIC_TYPE_USER_CRYPTO);
key->dPipp = NULL;
}
if (key->dQipp != NULL) {
XFREE(key->dQipp, NULL, DYNAMIC_TYPE_USER_CRYPTO);
key->dQipp = NULL;
}
if (key->uipp != NULL) {
XFREE(key->uipp, NULL, DYNAMIC_TYPE_USER_CRYPTO);
key->uipp = NULL;
}
USER_DEBUG(("\tExit wc_FreeRsaKey\n"));
(void)key;
return 0;
}
/* Some parsing functions from wolfSSL code needed to match wolfSSL API used */
static int GetLength(const byte* input, word32* inOutIdx, int* len,
word32 maxIdx)
{
int length = 0;
word32 idx = *inOutIdx;
byte b;
*len = 0; /* default length */
if ((idx + 1) > maxIdx) { /* for first read */
USER_DEBUG(("GetLength bad index on input\n"));
return USER_CRYPTO_ERROR;
}
b = input[idx++];
if (b >= 0x80) {
word32 bytes = b & 0x7F;
if ((idx + bytes) > maxIdx) { /* for reading bytes */
USER_DEBUG(("GetLength bad long length\n"));
return USER_CRYPTO_ERROR;
}
while (bytes--) {
b = input[idx++];
length = (length << 8) | b;
}
}
else
length = b;
if ((idx + length) > maxIdx) { /* for user of length */
USER_DEBUG(("GetLength value exceeds buffer length\n"));
return USER_CRYPTO_ERROR;
}
*inOutIdx = idx;
if (length > 0)
*len = length;
return length;
}
static int GetInt(IppsBigNumState** mpi, const byte* input, word32* inOutIdx,
word32 maxIdx)
{
IppStatus ret;
word32 idx = *inOutIdx;
byte b;
int length;
int ctxSz;
if ((idx + 1) > maxIdx)
return USER_CRYPTO_ERROR;
b = input[idx++];
if (b != 0x02)
return USER_CRYPTO_ERROR;
if (GetLength(input, &idx, &length, maxIdx) < 0)
return USER_CRYPTO_ERROR;
if (length > 0) {
/* remove leading zero */
if ( (b = input[idx++]) == 0x00)
length--;
else
idx--;
}
ret = ippsBigNumGetSize(length, &ctxSz);
if (ret != ippStsNoErr)
return USER_CRYPTO_ERROR;
*mpi = (IppsBigNumState*)XMALLOC(ctxSz, 0, DYNAMIC_TYPE_USER_CRYPTO);
if (*mpi == NULL)
return USER_CRYPTO_ERROR;
ret = ippsBigNumInit(length, *mpi);
if (ret != ippStsNoErr)
return USER_CRYPTO_ERROR;
ret = ippsSetOctString_BN((Ipp8u*)input + idx, length, *mpi);
if (ret != ippStsNoErr)
return USER_CRYPTO_ERROR;
*inOutIdx = idx + length;
return 0;
}
static int GetSequence(const byte* input, word32* inOutIdx, int* len,
word32 maxIdx)
{
int length = -1;
word32 idx = *inOutIdx;
if ((idx + 1) > maxIdx)
return USER_CRYPTO_ERROR;
if (input[idx++] != (0x10 | 0x20) ||
GetLength(input, &idx, &length, maxIdx) < 0)
return USER_CRYPTO_ERROR;
*len = length;
*inOutIdx = idx;
return length;
}
static int GetMyVersion(const byte* input, word32* inOutIdx,
int* version, word32 maxIdx)
{
word32 idx = *inOutIdx;
if ((idx + 3) > maxIdx)
return USER_CRYPTO_ERROR;
if (input[idx++] != 0x02)
return USER_CRYPTO_ERROR;
if (input[idx++] != 0x01)
return USER_CRYPTO_ERROR;
*version = input[idx++];
*inOutIdx = idx;
return *version;
}
int wc_RsaPrivateKeyDecode(const byte* input, word32* inOutIdx, RsaKey* key,
word32 inSz)
{
int version, length;
int ctxSz, pSz, qSz;
IppStatus ret;
if (input == NULL || inOutIdx == NULL || key == NULL) {
return USER_CRYPTO_ERROR;
}
USER_DEBUG(("Entering wc_RsaPrivateKeyDecode\n"));
/* read in key information */
if (GetSequence(input, inOutIdx, &length, inSz) < 0)
return USER_CRYPTO_ERROR;
if (GetMyVersion(input, inOutIdx, &version, inSz) < 0)
return USER_CRYPTO_ERROR;
key->type = RSA_PRIVATE;
if (GetInt(&key->n, input, inOutIdx, inSz) < 0 ||
GetInt(&key->e, input, inOutIdx, inSz) < 0 ||
GetInt(&key->dipp, input, inOutIdx, inSz) < 0 ||
GetInt(&key->pipp, input, inOutIdx, inSz) < 0 ||
GetInt(&key->qipp, input, inOutIdx, inSz) < 0 ||
GetInt(&key->dPipp, input, inOutIdx, inSz) < 0 ||
GetInt(&key->dQipp, input, inOutIdx, inSz) < 0 ||
GetInt(&key->uipp, input, inOutIdx, inSz) < 0 )
return USER_CRYPTO_ERROR;
/* get sizes of IPP BN key states created from input */
ret = ippsGetSize_BN(key->n, &key->nSz);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsGetSize_BN error %s\n", ippGetStatusString(ret)));
return USER_CRYPTO_ERROR;
}
ret = ippsGetSize_BN(key->e, &key->eSz);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsGetSize_BN error %s\n", ippGetStatusString(ret)));
return USER_CRYPTO_ERROR;
}
key->sz = key->nSz; /* set modulus size */
/* convert to size in bits */
key->nSz = key->nSz * 8;
key->eSz = key->eSz * 8;
/* set up public key state */
ret = ippsRSA_GetSizePublicKey(key->nSz, key->eSz, &ctxSz);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsRSA_GetSizePublicKey error %s\n",
ippGetStatusString(ret)));
return USER_CRYPTO_ERROR;
}
key->pPub = (IppsRSAPublicKeyState*)XMALLOC(ctxSz, NULL,
DYNAMIC_TYPE_USER_CRYPTO);
if (key->pPub == NULL)
return USER_CRYPTO_ERROR;
ret = ippsRSA_InitPublicKey(key->nSz, key->eSz, key->pPub, ctxSz);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsRSA_InitPublicKey error %s\n",
ippGetStatusString(ret)));
return USER_CRYPTO_ERROR;
}
ret = ippsRSA_SetPublicKey(key->n, key->e, key->pPub);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsRSA_SetPublicKey error %s\n",
ippGetStatusString(ret)));
return USER_CRYPTO_ERROR;
}
/* get bn sizes needed for private key set up */
ret = ippsGetSize_BN(key->pipp, &pSz);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsGetSize_BN error %s\n", ippGetStatusString(ret)));
return USER_CRYPTO_ERROR;
}
ret = ippsGetSize_BN(key->qipp, &qSz);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsGetSize_BN error %s\n", ippGetStatusString(ret)));
return USER_CRYPTO_ERROR;
}
/* store sizes needed for creating tmp private keys */
ret = ippsGetSize_BN(key->dipp, &key->dSz);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsGetSize_BN error %s\n", ippGetStatusString(ret)));
return USER_CRYPTO_ERROR;
}
/* convert to size in bits */
key->dSz = key->dSz * 8;
pSz = pSz * 8;
qSz = qSz * 8;
/* set up private key state */
ret = ippsRSA_GetSizePrivateKeyType2(pSz, qSz, &ctxSz);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsRSA_GetSizePrivateKey error %s\n",
ippGetStatusString(ret)));
return USER_CRYPTO_ERROR;
}
key->prvSz = ctxSz;
key->pPrv = (IppsRSAPrivateKeyState*)XMALLOC(ctxSz, 0,
DYNAMIC_TYPE_USER_CRYPTO);
if (key->pPrv == NULL)
return USER_CRYPTO_ERROR;
ret = ippsRSA_InitPrivateKeyType2(pSz, qSz, key->pPrv, ctxSz);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsRSA_InitPrivateKey error %s\n",
ippGetStatusString(ret)));
return USER_CRYPTO_ERROR;
}
ret = ippsRSA_SetPrivateKeyType2(key->pipp, key->qipp, key->dPipp,
key->dQipp, key->uipp, key->pPrv);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsRSA_SetPrivateKey error %s\n",
ippGetStatusString(ret)));
return USER_CRYPTO_ERROR;
}
USER_DEBUG(("\tExit wc_RsaPrivateKeyDecode\n"));
return 0;
}
/* read in a public RSA key */
int wc_RsaPublicKeyDecode(const byte* input, word32* inOutIdx, RsaKey* key,
word32 inSz)
{
int length;
int ctxSz;
IppStatus ret;
#if defined(OPENSSL_EXTRA) || defined(RSA_DECODE_EXTRA)
byte b;
#endif
if (input == NULL || inOutIdx == NULL || key == NULL) {
return USER_CRYPTO_ERROR;
}
USER_DEBUG(("Entering wc_RsaPublicKeyDecode\n"));
if (GetSequence(input, inOutIdx, &length, inSz) < 0)
return USER_CRYPTO_ERROR;
key->type = RSA_PUBLIC;
#if defined(OPENSSL_EXTRA) || defined(RSA_DECODE_EXTRA)
if ((*inOutIdx + 1) > inSz)
return USER_CRYPTO_ERROR;
b = input[*inOutIdx];
if (b != ASN_INTEGER) {
/* not from decoded cert, will have algo id, skip past */
if (GetSequence(input, inOutIdx, &length, inSz) < 0)
return USER_CRYPTO_ERROR;
b = input[(*inOutIdx)++];
if (b != ASN_OBJECT_ID)
return USER_CRYPTO_ERROR;
if (GetLength(input, inOutIdx, &length, inSz) < 0)
return USER_CRYPTO_ERROR;
*inOutIdx += length; /* skip past */
/* could have NULL tag and 0 terminator, but may not */
b = input[(*inOutIdx)++];
if (b == ASN_TAG_NULL) {
b = input[(*inOutIdx)++];
if (b != 0)
return USER_CRYPTO_ERROR;
}
else {
/* go back, didn't have it */
(*inOutIdx)--;
}
/* should have bit tag length and seq next */
b = input[(*inOutIdx)++];
if (b != ASN_BIT_STRING)
return USER_CRYPTO_ERROR;
if (GetLength(input, inOutIdx, &length, inSz) <= 0)
return USER_CRYPTO_ERROR;
/* could have 0 */
b = input[(*inOutIdx)++];
if (b != 0)
(*inOutIdx)--;
if (GetSequence(input, inOutIdx, &length, inSz) < 0)
return USER_CRYPTO_ERROR;
}
#endif /* OPENSSL_EXTRA || RSA_DECODE_EXTRA */
if (GetInt(&key->n, input, inOutIdx, inSz) < 0 ||
GetInt(&key->e, input, inOutIdx, inSz) < 0) {
return USER_CRYPTO_ERROR;
}
/* get sizes set for IPP BN states */
ret = ippsGetSize_BN(key->n, &key->nSz);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsGetSize_BN error %s\n", ippGetStatusString(ret)));
return USER_CRYPTO_ERROR;
}
ret = ippsGetSize_BN(key->e, &key->eSz);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsGetSize_BN error %s\n", ippGetStatusString(ret)));
return USER_CRYPTO_ERROR;
}
key->sz = key->nSz; /* set modulus size */
/* convert to size in bits */
key->nSz = key->nSz * 8;
key->eSz = key->eSz * 8;
/* set up public key state */
ret = ippsRSA_GetSizePublicKey(key->nSz, key->eSz, &ctxSz);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsRSA_GetSizePublicKey error %s\n",
ippGetStatusString(ret)));
return USER_CRYPTO_ERROR;
}
key->pPub = (IppsRSAPublicKeyState*)XMALLOC(ctxSz, NULL,
DYNAMIC_TYPE_USER_CRYPTO);
if (key->pPub == NULL)
return USER_CRYPTO_ERROR;
ret = ippsRSA_InitPublicKey(key->nSz, key->eSz, key->pPub, ctxSz);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsRSA_InitPublicKey error %s\n",
ippGetStatusString(ret)));
return USER_CRYPTO_ERROR;
}
ret = ippsRSA_SetPublicKey(key->n, key->e, key->pPub);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsRSA_SetPublicKey error %s\n",
ippGetStatusString(ret)));
return USER_CRYPTO_ERROR;
}
USER_DEBUG(("\tExit RsaPublicKeyDecode\n"));
return 0;
}
/* import RSA public key elements (n, e) into RsaKey structure (key) */
int wc_RsaPublicKeyDecodeRaw(const byte* n, word32 nSz, const byte* e,
word32 eSz, RsaKey* key)
{
IppStatus ret;
int ctxSz;
USER_DEBUG(("Entering wc_RsaPublicKeyDecodeRaw\n"));
if (n == NULL || e == NULL || key == NULL)
return USER_CRYPTO_ERROR;
/* set up IPP key states -- read in n */
ret = init_bn(&key->n, nSz);
if (ret != ippStsNoErr)
return USER_CRYPTO_ERROR;
ret = ippsSetOctString_BN((Ipp8u*)n, nSz, key->n);
if (ret != ippStsNoErr)
return USER_CRYPTO_ERROR;
/* read in e */
ret = init_bn(&key->e, eSz);
if (ret != ippStsNoErr)
return USER_CRYPTO_ERROR;
ret = ippsSetOctString_BN((Ipp8u*)e, eSz, key->e);
if (ret != ippStsNoErr)
return USER_CRYPTO_ERROR;
/* store size and convert to binary */
key->sz = nSz;
nSz = nSz * 8;
eSz = eSz * 8;
/* set up public key state */
ret = ippsRSA_GetSizePublicKey(nSz, eSz, &ctxSz);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsRSA_GetSizePublicKey error %s\n",
ippGetStatusString(ret)));
return USER_CRYPTO_ERROR;
}
key->pPub = (IppsRSAPublicKeyState*)XMALLOC(ctxSz, NULL,
DYNAMIC_TYPE_USER_CRYPTO);
if (key->pPub == NULL)
return USER_CRYPTO_ERROR;
ret = ippsRSA_InitPublicKey(nSz, eSz, key->pPub, ctxSz);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsRSA_InitPublicKey error %s\n",
ippGetStatusString(ret)));
return USER_CRYPTO_ERROR;
}
ret = ippsRSA_SetPublicKey(key->n,key->e, key->pPub);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsRSA_SetPublicKey error %s\n",
ippGetStatusString(ret)));
return USER_CRYPTO_ERROR;
}
key->nSz = nSz;
key->eSz = eSz;
key->type = RSA_PUBLIC;
return 0;
}
/* encrypt using PKCS v15 */
int wc_RsaPublicEncrypt(const byte* in, word32 inLen, byte* out, word32 outLen,
RsaKey* key, WC_RNG* rng)
{
IppStatus ret;
Ipp8u* scratchBuffer;
int scratchSz;
if (key == NULL || in == NULL || out == NULL)
return USER_CRYPTO_ERROR;
if (key->pPub == NULL || outLen < key->sz)
return USER_CRYPTO_ERROR;
/* set size of scratch buffer */
ret = ippsRSA_GetBufferSizePublicKey(&scratchSz, key->pPub);
if (ret != ippStsNoErr)
return USER_CRYPTO_ERROR;
scratchBuffer = (Ipp8u*)XMALLOC(scratchSz*(sizeof(Ipp8u)), 0,
DYNAMIC_TYPE_USER_CRYPTO);
if (scratchBuffer == NULL)
return USER_CRYPTO_ERROR;
ret = ippsRSAEncrypt_PKCSv15((Ipp8u*)in, inLen, NULL, (Ipp8u*)out,
key->pPub, scratchBuffer);
if (ret != ippStsNoErr) {
XFREE(scratchBuffer, NULL, DYNAMIC_TYPE_USER_CRYPTO);
USER_DEBUG(("encrypt error of %s\n", ippGetStatusString(ret)));
return USER_CRYPTO_ERROR;
}
XFREE(scratchBuffer, NULL, DYNAMIC_TYPE_USER_CRYPTO);
(void)rng;
return key->sz;
}
/* decrypt using PLCS v15 */
int wc_RsaPrivateDecrypt(const byte* in, word32 inLen, byte* out, word32 outLen,
RsaKey* key)
{
IppStatus ret;
Ipp8u* scratchBuffer;
int scratchSz;
int outSz;
if (in == NULL || out == NULL || key == NULL)
return USER_CRYPTO_ERROR;
if (key->pPrv == NULL || inLen != key->sz)
return USER_CRYPTO_ERROR;
outSz = outLen;
/* set size of scratch buffer */
ret = ippsRSA_GetBufferSizePrivateKey(&scratchSz, key->pPrv);
if (ret != ippStsNoErr) {
return USER_CRYPTO_ERROR;
}
scratchBuffer = (Ipp8u*)XMALLOC(scratchSz*(sizeof(Ipp8u)), 0,
DYNAMIC_TYPE_USER_CRYPTO);
if (scratchBuffer == NULL) {
return USER_CRYPTO_ERROR;
}
/* perform decryption using IPP */
ret = ippsRSADecrypt_PKCSv15((Ipp8u*)in, (Ipp8u*)out, &outSz, key->pPrv,
scratchBuffer);
if (ret != ippStsNoErr) {
XFREE(scratchBuffer, NULL, DYNAMIC_TYPE_USER_CRYPTO);
USER_DEBUG(("decrypt error of %s\n", ippGetStatusString(ret)));
return USER_CRYPTO_ERROR;
}
XFREE(scratchBuffer, NULL, DYNAMIC_TYPE_USER_CRYPTO);
return outSz;
}
/* out is a pointer that is set to the location in byte array "in" where input
data has been decrypted */
int wc_RsaPrivateDecryptInline(byte* in, word32 inLen, byte** out, RsaKey* key)
{
int outSz;
byte* tmp;
USER_DEBUG(("Entering wc_RsaPrivateDecryptInline\n"));
/* allocate a buffer for max decrypted text */
tmp = (byte*)XMALLOC(key->sz, NULL, DYNAMIC_TYPE_USER_CRYPTO);
if (tmp == NULL)
return USER_CRYPTO_ERROR;
outSz = wc_RsaPrivateDecrypt(in, inLen, tmp, key->sz, key);
if (outSz >= 0) {
XMEMCPY(in, tmp, outSz);
*out = in;
}
else {
XFREE(tmp, NULL, DYNAMIC_TYPE_USER_CRYPTO);
return USER_CRYPTO_ERROR;
}
XFREE(tmp, NULL, DYNAMIC_TYPE_USER_CRYPTO);
USER_DEBUG(("\tExit wc_RsaPrivateDecryptInline\n"));
return outSz;
}
/* Used to clean up memory when exiting, clean up memory used */
static int FreeHelper(IppsBigNumState* pTxt, IppsBigNumState* cTxt,
Ipp8u* scratchBuffer, void* pPub)
{
if (pTxt != NULL)
XFREE(pTxt, NULL, DYNAMIC_TYPE_USER_CRYPTO);
if (cTxt != NULL)
XFREE(cTxt, NULL, DYNAMIC_TYPE_USER_CRYPTO);
if (scratchBuffer != NULL)
XFREE(scratchBuffer, NULL, DYNAMIC_TYPE_USER_CRYPTO);
if (pPub != NULL)
XFREE(pPub, NULL, DYNAMIC_TYPE_USER_CRYPTO);
return 0;
}
/* for Rsa Verify
in : byte array to be verified
inLen : length of input array
out : pointer to location of in byte array that has been verified
*/
int wc_RsaSSL_VerifyInline(byte* in, word32 inLen, byte** out, RsaKey* key)
{
int ctxSz;
int scratchSz;
Ipp8u* scratchBuffer = NULL;
IppStatus ret;
IppsRSAPrivateKeyState* pPub = NULL;
IppsBigNumState* pTxt = NULL;
IppsBigNumState* cTxt = NULL;
USER_DEBUG(("Entering wc_RsaSSL_VerifyInline\n"));
if (key == NULL || key->n == NULL || key->e == NULL) {
USER_DEBUG(("n or e element was null\n"));
return USER_CRYPTO_ERROR;
}
if (in == NULL || inLen == 0 || out == NULL)
return USER_CRYPTO_ERROR;
/* set up a private key state using public key values */
ret = ippsRSA_GetSizePrivateKeyType1(key->nSz, key->eSz, &ctxSz);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsRSA_GetSizePrivateKey error %s\n",
ippGetStatusString(ret)));
return USER_CRYPTO_ERROR;
}
pPub = (IppsRSAPrivateKeyState*)XMALLOC(ctxSz, 0, DYNAMIC_TYPE_USER_CRYPTO);
if (pPub == NULL)
return USER_CRYPTO_ERROR;
ret = ippsRSA_InitPrivateKeyType1(key->nSz, key->eSz, pPub, ctxSz);
if (ret != ippStsNoErr) {
FreeHelper(pTxt, cTxt, scratchBuffer, pPub);
USER_DEBUG(("ippsRSA_InitPrivateKey error %s\n",
ippGetStatusString(ret)));
return USER_CRYPTO_ERROR;
}
ret = ippsRSA_SetPrivateKeyType1(key->n, key->e, pPub);
if (ret != ippStsNoErr) {
FreeHelper(pTxt, cTxt, scratchBuffer, pPub);
USER_DEBUG(("ippsRSA_SetPrivateKey error %s\n",
ippGetStatusString(ret)));
return USER_CRYPTO_ERROR;
}
/* set size of scratch buffer */
ret = ippsRSA_GetBufferSizePrivateKey(&scratchSz, pPub);
if (ret != ippStsNoErr) {
FreeHelper(pTxt, cTxt, scratchBuffer, pPub);
return USER_CRYPTO_ERROR;
}
scratchBuffer = (Ipp8u*)XMALLOC(scratchSz*(sizeof(Ipp8u)), 0,
DYNAMIC_TYPE_USER_CRYPTO);
if (scratchBuffer == NULL) {
FreeHelper(pTxt, cTxt, scratchBuffer, pPub);
return USER_CRYPTO_ERROR;
}
/* load plain and cipher into big num states */
ret = init_bn(&pTxt, key->sz);
if (ret != ippStsNoErr) {
FreeHelper(pTxt, cTxt, scratchBuffer, pPub);
return USER_CRYPTO_ERROR;
}
ret = ippsSetOctString_BN((Ipp8u*)in, key->sz, pTxt);
if (ret != ippStsNoErr) {
FreeHelper(pTxt, cTxt, scratchBuffer, pPub);
return USER_CRYPTO_ERROR;
}
/* set up cipher to hold signature */
ret = init_bn(&cTxt, key->sz);
if (ret != ippStsNoErr) {
FreeHelper(pTxt, cTxt, scratchBuffer, pPub);
return USER_CRYPTO_ERROR;
}
ret = ippsSetOctString_BN((Ipp8u*)in, key->sz, cTxt);
if (ret != ippStsNoErr) {
FreeHelper(pTxt, cTxt, scratchBuffer, pPub);
return USER_CRYPTO_ERROR;
}
/* decrypt using public key information */
ret = ippsRSA_Decrypt(cTxt, pTxt, pPub, scratchBuffer);
if (ret != ippStsNoErr) {
FreeHelper(pTxt, cTxt, scratchBuffer, pPub);
USER_DEBUG(("decrypt error of %s\n", ippGetStatusString(ret)));
return USER_CRYPTO_ERROR;
}
/* extract big num struct to octect string */
ret = ippsGetOctString_BN((Ipp8u*)in, key->sz, pTxt);
if (ret != ippStsNoErr) {
FreeHelper(pTxt, cTxt, scratchBuffer, pPub);
USER_DEBUG(("BN get string error of %s\n", ippGetStatusString(ret)));
return USER_CRYPTO_ERROR;
}
FreeHelper(pTxt, cTxt, scratchBuffer, pPub);
/* unpad the decrypted information and return size of array */
return RsaUnPad(in, inLen, out, RSA_BLOCK_TYPE_1);
}
/* sets up and call VerifyInline to verify a signature */
int wc_RsaSSL_Verify(const byte* in, word32 inLen, byte* out, word32 outLen,
RsaKey* key)
{
int plainLen;
byte* tmp;
byte* pad = 0;
if (out == NULL || in == NULL || key == NULL)
return USER_CRYPTO_ERROR;
tmp = (byte*)XMALLOC(inLen, key->heap, DYNAMIC_TYPE_USER_CRYPTO);
if (tmp == NULL) {
return USER_CRYPTO_ERROR;
}
XMEMCPY(tmp, in, inLen);
/* verify signature and test if output buffer is large enough */
plainLen = wc_RsaSSL_VerifyInline(tmp, inLen, &pad, key);
if (plainLen < 0) {
XFREE(tmp, NULL, DYNAMIC_TYPE_USER_CRYPTO);
return plainLen;
}
if (plainLen > (int)outLen)
plainLen = USER_CRYPTO_ERROR;
else
XMEMCPY(out, pad, plainLen);
ForceZero(tmp, inLen);
XFREE(tmp, NULL, DYNAMIC_TYPE_USER_CRYPTO);
return plainLen;
}
/* Check if a > b , if so c = a mod b
return ippStsNoErr on success */
static IppStatus reduce(IppsBigNumState* a, IppsBigNumState* b,
IppsBigNumState* c)
{
IppStatus ret;
if ((ret = ippsMod_BN(a, b, c)) != ippStsNoErr)
return ret;
return ippStsNoErr;
}
static IppStatus exptmod(IppsBigNumState* a, IppsBigNumState* b,
IppsMontState* mont, IppsBigNumState* out, IppsBigNumState* one)
{
IppStatus ret;
ret = ippsMontForm(a, mont, a);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsMontForm error of %s\n", ippGetStatusString(ret)));
return ret;
}
/* a = a^b mod mont */
ret = ippsMontExp(a, b, mont, out);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsMontExp error of %s\n", ippGetStatusString(ret)));
return ret;
}
/* convert back from montgomery */
ret = ippsMontMul(out, one, mont, out);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsMontMul error of %s\n", ippGetStatusString(ret)));
return ret;
}
return ippStsNoErr;
}
static void Free_BN(IppsBigNumState* bn)
{
int sz, ctxSz;
IppStatus ret;
if (bn != NULL) {
ret = ippStsNoErr;
ret |= ippsGetSize_BN(bn, &sz);
ret |= ippsBigNumGetSize(sz, &ctxSz);
if (ret == ippStsNoErr) {
ForceZero(bn, ctxSz);
}
else {
USER_DEBUG(("Issue with clearing a struct in RsaSSL_Sign free\n"));
}
XFREE(bn, NULL, DYNAMIC_TYPE_USER_CRYPTO);
bn = NULL;
}
}
/* free up memory used during CRT sign operation */
static void FreeSignHelper(IppsBigNumState* one, IppsBigNumState* tmp,
IppsBigNumState* tmpP, IppsBigNumState* tmpQ, IppsBigNumState* tmpa,
IppsBigNumState* tmpb)
{
Free_BN(one);
Free_BN(tmp);
Free_BN(tmpP);
Free_BN(tmpQ);
Free_BN(tmpa);
Free_BN(tmpb);
}
/* for Rsa Sign */
int wc_RsaSSL_Sign(const byte* in, word32 inLen, byte* out, word32 outLen,
RsaKey* key, WC_RNG* rng)
{
int sz, pSz, qSz;
IppStatus ret;
word32 outSz = outLen;
IppsMontState* pMont = NULL;
IppsMontState* qMont = NULL;
IppsBigNumState* one = NULL;
IppsBigNumState* tmp = NULL;
IppsBigNumState* tmpP = NULL;
IppsBigNumState* tmpQ = NULL;
IppsBigNumState* tmpa = NULL;
IppsBigNumState* tmpb = NULL;
IppsBigNumSGN sa, sb;
Ipp8u o[1];
o[0] = 1;
USER_DEBUG(("Entering wc_RsaSSL_Sign\n"));
if (in == NULL || out == NULL || key == NULL || rng == NULL) {
USER_DEBUG(("Bad argument to wc_RsaSSL_Sign\n"));
return USER_CRYPTO_ERROR;
}
sz = key->sz;
/* sanity check on key being used */
if (key->pipp == NULL || key->qipp == NULL || key->uipp == NULL ||
key->dPipp == NULL || key->dQipp == NULL) {
USER_DEBUG(("Bad key argument to wc_RsaSSL_Sign\n"));
return USER_CRYPTO_ERROR;
}
if (sz > (int)outLen) {
USER_DEBUG(("Bad argument outLen to wc_RsaSSL_Sign\n"));
return USER_CRYPTO_ERROR;
}
if (sz < RSA_MIN_PAD_SZ) {
USER_DEBUG(("Key size is too small\n"));
return USER_CRYPTO_ERROR;
}
if (inLen > (word32)(sz - RSA_MIN_PAD_SZ)) {
USER_DEBUG(("Bad argument inLen to wc_RsaSSL_Sign\n"));
return USER_CRYPTO_ERROR;
}
/* Set up needed pkcs v15 padding */
if (wc_RsaPad(in, inLen, out, sz, RSA_BLOCK_TYPE_1, rng) != 0) {
USER_DEBUG(("RSA Padding error\n"));
return USER_CRYPTO_ERROR;
}
/* tmp = intput to sign */
ret = init_bn(&tmp, sz);
if (ret != ippStsNoErr) {
USER_DEBUG(("init_BN error of %s\n", ippGetStatusString(ret)));
FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
return USER_CRYPTO_ERROR;
}
ret = ippsSetOctString_BN(out, sz, tmp);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsSetOctString_BN error of %s\n",
ippGetStatusString(ret)));
FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
return USER_CRYPTO_ERROR;
}
/* tmpP = tmp mod p */
ret = init_bn(&tmpP, sz);
if (ret != ippStsNoErr) {
USER_DEBUG(("init_BN error of %s\n", ippGetStatusString(ret)));
FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
return USER_CRYPTO_ERROR;
}
/* tmpQ = tmp mod q */
ret = init_bn(&tmpQ, sz);
if (ret != ippStsNoErr) {
USER_DEBUG(("init_BN error of %s\n", ippGetStatusString(ret)));
FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
return USER_CRYPTO_ERROR;
}
/* tmpa */
ret = init_bn(&tmpa, sz);
if (ret != ippStsNoErr) {
USER_DEBUG(("init_BN error of %s\n", ippGetStatusString(ret)));
FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
return USER_CRYPTO_ERROR;
}
/* tmpb */
ret = init_bn(&tmpb, sz);
if (ret != ippStsNoErr) {
USER_DEBUG(("init_BN error of %s\n", ippGetStatusString(ret)));
FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
return USER_CRYPTO_ERROR;
}
/* one : used for conversion from Montgomery to classical */
ret = init_bn(&one, sz);
if (ret != ippStsNoErr) {
USER_DEBUG(("init_BN error of %s\n", ippGetStatusString(ret)));
FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
return USER_CRYPTO_ERROR;
}
ret = ippsSetOctString_BN(o, 1, one);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsSetOctString_BN error of %s\n",
ippGetStatusString(ret)));
FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
return USER_CRYPTO_ERROR;
}
/**
Set up Montgomery state
*/
ret = init_mont(&pMont, &pSz, key->pipp);
if (ret != ippStsNoErr) {
USER_DEBUG(("init_mont error of %s\n", ippGetStatusString(ret)));
if (pMont != NULL) {
XFREE(pMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
}
FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
return USER_CRYPTO_ERROR;
}
ret = init_mont(&qMont, &qSz, key->qipp);
if (ret != ippStsNoErr) {
USER_DEBUG(("init_mont error of %s\n", ippGetStatusString(ret)));
if (qMont != NULL) {
XFREE(qMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
}
ForceZero(pMont, pSz);
XFREE(pMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
return USER_CRYPTO_ERROR;
}
/**
Check and reduce input
This is needed for calls to MontExp since required value of a < modulus
*/
ret = reduce(tmp, key->pipp, tmpP);
if (ret != ippStsNoErr)
{
USER_DEBUG(("reduce error of %s\n", ippGetStatusString(ret)));
ForceZero(pMont, pSz);
ForceZero(qMont, qSz);
XFREE(qMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
XFREE(pMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
return USER_CRYPTO_ERROR;
}
ret = reduce(tmp, key->qipp, tmpQ);
if (ret != ippStsNoErr)
{
USER_DEBUG(("reduce error of %s\n", ippGetStatusString(ret)));
ForceZero(pMont, pSz);
ForceZero(qMont, qSz);
XFREE(qMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
XFREE(pMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
return USER_CRYPTO_ERROR;
}
/* tmpa = (tmp mod p)^dP mod p */
ret = exptmod(tmpP, key->dPipp, pMont, tmpa, one);
if (ret != ippStsNoErr) {
USER_DEBUG(("exptmod error of %s\n", ippGetStatusString(ret)));
ForceZero(pMont, pSz);
ForceZero(qMont, qSz);
XFREE(qMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
XFREE(pMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
return USER_CRYPTO_ERROR;
}
/* tmpb = (tmp mod q)^dQ mod q */
ret = exptmod(tmpQ, key->dQipp, qMont, tmpb, one);
if (ret != ippStsNoErr) {
USER_DEBUG(("exptmod error of %s\n", ippGetStatusString(ret)));
ForceZero(pMont, pSz);
ForceZero(qMont, qSz);
XFREE(qMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
XFREE(pMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
return USER_CRYPTO_ERROR;
}
/* tmp = (tmpa - tmpb) * qInv (mod p) */
ret = ippsSub_BN(tmpa, tmpb, tmp);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsSub_BN error of %s\n", ippGetStatusString(ret)));
ForceZero(pMont, pSz);
ForceZero(qMont, qSz);
XFREE(qMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
XFREE(pMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
return USER_CRYPTO_ERROR;
}
ret = ippsMul_BN(tmp, key->uipp, tmp);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsMul_BN error of %s\n", ippGetStatusString(ret)));
ForceZero(pMont, pSz);
ForceZero(qMont, qSz);
XFREE(qMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
XFREE(pMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
return USER_CRYPTO_ERROR;
}
/* mod performed the same was as wolfSSL fp_mod -- tmpa is just scratch */
ret = ippsDiv_BN(tmp, key->pipp, tmpa, tmp);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsDiv_BN error of %s\n", ippGetStatusString(ret)));
ForceZero(pMont, pSz);
ForceZero(qMont, qSz);
XFREE(qMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
XFREE(pMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
return USER_CRYPTO_ERROR;
}
/* Check sign of values and perform conditional add */
ret = ippsExtGet_BN(&sa, NULL, NULL, tmp);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsExtGet_BN error of %s\n", ippGetStatusString(ret)));
ForceZero(pMont, pSz);
ForceZero(qMont, qSz);
XFREE(qMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
XFREE(pMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
return USER_CRYPTO_ERROR;
}
ret = ippsExtGet_BN(&sb, NULL, NULL, key->pipp);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsExtGet_BN error of %s\n", ippGetStatusString(ret)));
ForceZero(pMont, pSz);
ForceZero(qMont, qSz);
XFREE(qMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
XFREE(pMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
return USER_CRYPTO_ERROR;
}
if (sa != sb) {
ret = ippsAdd_BN(tmp, key->pipp, tmp);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsAdd_BN error of %s\n", ippGetStatusString(ret)));
ForceZero(pMont, pSz);
ForceZero(qMont, qSz);
XFREE(qMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
XFREE(pMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
return USER_CRYPTO_ERROR;
}
}
/* tmp = tmpb + q * tmp */
ret = ippsMul_BN(tmp, key->qipp, tmp);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsSub_BN error of %s\n", ippGetStatusString(ret)));
ForceZero(pMont, pSz);
ForceZero(qMont, qSz);
XFREE(qMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
XFREE(pMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
return USER_CRYPTO_ERROR;
}
ret = ippsAdd_BN(tmp, tmpb, tmp);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsSub_BN error of %s\n", ippGetStatusString(ret)));
ForceZero(pMont, pSz);
ForceZero(qMont, qSz);
XFREE(qMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
XFREE(pMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
return USER_CRYPTO_ERROR;
}
/* Extract the output */
ret = ippsGetOctString_BN(out, sz, tmp);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsGetOctString_BN error of %s\n",
ippGetStatusString(ret)));
ForceZero(pMont, pSz);
ForceZero(qMont, qSz);
XFREE(qMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
XFREE(pMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
return USER_CRYPTO_ERROR;
}
outSz = sz;
/* clear memory and free */
ForceZero(pMont, pSz);
ForceZero(qMont, qSz);
XFREE(qMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
XFREE(pMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
return outSz;
}
int wc_RsaEncryptSize(RsaKey* key)
{
if (key == NULL)
return 0;
return key->sz;
}
/* flatten RsaKey structure into individual elements (e, n) */
int wc_RsaFlattenPublicKey(RsaKey* key, byte* e, word32* eSz, byte* n,
word32* nSz)
{
int sz, bytSz;
IppStatus ret;
USER_DEBUG(("Entering wc_RsaFlattenPublicKey\n"));
if (key == NULL || e == NULL || eSz == NULL || n == NULL || nSz == NULL)
return USER_CRYPTO_ERROR;
bytSz = sizeof(byte) * 8;
ret = ippsExtGet_BN(NULL, &sz, NULL, key->e);
if (ret != ippStsNoErr)
return USER_CRYPTO_ERROR;
/* sz is in bits change to bytes */
sz = (sz / bytSz) + ((sz % bytSz)? 1 : 0);
if (*eSz < (word32)sz)
return USER_CRYPTO_ERROR;
ret = ippsGetOctString_BN(e, sz, key->e);
if (ret != ippStsNoErr)
return USER_CRYPTO_ERROR;
*eSz = (word32)sz;
/* flatten n */
ret = ippsExtGet_BN(NULL, &sz, NULL, key->n);
if (ret != ippStsNoErr)
return USER_CRYPTO_ERROR;
/* sz is in bits change to bytes */
sz = (sz / bytSz) + ((sz % bytSz)? 1: 0);
if (*nSz < (word32)sz)
return USER_CRYPTO_ERROR;
ret = ippsGetOctString_BN(n, sz, key->n);
if (ret != ippStsNoErr)
return USER_CRYPTO_ERROR;
*nSz = (word32)sz;
return 0;
}
IppStatus wolfSSL_rng(Ipp32u* pData, int nBits, void* pEbsParams);
IppStatus wolfSSL_rng(Ipp32u* pData, int nBits, void* pEbsParams)
{
int nBytes;
if (pData == NULL) {
USER_DEBUG(("error with wolfSSL_rng argument\n"));
return ippStsErr;
}
nBytes = (nBits/8) + ((nBits % 8)? 1: 0);
if (wc_RNG_GenerateBlock((WC_RNG*)pEbsParams, (byte*)pData, nBytes) != 0) {
USER_DEBUG(("error in generating random wolfSSL block\n"));
return ippStsErr;
}
return ippStsNoErr;
}
#ifdef WOLFSSL_KEY_GEN
/* Make an RSA key for size bits, with e specified, 65537 is a good e */
int wc_MakeRsaKey(RsaKey* key, int size, long e, WC_RNG* rng)
{
IppStatus ret;
int scratchSz;
int i; /* for trys on calling make key */
int ctxSz;
IppsBigNumState* pSrcPublicExp = NULL;
Ipp8u* scratchBuffer = NULL;
Ipp8u eAry[8];
int trys = 8; /* Miller-Rabin test parameter */
IppsPrimeState* pPrime = NULL;
int qBitSz; /* size of q factor */
int bytSz; /* size of key in bytes */
int leng;
USER_DEBUG(("Entering wc_MakeRsaKey\n"));
/* get byte size and individual private key size -- round up */
qBitSz = (size / 2) + ((size % 2)? 1: 0);
bytSz = (size / 8) + ((size % 8)? 1: 0);
if (key == NULL || rng == NULL) {
USER_DEBUG(("Error, NULL argument passed in\n"));
return USER_CRYPTO_ERROR;
}
if (e < 3 || (e&1) == 0)
return USER_CRYPTO_ERROR;
if (size > RSA_MAX_SIZE || size < RSA_MIN_SIZE)
return USER_CRYPTO_ERROR;
key->type = RSA_PRIVATE;
key->sz = bytSz;
/* initialize prime number */
ret = ippsPrimeGetSize(size, &ctxSz); /* size in bits */
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsPrimeGetSize error of %s\n", ippGetStatusString(ret)));
ret = USER_CRYPTO_ERROR;
goto makeKeyEnd;
}
pPrime = (IppsPrimeState*)XMALLOC(ctxSz, NULL, DYNAMIC_TYPE_USER_CRYPTO);
if (pPrime == NULL) {
ret = USER_CRYPTO_ERROR;
goto makeKeyEnd;
}
ret = ippsPrimeInit(size, pPrime);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsPrimeInit error of %s\n", ippGetStatusString(ret)));
ret = USER_CRYPTO_ERROR;
goto makeKeyEnd;
}
/* define RSA privete key type 2 */
/* length in bits of p and q factors */
ret = ippsRSA_GetSizePrivateKeyType2(qBitSz, qBitSz, &ctxSz);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsRSA_GetSizePrivateKeyType2 error of %s\n",
ippGetStatusString(ret)));
ret = USER_CRYPTO_ERROR;
goto makeKeyEnd;
}
key->prvSz = ctxSz; /* used when freeing private key */
key->pPrv = (IppsRSAPrivateKeyState*)XMALLOC(ctxSz, NULL,
DYNAMIC_TYPE_USER_CRYPTO);
if (key->pPrv == NULL) {
ret = USER_CRYPTO_ERROR;
goto makeKeyEnd;
}
/* length in bits of p and q factors */
ret = ippsRSA_InitPrivateKeyType2(qBitSz, qBitSz, key->pPrv, ctxSz);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsRSA_InitPrivateKeyType2 error of %s\n",
ippGetStatusString(ret)));
ret = USER_CRYPTO_ERROR;
goto makeKeyEnd;
}
/* allocate scratch buffer */
ret = ippsRSA_GetBufferSizePrivateKey(&scratchSz, key->pPrv);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsRSA_GetBufferSizePrivateKey error of %s\n",
ippGetStatusString(ret)));
ret = USER_CRYPTO_ERROR;
goto makeKeyEnd;
}
scratchBuffer = (Ipp8u*)XMALLOC(scratchSz, 0, DYNAMIC_TYPE_USER_CRYPTO);
if (scratchBuffer == NULL) {
ret = USER_CRYPTO_ERROR;
goto makeKeyEnd;
}
/* set up initial value of pScrPublicExp */
leng = (int)sizeof(long); /* # of Ipp32u in long */
/* place the value of e into the array eAry then load into BN */
for (i = 0; i < leng; i++) {
eAry[i] = (e >> (8 * (leng - 1 - i))) & 0XFF;
}
ret = init_bn(&pSrcPublicExp, leng);
if (ret != ippStsNoErr) {
ret = USER_CRYPTO_ERROR;
goto makeKeyEnd;
}
ret = ippsSetOctString_BN(eAry, leng, pSrcPublicExp);
if (ret != ippStsNoErr) {
ret = USER_CRYPTO_ERROR;
goto makeKeyEnd;
}
/* initializing key->n */
ret = init_bn(&key->n, bytSz);
if (ret != ippStsNoErr) {
ret = USER_CRYPTO_ERROR;
goto makeKeyEnd;
}
/* initializing public exponent key->e */
ret = init_bn(&key->e, leng);
if (ret != ippStsNoErr) {
ret = USER_CRYPTO_ERROR;
goto makeKeyEnd;
}
/* private exponent key->dipp */
ret = init_bn(&key->dipp, bytSz);
if (ret != ippStsNoErr) {
ret = USER_CRYPTO_ERROR;
goto makeKeyEnd;
}
/* call IPP to generate keys, if inseficent entropy error call again */
ret = ippStsInsufficientEntropy;
while (ret == ippStsInsufficientEntropy) {
ret = ippsRSA_GenerateKeys(pSrcPublicExp, key->n, key->e,
key->dipp, key->pPrv, scratchBuffer, trys, pPrime,
wolfSSL_rng, rng);
if (ret == ippStsNoErr) {
break;
}
/* catch all errors other than entropy error */
if (ret != ippStsInsufficientEntropy) {
USER_DEBUG(("ippsRSA_GeneratKeys error of %s\n",
ippGetStatusString(ret)));
ret = USER_CRYPTO_ERROR;
goto makeKeyEnd;
}
}
/* get bn sizes needed for private key set up */
ret = ippsExtGet_BN(NULL, &key->eSz, NULL, key->e);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsGetSize_BN error %s\n", ippGetStatusString(ret)));
ret = USER_CRYPTO_ERROR;
goto makeKeyEnd;
}
ret = ippsExtGet_BN(NULL, &key->nSz, NULL, key->n);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsGetSize_BN error %s\n", ippGetStatusString(ret)));
ret = USER_CRYPTO_ERROR;
goto makeKeyEnd;
}
/* set up public key state */
ret = ippsRSA_GetSizePublicKey(key->nSz, key->eSz, &ctxSz);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsRSA_GetSizePublicKey error %s nSz = %d eSz = %d\n",
ippGetStatusString(ret), key->nSz, key->eSz));
ret = USER_CRYPTO_ERROR;
goto makeKeyEnd;
}
key->pPub = (IppsRSAPublicKeyState*)XMALLOC(ctxSz, NULL,
DYNAMIC_TYPE_USER_CRYPTO);
if (key->pPub == NULL) {
ret = USER_CRYPTO_ERROR;
goto makeKeyEnd;
}
ret = ippsRSA_InitPublicKey(key->nSz, key->eSz, key->pPub, ctxSz);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsRSA_InitPublicKey error %s\n",
ippGetStatusString(ret)));
ret = USER_CRYPTO_ERROR;
goto makeKeyEnd;
}
ret = ippsRSA_SetPublicKey(key->n, key->e, key->pPub);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsRSA_SetPublicKey error %s\n",
ippGetStatusString(ret)));
ret = USER_CRYPTO_ERROR;
goto makeKeyEnd;
}
/* get private key information for key struct */
leng = size/16; /* size of q, p, u, dP, dQ */
ret = init_bn(&key->pipp, leng);
if (ret != ippStsNoErr) {
ret = USER_CRYPTO_ERROR;
goto makeKeyEnd;
}
/* set up q BN for key */
ret = init_bn(&key->qipp, leng);
if (ret != ippStsNoErr) {
ret = USER_CRYPTO_ERROR;
goto makeKeyEnd;
}
/* set up dP BN for key */
ret = init_bn(&key->dPipp, leng);
if (ret != ippStsNoErr) {
ret = USER_CRYPTO_ERROR;
goto makeKeyEnd;
}
/* set up dQ BN for key */
ret = init_bn(&key->dQipp, leng);
if (ret != ippStsNoErr) {
ret = USER_CRYPTO_ERROR;
goto makeKeyEnd;
}
/* set up u BN for key */
ret = init_bn(&key->uipp, leng);
if (ret != ippStsNoErr) {
ret = USER_CRYPTO_ERROR;
goto makeKeyEnd;
}
/* get values from created key */
ret = ippsRSA_GetPrivateKeyType2(key->pipp, key->qipp, key->dPipp,
key->dQipp, key->uipp, key->pPrv);
if (ret != ippStsNoErr) {
USER_DEBUG(("ippsRSA_GetPrivateKeyType2 error %s\n",
ippGetStatusString(ret)));
ret = USER_CRYPTO_ERROR;
goto makeKeyEnd;
}
ret = 0; /* success case */
makeKeyEnd:
/* clean up memory used */
XFREE(pSrcPublicExp, NULL, DYNAMIC_TYPE_USER_CRYPTO);
XFREE(scratchBuffer, NULL, DYNAMIC_TYPE_USER_CRYPTO);
XFREE(pPrime, NULL, DYNAMIC_TYPE_USER_CRYPTO);
if (ret != 0) { /* with fail case free RSA components created */
wc_FreeRsaKey(key);
}
return ret;
}
/********** duplicate code needed -- future refactor */
#define MAX_VERSION_SZ 5
#define MAX_SEQ_SZ 5
#define ASN_CONTEXT_SPECIFIC 0x80
#define ASN_CONSTRUCTED 0x20
#define ASN_LONG_LENGTH 0x80
#define ASN_SEQUENCE 0x10
#define RSA_INTS 8
#define FALSE 0
#define TRUE 1
#define MAX_LENGTH_SZ 4
#define RSAk 645
#define keyType 2
#define MAX_RSA_INT_SZ 517
#define MAX_RSA_E_SZ 16
#define MAX_ALGO_SZ 20
static word32 BytePrecision(word32 value)
{
word32 i;
for (i = sizeof(value); i; --i)
if (value >> ((i - 1) * WOLFSSL_BIT_SIZE))
break;
return i;
}
static int SetMyVersion(word32 version, byte* output, int header)
{
int i = 0;
if (output == NULL)
return USER_CRYPTO_ERROR;
if (header) {
output[i++] = ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED;
output[i++] = ASN_BIT_STRING;
}
output[i++] = ASN_INTEGER;
output[i++] = 0x01;
output[i++] = (byte)version;
return i;
}
static word32 SetLength(word32 length, byte* output)
{
word32 i = 0, j;
if (length < 0x80)
output[i++] = (byte)length;
else {
output[i++] = (byte)(BytePrecision(length) | ASN_LONG_LENGTH);
for (j = BytePrecision(length); j; --j) {
output[i] = (byte)(length >> ((j - 1) * WOLFSSL_BIT_SIZE));
i++;
}
}
return i;
}
static word32 SetSequence(word32 len, byte* output)
{
output[0] = ASN_SEQUENCE | ASN_CONSTRUCTED;
return SetLength(len, output + 1) + 1;
}
static word32 SetAlgoID(int algoOID, byte* output, int type, int curveSz)
{
/* adding TAG_NULL and 0 to end */
/* RSA keyType */
#ifndef NO_RSA
static const byte RSA_AlgoID[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
0x01, 0x01, 0x01, 0x05, 0x00};
#endif /* NO_RSA */
int algoSz = 0;
int tagSz = 2; /* tag null and terminator */
word32 idSz, seqSz;
const byte* algoName = 0;
byte ID_Length[MAX_LENGTH_SZ];
byte seqArray[MAX_SEQ_SZ + 1]; /* add object_id to end */
if (type == keyType) { /* keyType */
switch (algoOID) {
#ifndef NO_RSA
case RSAk:
algoSz = sizeof(RSA_AlgoID);
algoName = RSA_AlgoID;
break;
#endif /* NO_RSA */
default:
/* unknown key algo */
return 0;
}
}
else {
/* unknown algo type */
return 0;
}
idSz = SetLength(algoSz - tagSz, ID_Length); /* don't include tags */
seqSz = SetSequence(idSz + algoSz + 1 + curveSz, seqArray);
/* +1 for object id, curveID of curveSz follows for ecc */
seqArray[seqSz++] = ASN_OBJECT_ID;
XMEMCPY(output, seqArray, seqSz);
XMEMCPY(output + seqSz, ID_Length, idSz);
XMEMCPY(output + seqSz + idSz, algoName, algoSz);
return seqSz + idSz + algoSz;
}
/* Write a public RSA key to output */
static int SetRsaPublicKey(byte* output, RsaKey* key,
int outLen, int with_header)
{
#ifdef WOLFSSL_SMALL_STACK
byte* n = NULL;
byte* e = NULL;
#else
byte n[MAX_RSA_INT_SZ];
byte e[MAX_RSA_E_SZ];
#endif
byte seq[MAX_SEQ_SZ];
byte len[MAX_LENGTH_SZ + 1]; /* trailing 0 */
int nSz;
int eSz;
int seqSz;
int lenSz;
int idx;
int rawLen;
int leadingBit;
int err;
if (output == NULL || key == NULL || outLen < MAX_SEQ_SZ)
return USER_CRYPTO_ERROR;
/* n */
#ifdef WOLFSSL_SMALL_STACK
n = (byte*)XMALLOC(MAX_RSA_INT_SZ, NULL, DYNAMIC_TYPE_USER_CRYPTO);
if (n == NULL)
return USER_CRYPTO_ERROR;
#endif
leadingBit = wc_Rsa_leading_bit(key->n);
rawLen = wc_Rsa_unsigned_bin_size(key->n);
if ((int)rawLen < 0) {
return USER_CRYPTO_ERROR;
}
rawLen = rawLen + leadingBit;
n[0] = ASN_INTEGER;
nSz = SetLength(rawLen, n + 1) + 1; /* int tag */
if ( (nSz + rawLen) < MAX_RSA_INT_SZ) {
if (leadingBit)
n[nSz] = 0;
err = ippsGetOctString_BN((Ipp8u*)n + nSz, rawLen - leadingBit, key->n);
if (err == ippStsNoErr)
nSz += rawLen;
else {
#ifdef WOLFSSL_SMALL_STACK
XFREE(n, NULL, DYNAMIC_TYPE_USER_CRYPTO);
#endif
return USER_CRYPTO_ERROR;
}
}
else {
#ifdef WOLFSSL_SMALL_STACK
XFREE(n, NULL, DYNAMIC_TYPE_USER_CRYPTO);
#endif
return USER_CRYPTO_ERROR;
}
/* e */
#ifdef WOLFSSL_SMALL_STACK
e = (byte*)XMALLOC(MAX_RSA_E_SZ, NULL, DYNAMIC_TYPE_USER_CRYPTO);
if (e == NULL) {
#ifdef WOLFSSL_SMALL_STACK
XFREE(n, NULL, DYNAMIC_TYPE_USER_CRYPTO);
#endif
return USER_CRYPTO_ERROR;
}
#endif
leadingBit = wc_Rsa_leading_bit(key->e);
rawLen = wc_Rsa_unsigned_bin_size(key->e);
if ((int)rawLen < 0) {
return USER_CRYPTO_ERROR;
}
rawLen = rawLen + leadingBit;
e[0] = ASN_INTEGER;
eSz = SetLength(rawLen, e + 1) + 1; /* int tag */
if ( (eSz + rawLen) < MAX_RSA_E_SZ) {
if (leadingBit)
e[eSz] = 0;
err = ippsGetOctString_BN((Ipp8u*)e + eSz, rawLen - leadingBit, key->e);
if (err == ippStsNoErr)
eSz += rawLen;
else {
#ifdef WOLFSSL_SMALL_STACK
XFREE(n, NULL, DYNAMIC_TYPE_USER_CRYPTO);
XFREE(e, NULL, DYNAMIC_TYPE_USER_CRYPTO);
#endif
return USER_CRYPTO_ERROR;
}
}
else {
#ifdef WOLFSSL_SMALL_STACK
XFREE(n, NULL, DYNAMIC_TYPE_USER_CRYPTO);
XFREE(e, NULL, DYNAMIC_TYPE_USER_CRYPTO);
#endif
return USER_CRYPTO_ERROR;
}
seqSz = SetSequence(nSz + eSz, seq);
/* check output size */
if ( (seqSz + nSz + eSz) > outLen) {
#ifdef WOLFSSL_SMALL_STACK
XFREE(n, NULL, DYNAMIC_TYPE_USER_CRYPTO);
XFREE(e, NULL, DYNAMIC_TYPE_USER_CRYPTO);
#endif
return USER_CRYPTO_ERROR;
}
/* headers */
if (with_header) {
int algoSz;
#ifdef WOLFSSL_SMALL_STACK
byte* algo = NULL;
algo = (byte*)XMALLOC(MAX_ALGO_SZ, NULL, DYNAMIC_TYPE_USER_CRYPTO);
if (algo == NULL) {
XFREE(n, NULL, DYNAMIC_TYPE_USER_CRYPTO);
XFREE(e, NULL, DYNAMIC_TYPE_USER_CRYPTO);
return USER_CRYPTO_ERROR;
}
#else
byte algo[MAX_ALGO_SZ];
#endif
algoSz = SetAlgoID(RSAk, algo, keyType, 0);
lenSz = SetLength(seqSz + nSz + eSz + 1, len);
len[lenSz++] = 0; /* trailing 0 */
/* write, 1 is for ASN_BIT_STRING */
idx = SetSequence(nSz + eSz + seqSz + lenSz + 1 + algoSz, output);
/* check output size */
if ( (idx + algoSz + 1 + lenSz + seqSz + nSz + eSz) > outLen) {
#ifdef WOLFSSL_SMALL_STACK
XFREE(n, NULL, DYNAMIC_TYPE_USER_CRYPTO);
XFREE(e, NULL, DYNAMIC_TYPE_USER_CRYPTO);
XFREE(algo, NULL, DYNAMIC_TYPE_USER_CRYPTO);
#endif
return USER_CRYPTO_ERROR;
}
/* algo */
XMEMCPY(output + idx, algo, algoSz);
idx += algoSz;
/* bit string */
output[idx++] = ASN_BIT_STRING;
/* length */
XMEMCPY(output + idx, len, lenSz);
idx += lenSz;
#ifdef WOLFSSL_SMALL_STACK
XFREE(algo, NULL, DYNAMIC_TYPE_USER_CRYPTO);
#endif
}
else
idx = 0;
/* seq */
XMEMCPY(output + idx, seq, seqSz);
idx += seqSz;
/* n */
XMEMCPY(output + idx, n, nSz);
idx += nSz;
/* e */
XMEMCPY(output + idx, e, eSz);
idx += eSz;
#ifdef WOLFSSL_SMALL_STACK
XFREE(n, NULL, DYNAMIC_TYPE_USER_CRYPTO);
XFREE(e, NULL, DYNAMIC_TYPE_USER_CRYPTO);
#endif
return idx;
}
static IppsBigNumState* GetRsaInt(RsaKey* key, int idx)
{
if (idx == 0)
return key->n;
if (idx == 1)
return key->e;
if (idx == 2)
return key->dipp;
if (idx == 3)
return key->pipp;
if (idx == 4)
return key->qipp;
if (idx == 5)
return key->dPipp;
if (idx == 6)
return key->dQipp;
if (idx == 7)
return key->uipp;
return NULL;
}
/* Release Tmp RSA resources */
static INLINE void FreeTmpRsas(byte** tmps, void* heap)
{
int i;
(void)heap;
for (i = 0; i < RSA_INTS; i++)
XFREE(tmps[i], heap, DYNAMIC_TYPE_USER_CRYPTO);
}
/* Convert RsaKey key to DER format, write to output (inLen), return bytes
written */
int wc_RsaKeyToDer(RsaKey* key, byte* output, word32 inLen)
{
word32 seqSz, verSz, rawLen, intTotalLen = 0;
word32 sizes[RSA_INTS];
int i, j, outLen, ret = 0, lbit;
byte seq[MAX_SEQ_SZ];
byte ver[MAX_VERSION_SZ];
byte* tmps[RSA_INTS];
USER_DEBUG(("Entering RsaKeyToDer\n"));
if (!key || !output)
return USER_CRYPTO_ERROR;
if (key->type != RSA_PRIVATE)
return USER_CRYPTO_ERROR;
for (i = 0; i < RSA_INTS; i++)
tmps[i] = NULL;
/* write all big ints from key to DER tmps */
for (i = 0; i < RSA_INTS; i++) {
Ipp32u isZero;
IppsBigNumState* keyInt = GetRsaInt(key, i);
ippsCmpZero_BN(keyInt, &isZero); /* makes isZero 0 if true */
rawLen = wc_Rsa_unsigned_bin_size(keyInt);
if ((int)rawLen < 0) {
return USER_CRYPTO_ERROR;
}
/* leading zero */
if (!isZero || wc_Rsa_leading_bit(keyInt))
lbit = 1;
else
lbit = 0;
rawLen += lbit;
tmps[i] = (byte*)XMALLOC(rawLen + MAX_SEQ_SZ, key->heap,
DYNAMIC_TYPE_USER_CRYPTO);
if (tmps[i] == NULL) {
ret = USER_CRYPTO_ERROR;
break;
}
tmps[i][0] = ASN_INTEGER;
sizes[i] = SetLength(rawLen, tmps[i] + 1) + 1 + lbit; /* tag & lbit */
if (sizes[i] <= MAX_SEQ_SZ) {
int err;
/* leading zero */
if (lbit)
tmps[i][sizes[i]-1] = 0x00;
/* extract data*/
err = ippsGetOctString_BN((Ipp8u*)(tmps[i] + sizes[i]),
rawLen - lbit, keyInt);
if (err == ippStsOk) {
sizes[i] += (rawLen-lbit); /* lbit included in rawLen */
intTotalLen += sizes[i];
ret = 0;
}
else {
ret = USER_CRYPTO_ERROR;
USER_DEBUG(("ippsGetOctString_BN error %s\n",
ippGetStatusString(err)));
break;
}
}
else {
ret = USER_CRYPTO_ERROR;
break;
}
}
if (ret != 0) {
FreeTmpRsas(tmps, key->heap);
return ret;
}
/* make headers */
verSz = SetMyVersion(0, ver, FALSE);
seqSz = SetSequence(verSz + intTotalLen, seq);
outLen = seqSz + verSz + intTotalLen;
if (outLen > (int)inLen) {
return USER_CRYPTO_ERROR;
}
/* write to output */
XMEMCPY(output, seq, seqSz);
j = seqSz;
XMEMCPY(output + j, ver, verSz);
j += verSz;
for (i = 0; i < RSA_INTS; i++) {
XMEMCPY(output + j, tmps[i], sizes[i]);
j += sizes[i];
}
FreeTmpRsas(tmps, key->heap);
return outLen;
}
/* Convert Rsa Public key to DER format, write to output (inLen), return bytes
written
*/
int wc_RsaKeyToPublicDer(RsaKey* key, byte* output, word32 inLen)
{
return SetRsaPublicKey(output, key, inLen, 1);
}
#endif /* WOLFSSL_KEY_GEN */
#ifdef WC_RSA_BLINDING
int wc_RsaSetRNG(RsaKey* key, WC_RNG* rng)
{
if (key == NULL)
return USER_CRYPTO_ERROR;
(void)rng;
return 0;
}
#endif /* WC_RSA_BLINDING */
#endif /* NO_RSA */