From: Richard Levitte Date: Fri, 25 Sep 2020 18:02:56 +0000 (+0200) Subject: EVP: Adapt EVP_PKEY2PKCS8() to better handle provider-native keys X-Git-Tag: openssl-3.0.0-alpha9~110 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=31a6b52f6db009c639c67387a707dd235f29a430;p=thirdparty%2Fopenssl.git EVP: Adapt EVP_PKEY2PKCS8() to better handle provider-native keys It doesn't downgread the keys to legacy any more. Instead, it uses OSSL_ENCODER to encode the key to DER, and d2i_PKCS8_PRIV_KEY_INFO() to make a PKCS8_PRIV_KEY_INFO structure from that. Fixes #12990 Reviewed-by: Shane Lontis (Merged from https://github.com/openssl/openssl/pull/12995) --- diff --git a/crypto/evp/evp_pkey.c b/crypto/evp/evp_pkey.c index b5a8f1cd720..766dfb46ecb 100644 --- a/crypto/evp/evp_pkey.c +++ b/crypto/evp/evp_pkey.c @@ -12,6 +12,8 @@ #include "internal/cryptlib.h" #include #include +#include +#include "internal/provider.h" #include "crypto/asn1.h" #include "crypto/evp.h" #include "crypto/x509.h" @@ -69,35 +71,65 @@ EVP_PKEY *EVP_PKCS82PKEY(const PKCS8_PRIV_KEY_INFO *p8) PKCS8_PRIV_KEY_INFO *EVP_PKEY2PKCS8(const EVP_PKEY *pkey) { - PKCS8_PRIV_KEY_INFO *p8 = PKCS8_PRIV_KEY_INFO_new(); - if (p8 == NULL) { - EVPerr(EVP_F_EVP_PKEY2PKCS8, ERR_R_MALLOC_FAILURE); - return NULL; - } + PKCS8_PRIV_KEY_INFO *p8 = NULL; + OSSL_ENCODER_CTX *ctx = NULL; + + /* + * The implementation for provider-native keys is to encode the + * key to a DER encoded PKCS#8 structure, then convert it to a + * PKCS8_PRIV_KEY_INFO with good old d2i functions. + */ + if (evp_pkey_is_provided(pkey)) { + int selection = OSSL_KEYMGMT_SELECT_ALL; + const OSSL_PROVIDER *prov = EVP_KEYMGMT_provider(pkey->keymgmt); + OSSL_LIB_CTX *libctx = ossl_provider_libctx(prov); + unsigned char *der = NULL; + size_t derlen = 0; + const unsigned char *pp; + + if ((ctx = OSSL_ENCODER_CTX_new_by_EVP_PKEY(pkey, selection, + "DER", "pkcs8", + libctx, NULL)) == NULL + || !OSSL_ENCODER_to_data(ctx, &der, &derlen)) + goto error; - /* Force a key downgrade if that's possible */ - /* TODO(3.0) Is there a better way for provider-native keys? */ - if (EVP_PKEY_get0(pkey) == NULL) - goto error; + pp = der; + p8 = d2i_PKCS8_PRIV_KEY_INFO(NULL, &pp, (long)derlen); + OPENSSL_free(der); + if (p8 == NULL) + goto error; + } else { + p8 = PKCS8_PRIV_KEY_INFO_new(); + if (p8 == NULL) { + EVPerr(EVP_F_EVP_PKEY2PKCS8, ERR_R_MALLOC_FAILURE); + return NULL; + } - if (pkey->ameth) { - if (pkey->ameth->priv_encode) { - if (!pkey->ameth->priv_encode(p8, pkey)) { - EVPerr(EVP_F_EVP_PKEY2PKCS8, EVP_R_PRIVATE_KEY_ENCODE_ERROR); + if (pkey->ameth != NULL) { + if (pkey->ameth->priv_encode != NULL) { + if (!pkey->ameth->priv_encode(p8, pkey)) { + EVPerr(EVP_F_EVP_PKEY2PKCS8, + EVP_R_PRIVATE_KEY_ENCODE_ERROR); + goto error; + } + } else { + EVPerr(EVP_F_EVP_PKEY2PKCS8, EVP_R_METHOD_NOT_SUPPORTED); goto error; } } else { - EVPerr(EVP_F_EVP_PKEY2PKCS8, EVP_R_METHOD_NOT_SUPPORTED); + EVPerr(EVP_F_EVP_PKEY2PKCS8, + EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM); goto error; } - } else { - EVPerr(EVP_F_EVP_PKEY2PKCS8, EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM); - goto error; } - return p8; + goto end; error: PKCS8_PRIV_KEY_INFO_free(p8); - return NULL; + p8 = NULL; + end: + OSSL_ENCODER_CTX_free(ctx); + return p8; + } /* EVP_PKEY attribute functions */