+ locpctx = ctx->pctx;
+ evp_pkey_ctx_free_old_ops(locpctx);
+
+ /*
+ * TODO when we stop falling back to legacy, this and the ERR_pop_to_mark()
+ * calls can be removed.
+ */
+ ERR_set_mark();
+
+ if (locpctx->engine != NULL || locpctx->keytype == NULL)
+ goto legacy;
+
+ /*
+ * Ensure that the key is provided, either natively, or as a cached export.
+ * If not, go legacy
+ */
+ tmp_keymgmt = locpctx->keymgmt;
+ provkey = evp_pkey_export_to_provider(locpctx->pkey, locpctx->libctx,
+ &tmp_keymgmt, locpctx->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;
+ }
+ 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 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);
+
+ if (signature == NULL
+ || (EVP_KEYMGMT_provider(locpctx->keymgmt)
+ != EVP_SIGNATURE_provider(signature))) {
+ /*
+ * 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_SIGNATURE_free(signature);
+ goto 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();
+
+ /* No more legacy from here down to legacy: */
+
+ if (pctx != NULL)
+ *pctx = locpctx;
+
+ locpctx->op.sig.signature = signature;
+ 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) {
+ ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
+ goto err;
+ }
+ if (type != NULL) {
+ ctx->reqdigest = type;
+ if (mdname == NULL)
+ mdname = canon_mdname(EVP_MD_name(type));
+ } else {
+ if (mdname == NULL) {
+ if (evp_keymgmt_util_get_deflt_digest_name(tmp_keymgmt, provkey,
+ locmdname,
+ sizeof(locmdname)) > 0) {
+ mdname = canon_mdname(locmdname);
+ } else {
+ EVPerr(EVP_F_DO_SIGVER_INIT, EVP_R_NO_DEFAULT_DIGEST);
+ return 0;
+ }
+ }
+
+ if (mdname != NULL) {
+ /*
+ * This might be requested by a later call to EVP_MD_CTX_md().
+ * In that case the "explicit fetch" rules apply for that
+ * function (as per man pages), i.e. the ref count is not updated
+ * so the EVP_MD should not be used beyound the lifetime of the
+ * EVP_MD_CTX.
+ */
+ ctx->reqdigest = ctx->fetched_digest =
+ EVP_MD_fetch(locpctx->libctx, mdname, props);
+ }
+ }
+
+ if (ver) {
+ if (signature->digest_verify_init == NULL) {
+ ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
+ goto err;
+ }
+ ret = signature->digest_verify_init(locpctx->op.sig.sigprovctx,
+ mdname, props, provkey);
+ } else {
+ if (signature->digest_sign_init == NULL) {
+ ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
+ goto err;
+ }
+ ret = signature->digest_sign_init(locpctx->op.sig.sigprovctx,
+ mdname, props, provkey);
+ }
+
+ return ret ? 1 : 0;
+ err:
+ evp_pkey_ctx_free_old_ops(locpctx);
+ locpctx->operation = EVP_PKEY_OP_UNDEFINED;
+ return 0;
+
+ 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 (type == NULL && mdname != NULL)
+ type = evp_get_digestbyname_ex(locpctx->libctx, mdname);
+
+ if (ctx->pctx->pmeth == NULL) {
+ EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+ return 0;
+ }
+