aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIgor Ustinov <[email protected]>2026-10-20 14:27:17 +0200
committerTomas Mraz <[email protected]>2026-10-21 17:36:03 +0200
commit667bd7d15c86e523fe586b212c4c235c08ee0f14 (patch)
treee371dfdde684075019f7c35333cfaee18f580ede
parentDon't report held-back DTLS app data as readable in SSL_poll() (diff)
downloadopenssl-667bd7d15c86e523fe586b212c4c235c08ee0f14.tar.gz
openssl-667bd7d15c86e523fe586b212c4c235c08ee0f14.zip
CMS_verify() stops at the first failure without CMS_VERIFY_PARTIAL
When CMS_VERIFY_PARTIAL was added, every "goto err" on a failed certificate, signed attributes, CAdES or content check was replaced by "continue", so that the remaining SignerInfos are still checked. Without the flag one failure already makes the whole call fail, yet CMS_verify() went on checking all the other signers and reading the content, which only wastes time. Goto err on the first failure unless CMS_VERIFY_PARTIAL is set again. Fixes: 5af9dbf12832 "Implement partial verification for CMS with multiple signatures" Reported-by: Anthropic's OSS Scanner, ANT-2026-D12JMUYJ Assisted-by: Claude:claude-opus-5-5 Reviewed-by: Tomas Mraz <[email protected]> Reviewed-by: Milan Broz <[email protected]> Merge-date: Wed Oct 21 15:36:24 2026 Merged-from: https://github.com/openssl/openssl/pull/33283
-rw-r--r--crypto/cms/cms_smime.c11
-rw-r--r--test/cmsapitest.c30
2 files changed, 37 insertions, 4 deletions
diff --git a/crypto/cms/cms_smime.c b/crypto/cms/cms_smime.c
index 9315c35d1c3..6ed16afd82f 100644
--- a/crypto/cms/cms_smime.c
+++ b/crypto/cms/cms_smime.c
@@ -353,6 +353,7 @@ int CMS_verify(CMS_ContentInfo *cms, const STACK_OF(X509) *certs,
int i, n = 0, scount = 0, ret = 0;
BIO *cmsbio = NULL, *tmpin = NULL, *tmpout = NULL;
int cadesVerify = (flags & CMS_CADES) != 0;
+ int partial = (flags & CMS_VERIFY_PARTIAL) != 0;
const CMS_CTX *ctx = ossl_cms_get0_cmsctx(cms);
if (dcont == NULL && !check_content(cms)) {
@@ -439,6 +440,8 @@ int CMS_verify(CMS_ContentInfo *cms, const STACK_OF(X509) *certs,
si_chains ? &si_chains[i] : NULL,
ctx)) {
si->verify_result = 0;
+ if (!partial)
+ goto err;
continue;
}
si->cert_verified = 1;
@@ -458,6 +461,8 @@ int CMS_verify(CMS_ContentInfo *cms, const STACK_OF(X509) *certs,
}
if (CMS_SignerInfo_verify(si) <= 0) {
si->verify_result = 0;
+ if (!partial)
+ goto err;
continue;
}
if (cadesVerify) {
@@ -465,6 +470,8 @@ int CMS_verify(CMS_ContentInfo *cms, const STACK_OF(X509) *certs,
if (ossl_cms_check_signing_certs(si, si_chain) <= 0) {
si->verify_result = 0;
+ if (!partial)
+ goto err;
continue;
}
}
@@ -538,6 +545,8 @@ int CMS_verify(CMS_ContentInfo *cms, const STACK_OF(X509) *certs,
if (CMS_SignerInfo_verify_ex(si, cmsbio, tmpin) <= 0) {
ERR_raise(ERR_LIB_CMS, CMS_R_CONTENT_VERIFY_ERROR);
si->verify_result = 0;
+ if (!partial)
+ goto err;
continue;
}
si->content_verified = 1;
@@ -549,7 +558,7 @@ int CMS_verify(CMS_ContentInfo *cms, const STACK_OF(X509) *certs,
if (sk_CMS_SignerInfo_value(sinfos, i)->verify_result)
n++;
}
- if ((flags & CMS_VERIFY_PARTIAL) != 0)
+ if (partial)
ret = n > 0; /* One success is enough */
else
ret = n == scount; /* All must be successful */
diff --git a/test/cmsapitest.c b/test/cmsapitest.c
index 35ffa79ca0d..eff78841424 100644
--- a/test/cmsapitest.c
+++ b/test/cmsapitest.c
@@ -741,7 +741,8 @@ end:
* With two independently trusted signers and CMS_VERIFY_PARTIAL, one
* signer's signature failure must not affect the *other* signer's per-field
* results -- including once that other signer also fails and the overall
- * call fails too.
+ * call fails too. Without CMS_VERIFY_PARTIAL, verification must stop at
+ * the first failure.
*/
static int test_CMS_verify_result_partial_independence(void)
{
@@ -792,6 +793,24 @@ static int test_CMS_verify_result_partial_independence(void)
((uint8_t *)ASN1_STRING_get0_data(sig))[0] ^= 0xff;
ERR_clear_error();
+ if (!TEST_int_eq(CMS_verify(cms, NULL, store, NULL, out, CMS_BINARY), 0))
+ goto end;
+
+ /*
+ * Without CMS_VERIFY_PARTIAL, verification stops at signer 1's failure:
+ * signer 2's signed attributes are not checked and the content is not
+ * read.
+ */
+ if (!TEST_int_eq(CMS_SignerInfo_get_verification_result(si1, CMS_VERIFY_RESULT), 0)
+ || !TEST_int_eq(CMS_SignerInfo_get_verification_result(si1, CMS_VERIFY_CERT), 1)
+ || !TEST_int_eq(CMS_SignerInfo_get_verification_result(si1, CMS_VERIFY_ATTR), 0)
+ || !TEST_int_eq(CMS_SignerInfo_get_verification_result(si2, CMS_VERIFY_RESULT), 0)
+ || !TEST_int_eq(CMS_SignerInfo_get_verification_result(si2, CMS_VERIFY_CERT), 1)
+ || !TEST_int_eq(CMS_SignerInfo_get_verification_result(si2, CMS_VERIFY_ATTR), 0)
+ || !TEST_size_t_eq(BIO_ctrl_pending(out), 0))
+ goto end;
+
+ ERR_clear_error();
if (!TEST_int_eq(CMS_verify(cms, NULL, store, NULL, out,
CMS_BINARY | CMS_VERIFY_PARTIAL),
1))
@@ -804,8 +823,11 @@ static int test_CMS_verify_result_partial_independence(void)
*/
if (!TEST_int_eq(CMS_SignerInfo_get_verification_result(si1, CMS_VERIFY_RESULT), 0)
|| !TEST_int_eq(CMS_SignerInfo_get_verification_result(si1, CMS_VERIFY_CERT), 1)
+ || !TEST_int_eq(CMS_SignerInfo_get_verification_result(si1, CMS_VERIFY_ATTR), 0)
|| !TEST_int_eq(CMS_SignerInfo_get_verification_result(si2, CMS_VERIFY_RESULT), 1)
- || !TEST_int_eq(CMS_SignerInfo_get_verification_result(si2, CMS_VERIFY_CERT), 1))
+ || !TEST_int_eq(CMS_SignerInfo_get_verification_result(si2, CMS_VERIFY_CERT), 1)
+ || !TEST_int_eq(CMS_SignerInfo_get_verification_result(si2, CMS_VERIFY_ATTR), 1)
+ || !TEST_size_t_gt(BIO_ctrl_pending(out), 0))
goto end;
/* now also break signer 2's signature: the overall call must now fail */
@@ -828,8 +850,10 @@ static int test_CMS_verify_result_partial_independence(void)
*/
if (!TEST_int_eq(CMS_SignerInfo_get_verification_result(si1, CMS_VERIFY_RESULT), 0)
|| !TEST_int_eq(CMS_SignerInfo_get_verification_result(si1, CMS_VERIFY_CERT), 1)
+ || !TEST_int_eq(CMS_SignerInfo_get_verification_result(si1, CMS_VERIFY_ATTR), 0)
|| !TEST_int_eq(CMS_SignerInfo_get_verification_result(si2, CMS_VERIFY_RESULT), 0)
- || !TEST_int_eq(CMS_SignerInfo_get_verification_result(si2, CMS_VERIFY_CERT), 1))
+ || !TEST_int_eq(CMS_SignerInfo_get_verification_result(si2, CMS_VERIFY_CERT), 1)
+ || !TEST_int_eq(CMS_SignerInfo_get_verification_result(si2, CMS_VERIFY_ATTR), 0))
goto end;
ret = 1;