/* Provenance: openssl/openssl evp_md_init_internal (fixed). * repo: openssl/openssl * commit: 5485c56679d7c49b96e8fc8ca708b0b7e7c03c4b * parent: 9f0867da4cbf77ed642717b5e703e09ab2c087a0 * commit_url: https://github.com/openssl/openssl/commit/5485c56679d7c49b96e8fc8ca708b0b7e7c03c4b * cve: CVE-2022-3358 * license: Apache-2.0 * function: evp_md_init_internal * relpath: crypto/evp/digest.c */ static int evp_md_init_internal(EVP_MD_CTX *ctx, const EVP_MD *type, const OSSL_PARAM params[], ENGINE *impl) { #if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) ENGINE *tmpimpl = NULL; #endif #if !defined(FIPS_MODULE) if (ctx->pctx != NULL && EVP_PKEY_CTX_IS_SIGNATURE_OP(ctx->pctx) && ctx->pctx->op.sig.algctx != NULL) { /* * Prior to OpenSSL 3.0 calling EVP_DigestInit_ex() on an mdctx * previously initialised with EVP_DigestSignInit() would retain * information about the key, and re-initialise for another sign * operation. So in that case we redirect to EVP_DigestSignInit() */ if (ctx->pctx->operation == EVP_PKEY_OP_SIGNCTX) return EVP_DigestSignInit(ctx, NULL, type, impl, NULL); if (ctx->pctx->operation == EVP_PKEY_OP_VERIFYCTX) return EVP_DigestVerifyInit(ctx, NULL, type, impl, NULL); ERR_raise(ERR_LIB_EVP, EVP_R_UPDATE_ERROR); return 0; } #endif EVP_MD_CTX_clear_flags(ctx, EVP_MD_CTX_FLAG_CLEANED); if (ctx->algctx != NULL) { if (!ossl_assert(ctx->digest != NULL)) { ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); return 0; } if (ctx->digest->freectx != NULL) ctx->digest->freectx(ctx->algctx); ctx->algctx = NULL; } if (type != NULL) { ctx->reqdigest = type; } else { if (ctx->digest == NULL) { ERR_raise(ERR_LIB_EVP, EVP_R_NO_DIGEST_SET); return 0; } type = ctx->digest; } /* Code below to be removed when legacy support is dropped. */ #if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) /* * Whether it's nice or not, "Inits" can be used on "Final"'d contexts so * this context may already have an ENGINE! Try to avoid releasing the * previous handle, re-querying for an ENGINE, and having a * reinitialisation, when it may all be unnecessary. */ if (ctx->engine && ctx->digest && (type == NULL || (type->type == ctx->digest->type))) goto skip_to_init; if (type != NULL) { /* * Ensure an ENGINE left lying around from last time is cleared (the * previous check attempted to avoid this if the same ENGINE and * EVP_MD could be used). */ ENGINE_finish(ctx->engine); ctx->engine = NULL; } if (type != NULL && impl == NULL) tmpimpl = ENGINE_get_digest_engine(type->type); #endif /* * 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_MODULE) || tmpimpl != NULL #endif || (ctx->flags & EVP_MD_CTX_FLAG_NO_INIT) != 0 || (type != NULL && type->origin == EVP_ORIG_METH) || (type == NULL && ctx->digest != NULL && ctx->digest->origin == EVP_ORIG_METH)) { if (ctx->digest == ctx->fetched_digest) ctx->digest = NULL; EVP_MD_free(ctx->fetched_digest); ctx->fetched_digest = NULL; goto legacy; } cleanup_old_md_data(ctx, 1); /* Start of non-legacy code below */ if (type->prov == NULL) { #ifdef FIPS_MODULE /* We only do explicit fetches inside the FIPS module */ ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); return 0; #else /* The NULL digest is a special case */ EVP_MD *provmd = EVP_MD_fetch(NULL, type->type != NID_undef ? OBJ_nid2sn(type->type) : "NULL", ""); if (provmd == NULL) { ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); return 0; } type = provmd; EVP_MD_free(ctx->fetched_digest); ctx->fetched_digest = provmd; #endif } if (ctx->algctx != NULL && ctx->digest != NULL && ctx->digest != type) { if (ctx->digest->freectx != NULL) ctx->digest->freectx(ctx->algctx); ctx->algctx = NULL; } if (type->prov != NULL && ctx->fetched_digest != type) { if (!EVP_MD_up_ref((EVP_MD *)type)) { ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); return 0; } EVP_MD_free(ctx->fetched_digest); ctx->fetched_digest = (EVP_MD *)type; } ctx->digest = type; if (ctx->algctx == NULL) { ctx->algctx = ctx->digest->newctx(ossl_provider_ctx(type->prov)); if (ctx->algctx == NULL) { ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); return 0; } } if (ctx->digest->dinit == NULL) { ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); return 0; } return ctx->digest->dinit(ctx->algctx, params); /* Code below to be removed when legacy support is dropped. */ legacy: #if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) if (type) { if (impl != NULL) { if (!ENGINE_init(impl)) { ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); return 0; } } else { /* Ask if an ENGINE is reserved for this job */ impl = tmpimpl; } if (impl != NULL) { /* There's an ENGINE for this job ... (apparently) */ const EVP_MD *d = ENGINE_get_digest(impl, type->type); if (d == NULL) { ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); ENGINE_finish(impl); return 0; } /* We'll use the ENGINE's private digest definition */ type = d; /* * Store the ENGINE functional reference so we know 'type' came * from an ENGINE and we need to release it when done. */ ctx->engine = impl; } else ctx->engine = NULL; } #endif if (ctx->digest != type) { cleanup_old_md_data(ctx, 1); ctx->digest = type; if (!(ctx->flags & EVP_MD_CTX_FLAG_NO_INIT) && type->ctx_size) { ctx->update = type->update; ctx->md_data = OPENSSL_zalloc(type->ctx_size); if (ctx->md_data == NULL) { ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE); return 0; } } } #if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) skip_to_init: #endif #ifndef FIPS_MODULE 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); if (r <= 0 && (r != -2)) return 0; } #endif if (ctx->flags & EVP_MD_CTX_FLAG_NO_INIT) return 1; return ctx->digest->init(ctx); }