From 0fc00fc0e3867fc5f95fab1046ad7d2a85db06f8 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Thu, 23 Feb 2023 19:51:27 -0500 Subject: [PATCH] Do not fail if ctx dup does not succeed If the ctx was *really* needed we'll probably fail later with an error anyway, so no point in failing immediately. Document that this behavior is dependent on the provider used to implement the signature/verification. 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) --- crypto/evp/m_sigver.c | 37 ++++++++++++++----------------- crypto/evp/p_sign.c | 2 ++ crypto/evp/p_verify.c | 2 ++ doc/man3/EVP_DigestSignInit.pod | 7 ++++++ doc/man3/EVP_DigestVerifyInit.pod | 9 +++++++- doc/man3/EVP_SignInit.pod | 9 +++++++- doc/man3/EVP_VerifyInit.pod | 9 +++++++- 7 files changed, 52 insertions(+), 23 deletions(-) diff --git a/crypto/evp/m_sigver.c b/crypto/evp/m_sigver.c index 630d339c35..68ae957058 100644 --- a/crypto/evp/m_sigver.c +++ b/crypto/evp/m_sigver.c @@ -462,7 +462,7 @@ int EVP_DigestSignFinal(EVP_MD_CTX *ctx, unsigned char *sigret, size_t *siglen) { int sctx = 0, r = 0; - EVP_PKEY_CTX *dctx, *pctx = ctx->pctx; + EVP_PKEY_CTX *dctx = NULL, *pctx = ctx->pctx; if (pctx == NULL || pctx->operation != EVP_PKEY_OP_SIGNCTX @@ -470,17 +470,15 @@ int EVP_DigestSignFinal(EVP_MD_CTX *ctx, unsigned char *sigret, || pctx->op.sig.signature == NULL) goto legacy; - if (sigret == NULL || (ctx->flags & EVP_MD_CTX_FLAG_FINALISE) != 0) - return pctx->op.sig.signature->digest_sign_final(pctx->op.sig.algctx, - sigret, siglen, - sigret == NULL ? 0 : *siglen); - dctx = EVP_PKEY_CTX_dup(pctx); - if (dctx == NULL) - return 0; - - r = dctx->op.sig.signature->digest_sign_final(dctx->op.sig.algctx, + if (sigret != NULL && (ctx->flags & EVP_MD_CTX_FLAG_FINALISE) == 0) { + /* try dup */ + dctx = EVP_PKEY_CTX_dup(pctx); + if (dctx != NULL) + pctx = dctx; + } + r = pctx->op.sig.signature->digest_sign_final(pctx->op.sig.algctx, sigret, siglen, - *siglen); + sigret == NULL ? 0 : *siglen); EVP_PKEY_CTX_free(dctx); return r; @@ -589,7 +587,7 @@ int EVP_DigestVerifyFinal(EVP_MD_CTX *ctx, const unsigned char *sig, int r = 0; unsigned int mdlen = 0; int vctx = 0; - EVP_PKEY_CTX *dctx, *pctx = ctx->pctx; + EVP_PKEY_CTX *dctx = NULL, *pctx = ctx->pctx; if (pctx == NULL || pctx->operation != EVP_PKEY_OP_VERIFYCTX @@ -597,14 +595,13 @@ int EVP_DigestVerifyFinal(EVP_MD_CTX *ctx, const unsigned char *sig, || pctx->op.sig.signature == NULL) goto legacy; - if ((ctx->flags & EVP_MD_CTX_FLAG_FINALISE) != 0) - return pctx->op.sig.signature->digest_verify_final(pctx->op.sig.algctx, - sig, siglen); - dctx = EVP_PKEY_CTX_dup(pctx); - if (dctx == NULL) - return 0; - - r = dctx->op.sig.signature->digest_verify_final(dctx->op.sig.algctx, + if ((ctx->flags & EVP_MD_CTX_FLAG_FINALISE) == 0) { + /* try dup */ + dctx = EVP_PKEY_CTX_dup(pctx); + if (dctx != NULL) + pctx = dctx; + } + r = pctx->op.sig.signature->digest_verify_final(pctx->op.sig.algctx, sig, siglen); EVP_PKEY_CTX_free(dctx); return r; diff --git a/crypto/evp/p_sign.c b/crypto/evp/p_sign.c index 4eb34db267..ae0de57202 100644 --- a/crypto/evp/p_sign.c +++ b/crypto/evp/p_sign.c @@ -39,6 +39,8 @@ int EVP_SignFinal_ex(EVP_MD_CTX *ctx, unsigned char *sigret, rv = EVP_MD_CTX_copy_ex(tmp_ctx, ctx); if (rv) rv = EVP_DigestFinal_ex(tmp_ctx, m, &m_len); + else + rv = EVP_DigestFinal_ex(ctx, m, &m_len); EVP_MD_CTX_free(tmp_ctx); if (!rv) return 0; diff --git a/crypto/evp/p_verify.c b/crypto/evp/p_verify.c index eb5084f839..8478e643dd 100644 --- a/crypto/evp/p_verify.c +++ b/crypto/evp/p_verify.c @@ -37,6 +37,8 @@ int EVP_VerifyFinal_ex(EVP_MD_CTX *ctx, const unsigned char *sigbuf, rv = EVP_MD_CTX_copy_ex(tmp_ctx, ctx); if (rv) rv = EVP_DigestFinal_ex(tmp_ctx, m, &m_len); + else + rv = EVP_DigestFinal_ex(ctx, m, &m_len); EVP_MD_CTX_free(tmp_ctx); if (!rv) return 0; diff --git a/doc/man3/EVP_DigestSignInit.pod b/doc/man3/EVP_DigestSignInit.pod index fe4a686184..f38eefcbbf 100644 --- a/doc/man3/EVP_DigestSignInit.pod +++ b/doc/man3/EVP_DigestSignInit.pod @@ -166,6 +166,13 @@ external circumstances (see L), the operation will fail. The call to EVP_DigestSignFinal() internally finalizes a copy of the digest context. This means that calls to EVP_DigestSignUpdate() and EVP_DigestSignFinal() can be called later to digest and sign additional data. +Applications may disable this behavior by setting the EVP_MD_CTX_FLAG_FINALISE +context flag via L. + +Note that not all providers support continuation, in case the selected +provider does not allow to duplicate contexts EVP_DigestSignFinal() will +finalize the digest context and attempting to process additional data via +EVP_DigestSignUpdate() will result in an error. EVP_DigestSignInit() and EVP_DigestSignInit_ex() functions can be called multiple times on a context and the parameters set by previous calls should be diff --git a/doc/man3/EVP_DigestVerifyInit.pod b/doc/man3/EVP_DigestVerifyInit.pod index d4bb8163d1..0dc8151a90 100644 --- a/doc/man3/EVP_DigestVerifyInit.pod +++ b/doc/man3/EVP_DigestVerifyInit.pod @@ -154,7 +154,14 @@ external circumstances (see L), the operation will fail. The call to EVP_DigestVerifyFinal() internally finalizes a copy of the digest context. This means that EVP_VerifyUpdate() and EVP_VerifyFinal() can -be called later to digest and verify additional data. +be called later to digest and verify additional data. Applications may disable +this behavior by setting the EVP_MD_CTX_FLAG_FINALISE context flag via +L. + +Note that not all providers support continuation, in case the selected +provider does not allow to duplicate contexts EVP_DigestVerifyFinal() will +finalize the digest context and attempting to process additional data via +EVP_DigestVerifyUpdate() will result in an error. EVP_DigestVerifyInit() and EVP_DigestVerifyInit_ex() functions can be called multiple times on a context and the parameters set by previous calls should be diff --git a/doc/man3/EVP_SignInit.pod b/doc/man3/EVP_SignInit.pod index 11832ff761..c274ad9917 100644 --- a/doc/man3/EVP_SignInit.pod +++ b/doc/man3/EVP_SignInit.pod @@ -66,12 +66,19 @@ due to external circumstances (see L), the operation will fail. The call to EVP_SignFinal() internally finalizes a copy of the digest context. This means that calls to EVP_SignUpdate() and EVP_SignFinal() can be called -later to digest and sign additional data. +later to digest and sign additional data.cApplications may disable this +behavior by setting the EVP_MD_CTX_FLAG_FINALISE context flag via +L. Since only a copy of the digest context is ever finalized the context must be cleaned up after use by calling EVP_MD_CTX_free() or a memory leak will occur. +Note that not all providers support continuation, in case the selected +provider does not allow to duplicate contexts EVP_SignFinal() will +finalize the digest context and attempting to process additional data via +EVP_SignUpdate() will result in an error. + =head1 BUGS Older versions of this documentation wrongly stated that calls to diff --git a/doc/man3/EVP_VerifyInit.pod b/doc/man3/EVP_VerifyInit.pod index a6d5772c3b..f05b9135bf 100644 --- a/doc/man3/EVP_VerifyInit.pod +++ b/doc/man3/EVP_VerifyInit.pod @@ -62,12 +62,19 @@ transparent to the algorithm used and much more flexible. The call to EVP_VerifyFinal() internally finalizes a copy of the digest context. This means that calls to EVP_VerifyUpdate() and EVP_VerifyFinal() can be called -later to digest and verify additional data. +later to digest and verify additional data. Applications may disable this +behavior by setting the EVP_MD_CTX_FLAG_FINALISE context flag via +L. Since only a copy of the digest context is ever finalized the context must be cleaned up after use by calling EVP_MD_CTX_free() or a memory leak will occur. +Note that not all providers support continuation, in case the selected +provider does not allow to duplicate contexts EVP_VerifyFinal() will +finalize the digest context and attempting to process additional data via +EVP_VerifyUpdate() will result in an error. + =head1 BUGS Older versions of this documentation wrongly stated that calls to