/* rsa.c * * Copyright (C) 2006-2021 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 #endif #include #include #ifndef NO_RSA #define USER_CRYPTO_ERROR -101 #ifdef OPENSSL_EXTRA #include /* include for openssl compatibility */ #include #endif #include "user_rsa.h" #ifdef DEBUG_WOLFSSL /* debug done without variadric to allow older compilers */ #include #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 /* separator + 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) || defined(OPENSSL_EXTRA) /* 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 success */ 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 || WOLFSSL_KEY_GEN || OPENSSL_EXTRA */ #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 (key->type == RSA_PRIVATE) { 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 outputted padded msg pkcsBlockLen : length of outputted 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 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 sensitive 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 GetASNHeader(const byte* input, byte tag, word32* inOutIdx, int* len, word32 maxIdx) { word32 idx = *inOutIdx; byte b; int length; if ((idx + 1) > maxIdx) return USER_CRYPTO_ERROR; b = input[idx++]; if (b != tag) return USER_CRYPTO_ERROR; if (GetLength(input, &idx, &length, maxIdx) < 0) return USER_CRYPTO_ERROR; *len = length; *inOutIdx = idx; return length; } static int GetASNInt(const byte* input, word32* inOutIdx, int* len, word32 maxIdx) { int ret; ret = GetASNHeader(input, ASN_INTEGER, inOutIdx, len, maxIdx); if (ret < 0) return ret; if (*len > 0) { /* remove leading zero, unless there is only one 0x00 byte */ if ((input[*inOutIdx] == 0x00) && (*len > 1)) { (*inOutIdx)++; (*len)--; if (*len > 0 && (input[*inOutIdx] & 0x80) == 0) return USER_CRYPTO_ERROR; } } return 0; } static int GetInt(IppsBigNumState** mpi, const byte* input, word32* inOutIdx, word32 maxIdx) { IppStatus ret; word32 idx = *inOutIdx; int length; int ctxSz; if (GetASNInt(input, &idx, &length, maxIdx) < 0) { return USER_CRYPTO_ERROR; } 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; } int wc_RsaPublicKeyDecode_ex(const byte* input, word32* inOutIdx, word32 inSz, const byte** n, word32* nSz, const byte** e, word32* eSz) { IppStatus ret = 0; int length; #if defined(OPENSSL_EXTRA) || defined(RSA_DECODE_EXTRA) byte b; #endif if (input == NULL || inOutIdx == NULL) { return USER_CRYPTO_ERROR; } USER_DEBUG(("Entering wc_RsaPublicKeyDecode_ex\n")); if (GetSequence(input, inOutIdx, &length, inSz) < 0) return USER_CRYPTO_ERROR; #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 */ /* Get modulus */ ret = GetASNInt(input, inOutIdx, &length, inSz); if (ret < 0) { return USER_CRYPTO_ERROR; } if (nSz) *nSz = length; if (n) *n = &input[*inOutIdx]; *inOutIdx += length; /* Get exponent */ ret = GetASNInt(input, inOutIdx, &length, inSz); if (ret < 0) { return USER_CRYPTO_ERROR; } if (eSz) *eSz = length; if (e) *e = &input[*inOutIdx]; *inOutIdx += length; USER_DEBUG(("\tExit wc_RsaPublicKeyDecode_ex\n")); return ret; } /* read in a public RSA key */ int wc_RsaPublicKeyDecode(const byte* input, word32* inOutIdx, RsaKey* key, word32 inSz) { IppStatus ret; const byte *n = NULL, *e = NULL; word32 nSz = 0, eSz = 0; if (key == NULL) return USER_CRYPTO_ERROR; USER_DEBUG(("Entering wc_RsaPublicKeyDecode\n")); ret = wc_RsaPublicKeyDecode_ex(input, inOutIdx, inSz, &n, &nSz, &e, &eSz); if (ret == 0) { ret = wc_RsaPublicKeyDecodeRaw(n, nSz, e, eSz, key); } USER_DEBUG(("\tExit RsaPublicKeyDecode\n")); return ret; } /* 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 octet 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); } } /* 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; 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 = input 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; } #endif #if defined(WOLFSSL_KEY_GEN) || defined(OPENSSL_EXTRA) /********** 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; 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 WC_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) 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 (output) { 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); } /* Returns public DER version of the RSA key. If with_header is 0 then only a * seq + n + e is returned in ASN.1 DER format */ int wc_RsaKeyToPublicDer_ex(RsaKey* key, byte* output, word32 inLen, int with_header) { return SetRsaPublicKey(output, key, inLen, with_header); } #endif /* WOLFSSL_KEY_GEN || OPENSSL_EXTRA */ #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 */