summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--crypto/evp/evp_pkey.c70
1 files changed, 51 insertions, 19 deletions
diff --git a/crypto/evp/evp_pkey.c b/crypto/evp/evp_pkey.c
index b5a8f1cd72..766dfb46ec 100644
--- a/crypto/evp/evp_pkey.c
+++ b/crypto/evp/evp_pkey.c
@@ -12,6 +12,8 @@
#include "internal/cryptlib.h"
#include <openssl/x509.h>
#include <openssl/rand.h>
+#include <openssl/encoder.h>
+#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 */