From a08802ce296a90d8cf9032987b0dac959ccf00ad Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Mon, 5 Mar 2018 14:06:41 +0000 Subject: [PATCH] Add functions to create an EVP_PKEY from raw private/public key data Not all algorithms will support this, since their keys are not a simple block of data. But many can. Reviewed-by: Richard Levitte (Merged from https://github.com/openssl/openssl/pull/5520) --- crypto/err/openssl.txt | 2 + crypto/evp/evp_err.c | 4 ++ crypto/evp/p_lib.c | 75 +++++++++++++++++++++++++++--- crypto/include/internal/asn1_int.h | 3 ++ include/openssl/evp.h | 4 ++ include/openssl/evperr.h | 2 + util/libcrypto.num | 2 + 7 files changed, 85 insertions(+), 7 deletions(-) diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index 3f6169ee1c..f33e9612c0 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -703,6 +703,8 @@ EVP_F_EVP_PKEY_GET0_SIPHASH:172:EVP_PKEY_get0_siphash EVP_F_EVP_PKEY_KEYGEN:146:EVP_PKEY_keygen EVP_F_EVP_PKEY_KEYGEN_INIT:147:EVP_PKEY_keygen_init EVP_F_EVP_PKEY_NEW:106:EVP_PKEY_new +EVP_F_EVP_PKEY_NEW_PRIVATE_KEY:191:EVP_PKEY_new_private_key +EVP_F_EVP_PKEY_NEW_PUBLIC_KEY:192:EVP_PKEY_new_public_key EVP_F_EVP_PKEY_PARAMGEN:148:EVP_PKEY_paramgen EVP_F_EVP_PKEY_PARAMGEN_INIT:149:EVP_PKEY_paramgen_init EVP_F_EVP_PKEY_PARAM_CHECK:189:EVP_PKEY_param_check diff --git a/crypto/evp/evp_err.c b/crypto/evp/evp_err.c index a43de74605..d45f2b96b1 100644 --- a/crypto/evp/evp_err.c +++ b/crypto/evp/evp_err.c @@ -93,6 +93,10 @@ static const ERR_STRING_DATA EVP_str_functs[] = { {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_KEYGEN_INIT, 0), "EVP_PKEY_keygen_init"}, {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_NEW, 0), "EVP_PKEY_new"}, + {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_NEW_PRIVATE_KEY, 0), + "EVP_PKEY_new_private_key"}, + {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_NEW_PUBLIC_KEY, 0), + "EVP_PKEY_new_public_key"}, {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_PARAMGEN, 0), "EVP_PKEY_paramgen"}, {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_PARAMGEN_INIT, 0), "EVP_PKEY_paramgen_init"}, diff --git a/crypto/evp/p_lib.c b/crypto/evp/p_lib.c index 6177e04483..7ec1dd7800 100644 --- a/crypto/evp/p_lib.c +++ b/crypto/evp/p_lib.c @@ -174,10 +174,12 @@ int EVP_PKEY_up_ref(EVP_PKEY *pkey) * is NULL just return 1 or 0 if the algorithm exists. */ -static int pkey_set_type(EVP_PKEY *pkey, int type, const char *str, int len) +static int pkey_set_type(EVP_PKEY *pkey, ENGINE *e, int type, const char *str, + int len) { const EVP_PKEY_ASN1_METHOD *ameth; - ENGINE *e = NULL; + ENGINE **eptr = (e == NULL) ? &e : NULL; + if (pkey) { if (pkey->pkey.ptr) EVP_PKEY_free_it(pkey); @@ -196,11 +198,11 @@ static int pkey_set_type(EVP_PKEY *pkey, int type, const char *str, int len) #endif } if (str) - ameth = EVP_PKEY_asn1_find_str(&e, str, len); + ameth = EVP_PKEY_asn1_find_str(eptr, str, len); else - ameth = EVP_PKEY_asn1_find(&e, type); + ameth = EVP_PKEY_asn1_find(eptr, type); #ifndef OPENSSL_NO_ENGINE - if (pkey == NULL) + if (pkey == NULL && eptr != NULL) ENGINE_finish(e); #endif if (ameth == NULL) { @@ -217,14 +219,73 @@ static int pkey_set_type(EVP_PKEY *pkey, int type, const char *str, int len) return 1; } +EVP_PKEY *EVP_PKEY_new_private_key(int type, ENGINE *e, unsigned char *priv, + size_t len) +{ + EVP_PKEY *ret = EVP_PKEY_new(); + + if (ret == NULL + || !pkey_set_type(ret, e, type, NULL, -1)) { + /* EVPerr already called */ + goto err; + } + + if (ret->ameth->set_priv_key == NULL) { + EVPerr(EVP_F_EVP_PKEY_NEW_PRIVATE_KEY, + EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + goto err; + } + + if (!ret->ameth->set_priv_key(ret, priv, len)) { + /* We assume the method function calls EVPerr */ + goto err; + } + + return ret; + + err: + EVP_PKEY_free(ret); + return NULL; +} + +EVP_PKEY *EVP_PKEY_new_public_key(int type, ENGINE *e, unsigned char *pub, + size_t len) +{ + EVP_PKEY *ret = EVP_PKEY_new(); + + if (ret == NULL + || !pkey_set_type(ret, e, type, NULL, -1)) { + /* EVPerr already called */ + goto err; + } + + if (ret->ameth->set_pub_key == NULL) { + EVPerr(EVP_F_EVP_PKEY_NEW_PUBLIC_KEY, + EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + goto err; + } + + if (!ret->ameth->set_pub_key(ret, pub, len)) { + /* We assume the method function calls EVPerr */ + goto err; + } + + return ret; + + err: + EVP_PKEY_free(ret); + return NULL; +} + + int EVP_PKEY_set_type(EVP_PKEY *pkey, int type) { - return pkey_set_type(pkey, type, NULL, -1); + return pkey_set_type(pkey, NULL, type, NULL, -1); } int EVP_PKEY_set_type_str(EVP_PKEY *pkey, const char *str, int len) { - return pkey_set_type(pkey, EVP_PKEY_NONE, str, len); + return pkey_set_type(pkey, NULL, EVP_PKEY_NONE, str, len); } #ifndef OPENSSL_NO_ENGINE int EVP_PKEY_set1_engine(EVP_PKEY *pkey, ENGINE *e) diff --git a/crypto/include/internal/asn1_int.h b/crypto/include/internal/asn1_int.h index 664d4d69cb..90673ab3fe 100644 --- a/crypto/include/internal/asn1_int.h +++ b/crypto/include/internal/asn1_int.h @@ -58,6 +58,9 @@ struct evp_pkey_asn1_method_st { int (*pkey_check) (const EVP_PKEY *pk); int (*pkey_public_check) (const EVP_PKEY *pk); int (*pkey_param_check) (const EVP_PKEY *pk); + /* Get/set raw private/public key data */ + int (*set_priv_key) (EVP_PKEY *pk, const unsigned char *priv, size_t len); + int (*set_pub_key) (EVP_PKEY *pk, const unsigned char *pub, size_t len); } /* EVP_PKEY_ASN1_METHOD */ ; DEFINE_STACK_OF_CONST(EVP_PKEY_ASN1_METHOD) diff --git a/include/openssl/evp.h b/include/openssl/evp.h index 9727e9df30..04797635b9 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h @@ -1337,6 +1337,10 @@ void EVP_PKEY_CTX_set0_keygen_info(EVP_PKEY_CTX *ctx, int *dat, int datlen); EVP_PKEY *EVP_PKEY_new_mac_key(int type, ENGINE *e, const unsigned char *key, int keylen); +EVP_PKEY *EVP_PKEY_new_private_key(int type, ENGINE *e, unsigned char *priv, + size_t len); +EVP_PKEY *EVP_PKEY_new_public_key(int type, ENGINE *e, unsigned char *pub, + size_t len); void EVP_PKEY_CTX_set_data(EVP_PKEY_CTX *ctx, void *data); void *EVP_PKEY_CTX_get_data(EVP_PKEY_CTX *ctx); diff --git a/include/openssl/evperr.h b/include/openssl/evperr.h index 45e9fcfffb..83dcd053ea 100644 --- a/include/openssl/evperr.h +++ b/include/openssl/evperr.h @@ -78,6 +78,8 @@ int ERR_load_EVP_strings(void); # define EVP_F_EVP_PKEY_KEYGEN 146 # define EVP_F_EVP_PKEY_KEYGEN_INIT 147 # define EVP_F_EVP_PKEY_NEW 106 +# define EVP_F_EVP_PKEY_NEW_PRIVATE_KEY 191 +# define EVP_F_EVP_PKEY_NEW_PUBLIC_KEY 192 # define EVP_F_EVP_PKEY_PARAMGEN 148 # define EVP_F_EVP_PKEY_PARAMGEN_INIT 149 # define EVP_F_EVP_PKEY_PARAM_CHECK 189 diff --git a/util/libcrypto.num b/util/libcrypto.num index a96bd2f799..401d9fd9f6 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -4522,3 +4522,5 @@ OSSL_STORE_LOADER_set_find 4463 1_1_1 EXIST::FUNCTION: OSSL_STORE_SEARCH_free 4464 1_1_1 EXIST::FUNCTION: OSSL_STORE_SEARCH_get0_digest 4465 1_1_1 EXIST::FUNCTION: RAND_DRBG_set_reseed_defaults 4466 1_1_1 EXIST::FUNCTION: +EVP_PKEY_new_private_key 4467 1_1_1 EXIST::FUNCTION: +EVP_PKEY_new_public_key 4468 1_1_1 EXIST::FUNCTION: -- 2.39.5