mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-07-05 15:00:49 +02:00
beff858833
Add NID_X25519 and NID_X448 support to the EVP layer
2435 lines
73 KiB
C
2435 lines
73 KiB
C
/* evp_pk.c
|
|
*
|
|
* Copyright (C) 2006-2026 wolfSSL Inc.
|
|
*
|
|
* This file is part of wolfSSL.
|
|
*
|
|
* wolfSSL is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* wolfSSL is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
|
*/
|
|
|
|
#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
|
|
|
|
#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
|
|
|
|
/*******************************************************************************
|
|
* START OF d2i APIs
|
|
******************************************************************************/
|
|
|
|
#ifndef NO_CERTS
|
|
|
|
#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL)
|
|
/**
|
|
* Make an EVP PKEY and put data and type in.
|
|
*
|
|
* @param [in, out] out On in, an EVP PKEY or NULL.
|
|
* On out, an EVP PKEY or NULL.
|
|
* @param [in] mem Memory containing key data.
|
|
* @param [in] memSz Size of key data in bytes.
|
|
* @param [in] priv 1 means private key, 0 means public key.
|
|
* @param [in] type The type of public/private key.
|
|
* @return 1 on success.
|
|
* @return 0 otherwise.
|
|
*/
|
|
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;
|
|
|
|
/* Get or create the EVP PKEY object. */
|
|
if (*out != NULL) {
|
|
pkey = *out;
|
|
}
|
|
else {
|
|
pkey = wolfSSL_EVP_PKEY_new();
|
|
if (pkey == NULL) {
|
|
WOLFSSL_MSG("wolfSSL_EVP_PKEY_new error");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* Set the size and allocate memory for key data to be copied into. */
|
|
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) {
|
|
/* Copy in key data. */
|
|
XMEMCPY(pkey->pkey.ptr, mem, memSz);
|
|
}
|
|
}
|
|
if (ret == 1) {
|
|
/* Set key type passed in and return object. */
|
|
pkey->type = type;
|
|
*out = pkey;
|
|
}
|
|
if ((ret == 0) && (*out == NULL)) {
|
|
/* Dispose of object allocated in this function. */
|
|
wolfSSL_EVP_PKEY_free(pkey);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
#if !defined(NO_RSA)
|
|
/**
|
|
* Try to make an RSA EVP PKEY from data.
|
|
*
|
|
* @param [in, out] out On in, an EVP PKEY or NULL.
|
|
* On out, an EVP PKEY or NULL.
|
|
* @param [in] mem Memory containing key data.
|
|
* @param [in] memSz Size of key data in bytes.
|
|
* @param [in] priv 1 means private key, 0 means public key.
|
|
* @return 1 on success.
|
|
* @return 0 when input was recognized as this key type but
|
|
* object creation/import failed.
|
|
* @return WOLFSSL_FATAL_ERROR when input is not this key type.
|
|
*/
|
|
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;
|
|
}
|
|
/* Try decoding data as an RSA private/public key. */
|
|
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;
|
|
}
|
|
|
|
/* Create RSA key object from data. */
|
|
rsaObj = wolfssl_rsa_d2i(NULL, mem, keyIdx,
|
|
priv ? WOLFSSL_RSA_LOAD_PRIVATE : WOLFSSL_RSA_LOAD_PUBLIC);
|
|
if (rsaObj == NULL) {
|
|
ret = 0;
|
|
}
|
|
if (ret == 1) {
|
|
/* Create an EVP PKEY object. */
|
|
ret = d2i_make_pkey(out, mem, keyIdx, priv, WC_EVP_PKEY_RSA);
|
|
}
|
|
if (ret == 1) {
|
|
/* Put RSA key object into EVP PKEY object. */
|
|
(*out)->ownRsa = 1;
|
|
(*out)->rsa = rsaObj;
|
|
}
|
|
if (ret == 0) {
|
|
wolfSSL_RSA_free(rsaObj);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
#endif /* !NO_RSA */
|
|
|
|
#if defined(HAVE_ECC) && defined(OPENSSL_EXTRA)
|
|
/**
|
|
* Try to make an ECC EVP PKEY from data.
|
|
*
|
|
* @param [in, out] out On in, an EVP PKEY or NULL.
|
|
* On out, an EVP PKEY or NULL.
|
|
* @param [in] mem Memory containing key data.
|
|
* @param [in] memSz Size of key data in bytes.
|
|
* @param [in] priv 1 means private key, 0 means public key.
|
|
* @return 1 on success.
|
|
* @return 0 when input was recognized as this key type but
|
|
* object creation/import failed.
|
|
* @return WOLFSSL_FATAL_ERROR when input is not this key type.
|
|
*/
|
|
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;
|
|
}
|
|
|
|
/* Try decoding data as an ECC private/public key. */
|
|
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;
|
|
}
|
|
|
|
/* Create EC key object from data. */
|
|
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) {
|
|
/* Create an EVP PKEY object. */
|
|
ret = d2i_make_pkey(out, mem, keyIdx, priv, WC_EVP_PKEY_EC);
|
|
}
|
|
if (ret == 1) {
|
|
/* Put RSA key object into EVP PKEY object. */
|
|
(*out)->ownEcc = 1;
|
|
(*out)->ecc = ec;
|
|
}
|
|
if (ret == 0) {
|
|
wolfSSL_EC_KEY_free(ec);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
#endif /* HAVE_ECC && OPENSSL_EXTRA */
|
|
|
|
#ifdef HAVE_ED25519
|
|
/**
|
|
* Try to make an Ed25519 EVP PKEY from data.
|
|
*
|
|
* @param [in, out] out On in, an EVP PKEY or NULL.
|
|
* On out, an EVP PKEY or NULL.
|
|
* @param [in] mem Memory containing key data.
|
|
* @param [in] memSz Size of key data in bytes.
|
|
* @param [in] priv 1 means private key, 0 means public key.
|
|
* @return 1 on success.
|
|
* @return 0 when input was recognized as this key type but object
|
|
* creation/import failed.
|
|
* @return WOLFSSL_FATAL_ERROR when input is not this key type.
|
|
*/
|
|
static int d2iTryEd25519Key(WOLFSSL_EVP_PKEY** out, const unsigned char* mem,
|
|
long memSz, int priv)
|
|
{
|
|
ed25519_key* edKey = NULL;
|
|
word32 keyIdx = 0;
|
|
int isEdKey;
|
|
int ret = 1;
|
|
void* heap = NULL;
|
|
|
|
if (*out != NULL) {
|
|
heap = (*out)->heap;
|
|
}
|
|
|
|
edKey = wolfSSL_ED25519_new(heap, INVALID_DEVID);
|
|
if (edKey == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
/* Decode data as an Ed25519 key in DER form (SubjectPublicKeyInfo for
|
|
* public keys, PKCS#8 PrivateKeyInfo for private keys). */
|
|
if (priv) {
|
|
isEdKey = (wc_Ed25519PrivateKeyDecode(mem, &keyIdx, edKey,
|
|
(word32)memSz) == 0);
|
|
}
|
|
else {
|
|
isEdKey = (wc_Ed25519PublicKeyDecode(mem, &keyIdx, edKey,
|
|
(word32)memSz) == 0);
|
|
}
|
|
|
|
if (!isEdKey) {
|
|
wolfSSL_ED25519_free(edKey);
|
|
return WOLFSSL_FATAL_ERROR;
|
|
}
|
|
|
|
/* Create an EVP PKEY object holding the input DER bytes. If the caller
|
|
* already populated the EVP PKEY with the input bytes (pkey.ptr set),
|
|
* skip the allocate/copy. */
|
|
if (*out == NULL || (*out)->pkey.ptr == NULL) {
|
|
ret = d2i_make_pkey(out, mem, keyIdx, priv, WC_EVP_PKEY_ED25519);
|
|
}
|
|
if (ret == 1) {
|
|
(*out)->ownEd25519 = 1;
|
|
(*out)->ed25519 = edKey;
|
|
}
|
|
else {
|
|
wolfSSL_ED25519_free(edKey);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
#endif /* HAVE_ED25519 */
|
|
|
|
#ifdef HAVE_ED448
|
|
/**
|
|
* Try to make an Ed448 EVP PKEY from data.
|
|
*
|
|
* @param [in, out] out On in, an EVP PKEY or NULL.
|
|
* On out, an EVP PKEY or NULL.
|
|
* @param [in] mem Memory containing key data.
|
|
* @param [in] memSz Size of key data in bytes.
|
|
* @param [in] priv 1 means private key, 0 means public key.
|
|
* @return 1 on success.
|
|
* @return 0 when input was recognized as this key type but object
|
|
* creation/import failed.
|
|
* @return WOLFSSL_FATAL_ERROR when input is not this key type.
|
|
*/
|
|
static int d2iTryEd448Key(WOLFSSL_EVP_PKEY** out, const unsigned char* mem,
|
|
long memSz, int priv)
|
|
{
|
|
ed448_key* edKey = NULL;
|
|
word32 keyIdx = 0;
|
|
int isEdKey;
|
|
int ret = 1;
|
|
void* heap = NULL;
|
|
|
|
if (*out != NULL) {
|
|
heap = (*out)->heap;
|
|
}
|
|
|
|
edKey = wolfSSL_ED448_new(heap, INVALID_DEVID);
|
|
if (edKey == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
/* Decode data as an Ed448 key in DER form (SubjectPublicKeyInfo for
|
|
* public keys, PKCS#8 PrivateKeyInfo for private keys). */
|
|
if (priv) {
|
|
isEdKey = (wc_Ed448PrivateKeyDecode(mem, &keyIdx, edKey,
|
|
(word32)memSz) == 0);
|
|
}
|
|
else {
|
|
isEdKey = (wc_Ed448PublicKeyDecode(mem, &keyIdx, edKey,
|
|
(word32)memSz) == 0);
|
|
}
|
|
|
|
if (!isEdKey) {
|
|
wolfSSL_ED448_free(edKey);
|
|
return WOLFSSL_FATAL_ERROR;
|
|
}
|
|
|
|
/* Create an EVP PKEY object holding the input DER bytes. If the caller
|
|
* already populated the EVP PKEY with the input bytes (pkey.ptr set),
|
|
* skip the allocate/copy. */
|
|
if (*out == NULL || (*out)->pkey.ptr == NULL) {
|
|
ret = d2i_make_pkey(out, mem, keyIdx, priv, WC_EVP_PKEY_ED448);
|
|
}
|
|
if (ret == 1) {
|
|
(*out)->ownEd448 = 1;
|
|
(*out)->ed448 = edKey;
|
|
}
|
|
else {
|
|
wolfSSL_ED448_free(edKey);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
#endif /* HAVE_ED448 */
|
|
|
|
/* Create a new EVP_PKEY from raw Ed25519 or Ed448 key material.
|
|
*
|
|
* Used for for callers who already have the raw key bytes and shouldn't need
|
|
* to rewrap them in an SPKI just to decode.
|
|
*
|
|
* @param [in] type WC_EVP_PKEY_ED25519 or WC_EVP_PKEY_ED448.
|
|
* @param [in] e Engine. Ignored; accepted for OpenSSL API parity.
|
|
* @param [in] pub Raw public key bytes.
|
|
* @param [in] len Length of pub. Must match the curve's public key size
|
|
* (ED25519_PUB_KEY_SIZE or ED448_PUB_KEY_SIZE).
|
|
* @return WOLFSSL_EVP_PKEY on success, NULL on failure.
|
|
*/
|
|
WOLFSSL_EVP_PKEY* wolfSSL_EVP_PKEY_new_raw_public_key(int type,
|
|
WOLFSSL_ENGINE* e, const unsigned char* pub, size_t len)
|
|
{
|
|
WOLFSSL_EVP_PKEY* pkey;
|
|
int ok = 0;
|
|
|
|
(void)e;
|
|
WOLFSSL_ENTER("wolfSSL_EVP_PKEY_new_raw_public_key");
|
|
|
|
if (pub == NULL || len == 0) {
|
|
return NULL;
|
|
}
|
|
|
|
pkey = wolfSSL_EVP_PKEY_new();
|
|
if (pkey == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
switch (type) {
|
|
#ifdef HAVE_ED25519
|
|
case WC_EVP_PKEY_ED25519: {
|
|
ed25519_key* edKey;
|
|
if (len != ED25519_PUB_KEY_SIZE) {
|
|
break;
|
|
}
|
|
edKey = wolfSSL_ED25519_new(pkey->heap, INVALID_DEVID);
|
|
if (edKey == NULL) {
|
|
break;
|
|
}
|
|
if (wc_ed25519_import_public(pub, (word32)len, edKey) != 0) {
|
|
wolfSSL_ED25519_free(edKey);
|
|
break;
|
|
}
|
|
pkey->type = WC_EVP_PKEY_ED25519;
|
|
pkey->ed25519 = edKey;
|
|
pkey->ownEd25519 = 1;
|
|
ok = 1;
|
|
break;
|
|
}
|
|
#endif
|
|
#ifdef HAVE_ED448
|
|
case WC_EVP_PKEY_ED448: {
|
|
ed448_key* edKey;
|
|
if (len != ED448_PUB_KEY_SIZE) {
|
|
break;
|
|
}
|
|
edKey = wolfSSL_ED448_new(pkey->heap, INVALID_DEVID);
|
|
if (edKey == NULL) {
|
|
break;
|
|
}
|
|
if (wc_ed448_import_public(pub, (word32)len, edKey) != 0) {
|
|
wolfSSL_ED448_free(edKey);
|
|
break;
|
|
}
|
|
pkey->type = WC_EVP_PKEY_ED448;
|
|
pkey->ed448 = edKey;
|
|
pkey->ownEd448 = 1;
|
|
ok = 1;
|
|
break;
|
|
}
|
|
#endif
|
|
#ifdef HAVE_CURVE25519
|
|
case WC_EVP_PKEY_X25519: {
|
|
curve25519_key* cKey;
|
|
if (len != CURVE25519_PUB_KEY_SIZE) {
|
|
break;
|
|
}
|
|
cKey = (curve25519_key*)XMALLOC(sizeof(curve25519_key), pkey->heap,
|
|
DYNAMIC_TYPE_CURVE25519);
|
|
if (cKey == NULL) {
|
|
break;
|
|
}
|
|
if (wc_curve25519_init_ex(cKey, pkey->heap, INVALID_DEVID) != 0) {
|
|
XFREE(cKey, pkey->heap, DYNAMIC_TYPE_CURVE25519);
|
|
break;
|
|
}
|
|
/* Raw X25519 keys are little-endian (RFC 7748). */
|
|
if (wc_curve25519_import_public_ex(pub, (word32)len, cKey,
|
|
EC25519_LITTLE_ENDIAN) != 0) {
|
|
wc_curve25519_free(cKey);
|
|
XFREE(cKey, pkey->heap, DYNAMIC_TYPE_CURVE25519);
|
|
break;
|
|
}
|
|
pkey->type = WC_EVP_PKEY_X25519;
|
|
pkey->curve25519 = cKey;
|
|
pkey->ownCurve25519 = 1;
|
|
ok = 1;
|
|
break;
|
|
}
|
|
#endif
|
|
#ifdef HAVE_CURVE448
|
|
case WC_EVP_PKEY_X448: {
|
|
curve448_key* cKey;
|
|
if (len != CURVE448_PUB_KEY_SIZE) {
|
|
break;
|
|
}
|
|
cKey = (curve448_key*)XMALLOC(sizeof(curve448_key), pkey->heap,
|
|
DYNAMIC_TYPE_CURVE448);
|
|
if (cKey == NULL) {
|
|
break;
|
|
}
|
|
if (wc_curve448_init(cKey) != 0) {
|
|
XFREE(cKey, pkey->heap, DYNAMIC_TYPE_CURVE448);
|
|
break;
|
|
}
|
|
/* Raw X448 keys are little-endian (RFC 7748). */
|
|
if (wc_curve448_import_public_ex(pub, (word32)len, cKey,
|
|
EC448_LITTLE_ENDIAN) != 0) {
|
|
wc_curve448_free(cKey);
|
|
XFREE(cKey, pkey->heap, DYNAMIC_TYPE_CURVE448);
|
|
break;
|
|
}
|
|
pkey->type = WC_EVP_PKEY_X448;
|
|
pkey->curve448 = cKey;
|
|
pkey->ownCurve448 = 1;
|
|
ok = 1;
|
|
break;
|
|
}
|
|
#endif
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (!ok) {
|
|
wolfSSL_EVP_PKEY_free(pkey);
|
|
return NULL;
|
|
}
|
|
|
|
/* Stash the raw bytes so callers that later serialize the EVP_PKEY see
|
|
* consistent state. */
|
|
pkey->pkey.ptr = (char*)XMALLOC(len, pkey->heap, DYNAMIC_TYPE_PUBLIC_KEY);
|
|
if (pkey->pkey.ptr == NULL) {
|
|
wolfSSL_EVP_PKEY_free(pkey);
|
|
return NULL;
|
|
}
|
|
XMEMCPY(pkey->pkey.ptr, pub, len);
|
|
pkey->pkey_sz = (int)len;
|
|
|
|
return pkey;
|
|
}
|
|
|
|
/* Private-key counterpart to wolfSSL_EVP_PKEY_new_raw_public_key. The raw
|
|
* input is the 32-byte seed (Ed25519) or 57-byte seed (Ed448).
|
|
*/
|
|
WOLFSSL_EVP_PKEY* wolfSSL_EVP_PKEY_new_raw_private_key(int type,
|
|
WOLFSSL_ENGINE* e, const unsigned char* priv, size_t len)
|
|
{
|
|
WOLFSSL_EVP_PKEY* pkey;
|
|
int ok = 0;
|
|
|
|
(void)e;
|
|
WOLFSSL_ENTER("wolfSSL_EVP_PKEY_new_raw_private_key");
|
|
|
|
if (priv == NULL || len == 0) {
|
|
return NULL;
|
|
}
|
|
|
|
pkey = wolfSSL_EVP_PKEY_new();
|
|
if (pkey == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
switch (type) {
|
|
#ifdef HAVE_ED25519
|
|
case WC_EVP_PKEY_ED25519: {
|
|
ed25519_key* edKey;
|
|
if (len != ED25519_KEY_SIZE) {
|
|
break;
|
|
}
|
|
edKey = wolfSSL_ED25519_new(pkey->heap, INVALID_DEVID);
|
|
if (edKey == NULL) {
|
|
break;
|
|
}
|
|
if (wc_ed25519_import_private_only(priv, (word32)len, edKey)
|
|
!= 0) {
|
|
wolfSSL_ED25519_free(edKey);
|
|
break;
|
|
}
|
|
pkey->type = WC_EVP_PKEY_ED25519;
|
|
pkey->ed25519 = edKey;
|
|
pkey->ownEd25519 = 1;
|
|
ok = 1;
|
|
break;
|
|
}
|
|
#endif
|
|
#ifdef HAVE_ED448
|
|
case WC_EVP_PKEY_ED448: {
|
|
ed448_key* edKey;
|
|
if (len != ED448_KEY_SIZE) {
|
|
break;
|
|
}
|
|
edKey = wolfSSL_ED448_new(pkey->heap, INVALID_DEVID);
|
|
if (edKey == NULL) {
|
|
break;
|
|
}
|
|
if (wc_ed448_import_private_only(priv, (word32)len, edKey) != 0) {
|
|
wolfSSL_ED448_free(edKey);
|
|
break;
|
|
}
|
|
pkey->type = WC_EVP_PKEY_ED448;
|
|
pkey->ed448 = edKey;
|
|
pkey->ownEd448 = 1;
|
|
ok = 1;
|
|
break;
|
|
}
|
|
#endif
|
|
#ifdef HAVE_CURVE25519
|
|
case WC_EVP_PKEY_X25519: {
|
|
curve25519_key* cKey;
|
|
if (len != CURVE25519_KEYSIZE) {
|
|
break;
|
|
}
|
|
cKey = (curve25519_key*)XMALLOC(sizeof(curve25519_key), pkey->heap,
|
|
DYNAMIC_TYPE_CURVE25519);
|
|
if (cKey == NULL) {
|
|
break;
|
|
}
|
|
if (wc_curve25519_init_ex(cKey, pkey->heap, INVALID_DEVID) != 0) {
|
|
XFREE(cKey, pkey->heap, DYNAMIC_TYPE_CURVE25519);
|
|
break;
|
|
}
|
|
#ifdef WOLFSSL_CURVE25519_BLINDING
|
|
/* Use the EVP_PKEY's RNG for scalar blinding on shared-secret. */
|
|
(void)wc_curve25519_set_rng(cKey, &pkey->rng);
|
|
#endif
|
|
/* Raw X25519 keys are little-endian (RFC 7748). */
|
|
if (wc_curve25519_import_private_ex(priv, (word32)len, cKey,
|
|
EC25519_LITTLE_ENDIAN) != 0) {
|
|
wc_curve25519_free(cKey);
|
|
XFREE(cKey, pkey->heap, DYNAMIC_TYPE_CURVE25519);
|
|
break;
|
|
}
|
|
pkey->type = WC_EVP_PKEY_X25519;
|
|
pkey->curve25519 = cKey;
|
|
pkey->ownCurve25519 = 1;
|
|
ok = 1;
|
|
break;
|
|
}
|
|
#endif
|
|
#ifdef HAVE_CURVE448
|
|
case WC_EVP_PKEY_X448: {
|
|
curve448_key* cKey;
|
|
if (len != CURVE448_KEY_SIZE) {
|
|
break;
|
|
}
|
|
cKey = (curve448_key*)XMALLOC(sizeof(curve448_key), pkey->heap,
|
|
DYNAMIC_TYPE_CURVE448);
|
|
if (cKey == NULL) {
|
|
break;
|
|
}
|
|
if (wc_curve448_init(cKey) != 0) {
|
|
XFREE(cKey, pkey->heap, DYNAMIC_TYPE_CURVE448);
|
|
break;
|
|
}
|
|
/* Raw X448 keys are little-endian (RFC 7748). */
|
|
if (wc_curve448_import_private_ex(priv, (word32)len, cKey,
|
|
EC448_LITTLE_ENDIAN) != 0) {
|
|
wc_curve448_free(cKey);
|
|
XFREE(cKey, pkey->heap, DYNAMIC_TYPE_CURVE448);
|
|
break;
|
|
}
|
|
pkey->type = WC_EVP_PKEY_X448;
|
|
pkey->curve448 = cKey;
|
|
pkey->ownCurve448 = 1;
|
|
ok = 1;
|
|
break;
|
|
}
|
|
#endif
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (!ok) {
|
|
wolfSSL_EVP_PKEY_free(pkey);
|
|
return NULL;
|
|
}
|
|
|
|
pkey->pkey.ptr = (char*)XMALLOC(len, pkey->heap, DYNAMIC_TYPE_PRIVATE_KEY);
|
|
if (pkey->pkey.ptr == NULL) {
|
|
wolfSSL_EVP_PKEY_free(pkey);
|
|
return NULL;
|
|
}
|
|
XMEMCPY(pkey->pkey.ptr, priv, len);
|
|
pkey->pkey_sz = (int)len;
|
|
|
|
return pkey;
|
|
}
|
|
|
|
#if !defined(NO_DSA)
|
|
/**
|
|
* Try to make a DSA EVP PKEY from data.
|
|
*
|
|
* @param [in, out] out On in, an EVP PKEY or NULL.
|
|
* On out, an EVP PKEY or NULL.
|
|
* @param [in] mem Memory containing key data.
|
|
* @param [in] memSz Size of key data in bytes.
|
|
* @param [in] priv 1 means private key, 0 means public key.
|
|
* @return 1 on success.
|
|
* @return 0 when input was recognized as this key type but
|
|
* object creation/import failed.
|
|
* @return WOLFSSL_FATAL_ERROR when input is not this key type.
|
|
*/
|
|
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;
|
|
}
|
|
|
|
/* Try decoding data as a DSA private/public key. */
|
|
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);
|
|
|
|
/* test if DSA key */
|
|
if (!isDsaKey) {
|
|
return WOLFSSL_FATAL_ERROR;
|
|
}
|
|
|
|
/* Create DSA key object from data. */
|
|
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) {
|
|
/* Create an EVP PKEY object. */
|
|
ret = d2i_make_pkey(out, mem, keyIdx, priv, WC_EVP_PKEY_DSA);
|
|
}
|
|
if (ret == 1) {
|
|
/* Put RSA key object into EVP PKEY object. */
|
|
(*out)->ownDsa = 1;
|
|
(*out)->dsa = dsaObj;
|
|
}
|
|
if (ret == 0) {
|
|
wolfSSL_DSA_free(dsaObj);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
#endif /* NO_DSA */
|
|
|
|
#if !defined(NO_DH) && (defined(WOLFSSL_QT) || defined(OPENSSL_ALL))
|
|
#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \
|
|
(HAVE_FIPS_VERSION > 2))
|
|
/**
|
|
* Try to make a DH EVP PKEY from data.
|
|
*
|
|
* @param [in, out] out On in, an EVP PKEY or NULL.
|
|
* On out, an EVP PKEY or NULL.
|
|
* @param [in] mem Memory containing key data.
|
|
* @param [in] memSz Size of key data in bytes.
|
|
* @param [in] priv 1 means private key, 0 means public key.
|
|
* @return 1 on success.
|
|
* @return 0 when input was recognized as this key type but
|
|
* object creation/import failed.
|
|
* @return WOLFSSL_FATAL_ERROR when input is not this key type.
|
|
*/
|
|
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;
|
|
}
|
|
|
|
/* Try decoding data as a DH public key. */
|
|
isDhKey = (wc_DhKeyDecode(mem, &keyIdx, dh, (word32)memSz) == 0);
|
|
wc_FreeDhKey(dh);
|
|
WC_FREE_VAR_EX(dh, NULL, DYNAMIC_TYPE_DH);
|
|
|
|
/* test if DH key */
|
|
if (!isDhKey) {
|
|
return WOLFSSL_FATAL_ERROR;
|
|
}
|
|
|
|
/* Create DH key object from data. */
|
|
dhObj = wolfSSL_DH_new();
|
|
if (dhObj == NULL) {
|
|
ret = 0;
|
|
}
|
|
if ((ret == 1) && (wolfSSL_DH_LoadDer(dhObj, mem, keyIdx) != 1)) {
|
|
ret = 0;
|
|
}
|
|
if (ret == 1) {
|
|
/* Create an EVP PKEY object. */
|
|
ret = d2i_make_pkey(out, mem, keyIdx, priv, WC_EVP_PKEY_DH);
|
|
}
|
|
if (ret == 1) {
|
|
/* Put RSA key object into EVP PKEY object. */
|
|
(*out)->ownDh = 1;
|
|
(*out)->dh = dhObj;
|
|
}
|
|
if (ret == 0) {
|
|
wolfSSL_DH_free(dhObj);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
#endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */
|
|
#endif /* !NO_DH && (WOLFSSL_QT || OPENSSL_ALL) */
|
|
|
|
#if !defined(NO_DH) && defined(OPENSSL_EXTRA) && defined(WOLFSSL_DH_EXTRA)
|
|
#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \
|
|
(HAVE_FIPS_VERSION > 2))
|
|
/**
|
|
* Try to make a DH EVP PKEY from data.
|
|
*
|
|
* @param [in, out] out On in, an EVP PKEY or NULL.
|
|
* On out, an EVP PKEY or NULL.
|
|
* @param [in] mem Memory containing key data.
|
|
* @param [in] memSz Size of key data in bytes.
|
|
* @param [in] priv 1 means private key, 0 means public key.
|
|
* @return 1 on success.
|
|
* @return 0 when input was recognized as this key type but
|
|
* object creation/import failed.
|
|
* @return WOLFSSL_FATAL_ERROR when input is not this key type.
|
|
*/
|
|
static int d2iTryAltDhKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem,
|
|
long memSz, int priv)
|
|
{
|
|
WOLFSSL_DH* dhObj = NULL;
|
|
word32 keyIdx = 0;
|
|
DhKey* key = NULL;
|
|
int elements;
|
|
int ret = 1;
|
|
|
|
/* Create DH key object from data. */
|
|
dhObj = wolfSSL_DH_new();
|
|
if (dhObj == NULL) {
|
|
ret = WOLFSSL_FATAL_ERROR;
|
|
}
|
|
|
|
if (ret == 1) {
|
|
key = (DhKey*)dhObj->internal;
|
|
/* Try decoding data as a DH public key. */
|
|
if (wc_DhKeyDecode(mem, &keyIdx, key, (word32)memSz) != 0) {
|
|
ret = WOLFSSL_FATAL_ERROR;
|
|
}
|
|
}
|
|
if (ret == 1) {
|
|
/* DH key has data and is external to DH object. */
|
|
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) {
|
|
/* Create an EVP PKEY object. */
|
|
ret = d2i_make_pkey(out, mem, keyIdx, priv, WC_EVP_PKEY_DH);
|
|
}
|
|
if (ret == 1) {
|
|
/* Put DH key object into EVP PKEY object. */
|
|
(*out)->ownDh = 1;
|
|
(*out)->dh = dhObj;
|
|
}
|
|
else if (dhObj != NULL) {
|
|
wolfSSL_DH_free(dhObj);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
#endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */
|
|
#endif /* !NO_DH && OPENSSL_EXTRA && WOLFSSL_DH_EXTRA */
|
|
|
|
#ifdef HAVE_FALCON
|
|
/**
|
|
* Attempt to import a private Falcon key at a specified level.
|
|
*
|
|
* @param [in] falcon Falcon key object.
|
|
* @param [in] level Level of Falcon key.
|
|
* @param [in] mem Memory containing key data.
|
|
* @param [in] memSz Size of key data in bytes.
|
|
* @return 1 on success.
|
|
* @return 0 otherwise.
|
|
*/
|
|
static int d2i_falcon_priv_key_level(falcon_key* falcon, byte level,
|
|
const unsigned char* mem, long memSz)
|
|
{
|
|
word32 idx = 0;
|
|
return (wc_falcon_set_level(falcon, level) == 0) &&
|
|
(wc_Falcon_PrivateKeyDecode(mem, &idx, falcon,
|
|
(word32)memSz) == 0);
|
|
}
|
|
|
|
/**
|
|
* Attempt to import a public Falcon key at a specified level.
|
|
*
|
|
* @param [in] falcon Falcon key object.
|
|
* @param [in] level Level of Falcon key.
|
|
* @param [in] mem Memory containing key data.
|
|
* @param [in] memSz Size of key data in bytes.
|
|
* @return 1 on success.
|
|
* @return 0 otherwise.
|
|
*/
|
|
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);
|
|
}
|
|
|
|
/**
|
|
* Try to make a Falcon EVP PKEY from data.
|
|
*
|
|
* @param [in, out] out On in, an EVP PKEY or NULL.
|
|
* On out, an EVP PKEY or NULL.
|
|
* @param [in] mem Memory containing key data.
|
|
* @param [in] memSz Size of key data in bytes.
|
|
* @param [in] priv 1 means private key, 0 means public key.
|
|
* @return 1 on success.
|
|
* @return 0 when input was recognized as this key type but
|
|
* object creation/import failed.
|
|
* @return WOLFSSL_FATAL_ERROR when input is not this key type.
|
|
*/
|
|
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;
|
|
}
|
|
|
|
/* Try decoding data as a Falcon private/public key. */
|
|
if (priv) {
|
|
/* Try level 1 */
|
|
isFalcon = d2i_falcon_priv_key_level(falcon, 1, mem, memSz);
|
|
if (!isFalcon) {
|
|
/* Try level 5 */
|
|
isFalcon = d2i_falcon_priv_key_level(falcon, 5, mem, memSz);
|
|
}
|
|
}
|
|
else {
|
|
/* Try level 1 */
|
|
isFalcon = d2i_falcon_pub_key_level(falcon, 1, mem, memSz);
|
|
if (!isFalcon) {
|
|
/* Try level 5 */
|
|
isFalcon = d2i_falcon_pub_key_level(falcon, 5, mem, memSz);
|
|
}
|
|
}
|
|
/* Dispose of any Falcon key created. */
|
|
wc_falcon_free(falcon);
|
|
WC_FREE_VAR_EX(falcon, NULL, DYNAMIC_TYPE_FALCON);
|
|
|
|
if (!isFalcon) {
|
|
return WOLFSSL_FATAL_ERROR;
|
|
}
|
|
|
|
/* Create an EVP PKEY object. */
|
|
return d2i_make_pkey(out, NULL, 0, priv, WC_EVP_PKEY_FALCON);
|
|
}
|
|
#endif /* HAVE_FALCON */
|
|
|
|
#ifdef WOLFSSL_HAVE_MLDSA
|
|
/**
|
|
* Try to make an ML-DSA EVP PKEY from data.
|
|
*
|
|
* Accepts either raw key bytes or DER (PKCS#8 / SPKI). Raw bytes are
|
|
* size-keyed, so each level is tried in turn. DER input is decoded once,
|
|
* letting the decoder auto-detect the level from the OID.
|
|
*
|
|
* @param [in, out] out On in, an EVP PKEY or NULL.
|
|
* On out, an EVP PKEY or NULL.
|
|
* @param [in] mem Memory containing key data.
|
|
* @param [in] memSz Size of key data in bytes.
|
|
* @param [in] priv 1 means private key, 0 means public key.
|
|
* @return 1 on success.
|
|
* @return 0 when input was recognized as this key type but
|
|
* object creation/import failed.
|
|
* @return WOLFSSL_FATAL_ERROR when input is not this key type.
|
|
*/
|
|
static int d2iTryMlDsaKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem,
|
|
long memSz, int priv)
|
|
{
|
|
static const byte levels[] = { WC_ML_DSA_44, WC_ML_DSA_65, WC_ML_DSA_87 };
|
|
word32 inSz = (word32)memSz;
|
|
word32 keyIdx = 0;
|
|
int isMlDsa = 0;
|
|
int i, numLevels, rc;
|
|
WC_DECLARE_VAR(mldsa, wc_MlDsaKey, 1, NULL);
|
|
|
|
#if !defined(WOLFSSL_MLDSA_PRIVATE_KEY)
|
|
if (priv) {
|
|
return WOLFSSL_FATAL_ERROR;
|
|
}
|
|
#endif
|
|
|
|
WC_ALLOC_VAR_EX(mldsa, wc_MlDsaKey, 1, NULL, DYNAMIC_TYPE_MLDSA,
|
|
return 0);
|
|
|
|
if (wc_MlDsaKey_Init(mldsa, NULL, INVALID_DEVID) != 0) {
|
|
WC_FREE_VAR_EX(mldsa, NULL, DYNAMIC_TYPE_MLDSA);
|
|
return 0;
|
|
}
|
|
|
|
/* Raw key bytes are size-keyed, try each level */
|
|
numLevels = (int)(sizeof(levels) / sizeof(levels[0]));
|
|
for (i = 0; i < numLevels && !isMlDsa; i++) {
|
|
if (wc_MlDsaKey_SetParams(mldsa, levels[i]) != 0) {
|
|
continue;
|
|
}
|
|
#if defined(WOLFSSL_MLDSA_PRIVATE_KEY)
|
|
if (priv) {
|
|
rc = wc_MlDsaKey_ImportPrivRaw(mldsa, mem, inSz);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
rc = wc_MlDsaKey_ImportPubRaw(mldsa, mem, inSz);
|
|
}
|
|
if (rc == 0) {
|
|
isMlDsa = 1;
|
|
}
|
|
}
|
|
|
|
/* DER input includes auto level detection */
|
|
if (!isMlDsa) {
|
|
wc_MlDsaKey_Free(mldsa);
|
|
if (wc_MlDsaKey_Init(mldsa, NULL, INVALID_DEVID) != 0) {
|
|
WC_FREE_VAR_EX(mldsa, NULL, DYNAMIC_TYPE_MLDSA);
|
|
return 0;
|
|
}
|
|
#if defined(WOLFSSL_MLDSA_PRIVATE_KEY)
|
|
if (priv) {
|
|
rc = wc_MlDsaKey_PrivateKeyDecode(mldsa, mem, inSz, &keyIdx);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
rc = wc_MlDsaKey_PublicKeyDecode(mldsa, mem, inSz, &keyIdx);
|
|
}
|
|
if (rc == 0) {
|
|
isMlDsa = 1;
|
|
}
|
|
}
|
|
|
|
wc_MlDsaKey_Free(mldsa);
|
|
WC_FREE_VAR_EX(mldsa, NULL, DYNAMIC_TYPE_MLDSA);
|
|
|
|
if (!isMlDsa) {
|
|
return WOLFSSL_FATAL_ERROR;
|
|
}
|
|
|
|
/* Copy the consumed DER into pkey->pkey.ptr when the input was DER */
|
|
return d2i_make_pkey(out, mem, keyIdx, priv, WC_EVP_PKEY_DILITHIUM);
|
|
}
|
|
#endif /* WOLFSSL_HAVE_MLDSA */
|
|
|
|
/**
|
|
* Try to make a WOLFSSL_EVP_PKEY from data.
|
|
*
|
|
* @param [in, out] out On in, an EVP PKEY or NULL.
|
|
* On out, an EVP PKEY or NULL.
|
|
* @param [in] mem Memory containing key data.
|
|
* @param [in] memSz Size of key data in bytes.
|
|
* @param [in] priv 1 means private key, 0 means public key.
|
|
* @return Non-NULL WOLFSSL_EVP_PKEY* on success.
|
|
* @return NULL on bad arguments or unrecognized input type.
|
|
*/
|
|
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;
|
|
int found = 0;
|
|
|
|
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) {
|
|
found = 1;
|
|
}
|
|
else
|
|
#endif /* NO_RSA */
|
|
#if defined(HAVE_ECC) && defined(OPENSSL_EXTRA)
|
|
if (d2iTryEccKey(&pkey, *in, inSz, priv) >= 0) {
|
|
found = 1;
|
|
}
|
|
else
|
|
#endif /* HAVE_ECC && OPENSSL_EXTRA */
|
|
#if !defined(NO_DSA)
|
|
if (d2iTryDsaKey(&pkey, *in, inSz, priv) >= 0) {
|
|
found = 1;
|
|
}
|
|
else
|
|
#endif /* NO_DSA */
|
|
#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) {
|
|
found = 1;
|
|
}
|
|
else
|
|
#endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */
|
|
#endif /* !NO_DH && (WOLFSSL_QT || OPENSSL_ALL) */
|
|
|
|
#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) {
|
|
found = 1;
|
|
}
|
|
else
|
|
#endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */
|
|
#endif /* !NO_DH && OPENSSL_EXTRA && WOLFSSL_DH_EXTRA */
|
|
|
|
#ifdef HAVE_ED25519
|
|
if (d2iTryEd25519Key(&pkey, *in, inSz, priv) >= 0) {
|
|
found = 1;
|
|
}
|
|
else
|
|
#endif /* HAVE_ED25519 */
|
|
#ifdef HAVE_ED448
|
|
if (d2iTryEd448Key(&pkey, *in, inSz, priv) >= 0) {
|
|
found = 1;
|
|
}
|
|
else
|
|
#endif /* HAVE_ED448 */
|
|
#ifdef HAVE_FALCON
|
|
if (d2iTryFalconKey(&pkey, *in, inSz, priv) >= 0) {
|
|
found = 1;
|
|
}
|
|
else
|
|
#endif /* HAVE_FALCON */
|
|
#ifdef WOLFSSL_HAVE_MLDSA
|
|
if (d2iTryMlDsaKey(&pkey, *in, inSz, priv) >= 0) {
|
|
found = 1;
|
|
}
|
|
else
|
|
#endif /* WOLFSSL_HAVE_MLDSA */
|
|
{
|
|
WOLFSSL_MSG("d2i_evp_pkey_try couldn't determine key type");
|
|
}
|
|
|
|
if (!found) {
|
|
return NULL;
|
|
}
|
|
|
|
if ((pkey != NULL) && (out != NULL)) {
|
|
*out = pkey;
|
|
}
|
|
return pkey;
|
|
}
|
|
#endif /* OPENSSL_EXTRA || WPA_SMALL */
|
|
|
|
#ifdef OPENSSL_EXTRA
|
|
/* Converts a DER encoded public key to a WOLFSSL_EVP_PKEY structure.
|
|
*
|
|
* @param [in, out] out Pointer to new WOLFSSL_EVP_PKEY structure.
|
|
* Can be NULL.
|
|
* @param [in, out] in DER buffer to convert.
|
|
* @param [in] inSz Size of in buffer.
|
|
* @return Pointer to a new WOLFSSL_EVP_PKEY structure on success.
|
|
* @return NULL on failure. *out is left unchanged on failure; caller
|
|
* retains ownership of any pre-existing key passed via *out.
|
|
*/
|
|
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
|
|
/* Converts a DER encoded public key in a BIO to a WOLFSSL_EVP_PKEY structure.
|
|
*
|
|
* @param [in] bio BIO to read DER from.
|
|
* @param [out] out New WOLFSSL_EVP_PKEY pointer when not NULL.
|
|
* @return Pointer to a new WOLFSSL_EVP_PKEY structure on success.
|
|
* @return NULL on failure.
|
|
*/
|
|
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");
|
|
|
|
/* Validate parameters. */
|
|
if (bio == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
/* Get length of data in BIO. */
|
|
memSz = wolfSSL_BIO_get_len(bio);
|
|
if (memSz <= 0) {
|
|
return NULL;
|
|
}
|
|
/* Allocate memory to read all of BIO data into. */
|
|
mem = (unsigned char*)XMALLOC((size_t)memSz, bio->heap,
|
|
DYNAMIC_TYPE_TMP_BUFFER);
|
|
if (mem == NULL) {
|
|
return NULL;
|
|
}
|
|
/* Read all data into allocated buffer. */
|
|
if (wolfSSL_BIO_read(bio, mem, (int)memSz) == memSz) {
|
|
/* Create a WOLFSSL_EVP_PKEY from data. */
|
|
pkey = wolfSSL_d2i_PUBKEY(NULL, (const unsigned char**)&mem, memSz);
|
|
if (out != NULL && pkey != NULL) {
|
|
/* Return new WOLFSSL_EVP_PKEY through parameter. */
|
|
*out = pkey;
|
|
}
|
|
}
|
|
|
|
/* Dispose of memory holding BIO data. */
|
|
XFREE(mem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER);
|
|
return pkey;
|
|
}
|
|
#endif /* !NO_BIO */
|
|
#endif /* OPENSSL_EXTRA */
|
|
|
|
#if defined(OPENSSL_ALL) || defined(WOLFSSL_ASIO) || \
|
|
defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_NGINX) || \
|
|
defined(WOLFSSL_QT) || defined(WOLFSSL_WPAS_SMALL)
|
|
/* Converts a DER encoded private key to a WOLFSSL_EVP_PKEY structure.
|
|
*
|
|
* @param [in, out] out Pointer to new WOLFSSL_EVP_PKEY structure.
|
|
* Can be NULL.
|
|
* @param [in, out] in DER buffer to convert.
|
|
* @param [in] inSz Size of in buffer.
|
|
* @return Pointer to a new WOLFSSL_EVP_PKEY structure on success.
|
|
* @return NULL on failure. *out is left unchanged on failure; caller
|
|
* retains ownership of any pre-existing key passed via *out.
|
|
*/
|
|
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 /* OPENSSL_ALL || WOLFSSL_ASIO || WOLFSSL_HAPROXY || WOLFSSL_QT ||
|
|
* WOLFSSL_WPAS_SMALL*/
|
|
|
|
#if defined(OPENSSL_ALL) || defined(WOLFSSL_ASIO) || \
|
|
defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_QT)
|
|
|
|
#ifndef NO_BIO
|
|
/* Converts a DER encoded private key in a BIO to a WOLFSSL_EVP_PKEY structure.
|
|
*
|
|
* @param [in] bio BIO to read DER from.
|
|
* @param [out] out New WOLFSSL_EVP_PKEY pointer when not NULL.
|
|
* @return Pointer to a new WOLFSSL_EVP_PKEY structure on success.
|
|
* @return NULL on failure.
|
|
*/
|
|
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");
|
|
|
|
/* Validate parameters. */
|
|
if (bio == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
/* Get length of data in BIO. */
|
|
memSz = wolfSSL_BIO_get_len(bio);
|
|
if (memSz <= 0) {
|
|
WOLFSSL_MSG("wolfSSL_BIO_get_len() failure");
|
|
return NULL;
|
|
}
|
|
/* Allocate memory to read all of BIO data into. */
|
|
mem = (unsigned char*)XMALLOC((size_t)memSz, bio->heap,
|
|
DYNAMIC_TYPE_TMP_BUFFER);
|
|
if (mem == NULL) {
|
|
WOLFSSL_MSG("Malloc failure");
|
|
return NULL;
|
|
}
|
|
|
|
/* Read all of data. */
|
|
if (wolfSSL_BIO_read(bio, (unsigned char*)mem, memSz) == memSz) {
|
|
/* Determines key type and returns the new private EVP_PKEY object */
|
|
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;
|
|
}
|
|
|
|
/* Write extra data back into bio object if necessary. */
|
|
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;
|
|
}
|
|
}
|
|
|
|
/* Return key through parameter if required. */
|
|
if (out != NULL) {
|
|
*out = key;
|
|
}
|
|
}
|
|
|
|
/* Dispose of memory holding BIO data. */
|
|
XFREE(mem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER);
|
|
return key;
|
|
}
|
|
#endif /* !NO_BIO */
|
|
|
|
#endif /* OPENSSL_ALL || WOLFSSL_ASIO || WOLFSSL_HAPROXY || WOLFSSL_NGINX ||
|
|
* WOLFSSL_QT */
|
|
|
|
#ifdef OPENSSL_EXTRA
|
|
/* Reads in a DER format key. If PKCS8 headers are found they are stripped off.
|
|
*
|
|
* @param [in] type Type of key.
|
|
* @param [in, out] out Newly created WOLFSSL_EVP_PKEY structure.
|
|
* @param [in, out] in Pointer to input key DER.
|
|
* Pointer is advanced the same number of bytes read on
|
|
* success.
|
|
* @param [in] inSz Size of in buffer.
|
|
* @return A non null pointer on success.
|
|
* @return NULL on failure.
|
|
*/
|
|
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;
|
|
|
|
/* Validate parameters. */
|
|
if (in == NULL || inSz < 0) {
|
|
WOLFSSL_MSG("Bad argument");
|
|
return NULL;
|
|
}
|
|
|
|
if (priv == 1) {
|
|
/* Check if input buffer has PKCS8 header. In the case that it does not
|
|
* have a PKCS8 header then do not error out. */
|
|
if ((ret = ToTraditionalInline_ex((const byte*)(*in), &idx,
|
|
(word32)inSz, &algId)) >= 0) {
|
|
WOLFSSL_MSG("Found PKCS8 header");
|
|
pkcs8HeaderSz = (word16)idx;
|
|
|
|
/* Check header algorithm id matches algorithm type passed in. */
|
|
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)
|
|
#ifdef HAVE_ED25519
|
|
|| (type == WC_EVP_PKEY_ED25519 && algId != ED25519k)
|
|
#endif
|
|
#ifdef HAVE_ED448
|
|
|| (type == WC_EVP_PKEY_ED448 && algId != ED448k)
|
|
#endif
|
|
) {
|
|
WOLFSSL_MSG("PKCS8 does not match EVP key type");
|
|
return NULL;
|
|
}
|
|
|
|
(void)idx; /* not used */
|
|
}
|
|
/* Ensure no error occurred try to remove any PKCS#8 header. */
|
|
else if (ret != WC_NO_ERR_TRACE(ASN_PARSE_E)) {
|
|
WOLFSSL_MSG("Unexpected error with trying to remove PKCS8 header");
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/* Dispose of any WOLFSSL_EVP_PKEY passed in. */
|
|
if (out != NULL && *out != NULL) {
|
|
wolfSSL_EVP_PKEY_free(*out);
|
|
*out = NULL;
|
|
}
|
|
/* Create a new WOLFSSL_EVP_PKEY and populate. */
|
|
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;
|
|
|
|
/* Create an algorithm specific object into WOLFSSL_EVP_PKEY. */
|
|
switch (type) {
|
|
#ifndef NO_RSA
|
|
case WC_EVP_PKEY_RSA:
|
|
/* Create a WOLFSSL_RSA object. */
|
|
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 /* NO_RSA */
|
|
#ifdef HAVE_ECC
|
|
case WC_EVP_PKEY_EC:
|
|
/* Create a WOLFSSL_EC object. */
|
|
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 /* HAVE_ECC */
|
|
#if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) || defined(WOLFSSL_OPENSSH)
|
|
#ifndef NO_DSA
|
|
case WC_EVP_PKEY_DSA:
|
|
/* Create a WOLFSSL_DSA object. */
|
|
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 /* NO_DSA */
|
|
#ifndef NO_DH
|
|
#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION>2))
|
|
case WC_EVP_PKEY_DH:
|
|
/* Create a WOLFSSL_DH object. */
|
|
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 /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */
|
|
#endif /* HAVE_DH */
|
|
#endif /* WOLFSSL_QT || OPENSSL_ALL || WOLFSSL_OPENSSH */
|
|
#ifdef HAVE_ED25519
|
|
case WC_EVP_PKEY_ED25519:
|
|
/* local->pkey.ptr already holds the input bytes, so
|
|
* d2iTryEd25519Key will skip the d2i_make_pkey allocate/copy
|
|
* and just decode into local->ed25519. */
|
|
if (d2iTryEd25519Key(&local, p, local->pkey_sz, priv) != 1) {
|
|
wolfSSL_EVP_PKEY_free(local);
|
|
return NULL;
|
|
}
|
|
break;
|
|
#endif /* HAVE_ED25519 */
|
|
#ifdef HAVE_ED448
|
|
case WC_EVP_PKEY_ED448:
|
|
/* See WC_EVP_PKEY_ED25519 case above. */
|
|
if (d2iTryEd448Key(&local, p, local->pkey_sz, priv) != 1) {
|
|
wolfSSL_EVP_PKEY_free(local);
|
|
return NULL;
|
|
}
|
|
break;
|
|
#endif /* HAVE_ED448 */
|
|
default:
|
|
WOLFSSL_MSG("Unsupported key type");
|
|
wolfSSL_EVP_PKEY_free(local);
|
|
return NULL;
|
|
}
|
|
|
|
/* Advance pointer and return through parameter when required on success. */
|
|
if (local != NULL) {
|
|
if (local->pkey_sz <= (int)inSz) {
|
|
*in += local->pkey_sz;
|
|
}
|
|
if (out != NULL) {
|
|
*out = local;
|
|
}
|
|
}
|
|
|
|
/* Return newly allocated WOLFSSL_EVP_PKEY structure. */
|
|
return local;
|
|
}
|
|
|
|
/* Reads in a DER format key.
|
|
*
|
|
* @param [in] type Type of key.
|
|
* @param [in, out] out Newly created WOLFSSL_EVP_PKEY structure.
|
|
* @param [in, out] in Pointer to input key DER.
|
|
* Pointer is advanced the same number of bytes read on
|
|
* success.
|
|
* @param [in] inSz Size of in buffer.
|
|
* @return A non null pointer on success.
|
|
* @return NULL on failure.
|
|
*/
|
|
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);
|
|
}
|
|
|
|
/* Reads in a DER format key. If PKCS8 headers are found they are stripped off.
|
|
*
|
|
* @param [in] type Type of key.
|
|
* @param [in, out] out Newly created WOLFSSL_EVP_PKEY structure.
|
|
* @param [in, out] in Pointer to input key DER.
|
|
* Pointer is advanced the same number of bytes read on
|
|
* success.
|
|
* @param [in] inSz Size of in buffer.
|
|
* @return A non null pointer on success.
|
|
* @return NULL on failure.
|
|
*/
|
|
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 /* OPENSSL_EXTRA */
|
|
|
|
#ifdef OPENSSL_ALL
|
|
/* Detect RSA or EC key and decode private key DER.
|
|
*
|
|
* @param [in, out] pkey Newly created WOLFSSL_EVP_PKEY structure.
|
|
* @param [in, out] pp Pointer to private key DER data.
|
|
* @param [in] length Length in bytes of DER data.
|
|
*/
|
|
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;
|
|
|
|
/* Take off PKCS#8 wrapper if found. */
|
|
if ((len = ToTraditionalInline_ex(der, &idx, keyLen, &algId)) >= 0) {
|
|
der += idx;
|
|
keyLen = (word32)len;
|
|
}
|
|
|
|
idx = 0;
|
|
len = 0;
|
|
/* Use the number of elements in the outer sequence to determine key type.
|
|
*/
|
|
ret = GetSequence(der, &idx, &len, keyLen);
|
|
if (ret >= 0) {
|
|
word32 end = idx + (word32)len;
|
|
while (ret >= 0 && idx < end) {
|
|
/* Skip type */
|
|
idx++;
|
|
/* Get length and skip over - keeping count */
|
|
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;
|
|
/* ECC includes version, private[, curve][, public key] */
|
|
if (cnt >= 2 && cnt <= 4) {
|
|
type = WC_EVP_PKEY_EC;
|
|
}
|
|
else {
|
|
type = WC_EVP_PKEY_RSA;
|
|
}
|
|
|
|
/* Decode the detected type of private key. */
|
|
key = wolfSSL_d2i_PrivateKey(type, pkey, &der, keyLen);
|
|
/* Update the pointer to after the DER data. */
|
|
*pp = der;
|
|
}
|
|
|
|
return key;
|
|
}
|
|
|
|
#if !defined(NO_BIO) && !defined(NO_PWDBASED) && defined(HAVE_PKCS8)
|
|
/* Read all of the BIO data into a newly allocated buffer.
|
|
*
|
|
* @param [in] bio BIO to read from.
|
|
* @param [out] data Allocated buffer holding all BIO data.
|
|
* @return Number of bytes allocated and read.
|
|
* @return MEMORY_E on dynamic memory allocation failure.
|
|
* @return Other negative on error.
|
|
*/
|
|
static int bio_get_data(WOLFSSL_BIO* bio, byte** data)
|
|
{
|
|
int ret = 0;
|
|
byte* mem = NULL;
|
|
|
|
/* Get length of data in BIO. */
|
|
ret = wolfSSL_BIO_get_len(bio);
|
|
if (ret > 0) {
|
|
/* Allocate memory big enough to hold data in BIO. */
|
|
mem = (byte*)XMALLOC((size_t)ret, bio->heap, DYNAMIC_TYPE_OPENSSL);
|
|
if (mem == NULL) {
|
|
WOLFSSL_MSG("Memory error");
|
|
ret = MEMORY_E;
|
|
}
|
|
if (ret >= 0) {
|
|
/* Read data from BIO. */
|
|
if ((ret = wolfSSL_BIO_read(bio, mem, ret)) <= 0) {
|
|
XFREE(mem, bio->heap, DYNAMIC_TYPE_OPENSSL);
|
|
ret = MEMORY_E;
|
|
mem = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Return allocated buffer with data from BIO. */
|
|
*data = mem;
|
|
return ret;
|
|
}
|
|
|
|
/* Convert the algorithm id to a key type.
|
|
*
|
|
* @param [in] algId Algorithm Id.
|
|
* @return Key type on success.
|
|
* @return WC_EVP_PKEY_NONE when algorithm id not supported.
|
|
*/
|
|
static int wolfssl_i_alg_id_to_key_type(word32 algId)
|
|
{
|
|
int type;
|
|
|
|
/* Convert algorithm id into EVP PKEY id. */
|
|
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;
|
|
}
|
|
|
|
/* Creates an WOLFSSL_EVP_PKEY from PKCS#8 encrypted private DER in a BIO.
|
|
*
|
|
* Uses the PEM default password callback when cb is NULL.
|
|
*
|
|
* @param [in] bio BIO to read DER from.
|
|
* @param [in, out] pkey Newly created WOLFSSL_EVP_PKEY structure.
|
|
* @param [in] cb Password callback. May be NULL.
|
|
* @param [in] ctx Password callback context. May be NULL.
|
|
* @return A non null pointer on success.
|
|
* @return NULL on failure.
|
|
*/
|
|
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;
|
|
|
|
/* Get the data from the BIO into a newly allocated buffer. */
|
|
if ((len = bio_get_data(bio, &der)) < 0)
|
|
return NULL;
|
|
|
|
/* Use the PEM default callback if none supplied. */
|
|
if (cb == NULL) {
|
|
cb = wolfSSL_PEM_def_callback;
|
|
}
|
|
/* Get the password. */
|
|
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
|
|
|
|
/* Decrypt the PKCS#8 encrypted private key and get algorithm. */
|
|
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;
|
|
}
|
|
|
|
/* Get the key type from the algorithm id of the PKCS#8 header. */
|
|
if ((type = wolfssl_i_alg_id_to_key_type(algId)) == WC_EVP_PKEY_NONE) {
|
|
XFREE(der, bio->heap, DYNAMIC_TYPE_OPENSSL);
|
|
return NULL;
|
|
}
|
|
|
|
/* Decode private key with the known type. */
|
|
p = der;
|
|
key = d2i_evp_pkey(type, pkey, &p, len, 1);
|
|
|
|
/* Dispose of memory holding BIO data. */
|
|
XFREE(der, bio->heap, DYNAMIC_TYPE_OPENSSL);
|
|
return key;
|
|
}
|
|
#endif /* !NO_BIO && !NO_PWDBASED && HAVE_PKCS8 */
|
|
#endif /* OPENSSL_ALL */
|
|
|
|
#ifdef OPENSSL_EXTRA
|
|
/* Reads in a PKCS#8 DER format key.
|
|
*
|
|
* @param [in, out] pkey Newly created WOLFSSL_PKCS8_PRIV_KEY_INFO structure.
|
|
* @param [in, out] keyBuf Pointer to input key DER.
|
|
* Pointer is advanced the same number of bytes read on
|
|
* success.
|
|
* @param [in] keyLen Number of bytes in keyBuf.
|
|
* @return A non null pointer on success.
|
|
* @return NULL on failure.
|
|
*/
|
|
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;
|
|
#ifdef HAVE_DILITHIUM
|
|
word32 outerIdx = 0;
|
|
int outerLen = 0;
|
|
#endif
|
|
|
|
/* Clear the encryption information and DER buffer. */
|
|
XMEMSET(&info, 0, sizeof(info));
|
|
XMEMSET(&rawDer, 0, sizeof(rawDer));
|
|
|
|
/* Validate parameters. */
|
|
if ((keyBuf == NULL) || (*keyBuf == NULL) || (keyLen <= 0)) {
|
|
WOLFSSL_MSG("Bad key PEM/DER args");
|
|
return NULL;
|
|
}
|
|
|
|
/* Try to decode the PEM into DER. */
|
|
ret = PemToDer(*keyBuf, keyLen, PRIVATEKEY_TYPE, &pkcs8Der, NULL, &info,
|
|
NULL);
|
|
if (ret >= 0) {
|
|
/* Cache the amount of data in PEM formatted private key. */
|
|
advanceLen = (int)info.consumed;
|
|
}
|
|
else {
|
|
/* Not PEM - create a DerBuffer with the PKCS#8 DER data. */
|
|
WOLFSSL_MSG("Not PEM format");
|
|
ret = AllocDer(&pkcs8Der, (word32)keyLen, PRIVATEKEY_TYPE, NULL);
|
|
if (ret == 0) {
|
|
XMEMCPY(pkcs8Der->buffer, *keyBuf, keyLen);
|
|
}
|
|
}
|
|
|
|
if (ret == 0) {
|
|
/* Verify this is PKCS8 Key */
|
|
word32 inOutIdx = 0;
|
|
word32 algId;
|
|
|
|
ret = ToTraditionalInline_ex(pkcs8Der->buffer, &inOutIdx,
|
|
pkcs8Der->length, &algId);
|
|
if (ret >= 0) {
|
|
if (advanceLen == 0) {
|
|
/* Set only if not PEM */
|
|
advanceLen = (int)inOutIdx + ret;
|
|
}
|
|
if (algId == DHk) {
|
|
/* Special case for DH as we expect the DER buffer to be always
|
|
* in PKCS8 format */
|
|
rawDer.buffer = pkcs8Der->buffer;
|
|
rawDer.length = inOutIdx + (word32)ret;
|
|
}
|
|
#ifdef HAVE_DILITHIUM
|
|
else if (
|
|
#ifdef WOLFSSL_DILITHIUM_FIPS204_DRAFT
|
|
(algId == DILITHIUM_LEVEL2k) ||
|
|
(algId == DILITHIUM_LEVEL3k) ||
|
|
(algId == DILITHIUM_LEVEL5k) ||
|
|
#endif
|
|
(algId == ML_DSA_LEVEL2k) ||
|
|
(algId == ML_DSA_LEVEL3k) ||
|
|
(algId == ML_DSA_LEVEL5k)) {
|
|
|
|
/* Keep full PKCS#8 wrapper for level recovery from
|
|
* AlgorithmIdentifier parameters */
|
|
rawDer.buffer = pkcs8Der->buffer;
|
|
if (GetSequence(pkcs8Der->buffer, &outerIdx, &outerLen,
|
|
pkcs8Der->length) < 0) {
|
|
ret = ASN_PARSE_E;
|
|
}
|
|
else {
|
|
rawDer.length = outerIdx + (word32)outerLen;
|
|
}
|
|
}
|
|
#endif
|
|
else {
|
|
rawDer.buffer = pkcs8Der->buffer + inOutIdx;
|
|
rawDer.length = (word32)ret;
|
|
}
|
|
if (ret >= 0) {
|
|
ret = 0; /* good DER */
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ret == 0) {
|
|
/* Create a WOLFSSL_EVP_PKEY for a WOLFSSL_PKCS8_PRIV_KEY_INFO. */
|
|
pkcs8 = wolfSSL_EVP_PKEY_new();
|
|
if (pkcs8 == NULL) {
|
|
ret = MEMORY_E;
|
|
}
|
|
}
|
|
if (ret == 0) {
|
|
/* Allocate memory to hold DER. */
|
|
pkcs8->pkey.ptr = (char*)XMALLOC(rawDer.length, NULL,
|
|
DYNAMIC_TYPE_PUBLIC_KEY);
|
|
if (pkcs8->pkey.ptr == NULL) {
|
|
ret = MEMORY_E;
|
|
}
|
|
}
|
|
if (ret == 0) {
|
|
/* Copy in DER data and size. */
|
|
XMEMCPY(pkcs8->pkey.ptr, rawDer.buffer, rawDer.length);
|
|
pkcs8->pkey_sz = (int)rawDer.length;
|
|
}
|
|
|
|
/* Dispose of PKCS#8 DER data - raw DER reference data in pkcs8Der. */
|
|
FreeDer(&pkcs8Der);
|
|
if (ret != 0) {
|
|
/* Dispose of WOLFSSL_PKCS8_PRIV_KEY_INFO object on error. */
|
|
wolfSSL_EVP_PKEY_free(pkcs8);
|
|
pkcs8 = NULL;
|
|
}
|
|
else {
|
|
/* Advance the buffer past the key on success. */
|
|
*keyBuf += advanceLen;
|
|
}
|
|
if (pkey != NULL) {
|
|
/* Return the WOLFSSL_PKCS8_PRIV_KEY_INFO object through parameter. */
|
|
*pkey = pkcs8;
|
|
}
|
|
#else
|
|
(void)pkey;
|
|
(void)keyBuf;
|
|
(void)keyLen;
|
|
#endif /* WOLFSSL_PEM_TO_DER */
|
|
|
|
/* Return new WOLFSSL_PKCS8_PRIV_KEY_INFO object. */
|
|
return pkcs8;
|
|
}
|
|
|
|
#ifndef NO_BIO
|
|
/* Converts a DER format key read from BIO to a PKCS#8 structure.
|
|
*
|
|
* @param [in] bio Input BIO to read DER from.
|
|
* @param [out] pkey If not NULL then this pointer will be overwritten with a
|
|
* new PKCS8 structure.
|
|
* @return A WOLFSSL_PKCS8_PRIV_KEY_INFO pointer on success
|
|
* @return NULL on failure.
|
|
*/
|
|
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");
|
|
|
|
/* Validate parameters. */
|
|
if (bio == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
/* Get the memory buffer from the BIO. */
|
|
if ((memSz = wolfSSL_BIO_get_mem_data(bio, &mem)) < 0) {
|
|
return NULL;
|
|
}
|
|
|
|
/* Decode the PKCS#8 key into a WOLFSSL_PKCS8_PRIV_KEY_INFO object. */
|
|
pkcs8 = wolfSSL_d2i_PKCS8_PKEY(pkey, (const unsigned char**)&mem, memSz);
|
|
#else
|
|
(void)bio;
|
|
(void)pkey;
|
|
#endif /* WOLFSSL_PEM_TO_DER */
|
|
|
|
/* Return new WOLFSSL_PKCS8_PRIV_KEY_INFO object. */
|
|
return pkcs8;
|
|
}
|
|
#endif /* !NO_BIO */
|
|
|
|
#ifdef WOLF_PRIVATE_KEY_ID
|
|
/* Create an EVP structure for use with crypto callbacks.
|
|
*
|
|
* @param [in] type Type of private key.
|
|
* @param [out] out WOLFSSL_EVP_PKEY object created.
|
|
* @param [in] heap Heap hint for dynamic memory allocation.
|
|
* @param [in] devId Device id.
|
|
* @return A new WOLFSSL_EVP_PKEY object on success.
|
|
* @return NULL on failure.
|
|
*/
|
|
WOLFSSL_EVP_PKEY* wolfSSL_d2i_PrivateKey_id(int type, WOLFSSL_EVP_PKEY** out,
|
|
void* heap, int devId)
|
|
{
|
|
WOLFSSL_EVP_PKEY* local;
|
|
|
|
/* Dispose of any object passed in through out. */
|
|
if (out != NULL && *out != NULL) {
|
|
wolfSSL_EVP_PKEY_free(*out);
|
|
*out = NULL;
|
|
}
|
|
|
|
/* Create a local WOLFSSL_EVP_PKEY to be decoded into. */
|
|
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:
|
|
{
|
|
/* Create a WOLFSSL_RSA object into WOLFSSL_EVP_PKEY. */
|
|
local->rsa = wolfSSL_RSA_new_ex(heap, devId);
|
|
if (local->rsa == NULL) {
|
|
wolfSSL_EVP_PKEY_free(local);
|
|
return NULL;
|
|
}
|
|
local->ownRsa = 1;
|
|
/* Algorithm specific object set into WOLFSL_EVP_PKEY. */
|
|
local->rsa->inSet = 1;
|
|
#ifdef WOLF_CRYPTO_CB
|
|
((RsaKey*)local->rsa->internal)->devId = devId;
|
|
#endif
|
|
break;
|
|
}
|
|
#endif /* !NO_RSA */
|
|
#ifdef HAVE_ECC
|
|
case WC_EVP_PKEY_EC:
|
|
{
|
|
ecc_key* key;
|
|
|
|
/* Create a WOLFSSL_EC object into WOLFSSL_EVP_PKEY. */
|
|
local->ecc = wolfSSL_EC_KEY_new_ex(heap, devId);
|
|
if (local->ecc == NULL) {
|
|
wolfSSL_EVP_PKEY_free(local);
|
|
return NULL;
|
|
}
|
|
local->ownEcc = 1;
|
|
/* Algorithm specific object set into WOLFSL_EVP_PKEY. */
|
|
local->ecc->inSet = 1;
|
|
|
|
/* Get wolfSSL EC key and set fields. */
|
|
key = (ecc_key*)local->ecc->internal;
|
|
#ifdef WOLF_CRYPTO_CB
|
|
key->devId = devId;
|
|
#endif
|
|
key->type = ECC_PRIVATEKEY;
|
|
/* key is required to have a key size / curve set, although
|
|
* actual one used is determined by devId callback function. */
|
|
wc_ecc_set_curve(key, ECDHE_SIZE, ECC_CURVE_DEF);
|
|
break;
|
|
}
|
|
#endif /* HAVE_ECC */
|
|
default:
|
|
WOLFSSL_MSG("Unsupported private key id type");
|
|
wolfSSL_EVP_PKEY_free(local);
|
|
return NULL;
|
|
}
|
|
|
|
/* Return new WOLFSSL_EVP_PKEY through parameter if required. */
|
|
if (local != NULL && out != NULL) {
|
|
*out = local;
|
|
}
|
|
/* Return new WOLFSSL_EVP_PKEY. */
|
|
return local;
|
|
}
|
|
#endif /* WOLF_PRIVATE_KEY_ID */
|
|
#endif /* OPENSSL_EXTRA */
|
|
|
|
/*******************************************************************************
|
|
* END OF d2i APIs
|
|
******************************************************************************/
|
|
|
|
/*******************************************************************************
|
|
* START OF i2d APIs
|
|
******************************************************************************/
|
|
|
|
#ifdef OPENSSL_ALL
|
|
/* Encode PKCS#8 key as DER data.
|
|
*
|
|
* @param [in] key PKCS#8 private key to encode.
|
|
* @param [out] pp Pointer to buffer of encoded data.
|
|
* @return Length of DER encoded data on success.
|
|
* @return Less than zero on failure.
|
|
*/
|
|
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");
|
|
|
|
/* Validate parameters. */
|
|
if (key == NULL) {
|
|
return WOLFSSL_FATAL_ERROR;
|
|
}
|
|
|
|
/* Get the length of DER encoding. */
|
|
if (pkcs8_encode(key, NULL, &keySz) != WC_NO_ERR_TRACE(LENGTH_ONLY_E)) {
|
|
return WOLFSSL_FATAL_ERROR;
|
|
}
|
|
len = (int)keySz;
|
|
|
|
/* Return the length when output parameter is NULL. */
|
|
if ((pp == NULL) || (len == 0)) {
|
|
return len;
|
|
}
|
|
|
|
/* Allocate memory for DER encoding if NULL passed in for output buffer. */
|
|
if (*pp == NULL) {
|
|
out = (unsigned char*)XMALLOC((size_t)len, NULL, DYNAMIC_TYPE_ASN1);
|
|
if (out == NULL) {
|
|
return WOLFSSL_FATAL_ERROR;
|
|
}
|
|
}
|
|
else {
|
|
/* Use buffer passed in - assume it is big enough. */
|
|
out = *pp;
|
|
}
|
|
|
|
/* Encode the PKCS#8 key into the output buffer. */
|
|
if (pkcs8_encode(key, out, &keySz) != len) {
|
|
if (*pp == NULL) {
|
|
XFREE(out, NULL, DYNAMIC_TYPE_ASN1);
|
|
}
|
|
return WOLFSSL_FATAL_ERROR;
|
|
}
|
|
|
|
/* Return new output buffer or move pointer passed encoded data. */
|
|
if (*pp == NULL) {
|
|
*pp = out;
|
|
}
|
|
else {
|
|
*pp += len;
|
|
}
|
|
|
|
return len;
|
|
}
|
|
#endif
|
|
|
|
#ifdef OPENSSL_EXTRA
|
|
|
|
#if !defined(NO_ASN) && !defined(NO_PWDBASED)
|
|
/* Get raw pointer to DER buffer from WOLFSSL_EVP_PKEY.
|
|
*
|
|
* Assumes der is large enough if passed in.
|
|
*
|
|
* @param [in] key WOLFSSL_EVP_PKEY to get DER buffer for.
|
|
* @param [out] der Buffer holding DER encoding. May be NULL.
|
|
* @return Size of DER encoding on success.
|
|
* @return Less than 0 on failure.
|
|
*/
|
|
static int wolfssl_i_evp_pkey_get_der(const WOLFSSL_EVP_PKEY* key,
|
|
unsigned char** der)
|
|
{
|
|
int sz;
|
|
word16 pkcs8HeaderSz;
|
|
|
|
/* Validate parameters. */
|
|
if ((key == NULL) || (key->pkey_sz == 0)) {
|
|
return WOLFSSL_FATAL_ERROR;
|
|
}
|
|
|
|
/* If pkcs8HeaderSz is invalid, return all of the DER encoding. */
|
|
pkcs8HeaderSz = 0;
|
|
if (key->pkey_sz > key->pkcs8HeaderSz) {
|
|
pkcs8HeaderSz = key->pkcs8HeaderSz;
|
|
}
|
|
/* Calculate the size of the DER encoding to return. */
|
|
sz = key->pkey_sz - pkcs8HeaderSz;
|
|
/* Returning encoding when DER is not NULL. */
|
|
if (der != NULL) {
|
|
unsigned char* pt = (unsigned char*)key->pkey.ptr;
|
|
int bufferPassedIn = ((*der) != NULL);
|
|
|
|
if (!bufferPassedIn) {
|
|
/* Allocate buffer to hold DER encoding. */
|
|
*der = (unsigned char*)XMALLOC((size_t)sz, NULL,
|
|
DYNAMIC_TYPE_OPENSSL);
|
|
if (*der == NULL) {
|
|
return WOLFSSL_FATAL_ERROR;
|
|
}
|
|
}
|
|
/* Copy in non-PKCS#8 DER encoding. */
|
|
XMEMCPY(*der, pt + pkcs8HeaderSz, (size_t)sz);
|
|
/* Step past encoded key when buffer provided. */
|
|
if (bufferPassedIn) {
|
|
*der += sz;
|
|
}
|
|
}
|
|
|
|
/* Return size of DER encoded data. */
|
|
return sz;
|
|
}
|
|
|
|
/* Encode key as unencrypted DER data.
|
|
*
|
|
* @param [in] key PKCS#8 private key to encode.
|
|
* @param [out] der Pointer to buffer of encoded data.
|
|
* @return Length of DER encoded data on success.
|
|
* @return Less than zero on failure.
|
|
*/
|
|
int wolfSSL_i2d_PrivateKey(const WOLFSSL_EVP_PKEY* key, unsigned char** der)
|
|
{
|
|
return wolfssl_i_evp_pkey_get_der(key, der);
|
|
}
|
|
|
|
#ifndef NO_BIO
|
|
/* Encode key as unencrypted DER data and write to BIO.
|
|
*
|
|
* @param [in] bio BIO to write data to.
|
|
* @param [in] key PKCS#8 private key to encode.
|
|
* @return Length of DER encoded data on success.
|
|
* @return Less than zero on failure.
|
|
*/
|
|
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
|
|
/* Encode EC key as public key DER.
|
|
*
|
|
* @param [in] key WOLFSSL_EVP_KEY object to encode.
|
|
* @param [in] ec WOLFSSL_EC_KEY object to encode.
|
|
* @param [out] der Buffer with DER encoding of EC public key.
|
|
* @return Public key DER encoding size on success.
|
|
* @return WOLFSSL_FATAL_ERROR when dynamic memory allocation fails.
|
|
* @return WOLFSSL_FATAL_ERROR when encoding fails.
|
|
*/
|
|
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;
|
|
|
|
/* We need to get the DER, then convert it to a public key. But what we get
|
|
* might be a buffered private key so we need to decode it and then encode
|
|
* the public part. */
|
|
ret = wolfssl_i_evp_pkey_get_der(key, &local_der);
|
|
if (ret <= 0) {
|
|
/* In this case, there was no buffered DER at all. This could be the
|
|
* case where the key that was passed in was generated. So now we
|
|
* have to create the local DER. */
|
|
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;
|
|
}
|
|
}
|
|
|
|
/* Initialize a wolfCrypt ECC key. */
|
|
if (ret == 0) {
|
|
ret = wc_ecc_init(eccKey);
|
|
}
|
|
if (ret == 0) {
|
|
/* Decode the DER data with wolfCrypt ECC key. */
|
|
ret = wc_EccPublicKeyDecode(local_der, &inOutIdx, eccKey, local_derSz);
|
|
if (ret < 0) {
|
|
/* We now try again as x.963 [point type][x][opt y]. */
|
|
ret = wc_ecc_import_x963(local_der, local_derSz, eccKey);
|
|
}
|
|
}
|
|
|
|
if (ret == 0) {
|
|
/* Get the size of the encoding of the public key DER. */
|
|
pub_derSz = (word32)wc_EccPublicKeyDerSize(eccKey, 1);
|
|
if ((int)pub_derSz <= 0) {
|
|
ret = WOLFSSL_FAILURE;
|
|
}
|
|
}
|
|
|
|
if (ret == 0) {
|
|
/* Allocate memory for public key DER encoding. */
|
|
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) {
|
|
/* Encode public key as DER. */
|
|
pub_derSz = (word32)wc_EccPublicKeyToDer(eccKey, pub_der, pub_derSz, 1);
|
|
if ((int)pub_derSz <= 0) {
|
|
ret = WOLFSSL_FATAL_ERROR;
|
|
}
|
|
}
|
|
|
|
/* This block is for actually returning the DER of the public key */
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Dispose of allocated objects. */
|
|
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);
|
|
|
|
/* Return error or the size of the DER encoded public key. */
|
|
if (ret == 0) {
|
|
ret = (int)pub_derSz;
|
|
}
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
/* Encode the WOLFSSL_EVP_PKEY object as public key DER.
|
|
*
|
|
* @param [in] key WOLFSLS_EVP_PKEY object to encode.
|
|
* @param [out] der Buffer with DER encoding of public key.
|
|
* @return Public key DER encoding size on success.
|
|
* @return WOLFSSL_FATAL_ERROR when key is NULL.
|
|
* @return WOLFSSL_FATAL_ERROR when key type not supported.
|
|
* @return WOLFSSL_FATAL_ERROR when dynamic memory allocation fails.
|
|
*/
|
|
int wolfSSL_i2d_PublicKey(const WOLFSSL_EVP_PKEY *key, unsigned char **der)
|
|
{
|
|
int ret;
|
|
|
|
/* Validate parameters. */
|
|
if (key == NULL) {
|
|
return WOLFSSL_FATAL_ERROR;
|
|
}
|
|
|
|
/* Encode based on key type. */
|
|
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;
|
|
}
|
|
|
|
/* Encode the WOLFSSL_EVP_PKEY object as public key DER.
|
|
*
|
|
* @param [in] key WOLFSLS_EVP_PKEY object to encode.
|
|
* @param [out] der Buffer with DER encoding of public key.
|
|
* @return Public key DER encoding size on success.
|
|
* @return WOLFSSL_FATAL_ERROR when key is NULL.
|
|
* @return WOLFSSL_FATAL_ERROR when key type not supported.
|
|
* @return WOLFSSL_FATAL_ERROR when dynamic memory allocation fails.
|
|
*/
|
|
int wolfSSL_i2d_PUBKEY(const WOLFSSL_EVP_PKEY *key, unsigned char **der)
|
|
{
|
|
return wolfSSL_i2d_PublicKey(key, der);
|
|
}
|
|
#endif /* !NO_ASN && !NO_PWDBASED */
|
|
|
|
#endif /* OPENSSL_EXTRA */
|
|
|
|
#endif /* !NO_CERTS */
|
|
|
|
/*******************************************************************************
|
|
* END OF i2d APIs
|
|
******************************************************************************/
|
|
|
|
#endif /* !WOLFSSL_EVP_PK_INCLUDED */
|
|
|