#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
#if !defined(WOLFSSL_EVP_PK_INCLUDED)
#ifndef WOLFSSL_IGNORE_FILE_WARN
#warning evp_pk.c does not need to be compiled separately from ssl.c
#endif
#elif defined(WOLFCRYPT_ONLY)
#else
#ifndef NO_CERTS
#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL)
static int d2i_make_pkey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem,
word32 memSz, int priv, int type)
{
WOLFSSL_EVP_PKEY* pkey;
int ret = 1;
if (*out != NULL) {
pkey = *out;
}
else {
pkey = wolfSSL_EVP_PKEY_new();
if (pkey == NULL) {
WOLFSSL_MSG("wolfSSL_EVP_PKEY_new error");
return 0;
}
}
pkey->pkey_sz = (int)memSz;
if (memSz > 0) {
pkey->pkey.ptr = (char*)XMALLOC((size_t)memSz, NULL,
priv ? DYNAMIC_TYPE_PRIVATE_KEY : DYNAMIC_TYPE_PUBLIC_KEY);
if (pkey->pkey.ptr == NULL) {
ret = 0;
}
if (ret == 1) {
XMEMCPY(pkey->pkey.ptr, mem, memSz);
}
}
if (ret == 1) {
pkey->type = type;
*out = pkey;
}
if ((ret == 0) && (*out == NULL)) {
wolfSSL_EVP_PKEY_free(pkey);
}
return ret;
}
#if !defined(NO_RSA)
static int d2iTryRsaKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem,
long memSz, int priv)
{
WOLFSSL_RSA* rsaObj = NULL;
word32 keyIdx = 0;
int isRsaKey;
int ret = 1;
WC_DECLARE_VAR(rsa, RsaKey, 1, NULL);
WC_ALLOC_VAR_EX(rsa, RsaKey, 1, NULL, DYNAMIC_TYPE_RSA, return 0);
XMEMSET(rsa, 0, sizeof(RsaKey));
if (wc_InitRsaKey(rsa, NULL) != 0) {
WC_FREE_VAR_EX(rsa, NULL, DYNAMIC_TYPE_RSA);
return 0;
}
if (priv) {
isRsaKey =
(wc_RsaPrivateKeyDecode(mem, &keyIdx, rsa, (word32)memSz) == 0);
}
else {
isRsaKey =
(wc_RsaPublicKeyDecode(mem, &keyIdx, rsa, (word32)memSz) == 0);
}
wc_FreeRsaKey(rsa);
WC_FREE_VAR_EX(rsa, NULL, DYNAMIC_TYPE_RSA);
if (!isRsaKey) {
return WOLFSSL_FATAL_ERROR;
}
rsaObj = wolfssl_rsa_d2i(NULL, mem, keyIdx,
priv ? WOLFSSL_RSA_LOAD_PRIVATE : WOLFSSL_RSA_LOAD_PUBLIC);
if (rsaObj == NULL) {
ret = 0;
}
if (ret == 1) {
ret = d2i_make_pkey(out, mem, keyIdx, priv, WC_EVP_PKEY_RSA);
}
if (ret == 1) {
(*out)->ownRsa = 1;
(*out)->rsa = rsaObj;
}
if (ret == 0) {
wolfSSL_RSA_free(rsaObj);
}
return ret;
}
#endif
#if defined(HAVE_ECC) && defined(OPENSSL_EXTRA)
static int d2iTryEccKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem,
long memSz, int priv)
{
WOLFSSL_EC_KEY* ec = NULL;
word32 keyIdx = 0;
int isEccKey;
int ret = 1;
WC_DECLARE_VAR(ecc, ecc_key, 1, NULL);
WC_ALLOC_VAR_EX(ecc, ecc_key, 1, NULL, DYNAMIC_TYPE_ECC, return 0);
XMEMSET(ecc, 0, sizeof(ecc_key));
if (wc_ecc_init(ecc) != 0) {
WC_FREE_VAR_EX(ecc, NULL, DYNAMIC_TYPE_ECC);
return 0;
}
if (priv) {
isEccKey =
(wc_EccPrivateKeyDecode(mem, &keyIdx, ecc, (word32)memSz) == 0);
}
else {
isEccKey =
(wc_EccPublicKeyDecode(mem, &keyIdx, ecc, (word32)memSz) == 0);
}
wc_ecc_free(ecc);
WC_FREE_VAR_EX(ecc, NULL, DYNAMIC_TYPE_ECC);
if (!isEccKey) {
return WOLFSSL_FATAL_ERROR;
}
ec = wolfSSL_EC_KEY_new();
if (ec == NULL) {
ret = 0;
}
if ((ret == 1) && (wolfSSL_EC_KEY_LoadDer_ex(ec, mem, keyIdx,
priv ? WOLFSSL_RSA_LOAD_PRIVATE : WOLFSSL_RSA_LOAD_PUBLIC) != 1)) {
ret = 0;
}
if (ret == 1) {
ret = d2i_make_pkey(out, mem, keyIdx, priv, WC_EVP_PKEY_EC);
}
if (ret == 1) {
(*out)->ownEcc = 1;
(*out)->ecc = ec;
}
if (ret == 0) {
wolfSSL_EC_KEY_free(ec);
}
return ret;
}
#endif
#if !defined(NO_DSA)
static int d2iTryDsaKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem,
long memSz, int priv)
{
WOLFSSL_DSA* dsaObj;
word32 keyIdx = 0;
int isDsaKey;
int ret = 1;
WC_DECLARE_VAR(dsa, DsaKey, 1, NULL);
WC_ALLOC_VAR_EX(dsa, DsaKey, 1, NULL, DYNAMIC_TYPE_DSA, return 0);
XMEMSET(dsa, 0, sizeof(DsaKey));
if (wc_InitDsaKey(dsa) != 0) {
WC_FREE_VAR_EX(dsa, NULL, DYNAMIC_TYPE_DSA);
return 0;
}
if (priv) {
isDsaKey =
(wc_DsaPrivateKeyDecode(mem, &keyIdx, dsa, (word32)memSz) == 0);
}
else {
isDsaKey =
(wc_DsaPublicKeyDecode(mem, &keyIdx, dsa, (word32)memSz) == 0);
}
wc_FreeDsaKey(dsa);
WC_FREE_VAR_EX(dsa, NULL, DYNAMIC_TYPE_DSA);
if (!isDsaKey) {
return WOLFSSL_FATAL_ERROR;
}
dsaObj = wolfSSL_DSA_new();
if (dsaObj == NULL) {
ret = 0;
}
if ((ret == 1) && (wolfSSL_DSA_LoadDer_ex(dsaObj, mem, keyIdx,
priv ? WOLFSSL_RSA_LOAD_PRIVATE : WOLFSSL_RSA_LOAD_PUBLIC) != 1)) {
ret = 0;
}
if (ret == 1) {
ret = d2i_make_pkey(out, mem, keyIdx, priv, WC_EVP_PKEY_DSA);
}
if (ret == 1) {
(*out)->ownDsa = 1;
(*out)->dsa = dsaObj;
}
if (ret == 0) {
wolfSSL_DSA_free(dsaObj);
}
return ret;
}
#endif
#if !defined(NO_DH) && (defined(WOLFSSL_QT) || defined(OPENSSL_ALL))
#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \
(HAVE_FIPS_VERSION > 2))
static int d2iTryDhKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem,
long memSz, int priv)
{
WOLFSSL_DH* dhObj;
int isDhKey;
word32 keyIdx = 0;
int ret = 1;
WC_DECLARE_VAR(dh, DhKey, 1, NULL);
WC_ALLOC_VAR_EX(dh, DhKey, 1, NULL, DYNAMIC_TYPE_DH, return 0);
XMEMSET(dh, 0, sizeof(DhKey));
if (wc_InitDhKey(dh) != 0) {
WC_FREE_VAR_EX(dh, NULL, DYNAMIC_TYPE_DH);
return 0;
}
isDhKey = (wc_DhKeyDecode(mem, &keyIdx, dh, (word32)memSz) == 0);
wc_FreeDhKey(dh);
WC_FREE_VAR_EX(dh, NULL, DYNAMIC_TYPE_DH);
if (!isDhKey) {
return WOLFSSL_FATAL_ERROR;
}
dhObj = wolfSSL_DH_new();
if (dhObj == NULL) {
ret = 0;
}
if ((ret == 1) && (wolfSSL_DH_LoadDer(dhObj, mem, keyIdx) != 1)) {
ret = 0;
}
if (ret == 1) {
ret = d2i_make_pkey(out, mem, keyIdx, priv, WC_EVP_PKEY_DH);
}
if (ret == 1) {
(*out)->ownDh = 1;
(*out)->dh = dhObj;
}
if (ret == 0) {
wolfSSL_DH_free(dhObj);
}
return ret;
}
#endif
#endif
#if !defined(NO_DH) && defined(OPENSSL_EXTRA) && defined(WOLFSSL_DH_EXTRA)
#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \
(HAVE_FIPS_VERSION > 2))
static int d2iTryAltDhKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem,
long memSz, int priv)
{
WOLFSSL_DH* dhObj;
word32 keyIdx = 0;
DhKey* key = NULL;
int elements;
int ret = 1;
dhObj = wolfSSL_DH_new();
if (dhObj == NULL) {
return 0;
}
key = (DhKey*)dhObj->internal;
if (wc_DhKeyDecode(mem, &keyIdx, key, (word32)memSz) != 0) {
ret = 0;
}
if (ret == 1) {
elements = ELEMENT_P | ELEMENT_G | ELEMENT_Q | ELEMENT_PUB;
if (priv) {
elements |= ELEMENT_PRV;
}
if (SetDhExternal_ex(dhObj, elements) != WOLFSSL_SUCCESS ) {
ret = 0;
}
}
if (ret == 1) {
ret = d2i_make_pkey(out, mem, keyIdx, priv, WC_EVP_PKEY_DH);
}
if (ret == 1) {
(*out)->ownDh = 1;
(*out)->dh = dhObj;
}
if (ret == 0) {
wolfSSL_DH_free(dhObj);
}
return ret;
}
#endif
#endif
#ifdef HAVE_FALCON
static int d2i_falcon_priv_key_level(falcon_key* falcon, byte level,
const unsigned char* mem, long memSz)
{
return (wc_falcon_set_level(falcon, level) == 0) &&
(wc_falcon_import_private_only(mem, (word32)memSz, falcon) == 0);
}
static int d2i_falcon_pub_key_level(falcon_key* falcon, byte level,
const unsigned char* mem, long memSz)
{
return (wc_falcon_set_level(falcon, level) == 0) &&
(wc_falcon_import_public(mem, (word32)memSz, falcon) == 0);
}
static int d2iTryFalconKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem,
long memSz, int priv)
{
int isFalcon = 0;
WC_DECLARE_VAR(falcon, falcon_key, 1, NULL);
WC_ALLOC_VAR_EX(falcon, falcon_key, 1, NULL, DYNAMIC_TYPE_FALCON,
return 0);
if (wc_falcon_init(falcon) != 0) {
WC_FREE_VAR_EX(falcon, NULL, DYNAMIC_TYPE_FALCON);
return 0;
}
if (priv) {
isFalcon = d2i_falcon_priv_key_level(falcon, 1, mem, memSz);
if (!isFalcon) {
isFalcon = d2i_falcon_priv_key_level(falcon, 5, mem, memSz);
}
}
else {
isFalcon = d2i_falcon_pub_key_level(falcon, 1, mem, memSz);
if (!isFalcon) {
isFalcon = d2i_falcon_pub_key_level(falcon, 5, mem, memSz);
}
}
wc_falcon_free(falcon);
WC_FREE_VAR_EX(falcon, NULL, DYNAMIC_TYPE_FALCON);
if (!isFalcon) {
return WOLFSSL_FATAL_ERROR;
}
return d2i_make_pkey(out, NULL, 0, priv, WC_EVP_PKEY_FALCON);
}
#endif
#ifdef HAVE_DILITHIUM
static int d2i_dilithium_priv_key_level(dilithium_key* dilithium, byte level,
const unsigned char* mem, long memSz)
{
return (wc_dilithium_set_level(dilithium, level) == 0) &&
(wc_dilithium_import_private(mem, (word32)memSz, dilithium) == 0);
}
static int d2i_dilithium_pub_key_level(dilithium_key* dilithium, byte level,
const unsigned char* mem, long memSz)
{
return (wc_dilithium_set_level(dilithium, level) == 0) &&
(wc_dilithium_import_public(mem, (word32)memSz, dilithium) == 0);
}
static int d2iTryDilithiumKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem,
long memSz, int priv)
{
int isDilithium = 0;
WC_DECLARE_VAR(dilithium, dilithium_key, 1, NULL);
WC_ALLOC_VAR_EX(dilithium, dilithium_key, 1, NULL, DYNAMIC_TYPE_DILITHIUM,
return 0);
if (wc_dilithium_init(dilithium) != 0) {
WC_FREE_VAR_EX(dilithium, NULL, DYNAMIC_TYPE_DILITHIUM);
return 0;
}
if (priv) {
isDilithium = d2i_dilithium_priv_key_level(dilithium, WC_ML_DSA_44,
mem, memSz);
if (!isDilithium) {
isDilithium = d2i_dilithium_priv_key_level(dilithium, WC_ML_DSA_65,
mem, memSz);
}
if (!isDilithium) {
isDilithium = d2i_dilithium_priv_key_level(dilithium, WC_ML_DSA_87,
mem, memSz);
}
}
else {
isDilithium = d2i_dilithium_pub_key_level(dilithium, WC_ML_DSA_44,
mem, memSz);
if (!isDilithium) {
isDilithium = d2i_dilithium_pub_key_level(dilithium, WC_ML_DSA_65,
mem, memSz);
}
if (!isDilithium) {
isDilithium = d2i_dilithium_pub_key_level(dilithium, WC_ML_DSA_87,
mem, memSz);
}
}
wc_dilithium_free(dilithium);
WC_FREE_VAR_EX(dilithium, NULL, DYNAMIC_TYPE_DILITHIUM);
if (!isDilithium) {
return WOLFSSL_FATAL_ERROR;
}
return d2i_make_pkey(out, NULL, 0, priv, WC_EVP_PKEY_DILITHIUM);
}
#endif
static WOLFSSL_EVP_PKEY* d2i_evp_pkey_try(WOLFSSL_EVP_PKEY** out,
const unsigned char** in, long inSz, int priv)
{
WOLFSSL_EVP_PKEY* pkey = NULL;
WOLFSSL_ENTER("d2i_evp_pkey_try");
if (in == NULL || *in == NULL || inSz < 0) {
WOLFSSL_MSG("Bad argument");
return NULL;
}
if ((out != NULL) && (*out != NULL)) {
pkey = *out;
}
#if !defined(NO_RSA)
if (d2iTryRsaKey(&pkey, *in, inSz, priv) >= 0) {
;
}
else
#endif
#if defined(HAVE_ECC) && defined(OPENSSL_EXTRA)
if (d2iTryEccKey(&pkey, *in, inSz, priv) >= 0) {
;
}
else
#endif
#if !defined(NO_DSA)
if (d2iTryDsaKey(&pkey, *in, inSz, priv) >= 0) {
;
}
else
#endif
#if !defined(NO_DH) && (defined(WOLFSSL_QT) || defined(OPENSSL_ALL))
#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \
(HAVE_FIPS_VERSION > 2))
if (d2iTryDhKey(&pkey, *in, inSz, priv) >= 0) {
;
}
else
#endif
#endif
#if !defined(NO_DH) && defined(OPENSSL_EXTRA) && defined(WOLFSSL_DH_EXTRA)
#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \
(HAVE_FIPS_VERSION > 2))
if (d2iTryAltDhKey(&pkey, *in, inSz, priv) >= 0) {
;
}
else
#endif
#endif
#ifdef HAVE_FALCON
if (d2iTryFalconKey(&pkey, *in, inSz, priv) >= 0) {
;
}
else
#endif
#ifdef HAVE_DILITHIUM
if (d2iTryDilithiumKey(&pkey, *in, inSz, priv) >= 0) {
;
}
else
#endif
{
WOLFSSL_MSG("d2i_evp_pkey_try couldn't determine key type");
}
if ((pkey != NULL) && (out != NULL)) {
*out = pkey;
}
return pkey;
}
#endif
#ifdef OPENSSL_EXTRA
WOLFSSL_EVP_PKEY* wolfSSL_d2i_PUBKEY(WOLFSSL_EVP_PKEY** out,
const unsigned char** in, long inSz)
{
WOLFSSL_ENTER("wolfSSL_d2i_PUBKEY");
return d2i_evp_pkey_try(out, in, inSz, 0);
}
#ifndef NO_BIO
WOLFSSL_EVP_PKEY* wolfSSL_d2i_PUBKEY_bio(WOLFSSL_BIO* bio,
WOLFSSL_EVP_PKEY** out)
{
unsigned char* mem;
long memSz;
WOLFSSL_EVP_PKEY* pkey = NULL;
WOLFSSL_ENTER("wolfSSL_d2i_PUBKEY_bio");
if (bio == NULL) {
return NULL;
}
memSz = wolfSSL_BIO_get_len(bio);
if (memSz <= 0) {
return NULL;
}
mem = (unsigned char*)XMALLOC((size_t)memSz, bio->heap,
DYNAMIC_TYPE_TMP_BUFFER);
if (mem == NULL) {
return NULL;
}
if (wolfSSL_BIO_read(bio, mem, (int)memSz) == memSz) {
pkey = wolfSSL_d2i_PUBKEY(NULL, (const unsigned char**)&mem, memSz);
if (out != NULL && pkey != NULL) {
*out = pkey;
}
}
XFREE(mem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER);
return pkey;
}
#endif
#endif
#if defined(OPENSSL_ALL) || defined(WOLFSSL_ASIO) || \
defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_NGINX) || \
defined(WOLFSSL_QT) || defined(WOLFSSL_WPAS_SMALL)
WOLFSSL_EVP_PKEY* wolfSSL_d2i_PrivateKey_EVP(WOLFSSL_EVP_PKEY** out,
unsigned char** in, long inSz)
{
WOLFSSL_ENTER("wolfSSL_d2i_PrivateKey_EVP");
return d2i_evp_pkey_try(out, (const unsigned char**)in, inSz, 1);
}
#endif
#if defined(OPENSSL_ALL) || defined(WOLFSSL_ASIO) || \
defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_QT)
#ifndef NO_BIO
WOLFSSL_EVP_PKEY* wolfSSL_d2i_PrivateKey_bio(WOLFSSL_BIO* bio,
WOLFSSL_EVP_PKEY** out)
{
unsigned char* mem = NULL;
int memSz = 0;
WOLFSSL_EVP_PKEY* key = NULL;
WOLFSSL_ENTER("wolfSSL_d2i_PrivateKey_bio");
if (bio == NULL) {
return NULL;
}
memSz = wolfSSL_BIO_get_len(bio);
if (memSz <= 0) {
WOLFSSL_MSG("wolfSSL_BIO_get_len() failure");
return NULL;
}
mem = (unsigned char*)XMALLOC((size_t)memSz, bio->heap,
DYNAMIC_TYPE_TMP_BUFFER);
if (mem == NULL) {
WOLFSSL_MSG("Malloc failure");
return NULL;
}
if (wolfSSL_BIO_read(bio, (unsigned char*)mem, memSz) == memSz) {
if ((key = wolfSSL_d2i_PrivateKey_EVP(NULL, &mem, (long)memSz)) ==
NULL) {
WOLFSSL_MSG("wolfSSL_d2i_PrivateKey_EVP() failure");
XFREE(mem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER);
return NULL;
}
if (memSz > key->pkey_sz) {
wolfSSL_BIO_write(bio, mem + key->pkey_sz, memSz - key->pkey_sz);
if (wolfSSL_BIO_get_len(bio) <= 0) {
WOLFSSL_MSG("Failed to write memory to bio");
XFREE(mem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER);
return NULL;
}
}
if (out != NULL) {
*out = key;
}
}
XFREE(mem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER);
return key;
}
#endif
#endif
#ifdef OPENSSL_EXTRA
static WOLFSSL_EVP_PKEY* d2i_evp_pkey(int type, WOLFSSL_EVP_PKEY** out,
const unsigned char **in, long inSz, int priv)
{
int ret = 0;
word32 idx = 0, algId;
word16 pkcs8HeaderSz = 0;
WOLFSSL_EVP_PKEY* local;
const unsigned char* p;
int opt;
(void)opt;
if (in == NULL || inSz < 0) {
WOLFSSL_MSG("Bad argument");
return NULL;
}
if (priv == 1) {
if ((ret = ToTraditionalInline_ex((const byte*)(*in), &idx,
(word32)inSz, &algId)) >= 0) {
WOLFSSL_MSG("Found PKCS8 header");
pkcs8HeaderSz = (word16)idx;
if ((type == WC_EVP_PKEY_RSA && algId != RSAk
#ifdef WC_RSA_PSS
&& algId != RSAPSSk
#endif
) ||
(type == WC_EVP_PKEY_EC && algId != ECDSAk) ||
(type == WC_EVP_PKEY_DSA && algId != DSAk) ||
(type == WC_EVP_PKEY_DH && algId != DHk)) {
WOLFSSL_MSG("PKCS8 does not match EVP key type");
return NULL;
}
(void)idx;
}
else if (ret != WC_NO_ERR_TRACE(ASN_PARSE_E)) {
WOLFSSL_MSG("Unexpected error with trying to remove PKCS8 header");
return NULL;
}
}
if (out != NULL && *out != NULL) {
wolfSSL_EVP_PKEY_free(*out);
*out = NULL;
}
local = wolfSSL_EVP_PKEY_new();
if (local == NULL) {
return NULL;
}
local->type = type;
local->pkey_sz = (int)inSz;
local->pkcs8HeaderSz = pkcs8HeaderSz;
local->pkey.ptr = (char*)XMALLOC((size_t)inSz, NULL,
DYNAMIC_TYPE_PUBLIC_KEY);
if (local->pkey.ptr == NULL) {
wolfSSL_EVP_PKEY_free(local);
return NULL;
}
XMEMCPY(local->pkey.ptr, *in, (size_t)inSz);
p = (const unsigned char*)local->pkey.ptr;
switch (type) {
#ifndef NO_RSA
case WC_EVP_PKEY_RSA:
local->ownRsa = 1;
opt = priv ? WOLFSSL_RSA_LOAD_PRIVATE : WOLFSSL_RSA_LOAD_PUBLIC;
local->rsa = wolfssl_rsa_d2i(NULL, p, local->pkey_sz, opt);
if (local->rsa == NULL) {
wolfSSL_EVP_PKEY_free(local);
return NULL;
}
break;
#endif
#ifdef HAVE_ECC
case WC_EVP_PKEY_EC:
local->ownEcc = 1;
local->ecc = wolfSSL_EC_KEY_new();
if (local->ecc == NULL) {
wolfSSL_EVP_PKEY_free(local);
return NULL;
}
opt = priv ? WOLFSSL_EC_KEY_LOAD_PRIVATE :
WOLFSSL_EC_KEY_LOAD_PUBLIC;
if (wolfSSL_EC_KEY_LoadDer_ex(local->ecc, p, local->pkey_sz, opt) !=
WOLFSSL_SUCCESS) {
wolfSSL_EVP_PKEY_free(local);
return NULL;
}
break;
#endif
#if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) || defined(WOLFSSL_OPENSSH)
#ifndef NO_DSA
case WC_EVP_PKEY_DSA:
local->ownDsa = 1;
local->dsa = wolfSSL_DSA_new();
if (local->dsa == NULL) {
wolfSSL_EVP_PKEY_free(local);
return NULL;
}
opt = priv ? WOLFSSL_DSA_LOAD_PRIVATE : WOLFSSL_DSA_LOAD_PUBLIC;
if (wolfSSL_DSA_LoadDer_ex(local->dsa, p, local->pkey_sz, opt) !=
WOLFSSL_SUCCESS) {
wolfSSL_EVP_PKEY_free(local);
return NULL;
}
break;
#endif
#ifndef NO_DH
#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION>2))
case WC_EVP_PKEY_DH:
local->ownDh = 1;
local->dh = wolfSSL_DH_new();
if (local->dh == NULL) {
wolfSSL_EVP_PKEY_free(local);
return NULL;
}
if (wolfSSL_DH_LoadDer(local->dh, p, local->pkey_sz) !=
WOLFSSL_SUCCESS) {
wolfSSL_EVP_PKEY_free(local);
return NULL;
}
break;
#endif
#endif
#endif
default:
WOLFSSL_MSG("Unsupported key type");
wolfSSL_EVP_PKEY_free(local);
return NULL;
}
if (local != NULL) {
if (local->pkey_sz <= (int)inSz) {
*in += local->pkey_sz;
}
if (out != NULL) {
*out = local;
}
}
return local;
}
WOLFSSL_EVP_PKEY* wolfSSL_d2i_PublicKey(int type, WOLFSSL_EVP_PKEY** out,
const unsigned char **in, long inSz)
{
WOLFSSL_ENTER("wolfSSL_d2i_PublicKey");
return d2i_evp_pkey(type, out, in, inSz, 0);
}
WOLFSSL_EVP_PKEY* wolfSSL_d2i_PrivateKey(int type, WOLFSSL_EVP_PKEY** out,
const unsigned char **in, long inSz)
{
WOLFSSL_ENTER("wolfSSL_d2i_PrivateKey");
return d2i_evp_pkey(type, out, in, inSz, 1);
}
#endif
#ifdef OPENSSL_ALL
WOLFSSL_EVP_PKEY* wolfSSL_d2i_AutoPrivateKey(WOLFSSL_EVP_PKEY** pkey,
const unsigned char** pp, long length)
{
int ret;
WOLFSSL_EVP_PKEY* key = NULL;
const byte* der = *pp;
word32 idx = 0;
int len = 0;
int cnt = 0;
word32 algId;
word32 keyLen = (word32)length;
if ((len = ToTraditionalInline_ex(der, &idx, keyLen, &algId)) >= 0) {
der += idx;
keyLen = (word32)len;
}
idx = 0;
len = 0;
ret = GetSequence(der, &idx, &len, keyLen);
if (ret >= 0) {
word32 end = idx + (word32)len;
while (ret >= 0 && idx < end) {
idx++;
len = 0;
ret = GetLength(der, &idx, &len, keyLen);
if (ret >= 0) {
if (idx + (word32)len > end) {
ret = ASN_PARSE_E;
}
else {
idx += (word32)len;
cnt++;
}
}
}
}
if (ret >= 0) {
int type;
if (cnt >= 2 && cnt <= 4) {
type = WC_EVP_PKEY_EC;
}
else {
type = WC_EVP_PKEY_RSA;
}
key = wolfSSL_d2i_PrivateKey(type, pkey, &der, keyLen);
*pp = der;
}
return key;
}
#if !defined(NO_BIO) && !defined(NO_PWDBASED) && defined(HAVE_PKCS8)
static int bio_get_data(WOLFSSL_BIO* bio, byte** data)
{
int ret = 0;
byte* mem = NULL;
ret = wolfSSL_BIO_get_len(bio);
if (ret > 0) {
mem = (byte*)XMALLOC((size_t)ret, bio->heap, DYNAMIC_TYPE_OPENSSL);
if (mem == NULL) {
WOLFSSL_MSG("Memory error");
ret = MEMORY_E;
}
if (ret >= 0) {
if ((ret = wolfSSL_BIO_read(bio, mem, ret)) <= 0) {
XFREE(mem, bio->heap, DYNAMIC_TYPE_OPENSSL);
ret = MEMORY_E;
mem = NULL;
}
}
}
*data = mem;
return ret;
}
static int wolfssl_i_alg_id_to_key_type(word32 algId)
{
int type;
switch (algId) {
#ifndef NO_RSA
case RSAk:
#ifdef WC_RSA_PSS
case RSAPSSk:
#endif
type = WC_EVP_PKEY_RSA;
break;
#endif
#ifdef HAVE_ECC
case ECDSAk:
type = WC_EVP_PKEY_EC;
break;
#endif
#ifndef NO_DSA
case DSAk:
type = WC_EVP_PKEY_DSA;
break;
#endif
#ifndef NO_DH
case DHk:
type = WC_EVP_PKEY_DH;
break;
#endif
default:
WOLFSSL_MSG("PKEY algorithm, from PKCS#8 header, not supported");
type = WC_EVP_PKEY_NONE;
break;
}
return type;
}
WOLFSSL_EVP_PKEY* wolfSSL_d2i_PKCS8PrivateKey_bio(WOLFSSL_BIO* bio,
WOLFSSL_EVP_PKEY** pkey, wc_pem_password_cb* cb, void* ctx)
{
int ret;
const byte* p;
byte* der = NULL;
int len;
word32 algId;
WOLFSSL_EVP_PKEY* key;
int type;
char password[NAME_SZ];
int passwordSz;
if ((len = bio_get_data(bio, &der)) < 0)
return NULL;
if (cb == NULL) {
cb = wolfSSL_PEM_def_callback;
}
passwordSz = cb(password, sizeof(password), PEM_PASS_READ, ctx);
if (passwordSz < 0) {
XFREE(der, bio->heap, DYNAMIC_TYPE_OPENSSL);
return NULL;
}
#ifdef WOLFSSL_CHECK_MEM_ZERO
wc_MemZero_Add("wolfSSL_d2i_PKCS8PrivateKey_bio password", password,
passwordSz);
#endif
ret = ToTraditionalEnc(der, (word32)len, password, passwordSz, &algId);
ForceZero(password, (word32)passwordSz);
#ifdef WOLFSSL_CHECK_MEM_ZERO
wc_MemZero_Check(password, passwordSz);
#endif
if (ret < 0) {
XFREE(der, bio->heap, DYNAMIC_TYPE_OPENSSL);
return NULL;
}
if ((type = wolfssl_i_alg_id_to_key_type(algId)) == WC_EVP_PKEY_NONE) {
XFREE(der, bio->heap, DYNAMIC_TYPE_OPENSSL);
return NULL;
}
p = der;
key = d2i_evp_pkey(type, pkey, &p, len, 1);
XFREE(der, bio->heap, DYNAMIC_TYPE_OPENSSL);
return key;
}
#endif
#endif
#ifdef OPENSSL_EXTRA
WOLFSSL_PKCS8_PRIV_KEY_INFO* wolfSSL_d2i_PKCS8_PKEY(
WOLFSSL_PKCS8_PRIV_KEY_INFO** pkey, const unsigned char** keyBuf,
long keyLen)
{
WOLFSSL_PKCS8_PRIV_KEY_INFO* pkcs8 = NULL;
#ifdef WOLFSSL_PEM_TO_DER
int ret;
DerBuffer* pkcs8Der = NULL;
DerBuffer rawDer;
EncryptedInfo info;
int advanceLen = 0;
XMEMSET(&info, 0, sizeof(info));
XMEMSET(&rawDer, 0, sizeof(rawDer));
if ((keyBuf == NULL) || (*keyBuf == NULL) || (keyLen <= 0)) {
WOLFSSL_MSG("Bad key PEM/DER args");
return NULL;
}
ret = PemToDer(*keyBuf, keyLen, PRIVATEKEY_TYPE, &pkcs8Der, NULL, &info,
NULL);
if (ret >= 0) {
advanceLen = (int)info.consumed;
}
else {
WOLFSSL_MSG("Not PEM format");
ret = AllocDer(&pkcs8Der, (word32)keyLen, PRIVATEKEY_TYPE, NULL);
if (ret == 0) {
XMEMCPY(pkcs8Der->buffer, *keyBuf, keyLen);
}
}
if (ret == 0) {
word32 inOutIdx = 0;
word32 algId;
ret = ToTraditionalInline_ex(pkcs8Der->buffer, &inOutIdx,
pkcs8Der->length, &algId);
if (ret >= 0) {
if (advanceLen == 0) {
advanceLen = (int)inOutIdx + ret;
}
if (algId == DHk) {
rawDer.buffer = pkcs8Der->buffer;
rawDer.length = inOutIdx + (word32)ret;
}
else {
rawDer.buffer = pkcs8Der->buffer + inOutIdx;
rawDer.length = (word32)ret;
}
ret = 0;
}
}
if (ret == 0) {
pkcs8 = wolfSSL_EVP_PKEY_new();
if (pkcs8 == NULL) {
ret = MEMORY_E;
}
}
if (ret == 0) {
pkcs8->pkey.ptr = (char*)XMALLOC(rawDer.length, NULL,
DYNAMIC_TYPE_PUBLIC_KEY);
if (pkcs8->pkey.ptr == NULL) {
ret = MEMORY_E;
}
}
if (ret == 0) {
XMEMCPY(pkcs8->pkey.ptr, rawDer.buffer, rawDer.length);
pkcs8->pkey_sz = (int)rawDer.length;
}
FreeDer(&pkcs8Der);
if (ret != 0) {
wolfSSL_EVP_PKEY_free(pkcs8);
pkcs8 = NULL;
}
else {
*keyBuf += advanceLen;
}
if (pkey != NULL) {
*pkey = pkcs8;
}
#else
(void)pkey;
(void)keyBuf;
(void)keyLen;
#endif
return pkcs8;
}
#ifndef NO_BIO
WOLFSSL_PKCS8_PRIV_KEY_INFO* wolfSSL_d2i_PKCS8_PKEY_bio(WOLFSSL_BIO* bio,
WOLFSSL_PKCS8_PRIV_KEY_INFO** pkey)
{
WOLFSSL_PKCS8_PRIV_KEY_INFO* pkcs8 = NULL;
#ifdef WOLFSSL_PEM_TO_DER
unsigned char* mem = NULL;
int memSz;
WOLFSSL_ENTER("wolfSSL_d2i_PKCS8_PKEY_bio");
if (bio == NULL) {
return NULL;
}
if ((memSz = wolfSSL_BIO_get_mem_data(bio, &mem)) < 0) {
return NULL;
}
pkcs8 = wolfSSL_d2i_PKCS8_PKEY(pkey, (const unsigned char**)&mem, memSz);
#else
(void)bio;
(void)pkey;
#endif
return pkcs8;
}
#endif
#ifdef WOLF_PRIVATE_KEY_ID
WOLFSSL_EVP_PKEY* wolfSSL_d2i_PrivateKey_id(int type, WOLFSSL_EVP_PKEY** out,
void* heap, int devId)
{
WOLFSSL_EVP_PKEY* local;
if (out != NULL && *out != NULL) {
wolfSSL_EVP_PKEY_free(*out);
*out = NULL;
}
local = wolfSSL_EVP_PKEY_new_ex(heap);
if (local == NULL) {
return NULL;
}
local->type = type;
local->pkey_sz = 0;
local->pkcs8HeaderSz = 0;
switch (type) {
#ifndef NO_RSA
case WC_EVP_PKEY_RSA:
{
local->rsa = wolfSSL_RSA_new_ex(heap, devId);
if (local->rsa == NULL) {
wolfSSL_EVP_PKEY_free(local);
return NULL;
}
local->ownRsa = 1;
local->rsa->inSet = 1;
#ifdef WOLF_CRYPTO_CB
((RsaKey*)local->rsa->internal)->devId = devId;
#endif
break;
}
#endif
#ifdef HAVE_ECC
case WC_EVP_PKEY_EC:
{
ecc_key* key;
local->ecc = wolfSSL_EC_KEY_new_ex(heap, devId);
if (local->ecc == NULL) {
wolfSSL_EVP_PKEY_free(local);
return NULL;
}
local->ownEcc = 1;
local->ecc->inSet = 1;
key = (ecc_key*)local->ecc->internal;
#ifdef WOLF_CRYPTO_CB
key->devId = devId;
#endif
key->type = ECC_PRIVATEKEY;
wc_ecc_set_curve(key, ECDHE_SIZE, ECC_CURVE_DEF);
break;
}
#endif
default:
WOLFSSL_MSG("Unsupported private key id type");
wolfSSL_EVP_PKEY_free(local);
return NULL;
}
if (local != NULL && out != NULL) {
*out = local;
}
return local;
}
#endif
#endif
#ifdef OPENSSL_ALL
int wolfSSL_i2d_PKCS8_PKEY(WOLFSSL_PKCS8_PRIV_KEY_INFO* key, unsigned char** pp)
{
word32 keySz = 0;
unsigned char* out;
int len;
WOLFSSL_ENTER("wolfSSL_i2d_PKCS8_PKEY");
if (key == NULL) {
return WOLFSSL_FATAL_ERROR;
}
if (pkcs8_encode(key, NULL, &keySz) != WC_NO_ERR_TRACE(LENGTH_ONLY_E)) {
return WOLFSSL_FATAL_ERROR;
}
len = (int)keySz;
if ((pp == NULL) || (len == 0)) {
return len;
}
if (*pp == NULL) {
out = (unsigned char*)XMALLOC((size_t)len, NULL, DYNAMIC_TYPE_ASN1);
if (out == NULL) {
return WOLFSSL_FATAL_ERROR;
}
}
else {
out = *pp;
}
if (pkcs8_encode(key, out, &keySz) != len) {
if (*pp == NULL) {
XFREE(out, NULL, DYNAMIC_TYPE_ASN1);
}
return WOLFSSL_FATAL_ERROR;
}
if (*pp == NULL) {
*pp = out;
}
else {
*pp += len;
}
return len;
}
#endif
#ifdef OPENSSL_EXTRA
#if !defined(NO_ASN) && !defined(NO_PWDBASED)
static int wolfssl_i_evp_pkey_get_der(const WOLFSSL_EVP_PKEY* key,
unsigned char** der)
{
int sz;
word16 pkcs8HeaderSz;
if ((key == NULL) || (key->pkey_sz == 0)) {
return WOLFSSL_FATAL_ERROR;
}
pkcs8HeaderSz = 0;
if (key->pkey_sz > key->pkcs8HeaderSz) {
pkcs8HeaderSz = key->pkcs8HeaderSz;
}
sz = key->pkey_sz - pkcs8HeaderSz;
if (der != NULL) {
unsigned char* pt = (unsigned char*)key->pkey.ptr;
int bufferPassedIn = ((*der) != NULL);
if (!bufferPassedIn) {
*der = (unsigned char*)XMALLOC((size_t)sz, NULL,
DYNAMIC_TYPE_OPENSSL);
if (*der == NULL) {
return WOLFSSL_FATAL_ERROR;
}
}
XMEMCPY(*der, pt + pkcs8HeaderSz, (size_t)sz);
if (bufferPassedIn) {
*der += sz;
}
}
return sz;
}
int wolfSSL_i2d_PrivateKey(const WOLFSSL_EVP_PKEY* key, unsigned char** der)
{
return wolfssl_i_evp_pkey_get_der(key, der);
}
#ifndef NO_BIO
int wolfSSL_i2d_PrivateKey_bio(WOLFSSL_BIO* bio, WOLFSSL_EVP_PKEY* key)
{
int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE);
int derSz = 0;
byte* der = NULL;
if (bio == NULL || key == NULL) {
return WOLFSSL_FAILURE;
}
derSz = wolfSSL_i2d_PrivateKey(key, &der);
if (derSz <= 0) {
WOLFSSL_MSG("wolfSSL_i2d_PrivateKey (for getting size) failed");
return WOLFSSL_FAILURE;
}
if (wolfSSL_BIO_write(bio, der, derSz) != derSz) {
goto cleanup;
}
ret = WOLFSSL_SUCCESS;
cleanup:
XFREE(der, NULL, DYNAMIC_TYPE_OPENSSL);
return ret;
}
#endif
#ifdef HAVE_ECC
static int wolfssl_i_i2d_ecpublickey(const WOLFSSL_EVP_PKEY* key,
const WOLFSSL_EC_KEY *ec, unsigned char **der)
{
word32 pub_derSz = 0;
int ret;
unsigned char *local_der = NULL;
word32 local_derSz = 0;
unsigned char *pub_der = NULL;
ecc_key *eccKey = NULL;
word32 inOutIdx = 0;
ret = wolfssl_i_evp_pkey_get_der(key, &local_der);
if (ret <= 0) {
local_derSz = (word32)wolfSSL_i2d_ECPrivateKey(ec, &local_der);
if (local_derSz == 0) {
ret = WOLFSSL_FATAL_ERROR;
}
} else {
local_derSz = (word32)ret;
ret = 0;
}
if (ret == 0) {
eccKey = (ecc_key *)XMALLOC(sizeof(*eccKey), NULL, DYNAMIC_TYPE_ECC);
if (eccKey == NULL) {
WOLFSSL_MSG("Failed to allocate key buffer.");
ret = WOLFSSL_FATAL_ERROR;
}
}
if (ret == 0) {
ret = wc_ecc_init(eccKey);
}
if (ret == 0) {
ret = wc_EccPublicKeyDecode(local_der, &inOutIdx, eccKey, local_derSz);
if (ret < 0) {
ret = wc_ecc_import_x963(local_der, local_derSz, eccKey);
}
}
if (ret == 0) {
pub_derSz = (word32)wc_EccPublicKeyDerSize(eccKey, 1);
if ((int)pub_derSz <= 0) {
ret = WOLFSSL_FAILURE;
}
}
if (ret == 0) {
pub_der = (unsigned char*)XMALLOC(pub_derSz, NULL,
DYNAMIC_TYPE_PUBLIC_KEY);
if (pub_der == NULL) {
WOLFSSL_MSG("Failed to allocate output buffer.");
ret = WOLFSSL_FATAL_ERROR;
}
}
if (ret == 0) {
pub_derSz = (word32)wc_EccPublicKeyToDer(eccKey, pub_der, pub_derSz, 1);
if ((int)pub_derSz <= 0) {
ret = WOLFSSL_FATAL_ERROR;
}
}
if ((ret == 0) && (der != NULL)) {
int bufferPassedIn = ((*der) != NULL);
if (!bufferPassedIn) {
*der = (unsigned char*)XMALLOC(pub_derSz, NULL,
DYNAMIC_TYPE_PUBLIC_KEY);
if (*der == NULL) {
WOLFSSL_MSG("Failed to allocate output buffer.");
ret = WOLFSSL_FATAL_ERROR;
}
}
if (ret == 0) {
XMEMCPY(*der, pub_der, pub_derSz);
if (bufferPassedIn) {
*der += pub_derSz;
}
}
}
XFREE(pub_der, NULL, DYNAMIC_TYPE_PUBLIC_KEY);
XFREE(local_der, NULL, DYNAMIC_TYPE_OPENSSL);
wc_ecc_free(eccKey);
XFREE(eccKey, NULL, DYNAMIC_TYPE_ECC);
if (ret == 0) {
ret = (int)pub_derSz;
}
return ret;
}
#endif
int wolfSSL_i2d_PublicKey(const WOLFSSL_EVP_PKEY *key, unsigned char **der)
{
int ret;
if (key == NULL) {
return WOLFSSL_FATAL_ERROR;
}
switch (key->type) {
#ifndef NO_RSA
case WC_EVP_PKEY_RSA:
return wolfSSL_i2d_RSAPublicKey(key->rsa, der);
#endif
#ifdef HAVE_ECC
case WC_EVP_PKEY_EC:
return wolfssl_i_i2d_ecpublickey(key, key->ecc, der);
#endif
default:
ret = WOLFSSL_FATAL_ERROR;
break;
}
return ret;
}
int wolfSSL_i2d_PUBKEY(const WOLFSSL_EVP_PKEY *key, unsigned char **der)
{
return wolfSSL_i2d_PublicKey(key, der);
}
#endif
#endif
#endif
#endif