From c19d89785075393d27287c90086fa2aeaa842e62 Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Fri, 24 Apr 2020 16:19:25 +0100 Subject: [PATCH] Ensure EVP_PKEY_get_raw_[private|public]_key work with provider keys If the key is a provider key then we should export it from the provider. Fixes #11627 Reviewed-by: Shane Lontis (Merged from https://github.com/openssl/openssl/pull/11635) --- crypto/evp/p_lib.c | 71 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 65 insertions(+), 6 deletions(-) diff --git a/crypto/evp/p_lib.c b/crypto/evp/p_lib.c index ea74253bdd..9eb9f4937b 100644 --- a/crypto/evp/p_lib.c +++ b/crypto/evp/p_lib.c @@ -473,18 +473,61 @@ EVP_PKEY *EVP_PKEY_new_raw_public_key(int type, ENGINE *e, return new_raw_key_int(NULL, NULL, NULL, type, e, pub, len, 0); } +struct raw_key_details_st +{ + unsigned char **key; + size_t *len; + int selection; +}; + +static OSSL_CALLBACK get_raw_key_details; +static int get_raw_key_details(const OSSL_PARAM params[], void *arg) +{ + const OSSL_PARAM *p = NULL; + struct raw_key_details_st *raw_key = arg; + + if (raw_key->selection == OSSL_KEYMGMT_SELECT_PRIVATE_KEY) { + if ((p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PRIV_KEY)) + != NULL) + return OSSL_PARAM_get_octet_string(p, (void **)raw_key->key, + SIZE_MAX, raw_key->len); + } else if (raw_key->selection == OSSL_KEYMGMT_SELECT_PUBLIC_KEY) { + if ((p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PUB_KEY)) + != NULL) + return OSSL_PARAM_get_octet_string(p, (void **)raw_key->key, + SIZE_MAX, raw_key->len); + } + + return 0; +} + int EVP_PKEY_get_raw_private_key(const EVP_PKEY *pkey, unsigned char *priv, size_t *len) { - /* TODO(3.0) Do we need to do anything about provider side keys? */ - if (pkey->ameth->get_priv_key == NULL) { - EVPerr(EVP_F_EVP_PKEY_GET_RAW_PRIVATE_KEY, - EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + if (pkey->keymgmt != NULL) { + struct raw_key_details_st raw_key; + + raw_key.key = priv == NULL ? NULL : &priv; + raw_key.len = len; + raw_key.selection = OSSL_KEYMGMT_SELECT_PRIVATE_KEY; + + return evp_keymgmt_export(pkey->keymgmt, pkey->keydata, + OSSL_KEYMGMT_SELECT_PRIVATE_KEY, + get_raw_key_details, &raw_key); + } + + if (pkey->ameth == NULL) { + EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + return 0; + } + + if (pkey->ameth->get_priv_key == NULL) { + EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); return 0; } if (!pkey->ameth->get_priv_key(pkey, priv, len)) { - EVPerr(EVP_F_EVP_PKEY_GET_RAW_PRIVATE_KEY, EVP_R_GET_RAW_KEY_FAILED); + EVPerr(0, EVP_R_GET_RAW_KEY_FAILED); return 0; } @@ -494,7 +537,23 @@ int EVP_PKEY_get_raw_private_key(const EVP_PKEY *pkey, unsigned char *priv, int EVP_PKEY_get_raw_public_key(const EVP_PKEY *pkey, unsigned char *pub, size_t *len) { - /* TODO(3.0) Do we need to do anything about provider side keys? */ + if (pkey->keymgmt != NULL) { + struct raw_key_details_st raw_key; + + raw_key.key = pub == NULL ? NULL : &pub; + raw_key.len = len; + raw_key.selection = OSSL_KEYMGMT_SELECT_PUBLIC_KEY; + + return evp_keymgmt_export(pkey->keymgmt, pkey->keydata, + OSSL_KEYMGMT_SELECT_PUBLIC_KEY, + get_raw_key_details, &raw_key); + } + + if (pkey->ameth == NULL) { + EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + return 0; + } + if (pkey->ameth->get_pub_key == NULL) { EVPerr(EVP_F_EVP_PKEY_GET_RAW_PUBLIC_KEY, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); -- 2.25.1