From: Simo Sorce Date: Thu, 9 Mar 2023 16:45:02 +0000 (-0500) Subject: Add a flag so finalised contexts are not reused X-Git-Tag: openssl-3.2.0-alpha1~1168 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3fc2b7d6b8f961144905330dfd4689f5bd515199;p=thirdparty%2Fopenssl.git Add a flag so finalised contexts are not reused The EVP layer should not rely on the underlying low level code to handle catching incorrect reuse of contexts. Add a flag to mark a context as finalised as needed and then catch and immediately error on Update/Final operations if called improperly. Signed-off-by: Simo Sorce Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell Reviewed-by: Dmitry Belyavskiy (Merged from https://github.com/openssl/openssl/pull/20375) --- diff --git a/crypto/evp/digest.c b/crypto/evp/digest.c index 6ce80a1b031..e7590cda554 100644 --- a/crypto/evp/digest.c +++ b/crypto/evp/digest.c @@ -181,7 +181,8 @@ static int evp_md_init_internal(EVP_MD_CTX *ctx, const EVP_MD *type, } #endif - EVP_MD_CTX_clear_flags(ctx, EVP_MD_CTX_FLAG_CLEANED); + EVP_MD_CTX_clear_flags(ctx, EVP_MD_CTX_FLAG_CLEANED + | EVP_MD_CTX_FLAG_FINALISED); if (type != NULL) { ctx->reqdigest = type; @@ -387,6 +388,11 @@ int EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *data, size_t count) if (count == 0) return 1; + if ((ctx->flags & EVP_MD_CTX_FLAG_FINALISED) != 0) { + ERR_raise(ERR_LIB_EVP, EVP_R_UPDATE_ERROR); + return 0; + } + if (ctx->pctx != NULL && EVP_PKEY_CTX_IS_SIGNATURE_OP(ctx->pctx) && ctx->pctx->op.sig.algctx != NULL) { @@ -453,8 +459,15 @@ int EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *isize) return 0; } + if ((ctx->flags & EVP_MD_CTX_FLAG_FINALISED) != 0) { + ERR_raise(ERR_LIB_EVP, EVP_R_FINAL_ERROR); + return 0; + } + ret = ctx->digest->dfinal(ctx->algctx, md, &size, mdsize); + ctx->flags |= EVP_MD_CTX_FLAG_FINALISED; + if (isize != NULL) { if (size <= UINT_MAX) { *isize = (unsigned int)size; @@ -499,12 +512,19 @@ int EVP_DigestFinalXOF(EVP_MD_CTX *ctx, unsigned char *md, size_t size) return 0; } + if ((ctx->flags & EVP_MD_CTX_FLAG_FINALISED) != 0) { + ERR_raise(ERR_LIB_EVP, EVP_R_FINAL_ERROR); + return 0; + } + params[i++] = OSSL_PARAM_construct_size_t(OSSL_DIGEST_PARAM_XOFLEN, &size); params[i++] = OSSL_PARAM_construct_end(); if (EVP_MD_CTX_set_params(ctx, params) > 0) ret = ctx->digest->dfinal(ctx->algctx, md, &size, size); + ctx->flags |= EVP_MD_CTX_FLAG_FINALISED; + return ret; legacy: diff --git a/crypto/evp/m_sigver.c b/crypto/evp/m_sigver.c index 68ae9570581..e7888d2acd6 100644 --- a/crypto/evp/m_sigver.c +++ b/crypto/evp/m_sigver.c @@ -64,6 +64,8 @@ static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, if (ctx->pctx == NULL) return 0; + EVP_MD_CTX_clear_flags(ctx, EVP_MD_CTX_FLAG_FINALISED); + locpctx = ctx->pctx; ERR_set_mark(); @@ -401,6 +403,11 @@ int EVP_DigestSignUpdate(EVP_MD_CTX *ctx, const void *data, size_t dsize) { EVP_PKEY_CTX *pctx = ctx->pctx; + if ((ctx->flags & EVP_MD_CTX_FLAG_FINALISED) != 0) { + ERR_raise(ERR_LIB_EVP, EVP_R_UPDATE_ERROR); + return 0; + } + if (pctx == NULL || pctx->operation != EVP_PKEY_OP_SIGNCTX || pctx->op.sig.algctx == NULL @@ -431,6 +438,11 @@ int EVP_DigestVerifyUpdate(EVP_MD_CTX *ctx, const void *data, size_t dsize) { EVP_PKEY_CTX *pctx = ctx->pctx; + if ((ctx->flags & EVP_MD_CTX_FLAG_FINALISED) != 0) { + ERR_raise(ERR_LIB_EVP, EVP_R_UPDATE_ERROR); + return 0; + } + if (pctx == NULL || pctx->operation != EVP_PKEY_OP_VERIFYCTX || pctx->op.sig.algctx == NULL @@ -464,6 +476,11 @@ int EVP_DigestSignFinal(EVP_MD_CTX *ctx, unsigned char *sigret, int sctx = 0, r = 0; EVP_PKEY_CTX *dctx = NULL, *pctx = ctx->pctx; + if ((ctx->flags & EVP_MD_CTX_FLAG_FINALISED) != 0) { + ERR_raise(ERR_LIB_EVP, EVP_R_FINAL_ERROR); + return 0; + } + if (pctx == NULL || pctx->operation != EVP_PKEY_OP_SIGNCTX || pctx->op.sig.algctx == NULL @@ -479,7 +496,10 @@ int EVP_DigestSignFinal(EVP_MD_CTX *ctx, unsigned char *sigret, r = pctx->op.sig.signature->digest_sign_final(pctx->op.sig.algctx, sigret, siglen, sigret == NULL ? 0 : *siglen); - EVP_PKEY_CTX_free(dctx); + if (dctx == NULL && sigret != NULL) + ctx->flags |= EVP_MD_CTX_FLAG_FINALISED; + else + EVP_PKEY_CTX_free(dctx); return r; legacy: @@ -497,9 +517,10 @@ int EVP_DigestSignFinal(EVP_MD_CTX *ctx, unsigned char *sigret, if (pctx->pmeth->flags & EVP_PKEY_FLAG_SIGCTX_CUSTOM) { if (sigret == NULL) return pctx->pmeth->signctx(pctx, sigret, siglen, ctx); - if (ctx->flags & EVP_MD_CTX_FLAG_FINALISE) + if ((ctx->flags & EVP_MD_CTX_FLAG_FINALISE) != 0) { r = pctx->pmeth->signctx(pctx, sigret, siglen, ctx); - else { + ctx->flags |= EVP_MD_CTX_FLAG_FINALISED; + } else { dctx = EVP_PKEY_CTX_dup(pctx); if (dctx == NULL) return 0; @@ -560,15 +581,23 @@ int EVP_DigestSign(EVP_MD_CTX *ctx, unsigned char *sigret, size_t *siglen, { EVP_PKEY_CTX *pctx = ctx->pctx; + if ((ctx->flags & EVP_MD_CTX_FLAG_FINALISED) != 0) { + ERR_raise(ERR_LIB_EVP, EVP_R_FINAL_ERROR); + return 0; + } + if (pctx != NULL && pctx->operation == EVP_PKEY_OP_SIGNCTX && pctx->op.sig.algctx != NULL && pctx->op.sig.signature != NULL) { - if (pctx->op.sig.signature->digest_sign != NULL) + if (pctx->op.sig.signature->digest_sign != NULL) { + if (sigret != NULL) + ctx->flags |= EVP_MD_CTX_FLAG_FINALISED; return pctx->op.sig.signature->digest_sign(pctx->op.sig.algctx, sigret, siglen, sigret == NULL ? 0 : *siglen, tbs, tbslen); + } } else { /* legacy */ if (ctx->pctx->pmeth != NULL && ctx->pctx->pmeth->digestsign != NULL) @@ -589,6 +618,11 @@ int EVP_DigestVerifyFinal(EVP_MD_CTX *ctx, const unsigned char *sig, int vctx = 0; EVP_PKEY_CTX *dctx = NULL, *pctx = ctx->pctx; + if ((ctx->flags & EVP_MD_CTX_FLAG_FINALISED) != 0) { + ERR_raise(ERR_LIB_EVP, EVP_R_FINAL_ERROR); + return 0; + } + if (pctx == NULL || pctx->operation != EVP_PKEY_OP_VERIFYCTX || pctx->op.sig.algctx == NULL @@ -603,7 +637,10 @@ int EVP_DigestVerifyFinal(EVP_MD_CTX *ctx, const unsigned char *sig, } r = pctx->op.sig.signature->digest_verify_final(pctx->op.sig.algctx, sig, siglen); - EVP_PKEY_CTX_free(dctx); + if (dctx == NULL) + ctx->flags |= EVP_MD_CTX_FLAG_FINALISED; + else + EVP_PKEY_CTX_free(dctx); return r; legacy: @@ -623,9 +660,10 @@ int EVP_DigestVerifyFinal(EVP_MD_CTX *ctx, const unsigned char *sig, else vctx = 0; if (ctx->flags & EVP_MD_CTX_FLAG_FINALISE) { - if (vctx) + if (vctx) { r = pctx->pmeth->verifyctx(pctx, sig, siglen, ctx); - else + ctx->flags |= EVP_MD_CTX_FLAG_FINALISED; + } else r = EVP_DigestFinal_ex(ctx, md, &mdlen); } else { EVP_MD_CTX *tmp_ctx = EVP_MD_CTX_new(); @@ -652,14 +690,21 @@ int EVP_DigestVerify(EVP_MD_CTX *ctx, const unsigned char *sigret, { EVP_PKEY_CTX *pctx = ctx->pctx; + if ((ctx->flags & EVP_MD_CTX_FLAG_FINALISED) != 0) { + ERR_raise(ERR_LIB_EVP, EVP_R_FINAL_ERROR); + return 0; + } + if (pctx != NULL && pctx->operation == EVP_PKEY_OP_VERIFYCTX && pctx->op.sig.algctx != NULL && pctx->op.sig.signature != NULL) { - if (pctx->op.sig.signature->digest_verify != NULL) + if (pctx->op.sig.signature->digest_verify != NULL) { + ctx->flags |= EVP_MD_CTX_FLAG_FINALISED; return pctx->op.sig.signature->digest_verify(pctx->op.sig.algctx, sigret, siglen, tbs, tbslen); + } } else { /* legacy */ if (ctx->pctx->pmeth != NULL && ctx->pctx->pmeth->digestverify != NULL) diff --git a/include/crypto/evp.h b/include/crypto/evp.h index dbbdcccbda9..55b44cd8353 100644 --- a/include/crypto/evp.h +++ b/include/crypto/evp.h @@ -21,6 +21,7 @@ * values in evp.h */ #define EVP_MD_CTX_FLAG_KEEP_PKEY_CTX 0x0400 +#define EVP_MD_CTX_FLAG_FINALISED 0x0800 #define evp_pkey_ctx_is_legacy(ctx) \ ((ctx)->keymgmt == NULL) diff --git a/include/openssl/evp.h b/include/openssl/evp.h index b8bafe4e125..e10c0617a48 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h @@ -226,7 +226,8 @@ int (*EVP_MD_meth_get_ctrl(const EVP_MD *md))(EVP_MD_CTX *ctx, int cmd, * if the following flag is set. */ # define EVP_MD_CTX_FLAG_FINALISE 0x0200 -/* NOTE: 0x0400 is reserved for internal usage */ +/* NOTE: 0x0400 and 0x0800 are reserved for internal usage */ + # ifndef OPENSSL_NO_DEPRECATED_3_0 OSSL_DEPRECATEDIN_3_0 EVP_CIPHER *EVP_CIPHER_meth_new(int cipher_type, int block_size, int key_len);