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);
evp_pkey_ctx_free_old_ops(ctx);
ctx->operation = operation;
+ /*
+ * TODO when we stop falling back to legacy, this and the ERR_pop_to_mark()
+ * calls can be removed.
+ */
+ ERR_set_mark();
+
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);
+ /*
+ * Ensure that the key is provided, either natively, or as a cached export.
+ * If not, go legacy
+ */
+ tmp_keymgmt = ctx->keymgmt;
+ provkey = evp_pkey_export_to_provider(ctx->pkey, ctx->libctx,
+ &tmp_keymgmt, ctx->propquery);
+ if (provkey == NULL)
+ goto legacy;
+ if (!EVP_KEYMGMT_up_ref(tmp_keymgmt)) {
+ ERR_clear_last_mark();
+ ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
+ goto err;
}
-
- if (ctx->keymgmt == NULL
- || cipher == NULL
+ 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))) {
/*
- * We don't have the full support we need with provided methods,
- * let's go see if legacy does. Also, we don't need to free
- * ctx->keymgmt here, as it's not necessarily tied to this
- * operation. It will be freed by EVP_PKEY_CTX_free().
+ * We don't need to free ctx->keymgmt here, as it's not necessarily
+ * tied to this operation. It will be freed by EVP_PKEY_CTX_free().
*/
EVP_ASYM_CIPHER_free(cipher);
goto legacy;
}
- ctx->op.ciph.cipher = cipher;
+ /*
+ * TODO remove this when legacy is gone
+ * If we don't have the full support we need with provided methods,
+ * let's go see if legacy does.
+ */
+ ERR_pop_to_mark();
- 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;
- }
+ /* No more legacy from here down to legacy: */
+
+ ctx->op.ciph.cipher = cipher;
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 */
return 1;
legacy:
+ /*
+ * TODO remove this when legacy is gone
+ * If we don't have the full support we need with provided methods,
+ * let's go see if legacy does.
+ */
+ ERR_pop_to_mark();
+
if (ctx->pmeth == NULL || ctx->pmeth->encrypt == NULL) {
EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
return -2;