X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=crypto%2Fevp%2Fdigest.c;h=adde3e13aba583bf4a65393fa2e77986645b4d2e;hp=78e8756f2ac98f54797da56478b3aa1beac32a5a;hb=557d673783f82795e8ae8ca71b0092f9dbdaaeef;hpb=c540f00f383754fa490be76c2c3398ccd4d2a869 diff --git a/crypto/evp/digest.c b/crypto/evp/digest.c index 78e8756f2a..adde3e13ab 100644 --- a/crypto/evp/digest.c +++ b/crypto/evp/digest.c @@ -14,9 +14,9 @@ #include #include #include "internal/cryptlib.h" -#include "internal/evp_int.h" +#include "crypto/evp.h" #include "internal/provider.h" -#include "evp_locl.h" +#include "evp_local.h" /* This call frees resources associated with the context */ int EVP_MD_CTX_reset(EVP_MD_CTX *ctx) @@ -24,8 +24,19 @@ int EVP_MD_CTX_reset(EVP_MD_CTX *ctx) if (ctx == NULL) return 1; - if (ctx->digest == NULL || ctx->digest->prov == NULL) - goto legacy; +#ifndef FIPS_MODE + /* TODO(3.0): Temporarily no support for EVP_DigestSign* in FIPS module */ + /* + * pctx should be freed by the user of EVP_MD_CTX + * if EVP_MD_CTX_FLAG_KEEP_PKEY_CTX is set + */ + if (!EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_KEEP_PKEY_CTX)) + EVP_PKEY_CTX_free(ctx->pctx); +#endif + + EVP_MD_free(ctx->fetched_digest); + ctx->fetched_digest = NULL; + ctx->reqdigest = NULL; if (ctx->provctx != NULL) { if (ctx->digest->freectx != NULL) @@ -34,13 +45,7 @@ int EVP_MD_CTX_reset(EVP_MD_CTX *ctx) EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_CLEANED); } - if (ctx->pctx != NULL) - goto legacy; - - return 1; - /* TODO(3.0): Remove legacy code below */ - legacy: /* * Don't assume ctx->md_data was cleaned in EVP_Digest_Final, because @@ -53,19 +58,13 @@ int EVP_MD_CTX_reset(EVP_MD_CTX *ctx) && !EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_REUSE)) { OPENSSL_clear_free(ctx->md_data, ctx->digest->ctx_size); } - /* - * pctx should be freed by the user of EVP_MD_CTX - * if EVP_MD_CTX_FLAG_KEEP_PKEY_CTX is set - */ -#ifndef FIPS_MODE - /* TODO(3.0): Temporarily no support for EVP_DigestSign* in FIPS module */ - if (!EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_KEEP_PKEY_CTX)) - EVP_PKEY_CTX_free(ctx->pctx); -# ifndef OPENSSL_NO_ENGINE +#if !defined(FIPS_MODE) && !defined(OPENSSL_NO_ENGINE) ENGINE_finish(ctx->engine); -# endif #endif + + /* TODO(3.0): End of legacy code */ + OPENSSL_cleanse(ctx, sizeof(*ctx)); return 1; @@ -81,23 +80,10 @@ void EVP_MD_CTX_free(EVP_MD_CTX *ctx) if (ctx == NULL) return; - if (ctx->digest == NULL || ctx->digest->prov == NULL) - goto legacy; - EVP_MD_CTX_reset(ctx); - EVP_MD_meth_free(ctx->fetched_digest); - ctx->fetched_digest = NULL; - ctx->digest = NULL; - ctx->reqdigest = NULL; - OPENSSL_free(ctx); return; - - /* TODO(3.0): Remove legacy code below */ - legacy: - EVP_MD_CTX_reset(ctx); - OPENSSL_free(ctx); } int EVP_DigestInit(EVP_MD_CTX *ctx, const EVP_MD *type) @@ -114,6 +100,16 @@ int EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl) EVP_MD_CTX_clear_flags(ctx, EVP_MD_CTX_FLAG_CLEANED); + if (ctx->provctx != NULL) { + if (!ossl_assert(ctx->digest != NULL)) { + EVPerr(EVP_F_EVP_DIGESTINIT_EX, EVP_R_INITIALIZATION_ERROR); + return 0; + } + if (ctx->digest->freectx != NULL) + ctx->digest->freectx(ctx->provctx); + ctx->provctx = NULL; + } + if (type != NULL) ctx->reqdigest = type; @@ -144,19 +140,18 @@ int EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl) #endif /* - * If there are engines involved or if we're being used as part of - * EVP_DigestSignInit then we should use legacy handling for now. + * If there are engines involved or EVP_MD_CTX_FLAG_NO_INIT is set then we + * should use legacy handling for now. */ if (ctx->engine != NULL || impl != NULL #if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODE) || tmpimpl != NULL #endif - || ctx->pctx != NULL || (ctx->flags & EVP_MD_CTX_FLAG_NO_INIT) != 0) { if (ctx->digest == ctx->fetched_digest) ctx->digest = NULL; - EVP_MD_meth_free(ctx->fetched_digest); + EVP_MD_free(ctx->fetched_digest); ctx->fetched_digest = NULL; goto legacy; } @@ -170,7 +165,7 @@ int EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl) if (type->prov == NULL) { #ifdef FIPS_MODE - /* We only do explict fetches inside the FIPS module */ + /* We only do explicit fetches inside the FIPS module */ EVPerr(EVP_F_EVP_DIGESTINIT_EX, EVP_R_INITIALIZATION_ERROR); return 0; #else @@ -181,7 +176,7 @@ int EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl) return 0; } type = provmd; - EVP_MD_meth_free(ctx->fetched_digest); + EVP_MD_free(ctx->fetched_digest); ctx->fetched_digest = provmd; #endif } @@ -266,8 +261,13 @@ int EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl) skip_to_init: #endif #ifndef FIPS_MODE - /* TODO(3.0): Temporarily no support for EVP_DigestSign* in FIPS module */ - if (ctx->pctx != NULL) { + /* + * TODO(3.0): Temporarily no support for EVP_DigestSign* inside FIPS module + * or when using providers. + */ + if (ctx->pctx != NULL + && (!EVP_PKEY_CTX_IS_SIGNATURE_OP(ctx->pctx) + || ctx->pctx->op.sig.signature == NULL)) { int r; r = EVP_PKEY_CTX_ctrl(ctx->pctx, -1, EVP_PKEY_OP_TYPE_SIG, EVP_PKEY_CTRL_DIGESTINIT, 0, ctx); @@ -285,7 +285,27 @@ int EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *data, size_t count) if (count == 0) return 1; - if (ctx->digest == NULL || ctx->digest->prov == NULL) + if (ctx->pctx != NULL + && EVP_PKEY_CTX_IS_SIGNATURE_OP(ctx->pctx) + && ctx->pctx->op.sig.sigprovctx != NULL) { + /* + * Prior to OpenSSL 3.0 EVP_DigestSignUpdate() and + * EVP_DigestVerifyUpdate() were just macros for EVP_DigestUpdate(). + * Some code calls EVP_DigestUpdate() directly even when initialised + * with EVP_DigestSignInit_ex() or EVP_DigestVerifyInit_ex(), so we + * detect that and redirect to the correct EVP_Digest*Update() function + */ + if (ctx->pctx->operation == EVP_PKEY_OP_SIGNCTX) + return EVP_DigestSignUpdate(ctx, data, count); + if (ctx->pctx->operation == EVP_PKEY_OP_VERIFYCTX) + return EVP_DigestVerifyUpdate(ctx, data, count); + EVPerr(EVP_F_EVP_DIGESTUPDATE, EVP_R_UPDATE_ERROR); + return 0; + } + + if (ctx->digest == NULL + || ctx->digest->prov == NULL + || (ctx->flags & EVP_MD_CTX_FLAG_NO_INIT) != 0) goto legacy; if (ctx->digest->dupdate == NULL) { @@ -334,7 +354,6 @@ int EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *isize) } } - EVP_MD_CTX_reset(ctx); return ret; /* TODO(3.0): Remove legacy code below */ @@ -405,7 +424,8 @@ int EVP_MD_CTX_copy_ex(EVP_MD_CTX *out, const EVP_MD_CTX *in) return 0; } - if (in->digest->prov == NULL) + if (in->digest->prov == NULL + || (in->flags & EVP_MD_CTX_FLAG_NO_INIT) != 0) goto legacy; if (in->digest->dupctx == NULL) { @@ -415,7 +435,7 @@ int EVP_MD_CTX_copy_ex(EVP_MD_CTX *out, const EVP_MD_CTX *in) EVP_MD_CTX_reset(out); if (out->fetched_digest != NULL) - EVP_MD_meth_free(out->fetched_digest); + EVP_MD_free(out->fetched_digest); *out = *in; /* NULL out pointers in case of error */ out->pctx = NULL; @@ -524,73 +544,242 @@ int EVP_Digest(const void *data, size_t count, return ret; } +int EVP_MD_get_params(const EVP_MD *digest, OSSL_PARAM params[]) +{ + if (digest != NULL && digest->get_params != NULL) + return digest->get_params(params); + return 0; +} + +const OSSL_PARAM *EVP_MD_gettable_params(const EVP_MD *digest) +{ + if (digest != NULL && digest->gettable_params != NULL) + return digest->gettable_params(); + return NULL; +} + int EVP_MD_CTX_set_params(EVP_MD_CTX *ctx, const OSSL_PARAM params[]) { - if (ctx->digest != NULL && ctx->digest->set_params != NULL) - return ctx->digest->set_params(ctx->provctx, params); + EVP_PKEY_CTX *pctx = ctx->pctx; + + if (ctx->digest != NULL && ctx->digest->set_ctx_params != NULL) + return ctx->digest->set_ctx_params(ctx->provctx, params); + + if (pctx != NULL + && (pctx->operation == EVP_PKEY_OP_VERIFYCTX + || pctx->operation == EVP_PKEY_OP_SIGNCTX) + && pctx->op.sig.sigprovctx != NULL + && pctx->op.sig.signature->set_ctx_md_params != NULL) + return pctx->op.sig.signature->set_ctx_md_params(pctx->op.sig.sigprovctx, + params); return 0; } +const OSSL_PARAM *EVP_MD_settable_ctx_params(const EVP_MD *md) +{ + if (md != NULL && md->settable_ctx_params != NULL) + return md->settable_ctx_params(); + return NULL; +} + +const OSSL_PARAM *EVP_MD_CTX_settable_params(EVP_MD_CTX *ctx) +{ + EVP_PKEY_CTX *pctx; + + if (ctx != NULL + && ctx->digest != NULL + && ctx->digest->settable_ctx_params != NULL) + return ctx->digest->settable_ctx_params(); + + pctx = ctx->pctx; + if (pctx != NULL + && (pctx->operation == EVP_PKEY_OP_VERIFYCTX + || pctx->operation == EVP_PKEY_OP_SIGNCTX) + && pctx->op.sig.sigprovctx != NULL + && pctx->op.sig.signature->settable_ctx_md_params != NULL) + return pctx->op.sig.signature->settable_ctx_md_params( + pctx->op.sig.sigprovctx); + + return NULL; +} + int EVP_MD_CTX_get_params(EVP_MD_CTX *ctx, OSSL_PARAM params[]) { + EVP_PKEY_CTX *pctx = ctx->pctx; + if (ctx->digest != NULL && ctx->digest->get_params != NULL) - return ctx->digest->get_params(ctx->provctx, params); + return ctx->digest->get_ctx_params(ctx->provctx, params); + + if (pctx != NULL + && (pctx->operation == EVP_PKEY_OP_VERIFYCTX + || pctx->operation == EVP_PKEY_OP_SIGNCTX) + && pctx->op.sig.sigprovctx != NULL + && pctx->op.sig.signature->get_ctx_md_params != NULL) + return pctx->op.sig.signature->get_ctx_md_params(pctx->op.sig.sigprovctx, + params); + return 0; } +const OSSL_PARAM *EVP_MD_gettable_ctx_params(const EVP_MD *md) +{ + if (md != NULL && md->gettable_ctx_params != NULL) + return md->gettable_ctx_params(); + return NULL; +} + +const OSSL_PARAM *EVP_MD_CTX_gettable_params(EVP_MD_CTX *ctx) +{ + EVP_PKEY_CTX *pctx; + + if (ctx != NULL + && ctx->digest != NULL + && ctx->digest->gettable_ctx_params != NULL) + return ctx->digest->gettable_ctx_params(); + + pctx = ctx->pctx; + if (pctx != NULL + && (pctx->operation == EVP_PKEY_OP_VERIFYCTX + || pctx->operation == EVP_PKEY_OP_SIGNCTX) + && pctx->op.sig.sigprovctx != NULL + && pctx->op.sig.signature->gettable_ctx_md_params != NULL) + return pctx->op.sig.signature->gettable_ctx_md_params( + pctx->op.sig.sigprovctx); + + return NULL; +} + /* TODO(3.0): Remove legacy code below - only used by engines & DigestSign */ int EVP_MD_CTX_ctrl(EVP_MD_CTX *ctx, int cmd, int p1, void *p2) { - if (ctx->digest != NULL) { - if (ctx->digest->prov != NULL) { - OSSL_PARAM params[2]; - size_t i, n = 0; - - switch (cmd) { - case EVP_MD_CTRL_XOF_LEN: - if (ctx->digest->set_params == NULL) - break; - i = (size_t)p1; - params[n++] = - OSSL_PARAM_construct_size_t(OSSL_DIGEST_PARAM_XOFLEN, &i); - params[n++] = OSSL_PARAM_construct_end(); - return ctx->digest->set_params(ctx->provctx, params); - case EVP_MD_CTRL_MICALG: - if (ctx->digest->get_params == NULL) - break; - params[n++] = - OSSL_PARAM_construct_utf8_string(OSSL_DIGEST_PARAM_MICALG, + int ret = EVP_CTRL_RET_UNSUPPORTED; + int set_params = 1; + size_t sz; + OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; + + if (ctx == NULL || ctx->digest == NULL) { + ERR_raise(ERR_LIB_EVP, EVP_R_MESSAGE_DIGEST_IS_NULL); + return 0; + } + + if (ctx->digest->prov == NULL + && (ctx->pctx == NULL + || (ctx->pctx->operation != EVP_PKEY_OP_VERIFYCTX + && ctx->pctx->operation != EVP_PKEY_OP_SIGNCTX))) + goto legacy; + + switch (cmd) { + case EVP_MD_CTRL_XOF_LEN: + sz = (size_t)p1; + params[0] = OSSL_PARAM_construct_size_t(OSSL_DIGEST_PARAM_XOFLEN, &sz); + break; + case EVP_MD_CTRL_MICALG: + set_params = 0; + params[0] = OSSL_PARAM_construct_utf8_string(OSSL_DIGEST_PARAM_MICALG, p2, p1 ? p1 : 9999); - params[n++] = OSSL_PARAM_construct_end(); - return ctx->digest->get_params(ctx->provctx, params); - } - return 0; - } - /* legacy code */ - if (ctx->digest->md_ctrl != NULL) { - int ret = ctx->digest->md_ctrl(ctx, cmd, p1, p2); - if (ret <= 0) - return 0; - return 1; + break; + case EVP_CTRL_SSL3_MASTER_SECRET: + params[0] = OSSL_PARAM_construct_octet_string(OSSL_DIGEST_PARAM_SSL3_MS, + p2, p1); + break; + default: + goto conclude; + } + + if (set_params) + ret = EVP_MD_CTX_set_params(ctx, params); + else + ret = EVP_MD_CTX_get_params(ctx, params); + goto conclude; + + +/* TODO(3.0): Remove legacy code below */ + legacy: + if (ctx->digest->md_ctrl == NULL) { + ERR_raise(ERR_LIB_EVP, EVP_R_CTRL_NOT_IMPLEMENTED); + return 0; + } + + ret = ctx->digest->md_ctrl(ctx, cmd, p1, p2); + conclude: + if (ret <= 0) + return 0; + return ret; +} + +EVP_MD *evp_md_new(void) +{ + EVP_MD *md = OPENSSL_zalloc(sizeof(*md)); + + if (md != NULL) { + md->lock = CRYPTO_THREAD_lock_new(); + if (md->lock == NULL) { + OPENSSL_free(md); + return NULL; } + md->refcnt = 1; } - return 0; + return md; } -static void *evp_md_from_dispatch(const char *name, const OSSL_DISPATCH *fns, +/* + * FIPS module note: since internal fetches will be entirely + * provider based, we know that none of its code depends on legacy + * NIDs or any functionality that use them. + */ +#ifndef FIPS_MODE +/* TODO(3.x) get rid of the need for legacy NIDs */ +static void set_legacy_nid(const char *name, void *vlegacy_nid) +{ + int nid; + int *legacy_nid = vlegacy_nid; + /* + * We use lowest level function to get the associated method, because + * higher level functions such as EVP_get_digestbyname() have changed + * to look at providers too. + */ + const void *legacy_method = OBJ_NAME_get(name, OBJ_NAME_TYPE_MD_METH); + + if (*legacy_nid == -1) /* We found a clash already */ + return; + + if (legacy_method == NULL) + return; + nid = EVP_MD_nid(legacy_method); + if (*legacy_nid != NID_undef && *legacy_nid != nid) { + *legacy_nid = -1; + return; + } + *legacy_nid = nid; +} +#endif + +static void *evp_md_from_dispatch(int name_id, + const OSSL_DISPATCH *fns, OSSL_PROVIDER *prov) { EVP_MD *md = NULL; int fncnt = 0; /* EVP_MD_fetch() will set the legacy NID if available */ - if ((md = EVP_MD_meth_new(NID_undef, NID_undef)) == NULL - || (md->name = OPENSSL_strdup(name)) == NULL) { - EVP_MD_meth_free(md); + if ((md = evp_md_new()) == NULL) { EVPerr(0, ERR_R_MALLOC_FAILURE); return NULL; } +#ifndef FIPS_MODE + /* TODO(3.x) get rid of the need for legacy NIDs */ + md->type = NID_undef; + evp_names_do_all(prov, name_id, set_legacy_nid, &md->type); + if (md->type == -1) { + ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR); + EVP_MD_free(md); + return NULL; + } +#endif + + md->name_id = name_id; + for (; fns->function_id != 0; fns++) { switch (fns->function_id) { case OSSL_FUNC_DIGEST_NEWCTX: @@ -632,34 +821,44 @@ static void *evp_md_from_dispatch(const char *name, const OSSL_DISPATCH *fns, if (md->dupctx == NULL) md->dupctx = OSSL_get_OP_digest_dupctx(fns); break; - case OSSL_FUNC_DIGEST_SIZE: - if (md->size == NULL) - md->size = OSSL_get_OP_digest_size(fns); - break; - case OSSL_FUNC_DIGEST_BLOCK_SIZE: - if (md->dblock_size == NULL) - md->dblock_size = OSSL_get_OP_digest_block_size(fns); - break; - case OSSL_FUNC_DIGEST_SET_PARAMS: - if (md->set_params == NULL) - md->set_params = OSSL_get_OP_digest_set_params(fns); - break; case OSSL_FUNC_DIGEST_GET_PARAMS: if (md->get_params == NULL) md->get_params = OSSL_get_OP_digest_get_params(fns); break; + case OSSL_FUNC_DIGEST_SET_CTX_PARAMS: + if (md->set_ctx_params == NULL) + md->set_ctx_params = OSSL_get_OP_digest_set_ctx_params(fns); + break; + case OSSL_FUNC_DIGEST_GET_CTX_PARAMS: + if (md->get_ctx_params == NULL) + md->get_ctx_params = OSSL_get_OP_digest_get_ctx_params(fns); + break; + case OSSL_FUNC_DIGEST_GETTABLE_PARAMS: + if (md->gettable_params == NULL) + md->gettable_params = OSSL_get_OP_digest_gettable_params(fns); + break; + case OSSL_FUNC_DIGEST_SETTABLE_CTX_PARAMS: + if (md->settable_ctx_params == NULL) + md->settable_ctx_params = + OSSL_get_OP_digest_settable_ctx_params(fns); + break; + case OSSL_FUNC_DIGEST_GETTABLE_CTX_PARAMS: + if (md->gettable_ctx_params == NULL) + md->gettable_ctx_params = + OSSL_get_OP_digest_gettable_ctx_params(fns); + break; } } if ((fncnt != 0 && fncnt != 5) - || (fncnt == 0 && md->digest == NULL) - || md->size == NULL) { + || (fncnt == 0 && md->digest == NULL)) { /* * In order to be a consistent set of functions we either need the * whole set of init/update/final etc functions or none of them. * The "digest" function can standalone. We at least need one way to * generate digests. */ - EVP_MD_meth_free(md); + EVP_MD_free(md); + ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_PROVIDER_FUNCTIONS); return NULL; } md->prov = prov; @@ -676,7 +875,7 @@ static int evp_md_up_ref(void *md) static void evp_md_free(void *md) { - EVP_MD_meth_free(md); + EVP_MD_free(md); } EVP_MD *EVP_MD_fetch(OPENSSL_CTX *ctx, const char *algorithm, @@ -684,27 +883,37 @@ EVP_MD *EVP_MD_fetch(OPENSSL_CTX *ctx, const char *algorithm, { EVP_MD *md = evp_generic_fetch(ctx, OSSL_OP_DIGEST, algorithm, properties, - evp_md_from_dispatch, evp_md_up_ref, - evp_md_free); - -#ifndef FIPS_MODE - /* TODO(3.x) get rid of the need for legacy NIDs */ - if (md != NULL) { - /* - * FIPS module note: since internal fetches will be entirely - * provider based, we know that none of its code depends on legacy - * NIDs or any functionality that use them. - */ - md->type = OBJ_sn2nid(algorithm); - } -#endif + evp_md_from_dispatch, evp_md_up_ref, evp_md_free); return md; } -void EVP_MD_do_all_ex(OPENSSL_CTX *libctx, - void (*fn)(EVP_MD *mac, void *arg), - void *arg) +int EVP_MD_up_ref(EVP_MD *md) +{ + int ref = 0; + + CRYPTO_UP_REF(&md->refcnt, &ref, md->lock); + return 1; +} + +void EVP_MD_free(EVP_MD *md) +{ + int i; + + if (md == NULL) + return; + + CRYPTO_DOWN_REF(&md->refcnt, &i, md->lock); + if (i > 0) + return; + ossl_provider_free(md->prov); + CRYPTO_THREAD_lock_free(md->lock); + OPENSSL_free(md); +} + +void EVP_MD_do_all_provided(OPENSSL_CTX *libctx, + void (*fn)(EVP_MD *mac, void *arg), + void *arg) { evp_generic_do_all(libctx, OSSL_OP_DIGEST, (void (*)(void *, void *))fn, arg,