From: Matt Caswell Date: Mon, 2 Sep 2019 15:48:26 +0000 (+0100) Subject: Add support for verify/verify_recover functions to EVP_SIGNATURE X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=390acbebfa90500c79c5014e6659eacda861550c;p=openssl Add support for verify/verify_recover functions to EVP_SIGNATURE Reviewed-by: Richard Levitte (Merged from https://github.com/openssl/openssl/pull/9753) --- diff --git a/crypto/evp/evp_locl.h b/crypto/evp/evp_locl.h index 284be8c350..722eecfe43 100644 --- a/crypto/evp/evp_locl.h +++ b/crypto/evp/evp_locl.h @@ -124,6 +124,10 @@ struct evp_signature_st { OSSL_OP_signature_newctx_fn *newctx; OSSL_OP_signature_sign_init_fn *sign_init; OSSL_OP_signature_sign_fn *sign; + OSSL_OP_signature_verify_init_fn *verify_init; + OSSL_OP_signature_verify_fn *verify; + OSSL_OP_signature_verify_recover_init_fn *verify_recover_init; + OSSL_OP_signature_verify_recover_fn *verify_recover; OSSL_OP_signature_freectx_fn *freectx; OSSL_OP_signature_dupctx_fn *dupctx; OSSL_OP_signature_set_params_fn *set_params; diff --git a/crypto/evp/pmeth_fn.c b/crypto/evp/pmeth_fn.c index 53f4dbbf74..8fdb31c218 100644 --- a/crypto/evp/pmeth_fn.c +++ b/crypto/evp/pmeth_fn.c @@ -50,7 +50,7 @@ static void *evp_signature_from_dispatch(const char *name, EVP_KEYMGMT *keymgmt = EVP_KEYMGMT_fetch(keymgmt_data->ctx, name, keymgmt_data->properties); EVP_SIGNATURE *signature = NULL; - int fncnt = 0; + int ctxfncnt = 0, signfncnt = 0, verifyfncnt = 0, verifyrecfncnt = 0; if (keymgmt == NULL || EVP_KEYMGMT_provider(keymgmt) != prov) { ERR_raise(ERR_LIB_EVP, EVP_R_NO_KEYMGMT_AVAILABLE); @@ -72,25 +72,51 @@ static void *evp_signature_from_dispatch(const char *name, if (signature->newctx != NULL) break; signature->newctx = OSSL_get_OP_signature_newctx(fns); - fncnt++; + ctxfncnt++; break; case OSSL_FUNC_SIGNATURE_SIGN_INIT: if (signature->sign_init != NULL) break; signature->sign_init = OSSL_get_OP_signature_sign_init(fns); - fncnt++; + signfncnt++; break; case OSSL_FUNC_SIGNATURE_SIGN: if (signature->sign != NULL) break; signature->sign = OSSL_get_OP_signature_sign(fns); - fncnt++; + 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_FREECTX: if (signature->freectx != NULL) break; signature->freectx = OSSL_get_OP_signature_freectx(fns); - fncnt++; + ctxfncnt++; break; case OSSL_FUNC_SIGNATURE_DUPCTX: if (signature->dupctx != NULL) @@ -104,11 +130,14 @@ static void *evp_signature_from_dispatch(const char *name, break; } } - if (fncnt != 4) { + if (ctxfncnt != 2 + || (signfncnt != 2 && verifyfncnt != 2 && verifyrecfncnt != 2)) { /* * In order to be a consistent set of functions we must have at least - * a complete set of "signature" functions: sign_init, sign, newctx, - * and freectx. The dupctx function is optional. + * a set of context functions (newctx and freectx) as well as a pair of + * "signature" functions: (sign_init, sign) or (verify_init verify) or + * (verify_recover_init, verify_recover). The dupctx and set_params + * functions are optional. */ ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_PROVIDER_FUNCTIONS); goto err; @@ -167,9 +196,10 @@ EVP_SIGNATURE *EVP_SIGNATURE_fetch(OPENSSL_CTX *ctx, const char *algorithm, (void (*)(void *))EVP_SIGNATURE_free); } -int EVP_PKEY_sign_init_ex(EVP_PKEY_CTX *ctx, EVP_SIGNATURE *signature) +static int evp_pkey_signature_init(EVP_PKEY_CTX *ctx, EVP_SIGNATURE *signature, + int operation) { - int ret; + int ret = 0; void *provkey = NULL; if (ctx == NULL) { @@ -177,7 +207,7 @@ int EVP_PKEY_sign_init_ex(EVP_PKEY_CTX *ctx, EVP_SIGNATURE *signature) return -2; } - ctx->operation = EVP_PKEY_OP_SIGN; + ctx->operation = operation; if (ctx->engine != NULL) goto legacy; @@ -227,30 +257,91 @@ int EVP_PKEY_sign_init_ex(EVP_PKEY_CTX *ctx, EVP_SIGNATURE *signature) EVPerr(0, EVP_R_INITIALIZATION_ERROR); goto err; } - ret = signature->sign_init(ctx->sigprovctx, provkey); - return ret ? 1 : 0; - err: - ctx->operation = EVP_PKEY_OP_UNDEFINED; - return 0; + switch (operation) { + case EVP_PKEY_OP_SIGN: + if (signature->sign_init == NULL) { + EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + ret = -2; + goto err; + } + ret = signature->sign_init(ctx->sigprovctx, provkey); + break; + case EVP_PKEY_OP_VERIFY: + if (signature->verify_init == NULL) { + EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + ret = -2; + goto err; + } + ret = signature->verify_init(ctx->sigprovctx, provkey); + break; + case EVP_PKEY_OP_VERIFYRECOVER: + if (signature->verify_recover_init == NULL) { + EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + ret = -2; + goto err; + } + ret = signature->verify_recover_init(ctx->sigprovctx, provkey); + break; + default: + EVPerr(0, EVP_R_INITIALIZATION_ERROR); + goto err; + } + + if (ret <= 0) { + signature->freectx(ctx->sigprovctx); + ctx->sigprovctx = NULL; + goto err; + } + return 1; legacy: - if (ctx->pmeth == NULL || ctx->pmeth->sign == NULL) { + if (ctx->pmeth == NULL + || (operation == EVP_PKEY_OP_SIGN && ctx->pmeth->sign == NULL) + || (operation == EVP_PKEY_OP_VERIFY && ctx->pmeth->verify == NULL) + || (operation == EVP_PKEY_OP_VERIFYRECOVER + && ctx->pmeth->verify_recover == NULL)) { EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); return -2; } - if (ctx->pmeth->sign_init == NULL) - return 1; - ret = ctx->pmeth->sign_init(ctx); + switch (operation) { + case EVP_PKEY_OP_SIGN: + if (ctx->pmeth->sign_init == NULL) + return 1; + ret = ctx->pmeth->sign_init(ctx); + break; + case EVP_PKEY_OP_VERIFY: + if (ctx->pmeth->verify_init == NULL) + return 1; + ret = ctx->pmeth->verify_init(ctx); + break; + case EVP_PKEY_OP_VERIFYRECOVER: + if (ctx->pmeth->verify_recover_init == NULL) + return 1; + ret = ctx->pmeth->verify_recover_init(ctx); + break; + default: + EVPerr(0, EVP_R_INITIALIZATION_ERROR); + goto err; + } if (ret <= 0) - ctx->operation = EVP_PKEY_OP_UNDEFINED; + goto err; + return ret; + + err: + ctx->operation = EVP_PKEY_OP_UNDEFINED; return ret; } +int EVP_PKEY_sign_init_ex(EVP_PKEY_CTX *ctx, EVP_SIGNATURE *signature) +{ + return evp_pkey_signature_init(ctx, signature, EVP_PKEY_OP_SIGN); +} + int EVP_PKEY_sign_init(EVP_PKEY_CTX *ctx) { - return EVP_PKEY_sign_init_ex(ctx, NULL); + return evp_pkey_signature_init(ctx, NULL, EVP_PKEY_OP_SIGN); } int EVP_PKEY_sign(EVP_PKEY_CTX *ctx, @@ -287,69 +378,85 @@ int EVP_PKEY_sign(EVP_PKEY_CTX *ctx, return ctx->pmeth->sign(ctx, sig, siglen, tbs, tbslen); } +int EVP_PKEY_verify_init_ex(EVP_PKEY_CTX *ctx, EVP_SIGNATURE *signature) +{ + return evp_pkey_signature_init(ctx, signature, EVP_PKEY_OP_VERIFY); +} + int EVP_PKEY_verify_init(EVP_PKEY_CTX *ctx) { - int ret; - if (!ctx || !ctx->pmeth || !ctx->pmeth->verify) { - EVPerr(EVP_F_EVP_PKEY_VERIFY_INIT, - EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); - return -2; - } - ctx->operation = EVP_PKEY_OP_VERIFY; - if (!ctx->pmeth->verify_init) - return 1; - ret = ctx->pmeth->verify_init(ctx); - if (ret <= 0) - ctx->operation = EVP_PKEY_OP_UNDEFINED; - return ret; + return evp_pkey_signature_init(ctx, NULL, EVP_PKEY_OP_VERIFY); } int EVP_PKEY_verify(EVP_PKEY_CTX *ctx, const unsigned char *sig, size_t siglen, const unsigned char *tbs, size_t tbslen) { - if (!ctx || !ctx->pmeth || !ctx->pmeth->verify) { - EVPerr(EVP_F_EVP_PKEY_VERIFY, - EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + int ret; + + if (ctx == NULL) { + EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); return -2; } + if (ctx->operation != EVP_PKEY_OP_VERIFY) { - EVPerr(EVP_F_EVP_PKEY_VERIFY, EVP_R_OPERATON_NOT_INITIALIZED); + EVPerr(0, EVP_R_OPERATON_NOT_INITIALIZED); return -1; } + + if (ctx->sigprovctx == NULL) + goto legacy; + + ret = ctx->signature->verify(ctx->sigprovctx, sig, siglen, tbs, tbslen); + + return ret; + legacy: + if (ctx->pmeth == NULL || ctx->pmeth->verify == NULL) { + EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + return -2; + } + return ctx->pmeth->verify(ctx, sig, siglen, tbs, tbslen); } +int EVP_PKEY_verify_recover_init_ex(EVP_PKEY_CTX *ctx, EVP_SIGNATURE *signature) +{ + return evp_pkey_signature_init(ctx, signature, EVP_PKEY_OP_VERIFYRECOVER); +} + int EVP_PKEY_verify_recover_init(EVP_PKEY_CTX *ctx) { - int ret; - if (!ctx || !ctx->pmeth || !ctx->pmeth->verify_recover) { - EVPerr(EVP_F_EVP_PKEY_VERIFY_RECOVER_INIT, - EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); - return -2; - } - ctx->operation = EVP_PKEY_OP_VERIFYRECOVER; - if (!ctx->pmeth->verify_recover_init) - return 1; - ret = ctx->pmeth->verify_recover_init(ctx); - if (ret <= 0) - ctx->operation = EVP_PKEY_OP_UNDEFINED; - return ret; + return evp_pkey_signature_init(ctx, NULL, EVP_PKEY_OP_VERIFYRECOVER); } int EVP_PKEY_verify_recover(EVP_PKEY_CTX *ctx, unsigned char *rout, size_t *routlen, const unsigned char *sig, size_t siglen) { - if (!ctx || !ctx->pmeth || !ctx->pmeth->verify_recover) { - EVPerr(EVP_F_EVP_PKEY_VERIFY_RECOVER, - EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + int ret; + + if (ctx == NULL) { + EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); return -2; } + if (ctx->operation != EVP_PKEY_OP_VERIFYRECOVER) { - EVPerr(EVP_F_EVP_PKEY_VERIFY_RECOVER, EVP_R_OPERATON_NOT_INITIALIZED); + EVPerr(0, EVP_R_OPERATON_NOT_INITIALIZED); return -1; } + + if (ctx->sigprovctx == NULL) + goto legacy; + + ret = ctx->signature->verify_recover(ctx->sigprovctx, rout, routlen, + (rout == NULL ? 0 : *routlen), + sig, siglen); + return ret; + legacy: + if (ctx->pmeth == NULL || ctx->pmeth->verify_recover == NULL) { + EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + return -2; + } M_check_autoarg(ctx, rout, routlen, EVP_F_EVP_PKEY_VERIFY_RECOVER) return ctx->pmeth->verify_recover(ctx, rout, routlen, sig, siglen); } diff --git a/crypto/evp/pmeth_lib.c b/crypto/evp/pmeth_lib.c index 563a2bd7ba..534f857df1 100644 --- a/crypto/evp/pmeth_lib.c +++ b/crypto/evp/pmeth_lib.c @@ -19,6 +19,7 @@ #include "internal/asn1_int.h" #include "internal/evp_int.h" #include "internal/numbers.h" +#include "internal/provider.h" #include "evp_locl.h" typedef int sk_cmp_fn_type(const char *const *a, const char *const *b); @@ -470,6 +471,8 @@ static int legacy_ctrl_to_param(EVP_PKEY_CTX *ctx, int keytype, int optype, case EVP_PKEY_CTRL_DH_PAD: return EVP_PKEY_CTX_set_dh_pad(ctx, p1); #endif + case EVP_PKEY_CTRL_MD: + return EVP_PKEY_CTX_set_signature_md(ctx, p2); } return 0; } @@ -484,7 +487,7 @@ int EVP_PKEY_CTX_ctrl(EVP_PKEY_CTX *ctx, int keytype, int optype, return -2; } - if (ctx->exchprovctx != NULL) + if (ctx->exchprovctx != NULL || ctx->sigprovctx != NULL) return legacy_ctrl_to_param(ctx, keytype, optype, cmd, p1, p2); if (ctx->pmeth == NULL || ctx->pmeth->ctrl == NULL) { @@ -534,6 +537,18 @@ static int legacy_ctrl_str_to_param(EVP_PKEY_CTX *ctx, const char *name, return EVP_PKEY_CTX_set_dh_pad(ctx, pad); } #endif + if (strcmp(name, "digest") == 0) { + int ret; + EVP_MD *md + = EVP_MD_fetch(ossl_provider_library_context(ctx->signature->prov), + value, NULL); + if (md == NULL) + return 0; + ret = EVP_PKEY_CTX_set_signature_md(ctx, md); + EVP_MD_meth_free(md); + return ret; + } + return 0; } @@ -545,7 +560,7 @@ int EVP_PKEY_CTX_ctrl_str(EVP_PKEY_CTX *ctx, return -2; } - if (ctx->exchprovctx != NULL) + if (ctx->exchprovctx != NULL || ctx->sigprovctx != NULL) return legacy_ctrl_str_to_param(ctx, name, value); if (!ctx || !ctx->pmeth || !ctx->pmeth->ctrl_str) { diff --git a/include/openssl/core_numbers.h b/include/openssl/core_numbers.h index ea320537e7..35e6056ba1 100644 --- a/include/openssl/core_numbers.h +++ b/include/openssl/core_numbers.h @@ -406,9 +406,13 @@ OSSL_CORE_MAKE_FUNC(int, OP_keyexch_set_params, (void *ctx, # define OSSL_FUNC_SIGNATURE_NEWCTX 1 # define OSSL_FUNC_SIGNATURE_SIGN_INIT 2 # define OSSL_FUNC_SIGNATURE_SIGN 3 -# define OSSL_FUNC_SIGNATURE_FREECTX 4 -# define OSSL_FUNC_SIGNATURE_DUPCTX 5 -# define OSSL_FUNC_SIGNATURE_SET_PARAMS 6 +# define OSSL_FUNC_SIGNATURE_VERIFY_INIT 4 +# define OSSL_FUNC_SIGNATURE_VERIFY 5 +# define OSSL_FUNC_SIGNATURE_VERIFY_RECOVER_INIT 6 +# define OSSL_FUNC_SIGNATURE_VERIFY_RECOVER 7 +# define OSSL_FUNC_SIGNATURE_FREECTX 8 +# define OSSL_FUNC_SIGNATURE_DUPCTX 9 +# define OSSL_FUNC_SIGNATURE_SET_PARAMS 10 OSSL_CORE_MAKE_FUNC(void *, OP_signature_newctx, (void *provctx)) OSSL_CORE_MAKE_FUNC(int, OP_signature_sign_init, (void *ctx, void *provkey)) @@ -416,6 +420,20 @@ OSSL_CORE_MAKE_FUNC(int, OP_signature_sign, (void *ctx, unsigned char *sig, size_t *siglen, size_t sigsize, const unsigned char *tbs, size_t tbslen)) +OSSL_CORE_MAKE_FUNC(int, OP_signature_verify_init, (void *ctx, void *provkey)) +OSSL_CORE_MAKE_FUNC(int, OP_signature_verify, (void *ctx, + const unsigned char *sig, + size_t siglen, + const unsigned char *tbs, + size_t tbslen)) +OSSL_CORE_MAKE_FUNC(int, OP_signature_verify_recover_init, (void *ctx, + void *provkey)) +OSSL_CORE_MAKE_FUNC(int, OP_signature_verify_recover, (void *ctx, + unsigned char *rout, + size_t *routlen, + size_t routsize, + const unsigned char *sig, + size_t siglen)) OSSL_CORE_MAKE_FUNC(void, OP_signature_freectx, (void *ctx)) OSSL_CORE_MAKE_FUNC(void *, OP_signature_dupctx, (void *ctx)) OSSL_CORE_MAKE_FUNC(int, OP_signature_set_params, (void *ctx, diff --git a/include/openssl/evp.h b/include/openssl/evp.h index dc70686f8f..2ea8d2799f 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h @@ -1479,10 +1479,12 @@ int EVP_PKEY_sign_init(EVP_PKEY_CTX *ctx); int EVP_PKEY_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen, const unsigned char *tbs, size_t tbslen); +int EVP_PKEY_verify_init_ex(EVP_PKEY_CTX *ctx, EVP_SIGNATURE *signature); int EVP_PKEY_verify_init(EVP_PKEY_CTX *ctx); int EVP_PKEY_verify(EVP_PKEY_CTX *ctx, const unsigned char *sig, size_t siglen, const unsigned char *tbs, size_t tbslen); +int EVP_PKEY_verify_recover_init_ex(EVP_PKEY_CTX *ctx, EVP_SIGNATURE *signature); int EVP_PKEY_verify_recover_init(EVP_PKEY_CTX *ctx); int EVP_PKEY_verify_recover(EVP_PKEY_CTX *ctx, unsigned char *rout, size_t *routlen, diff --git a/providers/common/signature/dsa.c b/providers/common/signature/dsa.c index 69f4978729..c0cd29381c 100644 --- a/providers/common/signature/dsa.c +++ b/providers/common/signature/dsa.c @@ -15,7 +15,8 @@ #include "internal/provider_algs.h" static OSSL_OP_signature_newctx_fn dsa_newctx; -static OSSL_OP_signature_sign_init_fn dsa_sign_init; +static OSSL_OP_signature_sign_init_fn dsa_signature_init; +static OSSL_OP_signature_verify_init_fn dsa_signature_init; static OSSL_OP_signature_sign_fn dsa_sign; static OSSL_OP_signature_freectx_fn dsa_freectx; static OSSL_OP_signature_dupctx_fn dsa_dupctx; @@ -37,7 +38,7 @@ static void *dsa_newctx(void *provctx) return OPENSSL_zalloc(sizeof(PROV_DSA_CTX)); } -static int dsa_sign_init(void *vpdsactx, void *vdsa) +static int dsa_signature_init(void *vpdsactx, void *vdsa) { PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx; @@ -67,7 +68,7 @@ static int dsa_sign(void *vpdsactx, unsigned char *sig, size_t *siglen, if (pdsactx->mdsize != 0 && tbslen != pdsactx->mdsize) return 0; - ret = DSA_sign(0, tbs, tbslen, sig, &sltmp, pdsactx-> dsa); + ret = DSA_sign(0, tbs, tbslen, sig, &sltmp, pdsactx->dsa); if (ret <= 0) return 0; @@ -76,6 +77,18 @@ static int dsa_sign(void *vpdsactx, unsigned char *sig, size_t *siglen, return 1; } +static int dsa_verify(void *vpdsactx, const unsigned char *sig, size_t siglen, + const unsigned char *tbs, size_t tbslen) +{ + PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx; + + if (pdsactx->mdsize != 0 && tbslen != pdsactx->mdsize) + return 0; + + return DSA_verify(0, tbs, tbslen, sig, siglen, pdsactx->dsa); +} + + static void dsa_freectx(void *vpdsactx) { PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx; @@ -123,8 +136,10 @@ static int dsa_set_params(void *vpdsactx, const OSSL_PARAM params[]) const OSSL_DISPATCH dsa_signature_functions[] = { { OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))dsa_newctx }, - { OSSL_FUNC_SIGNATURE_SIGN_INIT, (void (*)(void))dsa_sign_init }, + { OSSL_FUNC_SIGNATURE_SIGN_INIT, (void (*)(void))dsa_signature_init }, { OSSL_FUNC_SIGNATURE_SIGN, (void (*)(void))dsa_sign }, + { OSSL_FUNC_SIGNATURE_VERIFY_INIT, (void (*)(void))dsa_signature_init }, + { OSSL_FUNC_SIGNATURE_VERIFY, (void (*)(void))dsa_verify }, { OSSL_FUNC_SIGNATURE_FREECTX, (void (*)(void))dsa_freectx }, { OSSL_FUNC_SIGNATURE_DUPCTX, (void (*)(void))dsa_dupctx }, { OSSL_FUNC_SIGNATURE_SET_PARAMS, (void (*)(void))dsa_set_params }, diff --git a/util/libcrypto.num b/util/libcrypto.num index dd89bd3f4a..a1a36f1f77 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -4746,3 +4746,5 @@ EVP_SIGNATURE_provider 4862 3_0_0 EXIST::FUNCTION: EVP_SIGNATURE_fetch 4863 3_0_0 EXIST::FUNCTION: EVP_PKEY_sign_init_ex 4864 3_0_0 EXIST::FUNCTION: EVP_PKEY_CTX_set_signature_md 4865 3_0_0 EXIST::FUNCTION: +EVP_PKEY_verify_init_ex 4866 3_0_0 EXIST::FUNCTION: +EVP_PKEY_verify_recover_init_ex 4867 3_0_0 EXIST::FUNCTION: