+ EVP_SIGNATURE *signature = NULL;
+ int ctxfncnt = 0, signfncnt = 0, verifyfncnt = 0, verifyrecfncnt = 0;
+ int digsignfncnt = 0, digverifyfncnt = 0;
+ int gparamfncnt = 0, sparamfncnt = 0, gmdparamfncnt = 0, smdparamfncnt = 0;
+
+ if ((signature = evp_signature_new(prov)) == NULL) {
+ ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ signature->name_id = name_id;
+
+ for (; fns->function_id != 0; fns++) {
+ switch (fns->function_id) {
+ case OSSL_FUNC_SIGNATURE_NEWCTX:
+ if (signature->newctx != NULL)
+ break;
+ signature->newctx = OSSL_get_OP_signature_newctx(fns);
+ ctxfncnt++;
+ break;
+ case OSSL_FUNC_SIGNATURE_SIGN_INIT:
+ if (signature->sign_init != NULL)
+ break;
+ signature->sign_init = OSSL_get_OP_signature_sign_init(fns);
+ signfncnt++;
+ break;
+ case OSSL_FUNC_SIGNATURE_SIGN:
+ if (signature->sign != NULL)
+ break;
+ signature->sign = OSSL_get_OP_signature_sign(fns);
+ signfncnt++;
+ break;
+ case OSSL_FUNC_SIGNATURE_VERIFY_INIT:
+ if (signature->verify_init != NULL)
+ break;
+ signature->verify_init = OSSL_get_OP_signature_verify_init(fns);
+ verifyfncnt++;
+ break;
+ case OSSL_FUNC_SIGNATURE_VERIFY:
+ if (signature->verify != NULL)
+ break;
+ signature->verify = OSSL_get_OP_signature_verify(fns);
+ verifyfncnt++;
+ break;
+ case OSSL_FUNC_SIGNATURE_VERIFY_RECOVER_INIT:
+ if (signature->verify_recover_init != NULL)
+ break;
+ signature->verify_recover_init
+ = OSSL_get_OP_signature_verify_recover_init(fns);
+ verifyrecfncnt++;
+ break;
+ case OSSL_FUNC_SIGNATURE_VERIFY_RECOVER:
+ if (signature->verify_recover != NULL)
+ break;
+ signature->verify_recover
+ = OSSL_get_OP_signature_verify_recover(fns);
+ verifyrecfncnt++;
+ break;
+ case OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT:
+ if (signature->digest_sign_init != NULL)
+ break;
+ signature->digest_sign_init
+ = OSSL_get_OP_signature_digest_sign_init(fns);
+ digsignfncnt++;
+ break;
+ case OSSL_FUNC_SIGNATURE_DIGEST_SIGN_UPDATE:
+ if (signature->digest_sign_update != NULL)
+ break;
+ signature->digest_sign_update
+ = OSSL_get_OP_signature_digest_sign_update(fns);
+ digsignfncnt++;
+ break;
+ case OSSL_FUNC_SIGNATURE_DIGEST_SIGN_FINAL:
+ if (signature->digest_sign_final != NULL)
+ break;
+ signature->digest_sign_final
+ = OSSL_get_OP_signature_digest_sign_final(fns);
+ digsignfncnt++;
+ break;
+ case OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_INIT:
+ if (signature->digest_verify_init != NULL)
+ break;
+ signature->digest_verify_init
+ = OSSL_get_OP_signature_digest_verify_init(fns);
+ digverifyfncnt++;
+ break;
+ case OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_UPDATE:
+ if (signature->digest_verify_update != NULL)
+ break;
+ signature->digest_verify_update
+ = OSSL_get_OP_signature_digest_verify_update(fns);
+ digverifyfncnt++;
+ break;
+ case OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_FINAL:
+ if (signature->digest_verify_final != NULL)
+ break;
+ signature->digest_verify_final
+ = OSSL_get_OP_signature_digest_verify_final(fns);
+ digverifyfncnt++;
+ break;
+ case OSSL_FUNC_SIGNATURE_FREECTX:
+ if (signature->freectx != NULL)
+ break;
+ signature->freectx = OSSL_get_OP_signature_freectx(fns);
+ ctxfncnt++;
+ break;
+ case OSSL_FUNC_SIGNATURE_DUPCTX:
+ if (signature->dupctx != NULL)
+ break;
+ signature->dupctx = OSSL_get_OP_signature_dupctx(fns);
+ break;
+ case OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS:
+ if (signature->get_ctx_params != NULL)
+ break;
+ signature->get_ctx_params
+ = OSSL_get_OP_signature_get_ctx_params(fns);
+ gparamfncnt++;
+ break;
+ case OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS:
+ if (signature->gettable_ctx_params != NULL)
+ break;
+ signature->gettable_ctx_params
+ = OSSL_get_OP_signature_gettable_ctx_params(fns);
+ gparamfncnt++;
+ break;
+ case OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS:
+ if (signature->set_ctx_params != NULL)
+ break;
+ signature->set_ctx_params
+ = OSSL_get_OP_signature_set_ctx_params(fns);
+ sparamfncnt++;
+ break;
+ case OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS:
+ if (signature->settable_ctx_params != NULL)
+ break;
+ signature->settable_ctx_params
+ = OSSL_get_OP_signature_settable_ctx_params(fns);
+ sparamfncnt++;
+ break;
+ case OSSL_FUNC_SIGNATURE_GET_CTX_MD_PARAMS:
+ if (signature->get_ctx_md_params != NULL)
+ break;
+ signature->get_ctx_md_params
+ = OSSL_get_OP_signature_get_ctx_md_params(fns);
+ gmdparamfncnt++;
+ break;
+ case OSSL_FUNC_SIGNATURE_GETTABLE_CTX_MD_PARAMS:
+ if (signature->gettable_ctx_md_params != NULL)
+ break;
+ signature->gettable_ctx_md_params
+ = OSSL_get_OP_signature_gettable_ctx_md_params(fns);
+ gmdparamfncnt++;
+ break;
+ case OSSL_FUNC_SIGNATURE_SET_CTX_MD_PARAMS:
+ if (signature->set_ctx_md_params != NULL)
+ break;
+ signature->set_ctx_md_params
+ = OSSL_get_OP_signature_set_ctx_md_params(fns);
+ smdparamfncnt++;
+ break;
+ case OSSL_FUNC_SIGNATURE_SETTABLE_CTX_MD_PARAMS:
+ if (signature->settable_ctx_md_params != NULL)
+ break;
+ signature->settable_ctx_md_params
+ = OSSL_get_OP_signature_settable_ctx_md_params(fns);
+ smdparamfncnt++;
+ break;
+ }
+ }
+ if (ctxfncnt != 2
+ || (signfncnt == 0
+ && verifyfncnt == 0
+ && verifyrecfncnt == 0
+ && digsignfncnt == 0
+ && digverifyfncnt == 0)
+ || (signfncnt != 0 && signfncnt != 2)
+ || (verifyfncnt != 0 && verifyfncnt != 2)
+ || (verifyrecfncnt != 0 && verifyrecfncnt != 2)
+ || (digsignfncnt != 0 && digsignfncnt != 3)
+ || (digverifyfncnt != 0 && digverifyfncnt != 3)
+ || (gparamfncnt != 0 && gparamfncnt != 2)
+ || (sparamfncnt != 0 && sparamfncnt != 2)
+ || (gmdparamfncnt != 0 && gmdparamfncnt != 2)
+ || (smdparamfncnt != 0 && smdparamfncnt != 2)) {
+ /*
+ * In order to be a consistent set of functions we must have at least
+ * a set of context functions (newctx and freectx) as well as a set of
+ * "signature" functions:
+ * (sign_init, sign) or
+ * (verify_init verify) or
+ * (verify_recover_init, verify_recover) or
+ * (digest_sign_init, digest_sign_update, digest_sign_final) or
+ * (digest_verify_init, digest_verify_update, digest_verify_final).
+ *
+ * set_ctx_params and settable_ctx_params are optional, but if one of
+ * them is present then the other one must also be present. The same
+ * applies to get_ctx_params and gettable_ctx_params. The same rules
+ * apply to the "md_params" functions. The dupctx function is optional.
+ */
+ ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_PROVIDER_FUNCTIONS);
+ goto err;
+ }
+
+ return signature;
+ err:
+ EVP_SIGNATURE_free(signature);
+ return NULL;
+}
+
+void EVP_SIGNATURE_free(EVP_SIGNATURE *signature)
+{
+ if (signature != NULL) {
+ int i;
+
+ CRYPTO_DOWN_REF(&signature->refcnt, &i, signature->lock);
+ if (i > 0)
+ return;
+ ossl_provider_free(signature->prov);
+ CRYPTO_THREAD_lock_free(signature->lock);
+ OPENSSL_free(signature);
+ }
+}
+
+int EVP_SIGNATURE_up_ref(EVP_SIGNATURE *signature)
+{
+ int ref = 0;
+
+ CRYPTO_UP_REF(&signature->refcnt, &ref, signature->lock);
+ return 1;
+}
+
+OSSL_PROVIDER *EVP_SIGNATURE_provider(const EVP_SIGNATURE *signature)
+{
+ return signature->prov;
+}
+
+EVP_SIGNATURE *EVP_SIGNATURE_fetch(OPENSSL_CTX *ctx, const char *algorithm,
+ const char *properties)
+{
+ return evp_generic_fetch(ctx, OSSL_OP_SIGNATURE, algorithm, properties,
+ evp_signature_from_dispatch,
+ (int (*)(void *))EVP_SIGNATURE_up_ref,
+ (void (*)(void *))EVP_SIGNATURE_free);
+}
+
+int EVP_SIGNATURE_is_a(const EVP_SIGNATURE *signature, const char *name)
+{
+ return evp_is_a(signature->prov, signature->name_id, name);
+}
+
+int EVP_SIGNATURE_number(const EVP_SIGNATURE *signature)
+{
+ return signature->name_id;
+}
+
+void EVP_SIGNATURE_do_all_provided(OPENSSL_CTX *libctx,
+ void (*fn)(EVP_SIGNATURE *signature,
+ void *arg),
+ void *arg)
+{
+ evp_generic_do_all(libctx, OSSL_OP_SIGNATURE,
+ (void (*)(void *, void *))fn, arg,
+ evp_signature_from_dispatch,
+ (void (*)(void *))EVP_SIGNATURE_free);
+}
+
+
+void EVP_SIGNATURE_names_do_all(const EVP_SIGNATURE *signature,
+ void (*fn)(const char *name, void *data),
+ void *data)
+{
+ if (signature->prov != NULL)
+ evp_names_do_all(signature->prov, signature->name_id, fn, data);
+}
+
+static int evp_pkey_signature_init(EVP_PKEY_CTX *ctx, int operation)
+{
+ int ret = 0;
+ void *provkey = NULL;
+ EVP_SIGNATURE *signature = NULL;
+
+ if (ctx == NULL) {
+ EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);