void (*fn)(const char *name, void *data),
void *data);
int evp_cipher_cache_constants(EVP_CIPHER *cipher);
+void *evp_pkey_make_provided(EVP_PKEY *pk, OPENSSL_CTX *libctx,
+ EVP_KEYMGMT **keymgmt, const char *propquery,
+ int domainparams);
int ret;
void *provkey = NULL;
EVP_KEYEXCH *exchange = NULL;
+ EVP_KEYMGMT *tmp_keymgmt = NULL;
+ const char *supported_exch = NULL;
if (ctx == NULL) {
EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
if (ctx->engine != NULL || ctx->keytype == NULL)
goto legacy;
- if (ctx->keymgmt == NULL)
- ctx->keymgmt =
- EVP_KEYMGMT_fetch(ctx->libctx, ctx->keytype, ctx->propquery);
- if (ctx->keymgmt != NULL) {
- const char *supported_exch = NULL;
+ /* Ensure that the key is provided. If not, go legacy */
+ tmp_keymgmt = ctx->keymgmt;
+ provkey = evp_pkey_make_provided(ctx->pkey, ctx->libctx,
+ &tmp_keymgmt, ctx->propquery, 0);
+ if (provkey == NULL)
+ goto legacy;
+ if (!EVP_KEYMGMT_up_ref(tmp_keymgmt)) {
+ ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
+ goto err;
+ }
+ EVP_KEYMGMT_free(ctx->keymgmt);
+ ctx->keymgmt = tmp_keymgmt;
- if (ctx->keymgmt->query_operation_name != NULL)
- supported_exch =
- ctx->keymgmt->query_operation_name(OSSL_OP_KEYEXCH);
+ if (ctx->keymgmt->query_operation_name != NULL)
+ supported_exch = ctx->keymgmt->query_operation_name(OSSL_OP_KEYEXCH);
- /*
- * If we didn't get a supported exch, assume there is one with the
- * same name as the key type.
- */
- if (supported_exch == NULL)
- supported_exch = ctx->keytype;
+ /*
+ * If we didn't get a supported exch, assume there is one with the
+ * same name as the key type.
+ */
+ if (supported_exch == NULL)
+ supported_exch = ctx->keytype;
- /*
- * Because we cleared out old ops, we shouldn't need to worry about
- * checking if exchange is already there.
- */
- exchange =
- EVP_KEYEXCH_fetch(ctx->libctx, supported_exch, ctx->propquery);
- }
+ /*
+ * Because we cleared out old ops, we shouldn't need to worry about
+ * checking if exchange is already there.
+ */
+ exchange = EVP_KEYEXCH_fetch(ctx->libctx, supported_exch, ctx->propquery);
- if (ctx->keymgmt == NULL
- || exchange == NULL
+ if (exchange == NULL
|| (EVP_KEYMGMT_provider(ctx->keymgmt)
!= EVP_KEYEXCH_provider(exchange))) {
/*
ctx->op.kex.exchange = exchange;
-
- if (ctx->pkey != NULL) {
- provkey = evp_keymgmt_export_to_provider(ctx->pkey, ctx->keymgmt, 0);
- /* If export failed, legacy may be able to pick it up */
- if (provkey == NULL)
- goto legacy;
- }
ctx->op.kex.exchprovctx = exchange->newctx(ossl_provider_ctx(exchange->prov));
if (ctx->op.kex.exchprovctx == NULL) {
/* The provider key can stay in the cache */
{
EVP_PKEY_CTX *locpctx = NULL;
EVP_SIGNATURE *signature = NULL;
+ EVP_KEYMGMT *tmp_keymgmt = NULL;
+ const char *supported_sig = NULL;
void *provkey = NULL;
int ret;
}
}
- if (locpctx->keymgmt == NULL)
- locpctx->keymgmt = EVP_KEYMGMT_fetch(locpctx->libctx, locpctx->keytype,
- locpctx->propquery);
- if (locpctx->keymgmt != NULL) {
- const char *supported_sig = NULL;
+ /* Ensure that the key is provided. If not, go legacy */
+ tmp_keymgmt = locpctx->keymgmt;
+ provkey = evp_pkey_make_provided(locpctx->pkey, locpctx->libctx,
+ &tmp_keymgmt, locpctx->propquery, 0);
+ if (provkey == NULL)
+ goto legacy;
+ if (!EVP_KEYMGMT_up_ref(tmp_keymgmt)) {
+ ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
+ goto err;
+ }
+ EVP_KEYMGMT_free(locpctx->keymgmt);
+ locpctx->keymgmt = tmp_keymgmt;
- if (locpctx->keymgmt->query_operation_name != NULL)
- supported_sig =
- locpctx->keymgmt->query_operation_name(OSSL_OP_SIGNATURE);
+ if (locpctx->keymgmt->query_operation_name != NULL)
+ supported_sig =
+ locpctx->keymgmt->query_operation_name(OSSL_OP_SIGNATURE);
- /*
- * If we didn't get a supported sig, assume there is one with the
- * same name as the key type.
- */
- if (supported_sig == NULL)
- supported_sig = locpctx->keytype;
+ /*
+ * If we didn't get a supported sig, assume there is one with the
+ * same name as the key type.
+ */
+ if (supported_sig == NULL)
+ supported_sig = locpctx->keytype;
- /*
- * Because we cleared out old ops, we shouldn't need to worry about
- * checking if signature is already there.
- */
- signature = EVP_SIGNATURE_fetch(locpctx->libctx, supported_sig,
- locpctx->propquery);
- }
+ /*
+ * Because we cleared out old ops, we shouldn't need to worry about
+ * checking if signature is already there.
+ */
+ signature = EVP_SIGNATURE_fetch(locpctx->libctx, supported_sig,
+ locpctx->propquery);
- if (locpctx->keymgmt == NULL
- || signature == NULL
+ if (signature == NULL
|| (EVP_KEYMGMT_provider(locpctx->keymgmt)
!= EVP_SIGNATURE_provider(signature))) {
/*
/* No more legacy from here down to legacy: */
locpctx->op.sig.signature = signature;
-
- provkey =
- evp_keymgmt_export_to_provider(locpctx->pkey, locpctx->keymgmt, 0);
- /* If export failed, legacy may be able to pick it up */
- if (provkey == NULL)
- goto legacy;
-
locpctx->operation = ver ? EVP_PKEY_OP_VERIFYCTX
: EVP_PKEY_OP_SIGNCTX;
-
locpctx->op.sig.sigprovctx
= signature->newctx(ossl_provider_ctx(signature->prov));
if (locpctx->op.sig.sigprovctx == NULL) {
#include "crypto/asn1.h"
#include "crypto/evp.h"
#include "internal/provider.h"
+#include "evp_local.h"
static void evp_pkey_free_it(EVP_PKEY *key);
}
return 0;
}
+
+void *evp_pkey_make_provided(EVP_PKEY *pk, OPENSSL_CTX *libctx,
+ EVP_KEYMGMT **keymgmt, const char *propquery,
+ int domainparams)
+{
+ EVP_KEYMGMT *allocated_keymgmt = NULL;
+ EVP_KEYMGMT *tmp_keymgmt = NULL;
+ void *provdata = NULL;
+
+ if (pk == NULL)
+ return NULL;
+
+ if (keymgmt != NULL) {
+ tmp_keymgmt = *keymgmt;
+ *keymgmt = NULL;
+ }
+
+ if (tmp_keymgmt == NULL) {
+ EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_pkey(libctx, pk);
+
+ if (ctx != NULL && ctx->keytype != NULL)
+ tmp_keymgmt = allocated_keymgmt =
+ EVP_KEYMGMT_fetch(ctx->libctx, ctx->keytype, propquery);
+ EVP_PKEY_CTX_free(ctx);
+ }
+
+ if (tmp_keymgmt != NULL)
+ provdata =
+ evp_keymgmt_export_to_provider(pk, tmp_keymgmt, domainparams);
+
+ /*
+ * If nothing was exported, |tmp_keymgmt| might point at a freed
+ * EVP_KEYMGMT, so we clear it to be safe. It shouldn't be useful for
+ * the caller either way in that case.
+ */
+ if (provdata == NULL)
+ tmp_keymgmt = NULL;
+
+ if (keymgmt != NULL)
+ *keymgmt = tmp_keymgmt;
+
+ EVP_KEYMGMT_free(allocated_keymgmt);
+ return provdata;
+}
int ret = 0;
void *provkey = NULL;
EVP_ASYM_CIPHER *cipher = NULL;
+ EVP_KEYMGMT *tmp_keymgmt = NULL;
+ const char *supported_ciph = NULL;
if (ctx == NULL) {
EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
if (ctx->keytype == NULL || ctx->engine != NULL)
goto legacy;
- if (ctx->keymgmt == NULL)
- ctx->keymgmt =
- EVP_KEYMGMT_fetch(ctx->libctx, ctx->keytype, ctx->propquery);
- if (ctx->keymgmt != NULL) {
- const char *supported_ciph = NULL;
-
- if (ctx->keymgmt->query_operation_name != NULL)
- supported_ciph =
- ctx->keymgmt->query_operation_name(OSSL_OP_ASYM_CIPHER);
-
- /*
- * If we didn't get a supported ciph, assume there is one with the
- * same name as the key type.
- */
- if (supported_ciph == NULL)
- supported_ciph = ctx->keytype;
-
- /*
- * Because we cleared out old ops, we shouldn't need to worry about
- * checking if cipher is already there.
- */
- cipher =
- EVP_ASYM_CIPHER_fetch(ctx->libctx, supported_ciph, ctx->propquery);
- }
-
- if (ctx->keymgmt == NULL
- || cipher == NULL
+ /* Ensure that the key is provided. If not, go legacy */
+ tmp_keymgmt = ctx->keymgmt;
+ provkey = evp_pkey_make_provided(ctx->pkey, ctx->libctx,
+ &tmp_keymgmt, ctx->propquery, 0);
+ if (provkey == NULL)
+ goto legacy;
+ EVP_KEYMGMT_up_ref(tmp_keymgmt);
+ EVP_KEYMGMT_free(ctx->keymgmt);
+ ctx->keymgmt = tmp_keymgmt;
+
+ if (ctx->keymgmt->query_operation_name != NULL)
+ supported_ciph =
+ ctx->keymgmt->query_operation_name(OSSL_OP_ASYM_CIPHER);
+
+ /*
+ * If we didn't get a supported ciph, assume there is one with the
+ * same name as the key type.
+ */
+ if (supported_ciph == NULL)
+ supported_ciph = ctx->keytype;
+
+ /*
+ * Because we cleared out old ops, we shouldn't need to worry about
+ * checking if cipher is already there.
+ */
+ cipher =
+ EVP_ASYM_CIPHER_fetch(ctx->libctx, supported_ciph, ctx->propquery);
+
+ if (cipher == NULL
|| (EVP_KEYMGMT_provider(ctx->keymgmt)
!= EVP_ASYM_CIPHER_provider(cipher))) {
/*
}
ctx->op.ciph.cipher = cipher;
-
- if (ctx->pkey != NULL) {
- provkey = evp_keymgmt_export_to_provider(ctx->pkey, ctx->keymgmt, 0);
- /* If export failed, legacy may be able to pick it up */
- if (provkey == NULL)
- goto legacy;
- }
ctx->op.ciph.ciphprovctx = cipher->newctx(ossl_provider_ctx(cipher->prov));
if (ctx->op.ciph.ciphprovctx == NULL) {
/* The provider key can stay in the cache */
int ret = 0;
void *provkey = NULL;
EVP_SIGNATURE *signature = NULL;
+ EVP_KEYMGMT *tmp_keymgmt = NULL;
+ const char *supported_sig = NULL;
if (ctx == NULL) {
EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
if (ctx->keytype == NULL)
goto legacy;
- if (ctx->keymgmt == NULL)
- ctx->keymgmt =
- EVP_KEYMGMT_fetch(ctx->libctx, ctx->keytype, ctx->propquery);
- if (ctx->keymgmt != NULL) {
- const char *supported_sig = NULL;
-
- if (ctx->keymgmt->query_operation_name != NULL)
- supported_sig =
- ctx->keymgmt->query_operation_name(OSSL_OP_SIGNATURE);
-
- /*
- * If we didn't get a supported sig, assume there is one with the
- * same name as the key type.
- */
- if (supported_sig == NULL)
- supported_sig = ctx->keytype;
-
- /*
- * Because we cleared out old ops, we shouldn't need to worry about
- * checking if signature is already there.
- */
- signature =
- EVP_SIGNATURE_fetch(ctx->libctx, supported_sig, ctx->propquery);
+ /* Ensure that the key is provided. If not, go legacy */
+ tmp_keymgmt = ctx->keymgmt;
+ provkey = evp_pkey_make_provided(ctx->pkey, ctx->libctx,
+ &tmp_keymgmt, ctx->propquery, 0);
+ if (provkey == NULL)
+ goto legacy;
+ if (!EVP_KEYMGMT_up_ref(tmp_keymgmt)) {
+ ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
+ goto err;
}
-
- if (ctx->keymgmt == NULL
- || signature == NULL
+ EVP_KEYMGMT_free(ctx->keymgmt);
+ ctx->keymgmt = tmp_keymgmt;
+
+ if (ctx->keymgmt->query_operation_name != NULL)
+ supported_sig = ctx->keymgmt->query_operation_name(OSSL_OP_SIGNATURE);
+
+ /*
+ * If we didn't get a supported sig, assume there is one with the
+ * same name as the key type.
+ */
+ if (supported_sig == NULL)
+ supported_sig = ctx->keytype;
+
+ /*
+ * Because we cleared out old ops, we shouldn't need to worry about
+ * checking if signature is already there.
+ */
+ signature =
+ EVP_SIGNATURE_fetch(ctx->libctx, supported_sig, ctx->propquery);
+
+ if (signature == NULL
|| (EVP_KEYMGMT_provider(ctx->keymgmt)
!= EVP_SIGNATURE_provider(signature))) {
/*
}
ctx->op.sig.signature = signature;
-
- if (ctx->pkey != NULL) {
- provkey =
- evp_keymgmt_export_to_provider(ctx->pkey, ctx->keymgmt, 0);
- /* If export failed, legacy may be able to pick it up */
- if (provkey == NULL)
- goto legacy;
- }
ctx->op.sig.sigprovctx = signature->newctx(ossl_provider_ctx(signature->prov));
if (ctx->op.sig.sigprovctx == NULL) {
/* The provider key can stay in the cache */
--- /dev/null
+=pod
+
+=head1 NAME
+
+evp_pkey_make_provided - internal EVP_PKEY support functions for providers
+
+=head1 SYNOPSIS
+
+ /* Only for EVP source */
+ #include "evp_local.h"
+
+ void *evp_pkey_make_provided(EVP_PKEY *pk, OPENSSL_CTX *libctx,
+ EVP_KEYMGMT **keymgmt, const char *propquery,
+ int domainparams);
+
+=head1 DESCRIPTION
+
+evp_pkey_make_provided() ensures that the B<EVP_PKEY> I<pk> is provided within
+the library context I<libctx> (NULL means the default context). I<keymgmt>
+may point at a reference to a B<EVP_KEYMGMT>, and works as an input/output
+parameter.
+As input to this function, it can be used to specify a B<EVP_KEYMGMT> to be
+used for exporting. If not (I<*keymgmt> is NULL), then this function will
+fetch an B<EVP_KEYMGMT> implicitly, using I<propquery> as property query string.
+As output from this function, I<*keymgmt> will be assigned the B<EVP_KEYMGMT>
+that was used, if the export was successful, otherwise it will be assigned NULL.
+I<domainparams> decides if I<pk> should be considered domain parameters or the
+actual key.
+
+=head1 RETURN VALUES
+
+evp_pkey_make_provided() returns the provider key data that was exported if
+I<pk> was successfully provided. Otherwise, NULL is returned.
+
+=head1 NOTES
+
+Some functions calling evp_pkey_make_provided() may have received a const
+key, and may therefore have to cast the key to non-const form to call this
+function. Since B<EVP_PKEY> is always dynamically allocated, this is OK.
+
+=head1 SEE ALSO
+
+L<OPENSSL_CTX(3)>, L<EVP_KEYMGMT(3)>
+
+=head1 HISTORY
+
+The functions described here were all added in OpenSSL 3.0.
+
+=head1 COPYRIGHT
+
+Copyright 2020 The OpenSSL Project Authors. All Rights Reserved.
+
+Licensed under the Apache License 2.0 (the "License"). You may not use
+this file except in compliance with the License. You can obtain a copy
+in the file LICENSE in the source distribution or at
+L<https://www.openssl.org/source/license.html>.
+
+=cut