From: Ingo Franzki Date: Tue, 22 Jul 2025 13:09:27 +0000 (+0200) Subject: Only report generic error if provider did not put an error on the error queue X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f9f0207b96f3b49a6eb5113c171b1d9bf538d74d;p=thirdparty%2Fopenssl.git Only report generic error if provider did not put an error on the error queue Commit 72351b0d18078170af270418b2d5e9fc579cb1af added code to unconditionally put a generic error onto the error stack, if key generation, encryption, decryption, sign, or verify fails to ensure that there is an error entry on the error queue, even if the provider did not itself put a specific error onto the queue. However, this can hide error details if an application just looks at the very last error entry and checks for specific errors. Now, the generic error is always the last entry, and the application won't find the expected error entry, although it would be there as second last entry. This can lead to different application behavior in error situations than before this change. To fix this, only add the generic error entry if the provider did not itself add an error entry onto the queue. That way, there always is an error on the error queue in case of a failure, but no behavior change in case the provider emitted the error entry itself. Closes: https://github.com/openssl/openssl/issues/27992 Signed-off-by: Ingo Franzki Reviewed-by: Dmitry Belyavskiy Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/28073) (cherry picked from commit b9ff440dd613e0c65527ef7eaf565f618979ecce) --- diff --git a/crypto/evp/asymcipher.c b/crypto/evp/asymcipher.c index 975170c0aa0..c97ce338fdf 100644 --- a/crypto/evp/asymcipher.c +++ b/crypto/evp/asymcipher.c @@ -261,10 +261,12 @@ int EVP_PKEY_encrypt(EVP_PKEY_CTX *ctx, cipher = ctx->op.ciph.cipher; desc = cipher->description != NULL ? cipher->description : ""; + ERR_set_mark(); ret = cipher->encrypt(ctx->op.ciph.algctx, out, outlen, (out == NULL ? 0 : *outlen), in, inlen); - if (ret <= 0) + if (ret <= 0 && ERR_count_to_mark() == 0) ERR_raise_data(ERR_LIB_EVP, EVP_R_PROVIDER_ASYM_CIPHER_FAILURE, "%s encrypt:%s", cipher->type_name, desc); + ERR_clear_last_mark(); return ret; legacy: @@ -309,10 +311,12 @@ int EVP_PKEY_decrypt(EVP_PKEY_CTX *ctx, cipher = ctx->op.ciph.cipher; desc = cipher->description != NULL ? cipher->description : ""; + ERR_set_mark(); ret = cipher->decrypt(ctx->op.ciph.algctx, out, outlen, (out == NULL ? 0 : *outlen), in, inlen); - if (ret <= 0) + if (ret <= 0 && ERR_count_to_mark() == 0) ERR_raise_data(ERR_LIB_EVP, EVP_R_PROVIDER_ASYM_CIPHER_FAILURE, "%s decrypt:%s", cipher->type_name, desc); + ERR_clear_last_mark(); return ret; diff --git a/crypto/evp/keymgmt_meth.c b/crypto/evp/keymgmt_meth.c index f54684852b7..f57153b2c1a 100644 --- a/crypto/evp/keymgmt_meth.c +++ b/crypto/evp/keymgmt_meth.c @@ -460,10 +460,12 @@ void *evp_keymgmt_gen(const EVP_KEYMGMT *keymgmt, void *genctx, return NULL; } + ERR_set_mark(); ret = keymgmt->gen(genctx, cb, cbarg); - if (ret == NULL) + if (ret == NULL && ERR_count_to_mark() == 0) ERR_raise_data(ERR_LIB_EVP, EVP_R_PROVIDER_KEYMGMT_FAILURE, "%s key generation:%s", keymgmt->type_name, desc); + ERR_clear_last_mark(); return ret; } diff --git a/crypto/evp/m_sigver.c b/crypto/evp/m_sigver.c index d5df497da77..c27ed6dbe9b 100644 --- a/crypto/evp/m_sigver.c +++ b/crypto/evp/m_sigver.c @@ -426,10 +426,12 @@ int EVP_DigestSignUpdate(EVP_MD_CTX *ctx, const void *data, size_t dsize) return 0; } + ERR_set_mark(); ret = signature->digest_sign_update(pctx->op.sig.algctx, data, dsize); - if (ret <= 0) + if (ret <= 0 && ERR_count_to_mark() == 0) ERR_raise_data(ERR_LIB_EVP, EVP_R_PROVIDER_SIGNATURE_FAILURE, "%s digest_sign_update:%s", signature->type_name, desc); + ERR_clear_last_mark(); return ret; legacy: @@ -470,10 +472,12 @@ int EVP_DigestVerifyUpdate(EVP_MD_CTX *ctx, const void *data, size_t dsize) return 0; } + ERR_set_mark(); ret = signature->digest_verify_update(pctx->op.sig.algctx, data, dsize); - if (ret <= 0) + if (ret <= 0 && ERR_count_to_mark() == 0) ERR_raise_data(ERR_LIB_EVP, EVP_R_PROVIDER_SIGNATURE_FAILURE, "%s digest_verify_update:%s", signature->type_name, desc); + ERR_clear_last_mark(); return ret; legacy: @@ -523,11 +527,13 @@ int EVP_DigestSignFinal(EVP_MD_CTX *ctx, unsigned char *sigret, pctx = dctx; } + ERR_set_mark(); r = signature->digest_sign_final(pctx->op.sig.algctx, sigret, siglen, sigret == NULL ? 0 : *siglen); - if (!r) + if (!r && ERR_count_to_mark() == 0) ERR_raise_data(ERR_LIB_EVP, EVP_R_PROVIDER_SIGNATURE_FAILURE, "%s digest_sign_final:%s", signature->type_name, desc); + ERR_clear_last_mark(); if (dctx == NULL && sigret != NULL) ctx->flags |= EVP_MD_CTX_FLAG_FINALISED; else @@ -634,11 +640,13 @@ int EVP_DigestSign(EVP_MD_CTX *ctx, unsigned char *sigret, size_t *siglen, if (sigret != NULL) ctx->flags |= EVP_MD_CTX_FLAG_FINALISED; + ERR_set_mark(); ret = signature->digest_sign(pctx->op.sig.algctx, sigret, siglen, sigret == NULL ? 0 : *siglen, tbs, tbslen); - if (ret <= 0) + if (ret <= 0 && ERR_count_to_mark() == 0) ERR_raise_data(ERR_LIB_EVP, EVP_R_PROVIDER_SIGNATURE_FAILURE, "%s digest_sign:%s", signature->type_name, desc); + ERR_clear_last_mark(); return ret; } } else { @@ -689,10 +697,12 @@ int EVP_DigestVerifyFinal(EVP_MD_CTX *ctx, const unsigned char *sig, pctx = dctx; } + ERR_set_mark(); r = signature->digest_verify_final(pctx->op.sig.algctx, sig, siglen); - if (!r) + if (!r && ERR_count_to_mark() == 0) ERR_raise_data(ERR_LIB_EVP, EVP_R_PROVIDER_SIGNATURE_FAILURE, "%s digest_verify_final:%s", signature->type_name, desc); + ERR_clear_last_mark(); if (dctx == NULL) ctx->flags |= EVP_MD_CTX_FLAG_FINALISED; else @@ -765,10 +775,12 @@ int EVP_DigestVerify(EVP_MD_CTX *ctx, const unsigned char *sigret, int ret; ctx->flags |= EVP_MD_CTX_FLAG_FINALISED; + ERR_set_mark(); ret = signature->digest_verify(pctx->op.sig.algctx, sigret, siglen, tbs, tbslen); - if (ret <= 0) + if (ret <= 0 && ERR_count_to_mark() == 0) ERR_raise_data(ERR_LIB_EVP, EVP_R_PROVIDER_SIGNATURE_FAILURE, "%s digest_verify:%s", signature->type_name, desc); + ERR_clear_last_mark(); return ret; } } else {