diff --git a/crates/sign/src/cms.rs b/crates/sign/src/cms.rs index c4cf5e027..d593bce8c 100644 --- a/crates/sign/src/cms.rs +++ b/crates/sign/src/cms.rs @@ -89,7 +89,13 @@ pub fn certificate_bundle(bytes: &[u8]) -> Result, SignError> { // then signerInfos (RFC 5652 ยง5.1). let [version, digests, encap, middle @ .., signers] = sd.as_slice() else { return Err(bad("SignedData")) }; let shape = [(version, tag::INTEGER), (digests, tag::SET), (encap, tag::SEQUENCE), (signers, tag::SET)]; - if shape.iter().any(|(t, want)| t.tag != *want) || middle.iter().any(|t| t.tag != tag::ctx(0) && t.tag != tag::ctx(1)) { + // At most one [0] certificates and one [1] CRLs, in that order. + const CERTS: u8 = tag::ctx(0); + const CRLS: u8 = tag::ctx(1); + let middle_ok = matches!(middle.iter().map(|t| t.tag).collect::>().as_slice(), [] | [CERTS] | [CRLS] | [CERTS, CRLS]); + // encapContentInfo starts with its eContentType OID. + let encap_ok = encap.children()?.first().is_some_and(|t| t.tag == tag::OID); + if shape.iter().any(|(t, want)| t.tag != *want) || !middle_ok || !encap_ok { return Err(bad("SignedData")); } let mut certificates = Vec::new(); diff --git a/crates/sign/tests/crypto.rs b/crates/sign/tests/crypto.rs index 05eacfde4..c23543581 100644 --- a/crates/sign/tests/crypto.rs +++ b/crates/sign/tests/crypto.rs @@ -303,6 +303,12 @@ fn certificates_load_from_pkcs7_bundles() { assert_eq!(load_certificates(&wrap(&[&int(1), &set_of(&[]), &encap, &certs, &set_of(&[])])).unwrap().len(), 2); assert!(load_certificates(&wrap(&[&int(1), &set_of(&[]), &encap, &certs])).is_err()); assert!(load_certificates(&wrap(&[&set_of(&[]), &set_of(&[]), &encap, &certs, &set_of(&[])])).is_err()); + // An empty encapContentInfo, a repeated [0], and [1] CRLs before [0] certificates. + let crls = tlv(0xA1, &[]); + assert!(load_certificates(&wrap(&[&int(1), &set_of(&[]), &seq(&[]), &certs, &set_of(&[])])).is_err()); + assert!(load_certificates(&wrap(&[&int(1), &set_of(&[]), &encap, &certs, &certs, &set_of(&[])])).is_err()); + assert!(load_certificates(&wrap(&[&int(1), &set_of(&[]), &encap, &crls, &certs, &set_of(&[])])).is_err()); + assert_eq!(load_certificates(&wrap(&[&int(1), &set_of(&[]), &encap, &certs, &crls, &set_of(&[])])).unwrap().len(), 2); } let mut trailing = bundle.clone(); trailing.extend_from_slice(&[0x05, 0x00]);