diff --git a/.gitignore b/.gitignore index e75e92f8..61b5abb7 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,6 @@ target/ # Benchmark data benches/*.der + +# Python virtualenv +.venv diff --git a/tests/client_auth_revocation.rs b/tests/client_auth_revocation.rs index 965da352..f05e217a 100644 --- a/tests/client_auth_revocation.rs +++ b/tests/client_auth_revocation.rs @@ -14,28 +14,18 @@ #![cfg(feature = "ring")] -use webpki::{KeyUsage, RevocationCheckDepth, RevocationOptionsBuilder}; +use webpki::{KeyUsage, RevocationCheckDepth, RevocationOptions, RevocationOptionsBuilder}; fn check_cert( ee: &[u8], intermediates: &[&[u8]], ca: &[u8], - crls: &[&dyn webpki::CertRevocationList], + revocation: Option, ) -> Result<(), webpki::Error> { let anchors = &[webpki::TrustAnchor::try_from_cert_der(ca).unwrap()]; let cert = webpki::EndEntityCert::try_from(ee).unwrap(); let time = webpki::Time::from_seconds_since_unix_epoch(0x1fed_f00d); - // TODO(XXX): Allow configuring depth and revocation status requirements per-test. - let revocation = match crls.len() { - 0 => None, - _ => Some( - RevocationOptionsBuilder::new(crls) - .unwrap() - .with_depth(RevocationCheckDepth::Chain) - .allow_unknown_status() - .build(), - ), - }; + cert.verify_for_usage( &[webpki::ECDSA_P256_SHA256], anchors, @@ -49,61 +39,77 @@ fn check_cert( // DO NOT EDIT BELOW: generated by tests/generate.py #[test] -fn no_crls_test_ee_depth() { +fn no_crls_test() { let ee = include_bytes!("client_auth_revocation/no_ku_chain.ee.der"); let intermediates = &[ include_bytes!("client_auth_revocation/no_ku_chain.int.a.ca.der").as_slice(), include_bytes!("client_auth_revocation/no_ku_chain.int.b.ca.der").as_slice(), ]; let ca = include_bytes!("client_auth_revocation/no_ku_chain.root.ca.der"); - let crls = &[]; - assert_eq!(check_cert(ee, intermediates, ca, crls), Ok(())); + let revocation = None; + assert_eq!(check_cert(ee, intermediates, ca, revocation), Ok(())); } #[cfg(feature = "alloc")] #[test] -fn no_crls_test_ee_depth_owned() { +fn no_crls_test_owned() { let ee = include_bytes!("client_auth_revocation/no_ku_chain.ee.der"); let intermediates = &[ include_bytes!("client_auth_revocation/no_ku_chain.int.a.ca.der").as_slice(), include_bytes!("client_auth_revocation/no_ku_chain.int.b.ca.der").as_slice(), ]; let ca = include_bytes!("client_auth_revocation/no_ku_chain.root.ca.der"); - let crls = &[]; - assert_eq!(check_cert(ee, intermediates, ca, crls), Ok(())); + let revocation = None; + assert_eq!(check_cert(ee, intermediates, ca, revocation), Ok(())); } #[test] -fn no_relevant_crl_ee_depth() { +fn no_relevant_crl_ee_depth_allow_unknown() { let ee = include_bytes!("client_auth_revocation/no_ku_chain.ee.der"); let intermediates = &[ include_bytes!("client_auth_revocation/no_ku_chain.int.a.ca.der").as_slice(), include_bytes!("client_auth_revocation/no_ku_chain.int.b.ca.der").as_slice(), ]; let ca = include_bytes!("client_auth_revocation/no_ku_chain.root.ca.der"); + let crls = &[&webpki::BorrowedCertRevocationList::from_der( - include_bytes!("client_auth_revocation/no_relevant_crl_ee_depth.crl.der").as_slice(), + include_bytes!("client_auth_revocation/no_relevant_crl_ee_depth_allow_unknown.crl.der") + .as_slice(), ) .unwrap() as &dyn webpki::CertRevocationList]; - assert_eq!(check_cert(ee, intermediates, ca, crls), Ok(())); + let builder = RevocationOptionsBuilder::new(crls).unwrap(); + + let builder = builder.with_depth(RevocationCheckDepth::EndEntity); + + let builder = builder.allow_unknown_status(); + let revocation = Some(builder.build()); + assert_eq!(check_cert(ee, intermediates, ca, revocation), Ok(())); } #[cfg(feature = "alloc")] #[test] -fn no_relevant_crl_ee_depth_owned() { +fn no_relevant_crl_ee_depth_allow_unknown_owned() { let ee = include_bytes!("client_auth_revocation/no_ku_chain.ee.der"); let intermediates = &[ include_bytes!("client_auth_revocation/no_ku_chain.int.a.ca.der").as_slice(), include_bytes!("client_auth_revocation/no_ku_chain.int.b.ca.der").as_slice(), ]; let ca = include_bytes!("client_auth_revocation/no_ku_chain.root.ca.der"); + let crls = &[&webpki::BorrowedCertRevocationList::from_der( - include_bytes!("client_auth_revocation/no_relevant_crl_ee_depth.crl.der").as_slice(), + include_bytes!("client_auth_revocation/no_relevant_crl_ee_depth_allow_unknown.crl.der") + .as_slice(), ) .unwrap() .to_owned() .unwrap() as &dyn webpki::CertRevocationList]; - assert_eq!(check_cert(ee, intermediates, ca, crls), Ok(())); + let builder = RevocationOptionsBuilder::new(crls).unwrap(); + + let builder = builder.with_depth(RevocationCheckDepth::EndEntity); + + let builder = builder.allow_unknown_status(); + let revocation = Some(builder.build()); + assert_eq!(check_cert(ee, intermediates, ca, revocation), Ok(())); } #[test] @@ -114,11 +120,18 @@ fn ee_not_revoked_ee_depth() { include_bytes!("client_auth_revocation/no_ku_chain.int.b.ca.der").as_slice(), ]; let ca = include_bytes!("client_auth_revocation/no_ku_chain.root.ca.der"); + let crls = &[&webpki::BorrowedCertRevocationList::from_der( include_bytes!("client_auth_revocation/ee_not_revoked_ee_depth.crl.der").as_slice(), ) .unwrap() as &dyn webpki::CertRevocationList]; - assert_eq!(check_cert(ee, intermediates, ca, crls), Ok(())); + let builder = RevocationOptionsBuilder::new(crls).unwrap(); + + let builder = builder.with_depth(RevocationCheckDepth::EndEntity); + + let builder = builder.allow_unknown_status(); + let revocation = Some(builder.build()); + assert_eq!(check_cert(ee, intermediates, ca, revocation), Ok(())); } #[cfg(feature = "alloc")] @@ -130,13 +143,20 @@ fn ee_not_revoked_ee_depth_owned() { include_bytes!("client_auth_revocation/no_ku_chain.int.b.ca.der").as_slice(), ]; let ca = include_bytes!("client_auth_revocation/no_ku_chain.root.ca.der"); + let crls = &[&webpki::BorrowedCertRevocationList::from_der( include_bytes!("client_auth_revocation/ee_not_revoked_ee_depth.crl.der").as_slice(), ) .unwrap() .to_owned() .unwrap() as &dyn webpki::CertRevocationList]; - assert_eq!(check_cert(ee, intermediates, ca, crls), Ok(())); + let builder = RevocationOptionsBuilder::new(crls).unwrap(); + + let builder = builder.with_depth(RevocationCheckDepth::EndEntity); + + let builder = builder.allow_unknown_status(); + let revocation = Some(builder.build()); + assert_eq!(check_cert(ee, intermediates, ca, revocation), Ok(())); } #[test] @@ -147,12 +167,19 @@ fn ee_revoked_badsig_ee_depth() { include_bytes!("client_auth_revocation/no_ku_chain.int.b.ca.der").as_slice(), ]; let ca = include_bytes!("client_auth_revocation/no_ku_chain.root.ca.der"); + let crls = &[&webpki::BorrowedCertRevocationList::from_der( include_bytes!("client_auth_revocation/ee_revoked_badsig_ee_depth.crl.der").as_slice(), ) .unwrap() as &dyn webpki::CertRevocationList]; + let builder = RevocationOptionsBuilder::new(crls).unwrap(); + + let builder = builder.with_depth(RevocationCheckDepth::EndEntity); + + let builder = builder.allow_unknown_status(); + let revocation = Some(builder.build()); assert_eq!( - check_cert(ee, intermediates, ca, crls), + check_cert(ee, intermediates, ca, revocation), Err(webpki::Error::InvalidCrlSignatureForPublicKey) ); } @@ -166,14 +193,21 @@ fn ee_revoked_badsig_ee_depth_owned() { include_bytes!("client_auth_revocation/no_ku_chain.int.b.ca.der").as_slice(), ]; let ca = include_bytes!("client_auth_revocation/no_ku_chain.root.ca.der"); + let crls = &[&webpki::BorrowedCertRevocationList::from_der( include_bytes!("client_auth_revocation/ee_revoked_badsig_ee_depth.crl.der").as_slice(), ) .unwrap() .to_owned() .unwrap() as &dyn webpki::CertRevocationList]; + let builder = RevocationOptionsBuilder::new(crls).unwrap(); + + let builder = builder.with_depth(RevocationCheckDepth::EndEntity); + + let builder = builder.allow_unknown_status(); + let revocation = Some(builder.build()); assert_eq!( - check_cert(ee, intermediates, ca, crls), + check_cert(ee, intermediates, ca, revocation), Err(webpki::Error::InvalidCrlSignatureForPublicKey) ); } @@ -186,12 +220,19 @@ fn ee_revoked_wrong_ku_ee_depth() { include_bytes!("client_auth_revocation/no_crl_ku_chain.int.b.ca.der").as_slice(), ]; let ca = include_bytes!("client_auth_revocation/no_crl_ku_chain.root.ca.der"); + let crls = &[&webpki::BorrowedCertRevocationList::from_der( include_bytes!("client_auth_revocation/ee_revoked_wrong_ku_ee_depth.crl.der").as_slice(), ) .unwrap() as &dyn webpki::CertRevocationList]; + let builder = RevocationOptionsBuilder::new(crls).unwrap(); + + let builder = builder.with_depth(RevocationCheckDepth::EndEntity); + + let builder = builder.allow_unknown_status(); + let revocation = Some(builder.build()); assert_eq!( - check_cert(ee, intermediates, ca, crls), + check_cert(ee, intermediates, ca, revocation), Err(webpki::Error::IssuerNotCrlSigner) ); } @@ -205,14 +246,21 @@ fn ee_revoked_wrong_ku_ee_depth_owned() { include_bytes!("client_auth_revocation/no_crl_ku_chain.int.b.ca.der").as_slice(), ]; let ca = include_bytes!("client_auth_revocation/no_crl_ku_chain.root.ca.der"); + let crls = &[&webpki::BorrowedCertRevocationList::from_der( include_bytes!("client_auth_revocation/ee_revoked_wrong_ku_ee_depth.crl.der").as_slice(), ) .unwrap() .to_owned() .unwrap() as &dyn webpki::CertRevocationList]; + let builder = RevocationOptionsBuilder::new(crls).unwrap(); + + let builder = builder.with_depth(RevocationCheckDepth::EndEntity); + + let builder = builder.allow_unknown_status(); + let revocation = Some(builder.build()); assert_eq!( - check_cert(ee, intermediates, ca, crls), + check_cert(ee, intermediates, ca, revocation), Err(webpki::Error::IssuerNotCrlSigner) ); } @@ -225,13 +273,20 @@ fn ee_not_revoked_wrong_ku_ee_depth() { include_bytes!("client_auth_revocation/no_crl_ku_chain.int.b.ca.der").as_slice(), ]; let ca = include_bytes!("client_auth_revocation/no_crl_ku_chain.root.ca.der"); + let crls = &[&webpki::BorrowedCertRevocationList::from_der( include_bytes!("client_auth_revocation/ee_not_revoked_wrong_ku_ee_depth.crl.der") .as_slice(), ) .unwrap() as &dyn webpki::CertRevocationList]; + let builder = RevocationOptionsBuilder::new(crls).unwrap(); + + let builder = builder.with_depth(RevocationCheckDepth::EndEntity); + + let builder = builder.allow_unknown_status(); + let revocation = Some(builder.build()); assert_eq!( - check_cert(ee, intermediates, ca, crls), + check_cert(ee, intermediates, ca, revocation), Err(webpki::Error::IssuerNotCrlSigner) ); } @@ -245,6 +300,7 @@ fn ee_not_revoked_wrong_ku_ee_depth_owned() { include_bytes!("client_auth_revocation/no_crl_ku_chain.int.b.ca.der").as_slice(), ]; let ca = include_bytes!("client_auth_revocation/no_crl_ku_chain.root.ca.der"); + let crls = &[&webpki::BorrowedCertRevocationList::from_der( include_bytes!("client_auth_revocation/ee_not_revoked_wrong_ku_ee_depth.crl.der") .as_slice(), @@ -252,8 +308,14 @@ fn ee_not_revoked_wrong_ku_ee_depth_owned() { .unwrap() .to_owned() .unwrap() as &dyn webpki::CertRevocationList]; + let builder = RevocationOptionsBuilder::new(crls).unwrap(); + + let builder = builder.with_depth(RevocationCheckDepth::EndEntity); + + let builder = builder.allow_unknown_status(); + let revocation = Some(builder.build()); assert_eq!( - check_cert(ee, intermediates, ca, crls), + check_cert(ee, intermediates, ca, revocation), Err(webpki::Error::IssuerNotCrlSigner) ); } @@ -266,12 +328,19 @@ fn ee_revoked_no_ku_ee_depth() { include_bytes!("client_auth_revocation/no_ku_chain.int.b.ca.der").as_slice(), ]; let ca = include_bytes!("client_auth_revocation/no_ku_chain.root.ca.der"); + let crls = &[&webpki::BorrowedCertRevocationList::from_der( include_bytes!("client_auth_revocation/ee_revoked_no_ku_ee_depth.crl.der").as_slice(), ) .unwrap() as &dyn webpki::CertRevocationList]; + let builder = RevocationOptionsBuilder::new(crls).unwrap(); + + let builder = builder.with_depth(RevocationCheckDepth::EndEntity); + + let builder = builder.allow_unknown_status(); + let revocation = Some(builder.build()); assert_eq!( - check_cert(ee, intermediates, ca, crls), + check_cert(ee, intermediates, ca, revocation), Err(webpki::Error::CertRevoked) ); } @@ -285,14 +354,21 @@ fn ee_revoked_no_ku_ee_depth_owned() { include_bytes!("client_auth_revocation/no_ku_chain.int.b.ca.der").as_slice(), ]; let ca = include_bytes!("client_auth_revocation/no_ku_chain.root.ca.der"); + let crls = &[&webpki::BorrowedCertRevocationList::from_der( include_bytes!("client_auth_revocation/ee_revoked_no_ku_ee_depth.crl.der").as_slice(), ) .unwrap() .to_owned() .unwrap() as &dyn webpki::CertRevocationList]; + let builder = RevocationOptionsBuilder::new(crls).unwrap(); + + let builder = builder.with_depth(RevocationCheckDepth::EndEntity); + + let builder = builder.allow_unknown_status(); + let revocation = Some(builder.build()); assert_eq!( - check_cert(ee, intermediates, ca, crls), + check_cert(ee, intermediates, ca, revocation), Err(webpki::Error::CertRevoked) ); } @@ -305,12 +381,19 @@ fn ee_revoked_crl_ku_ee_depth() { include_bytes!("client_auth_revocation/ku_chain.int.b.ca.der").as_slice(), ]; let ca = include_bytes!("client_auth_revocation/ku_chain.root.ca.der"); + let crls = &[&webpki::BorrowedCertRevocationList::from_der( include_bytes!("client_auth_revocation/ee_revoked_crl_ku_ee_depth.crl.der").as_slice(), ) .unwrap() as &dyn webpki::CertRevocationList]; + let builder = RevocationOptionsBuilder::new(crls).unwrap(); + + let builder = builder.with_depth(RevocationCheckDepth::EndEntity); + + let builder = builder.allow_unknown_status(); + let revocation = Some(builder.build()); assert_eq!( - check_cert(ee, intermediates, ca, crls), + check_cert(ee, intermediates, ca, revocation), Err(webpki::Error::CertRevoked) ); } @@ -324,14 +407,21 @@ fn ee_revoked_crl_ku_ee_depth_owned() { include_bytes!("client_auth_revocation/ku_chain.int.b.ca.der").as_slice(), ]; let ca = include_bytes!("client_auth_revocation/ku_chain.root.ca.der"); + let crls = &[&webpki::BorrowedCertRevocationList::from_der( include_bytes!("client_auth_revocation/ee_revoked_crl_ku_ee_depth.crl.der").as_slice(), ) .unwrap() .to_owned() .unwrap() as &dyn webpki::CertRevocationList]; + let builder = RevocationOptionsBuilder::new(crls).unwrap(); + + let builder = builder.with_depth(RevocationCheckDepth::EndEntity); + + let builder = builder.allow_unknown_status(); + let revocation = Some(builder.build()); assert_eq!( - check_cert(ee, intermediates, ca, crls), + check_cert(ee, intermediates, ca, revocation), Err(webpki::Error::CertRevoked) ); } @@ -344,8 +434,8 @@ fn no_crls_test_chain_depth() { include_bytes!("client_auth_revocation/no_ku_chain.int.b.ca.der").as_slice(), ]; let ca = include_bytes!("client_auth_revocation/no_ku_chain.root.ca.der"); - let crls = &[]; - assert_eq!(check_cert(ee, intermediates, ca, crls), Ok(())); + let revocation = None; + assert_eq!(check_cert(ee, intermediates, ca, revocation), Ok(())); } #[test] @@ -356,11 +446,16 @@ fn no_relevant_crl_chain_depth() { include_bytes!("client_auth_revocation/no_ku_chain.int.b.ca.der").as_slice(), ]; let ca = include_bytes!("client_auth_revocation/no_ku_chain.root.ca.der"); + let crls = &[&webpki::BorrowedCertRevocationList::from_der( include_bytes!("client_auth_revocation/no_relevant_crl_chain_depth.crl.der").as_slice(), ) .unwrap() as &dyn webpki::CertRevocationList]; - assert_eq!(check_cert(ee, intermediates, ca, crls), Ok(())); + let builder = RevocationOptionsBuilder::new(crls).unwrap(); + + let builder = builder.allow_unknown_status(); + let revocation = Some(builder.build()); + assert_eq!(check_cert(ee, intermediates, ca, revocation), Ok(())); } #[cfg(feature = "alloc")] @@ -372,13 +467,18 @@ fn no_relevant_crl_chain_depth_owned() { include_bytes!("client_auth_revocation/no_ku_chain.int.b.ca.der").as_slice(), ]; let ca = include_bytes!("client_auth_revocation/no_ku_chain.root.ca.der"); + let crls = &[&webpki::BorrowedCertRevocationList::from_der( include_bytes!("client_auth_revocation/no_relevant_crl_chain_depth.crl.der").as_slice(), ) .unwrap() .to_owned() .unwrap() as &dyn webpki::CertRevocationList]; - assert_eq!(check_cert(ee, intermediates, ca, crls), Ok(())); + let builder = RevocationOptionsBuilder::new(crls).unwrap(); + + let builder = builder.allow_unknown_status(); + let revocation = Some(builder.build()); + assert_eq!(check_cert(ee, intermediates, ca, revocation), Ok(())); } #[test] @@ -389,11 +489,16 @@ fn int_not_revoked_chain_depth() { include_bytes!("client_auth_revocation/no_ku_chain.int.b.ca.der").as_slice(), ]; let ca = include_bytes!("client_auth_revocation/no_ku_chain.root.ca.der"); + let crls = &[&webpki::BorrowedCertRevocationList::from_der( include_bytes!("client_auth_revocation/int_not_revoked_chain_depth.crl.der").as_slice(), ) .unwrap() as &dyn webpki::CertRevocationList]; - assert_eq!(check_cert(ee, intermediates, ca, crls), Ok(())); + let builder = RevocationOptionsBuilder::new(crls).unwrap(); + + let builder = builder.allow_unknown_status(); + let revocation = Some(builder.build()); + assert_eq!(check_cert(ee, intermediates, ca, revocation), Ok(())); } #[cfg(feature = "alloc")] @@ -405,13 +510,18 @@ fn int_not_revoked_chain_depth_owned() { include_bytes!("client_auth_revocation/no_ku_chain.int.b.ca.der").as_slice(), ]; let ca = include_bytes!("client_auth_revocation/no_ku_chain.root.ca.der"); + let crls = &[&webpki::BorrowedCertRevocationList::from_der( include_bytes!("client_auth_revocation/int_not_revoked_chain_depth.crl.der").as_slice(), ) .unwrap() .to_owned() .unwrap() as &dyn webpki::CertRevocationList]; - assert_eq!(check_cert(ee, intermediates, ca, crls), Ok(())); + let builder = RevocationOptionsBuilder::new(crls).unwrap(); + + let builder = builder.allow_unknown_status(); + let revocation = Some(builder.build()); + assert_eq!(check_cert(ee, intermediates, ca, revocation), Ok(())); } #[test] @@ -422,12 +532,17 @@ fn int_revoked_badsig_chain_depth() { include_bytes!("client_auth_revocation/no_ku_chain.int.b.ca.der").as_slice(), ]; let ca = include_bytes!("client_auth_revocation/no_ku_chain.root.ca.der"); + let crls = &[&webpki::BorrowedCertRevocationList::from_der( include_bytes!("client_auth_revocation/int_revoked_badsig_chain_depth.crl.der").as_slice(), ) .unwrap() as &dyn webpki::CertRevocationList]; + let builder = RevocationOptionsBuilder::new(crls).unwrap(); + + let builder = builder.allow_unknown_status(); + let revocation = Some(builder.build()); assert_eq!( - check_cert(ee, intermediates, ca, crls), + check_cert(ee, intermediates, ca, revocation), Err(webpki::Error::InvalidCrlSignatureForPublicKey) ); } @@ -441,14 +556,19 @@ fn int_revoked_badsig_chain_depth_owned() { include_bytes!("client_auth_revocation/no_ku_chain.int.b.ca.der").as_slice(), ]; let ca = include_bytes!("client_auth_revocation/no_ku_chain.root.ca.der"); + let crls = &[&webpki::BorrowedCertRevocationList::from_der( include_bytes!("client_auth_revocation/int_revoked_badsig_chain_depth.crl.der").as_slice(), ) .unwrap() .to_owned() .unwrap() as &dyn webpki::CertRevocationList]; + let builder = RevocationOptionsBuilder::new(crls).unwrap(); + + let builder = builder.allow_unknown_status(); + let revocation = Some(builder.build()); assert_eq!( - check_cert(ee, intermediates, ca, crls), + check_cert(ee, intermediates, ca, revocation), Err(webpki::Error::InvalidCrlSignatureForPublicKey) ); } @@ -461,13 +581,18 @@ fn int_revoked_wrong_ku_chain_depth() { include_bytes!("client_auth_revocation/no_crl_ku_chain.int.b.ca.der").as_slice(), ]; let ca = include_bytes!("client_auth_revocation/no_crl_ku_chain.root.ca.der"); + let crls = &[&webpki::BorrowedCertRevocationList::from_der( include_bytes!("client_auth_revocation/int_revoked_wrong_ku_chain_depth.crl.der") .as_slice(), ) .unwrap() as &dyn webpki::CertRevocationList]; + let builder = RevocationOptionsBuilder::new(crls).unwrap(); + + let builder = builder.allow_unknown_status(); + let revocation = Some(builder.build()); assert_eq!( - check_cert(ee, intermediates, ca, crls), + check_cert(ee, intermediates, ca, revocation), Err(webpki::Error::IssuerNotCrlSigner) ); } @@ -481,6 +606,7 @@ fn int_revoked_wrong_ku_chain_depth_owned() { include_bytes!("client_auth_revocation/no_crl_ku_chain.int.b.ca.der").as_slice(), ]; let ca = include_bytes!("client_auth_revocation/no_crl_ku_chain.root.ca.der"); + let crls = &[&webpki::BorrowedCertRevocationList::from_der( include_bytes!("client_auth_revocation/int_revoked_wrong_ku_chain_depth.crl.der") .as_slice(), @@ -488,8 +614,12 @@ fn int_revoked_wrong_ku_chain_depth_owned() { .unwrap() .to_owned() .unwrap() as &dyn webpki::CertRevocationList]; + let builder = RevocationOptionsBuilder::new(crls).unwrap(); + + let builder = builder.allow_unknown_status(); + let revocation = Some(builder.build()); assert_eq!( - check_cert(ee, intermediates, ca, crls), + check_cert(ee, intermediates, ca, revocation), Err(webpki::Error::IssuerNotCrlSigner) ); } @@ -502,12 +632,17 @@ fn ee_revoked_chain_depth() { include_bytes!("client_auth_revocation/no_ku_chain.int.b.ca.der").as_slice(), ]; let ca = include_bytes!("client_auth_revocation/no_ku_chain.root.ca.der"); + let crls = &[&webpki::BorrowedCertRevocationList::from_der( include_bytes!("client_auth_revocation/ee_revoked_chain_depth.crl.der").as_slice(), ) .unwrap() as &dyn webpki::CertRevocationList]; + let builder = RevocationOptionsBuilder::new(crls).unwrap(); + + let builder = builder.allow_unknown_status(); + let revocation = Some(builder.build()); assert_eq!( - check_cert(ee, intermediates, ca, crls), + check_cert(ee, intermediates, ca, revocation), Err(webpki::Error::CertRevoked) ); } @@ -521,14 +656,19 @@ fn ee_revoked_chain_depth_owned() { include_bytes!("client_auth_revocation/no_ku_chain.int.b.ca.der").as_slice(), ]; let ca = include_bytes!("client_auth_revocation/no_ku_chain.root.ca.der"); + let crls = &[&webpki::BorrowedCertRevocationList::from_der( include_bytes!("client_auth_revocation/ee_revoked_chain_depth.crl.der").as_slice(), ) .unwrap() .to_owned() .unwrap() as &dyn webpki::CertRevocationList]; + let builder = RevocationOptionsBuilder::new(crls).unwrap(); + + let builder = builder.allow_unknown_status(); + let revocation = Some(builder.build()); assert_eq!( - check_cert(ee, intermediates, ca, crls), + check_cert(ee, intermediates, ca, revocation), Err(webpki::Error::CertRevoked) ); } @@ -541,12 +681,17 @@ fn int_revoked_no_ku_chain_depth() { include_bytes!("client_auth_revocation/no_ku_chain.int.b.ca.der").as_slice(), ]; let ca = include_bytes!("client_auth_revocation/no_ku_chain.root.ca.der"); + let crls = &[&webpki::BorrowedCertRevocationList::from_der( include_bytes!("client_auth_revocation/int_revoked_no_ku_chain_depth.crl.der").as_slice(), ) .unwrap() as &dyn webpki::CertRevocationList]; + let builder = RevocationOptionsBuilder::new(crls).unwrap(); + + let builder = builder.allow_unknown_status(); + let revocation = Some(builder.build()); assert_eq!( - check_cert(ee, intermediates, ca, crls), + check_cert(ee, intermediates, ca, revocation), Err(webpki::Error::CertRevoked) ); } @@ -560,14 +705,19 @@ fn int_revoked_no_ku_chain_depth_owned() { include_bytes!("client_auth_revocation/no_ku_chain.int.b.ca.der").as_slice(), ]; let ca = include_bytes!("client_auth_revocation/no_ku_chain.root.ca.der"); + let crls = &[&webpki::BorrowedCertRevocationList::from_der( include_bytes!("client_auth_revocation/int_revoked_no_ku_chain_depth.crl.der").as_slice(), ) .unwrap() .to_owned() .unwrap() as &dyn webpki::CertRevocationList]; + let builder = RevocationOptionsBuilder::new(crls).unwrap(); + + let builder = builder.allow_unknown_status(); + let revocation = Some(builder.build()); assert_eq!( - check_cert(ee, intermediates, ca, crls), + check_cert(ee, intermediates, ca, revocation), Err(webpki::Error::CertRevoked) ); } @@ -580,12 +730,17 @@ fn int_revoked_crl_ku_chain_depth() { include_bytes!("client_auth_revocation/ku_chain.int.b.ca.der").as_slice(), ]; let ca = include_bytes!("client_auth_revocation/ku_chain.root.ca.der"); + let crls = &[&webpki::BorrowedCertRevocationList::from_der( include_bytes!("client_auth_revocation/int_revoked_crl_ku_chain_depth.crl.der").as_slice(), ) .unwrap() as &dyn webpki::CertRevocationList]; + let builder = RevocationOptionsBuilder::new(crls).unwrap(); + + let builder = builder.allow_unknown_status(); + let revocation = Some(builder.build()); assert_eq!( - check_cert(ee, intermediates, ca, crls), + check_cert(ee, intermediates, ca, revocation), Err(webpki::Error::CertRevoked) ); } @@ -599,14 +754,19 @@ fn int_revoked_crl_ku_chain_depth_owned() { include_bytes!("client_auth_revocation/ku_chain.int.b.ca.der").as_slice(), ]; let ca = include_bytes!("client_auth_revocation/ku_chain.root.ca.der"); + let crls = &[&webpki::BorrowedCertRevocationList::from_der( include_bytes!("client_auth_revocation/int_revoked_crl_ku_chain_depth.crl.der").as_slice(), ) .unwrap() .to_owned() .unwrap() as &dyn webpki::CertRevocationList]; + let builder = RevocationOptionsBuilder::new(crls).unwrap(); + + let builder = builder.allow_unknown_status(); + let revocation = Some(builder.build()); assert_eq!( - check_cert(ee, intermediates, ca, crls), + check_cert(ee, intermediates, ca, revocation), Err(webpki::Error::CertRevoked) ); } @@ -619,13 +779,18 @@ fn ee_with_top_bit_set_serial_revoked() { include_bytes!("client_auth_revocation/ku_chain.int.b.ca.der").as_slice(), ]; let ca = include_bytes!("client_auth_revocation/ku_chain.root.ca.der"); + let crls = &[&webpki::BorrowedCertRevocationList::from_der( include_bytes!("client_auth_revocation/ee_with_top_bit_set_serial_revoked.crl.der") .as_slice(), ) .unwrap() as &dyn webpki::CertRevocationList]; + let builder = RevocationOptionsBuilder::new(crls).unwrap(); + + let builder = builder.allow_unknown_status(); + let revocation = Some(builder.build()); assert_eq!( - check_cert(ee, intermediates, ca, crls), + check_cert(ee, intermediates, ca, revocation), Err(webpki::Error::CertRevoked) ); } @@ -639,6 +804,7 @@ fn ee_with_top_bit_set_serial_revoked_owned() { include_bytes!("client_auth_revocation/ku_chain.int.b.ca.der").as_slice(), ]; let ca = include_bytes!("client_auth_revocation/ku_chain.root.ca.der"); + let crls = &[&webpki::BorrowedCertRevocationList::from_der( include_bytes!("client_auth_revocation/ee_with_top_bit_set_serial_revoked.crl.der") .as_slice(), @@ -646,8 +812,394 @@ fn ee_with_top_bit_set_serial_revoked_owned() { .unwrap() .to_owned() .unwrap() as &dyn webpki::CertRevocationList]; + let builder = RevocationOptionsBuilder::new(crls).unwrap(); + + let builder = builder.allow_unknown_status(); + let revocation = Some(builder.build()); assert_eq!( - check_cert(ee, intermediates, ca, crls), + check_cert(ee, intermediates, ca, revocation), Err(webpki::Error::CertRevoked) ); } + +#[test] +fn ee_no_dp_crl_idp() { + let ee = include_bytes!("client_auth_revocation/no_ku_chain.ee.der"); + let intermediates = &[ + include_bytes!("client_auth_revocation/no_ku_chain.int.a.ca.der").as_slice(), + include_bytes!("client_auth_revocation/no_ku_chain.int.b.ca.der").as_slice(), + ]; + let ca = include_bytes!("client_auth_revocation/no_ku_chain.root.ca.der"); + + let crls = &[&webpki::BorrowedCertRevocationList::from_der( + include_bytes!("client_auth_revocation/ee_no_dp_crl_idp.crl.der").as_slice(), + ) + .unwrap() as &dyn webpki::CertRevocationList]; + let builder = RevocationOptionsBuilder::new(crls).unwrap(); + + let builder = builder.with_depth(RevocationCheckDepth::EndEntity); + let revocation = Some(builder.build()); + assert_eq!(check_cert(ee, intermediates, ca, revocation), Ok(())); +} + +#[cfg(feature = "alloc")] +#[test] +fn ee_no_dp_crl_idp_owned() { + let ee = include_bytes!("client_auth_revocation/no_ku_chain.ee.der"); + let intermediates = &[ + include_bytes!("client_auth_revocation/no_ku_chain.int.a.ca.der").as_slice(), + include_bytes!("client_auth_revocation/no_ku_chain.int.b.ca.der").as_slice(), + ]; + let ca = include_bytes!("client_auth_revocation/no_ku_chain.root.ca.der"); + + let crls = &[&webpki::BorrowedCertRevocationList::from_der( + include_bytes!("client_auth_revocation/ee_no_dp_crl_idp.crl.der").as_slice(), + ) + .unwrap() + .to_owned() + .unwrap() as &dyn webpki::CertRevocationList]; + let builder = RevocationOptionsBuilder::new(crls).unwrap(); + + let builder = builder.with_depth(RevocationCheckDepth::EndEntity); + let revocation = Some(builder.build()); + assert_eq!(check_cert(ee, intermediates, ca, revocation), Ok(())); +} + +#[test] +fn ee_crl_no_idp_unknown_status() { + let ee = include_bytes!("client_auth_revocation/dp_chain.ee.der"); + let intermediates = &[ + include_bytes!("client_auth_revocation/dp_chain.int.a.ca.der").as_slice(), + include_bytes!("client_auth_revocation/dp_chain.int.b.ca.der").as_slice(), + ]; + let ca = include_bytes!("client_auth_revocation/dp_chain.root.ca.der"); + + let crls = &[&webpki::BorrowedCertRevocationList::from_der( + include_bytes!("client_auth_revocation/ee_crl_no_idp_unknown_status.crl.der").as_slice(), + ) + .unwrap() as &dyn webpki::CertRevocationList]; + let builder = RevocationOptionsBuilder::new(crls).unwrap(); + + let builder = builder.with_depth(RevocationCheckDepth::EndEntity); + let revocation = Some(builder.build()); + assert_eq!( + check_cert(ee, intermediates, ca, revocation), + Err(webpki::Error::UnknownRevocationStatus) + ); +} + +#[cfg(feature = "alloc")] +#[test] +fn ee_crl_no_idp_unknown_status_owned() { + let ee = include_bytes!("client_auth_revocation/dp_chain.ee.der"); + let intermediates = &[ + include_bytes!("client_auth_revocation/dp_chain.int.a.ca.der").as_slice(), + include_bytes!("client_auth_revocation/dp_chain.int.b.ca.der").as_slice(), + ]; + let ca = include_bytes!("client_auth_revocation/dp_chain.root.ca.der"); + + let crls = &[&webpki::BorrowedCertRevocationList::from_der( + include_bytes!("client_auth_revocation/ee_crl_no_idp_unknown_status.crl.der").as_slice(), + ) + .unwrap() + .to_owned() + .unwrap() as &dyn webpki::CertRevocationList]; + let builder = RevocationOptionsBuilder::new(crls).unwrap(); + + let builder = builder.with_depth(RevocationCheckDepth::EndEntity); + let revocation = Some(builder.build()); + assert_eq!( + check_cert(ee, intermediates, ca, revocation), + Err(webpki::Error::UnknownRevocationStatus) + ); +} + +#[test] +fn ee_crl_mismatched_idp_unknown_status() { + let ee = include_bytes!("client_auth_revocation/dp_chain.ee.der"); + let intermediates = &[ + include_bytes!("client_auth_revocation/dp_chain.int.a.ca.der").as_slice(), + include_bytes!("client_auth_revocation/dp_chain.int.b.ca.der").as_slice(), + ]; + let ca = include_bytes!("client_auth_revocation/dp_chain.root.ca.der"); + + let crls = &[&webpki::BorrowedCertRevocationList::from_der( + include_bytes!("client_auth_revocation/ee_crl_mismatched_idp_unknown_status.crl.der") + .as_slice(), + ) + .unwrap() as &dyn webpki::CertRevocationList]; + let builder = RevocationOptionsBuilder::new(crls).unwrap(); + + let builder = builder.with_depth(RevocationCheckDepth::EndEntity); + let revocation = Some(builder.build()); + assert_eq!( + check_cert(ee, intermediates, ca, revocation), + Err(webpki::Error::UnknownRevocationStatus) + ); +} + +#[cfg(feature = "alloc")] +#[test] +fn ee_crl_mismatched_idp_unknown_status_owned() { + let ee = include_bytes!("client_auth_revocation/dp_chain.ee.der"); + let intermediates = &[ + include_bytes!("client_auth_revocation/dp_chain.int.a.ca.der").as_slice(), + include_bytes!("client_auth_revocation/dp_chain.int.b.ca.der").as_slice(), + ]; + let ca = include_bytes!("client_auth_revocation/dp_chain.root.ca.der"); + + let crls = &[&webpki::BorrowedCertRevocationList::from_der( + include_bytes!("client_auth_revocation/ee_crl_mismatched_idp_unknown_status.crl.der") + .as_slice(), + ) + .unwrap() + .to_owned() + .unwrap() as &dyn webpki::CertRevocationList]; + let builder = RevocationOptionsBuilder::new(crls).unwrap(); + + let builder = builder.with_depth(RevocationCheckDepth::EndEntity); + let revocation = Some(builder.build()); + assert_eq!( + check_cert(ee, intermediates, ca, revocation), + Err(webpki::Error::UnknownRevocationStatus) + ); +} + +#[test] +fn ee_indirect_dp_unknown_status() { + let ee = include_bytes!("client_auth_revocation/indirect_dp_chain.ee.der"); + let intermediates = &[ + include_bytes!("client_auth_revocation/indirect_dp_chain.int.a.ca.der").as_slice(), + include_bytes!("client_auth_revocation/indirect_dp_chain.int.b.ca.der").as_slice(), + ]; + let ca = include_bytes!("client_auth_revocation/indirect_dp_chain.root.ca.der"); + + let crls = &[&webpki::BorrowedCertRevocationList::from_der( + include_bytes!("client_auth_revocation/ee_indirect_dp_unknown_status.crl.der").as_slice(), + ) + .unwrap() as &dyn webpki::CertRevocationList]; + let builder = RevocationOptionsBuilder::new(crls).unwrap(); + + let builder = builder.with_depth(RevocationCheckDepth::EndEntity); + let revocation = Some(builder.build()); + assert_eq!( + check_cert(ee, intermediates, ca, revocation), + Err(webpki::Error::UnknownRevocationStatus) + ); +} + +#[cfg(feature = "alloc")] +#[test] +fn ee_indirect_dp_unknown_status_owned() { + let ee = include_bytes!("client_auth_revocation/indirect_dp_chain.ee.der"); + let intermediates = &[ + include_bytes!("client_auth_revocation/indirect_dp_chain.int.a.ca.der").as_slice(), + include_bytes!("client_auth_revocation/indirect_dp_chain.int.b.ca.der").as_slice(), + ]; + let ca = include_bytes!("client_auth_revocation/indirect_dp_chain.root.ca.der"); + + let crls = &[&webpki::BorrowedCertRevocationList::from_der( + include_bytes!("client_auth_revocation/ee_indirect_dp_unknown_status.crl.der").as_slice(), + ) + .unwrap() + .to_owned() + .unwrap() as &dyn webpki::CertRevocationList]; + let builder = RevocationOptionsBuilder::new(crls).unwrap(); + + let builder = builder.with_depth(RevocationCheckDepth::EndEntity); + let revocation = Some(builder.build()); + assert_eq!( + check_cert(ee, intermediates, ca, revocation), + Err(webpki::Error::UnknownRevocationStatus) + ); +} + +#[test] +fn ee_reasons_dp_unknown_status() { + let ee = include_bytes!("client_auth_revocation/reasons_dp_chain.ee.der"); + let intermediates = &[ + include_bytes!("client_auth_revocation/reasons_dp_chain.int.a.ca.der").as_slice(), + include_bytes!("client_auth_revocation/reasons_dp_chain.int.b.ca.der").as_slice(), + ]; + let ca = include_bytes!("client_auth_revocation/reasons_dp_chain.root.ca.der"); + + let crls = &[&webpki::BorrowedCertRevocationList::from_der( + include_bytes!("client_auth_revocation/ee_reasons_dp_unknown_status.crl.der").as_slice(), + ) + .unwrap() as &dyn webpki::CertRevocationList]; + let builder = RevocationOptionsBuilder::new(crls).unwrap(); + + let builder = builder.with_depth(RevocationCheckDepth::EndEntity); + let revocation = Some(builder.build()); + assert_eq!( + check_cert(ee, intermediates, ca, revocation), + Err(webpki::Error::UnknownRevocationStatus) + ); +} + +#[cfg(feature = "alloc")] +#[test] +fn ee_reasons_dp_unknown_status_owned() { + let ee = include_bytes!("client_auth_revocation/reasons_dp_chain.ee.der"); + let intermediates = &[ + include_bytes!("client_auth_revocation/reasons_dp_chain.int.a.ca.der").as_slice(), + include_bytes!("client_auth_revocation/reasons_dp_chain.int.b.ca.der").as_slice(), + ]; + let ca = include_bytes!("client_auth_revocation/reasons_dp_chain.root.ca.der"); + + let crls = &[&webpki::BorrowedCertRevocationList::from_der( + include_bytes!("client_auth_revocation/ee_reasons_dp_unknown_status.crl.der").as_slice(), + ) + .unwrap() + .to_owned() + .unwrap() as &dyn webpki::CertRevocationList]; + let builder = RevocationOptionsBuilder::new(crls).unwrap(); + + let builder = builder.with_depth(RevocationCheckDepth::EndEntity); + let revocation = Some(builder.build()); + assert_eq!( + check_cert(ee, intermediates, ca, revocation), + Err(webpki::Error::UnknownRevocationStatus) + ); +} + +#[test] +fn ee_nofullname_dp_unknown_status() { + let ee = include_bytes!("client_auth_revocation/nofullname_dp_chain.ee.der"); + let intermediates = &[ + include_bytes!("client_auth_revocation/nofullname_dp_chain.int.a.ca.der").as_slice(), + include_bytes!("client_auth_revocation/nofullname_dp_chain.int.b.ca.der").as_slice(), + ]; + let ca = include_bytes!("client_auth_revocation/nofullname_dp_chain.root.ca.der"); + + let crls = &[&webpki::BorrowedCertRevocationList::from_der( + include_bytes!("client_auth_revocation/ee_nofullname_dp_unknown_status.crl.der").as_slice(), + ) + .unwrap() as &dyn webpki::CertRevocationList]; + let builder = RevocationOptionsBuilder::new(crls).unwrap(); + + let builder = builder.with_depth(RevocationCheckDepth::EndEntity); + let revocation = Some(builder.build()); + assert_eq!( + check_cert(ee, intermediates, ca, revocation), + Err(webpki::Error::UnknownRevocationStatus) + ); +} + +#[cfg(feature = "alloc")] +#[test] +fn ee_nofullname_dp_unknown_status_owned() { + let ee = include_bytes!("client_auth_revocation/nofullname_dp_chain.ee.der"); + let intermediates = &[ + include_bytes!("client_auth_revocation/nofullname_dp_chain.int.a.ca.der").as_slice(), + include_bytes!("client_auth_revocation/nofullname_dp_chain.int.b.ca.der").as_slice(), + ]; + let ca = include_bytes!("client_auth_revocation/nofullname_dp_chain.root.ca.der"); + + let crls = &[&webpki::BorrowedCertRevocationList::from_der( + include_bytes!("client_auth_revocation/ee_nofullname_dp_unknown_status.crl.der").as_slice(), + ) + .unwrap() + .to_owned() + .unwrap() as &dyn webpki::CertRevocationList]; + let builder = RevocationOptionsBuilder::new(crls).unwrap(); + + let builder = builder.with_depth(RevocationCheckDepth::EndEntity); + let revocation = Some(builder.build()); + assert_eq!( + check_cert(ee, intermediates, ca, revocation), + Err(webpki::Error::UnknownRevocationStatus) + ); +} + +#[test] +fn ee_dp_idp_match() { + let ee = include_bytes!("client_auth_revocation/dp_chain.ee.der"); + let intermediates = &[ + include_bytes!("client_auth_revocation/dp_chain.int.a.ca.der").as_slice(), + include_bytes!("client_auth_revocation/dp_chain.int.b.ca.der").as_slice(), + ]; + let ca = include_bytes!("client_auth_revocation/dp_chain.root.ca.der"); + + let crls = &[&webpki::BorrowedCertRevocationList::from_der( + include_bytes!("client_auth_revocation/ee_dp_idp_match.crl.der").as_slice(), + ) + .unwrap() as &dyn webpki::CertRevocationList]; + let builder = RevocationOptionsBuilder::new(crls).unwrap(); + + let builder = builder.with_depth(RevocationCheckDepth::EndEntity); + let revocation = Some(builder.build()); + assert_eq!(check_cert(ee, intermediates, ca, revocation), Ok(())); +} + +#[cfg(feature = "alloc")] +#[test] +fn ee_dp_idp_match_owned() { + let ee = include_bytes!("client_auth_revocation/dp_chain.ee.der"); + let intermediates = &[ + include_bytes!("client_auth_revocation/dp_chain.int.a.ca.der").as_slice(), + include_bytes!("client_auth_revocation/dp_chain.int.b.ca.der").as_slice(), + ]; + let ca = include_bytes!("client_auth_revocation/dp_chain.root.ca.der"); + + let crls = &[&webpki::BorrowedCertRevocationList::from_der( + include_bytes!("client_auth_revocation/ee_dp_idp_match.crl.der").as_slice(), + ) + .unwrap() + .to_owned() + .unwrap() as &dyn webpki::CertRevocationList]; + let builder = RevocationOptionsBuilder::new(crls).unwrap(); + + let builder = builder.with_depth(RevocationCheckDepth::EndEntity); + let revocation = Some(builder.build()); + assert_eq!(check_cert(ee, intermediates, ca, revocation), Ok(())); +} + +#[test] +fn ee_dp_invalid() { + let ee = include_bytes!("client_auth_revocation/invalid_dp_chain.ee.der"); + let intermediates = &[ + include_bytes!("client_auth_revocation/invalid_dp_chain.int.a.ca.der").as_slice(), + include_bytes!("client_auth_revocation/invalid_dp_chain.int.b.ca.der").as_slice(), + ]; + let ca = include_bytes!("client_auth_revocation/invalid_dp_chain.root.ca.der"); + + let crls = &[&webpki::BorrowedCertRevocationList::from_der( + include_bytes!("client_auth_revocation/ee_dp_invalid.crl.der").as_slice(), + ) + .unwrap() as &dyn webpki::CertRevocationList]; + let builder = RevocationOptionsBuilder::new(crls).unwrap(); + + let builder = builder.with_depth(RevocationCheckDepth::EndEntity); + let revocation = Some(builder.build()); + assert_eq!( + check_cert(ee, intermediates, ca, revocation), + Err(webpki::Error::UnknownRevocationStatus) + ); +} + +#[cfg(feature = "alloc")] +#[test] +fn ee_dp_invalid_owned() { + let ee = include_bytes!("client_auth_revocation/invalid_dp_chain.ee.der"); + let intermediates = &[ + include_bytes!("client_auth_revocation/invalid_dp_chain.int.a.ca.der").as_slice(), + include_bytes!("client_auth_revocation/invalid_dp_chain.int.b.ca.der").as_slice(), + ]; + let ca = include_bytes!("client_auth_revocation/invalid_dp_chain.root.ca.der"); + + let crls = &[&webpki::BorrowedCertRevocationList::from_der( + include_bytes!("client_auth_revocation/ee_dp_invalid.crl.der").as_slice(), + ) + .unwrap() + .to_owned() + .unwrap() as &dyn webpki::CertRevocationList]; + let builder = RevocationOptionsBuilder::new(crls).unwrap(); + + let builder = builder.with_depth(RevocationCheckDepth::EndEntity); + let revocation = Some(builder.build()); + assert_eq!( + check_cert(ee, intermediates, ca, revocation), + Err(webpki::Error::UnknownRevocationStatus) + ); +} diff --git a/tests/client_auth_revocation/dp_chain.ee.der b/tests/client_auth_revocation/dp_chain.ee.der new file mode 100644 index 00000000..588e4c5a Binary files /dev/null and b/tests/client_auth_revocation/dp_chain.ee.der differ diff --git a/tests/client_auth_revocation/dp_chain.int.a.ca.der b/tests/client_auth_revocation/dp_chain.int.a.ca.der new file mode 100644 index 00000000..b552ce61 Binary files /dev/null and b/tests/client_auth_revocation/dp_chain.int.a.ca.der differ diff --git a/tests/client_auth_revocation/dp_chain.int.b.ca.der b/tests/client_auth_revocation/dp_chain.int.b.ca.der new file mode 100644 index 00000000..dd2a9e75 Binary files /dev/null and b/tests/client_auth_revocation/dp_chain.int.b.ca.der differ diff --git a/tests/client_auth_revocation/dp_chain.root.ca.der b/tests/client_auth_revocation/dp_chain.root.ca.der new file mode 100644 index 00000000..5b16d262 Binary files /dev/null and b/tests/client_auth_revocation/dp_chain.root.ca.der differ diff --git a/tests/client_auth_revocation/dp_chain.topbit.ee.der b/tests/client_auth_revocation/dp_chain.topbit.ee.der new file mode 100644 index 00000000..c208ef9d Binary files /dev/null and b/tests/client_auth_revocation/dp_chain.topbit.ee.der differ diff --git a/tests/client_auth_revocation/ee_crl_mismatched_idp_unknown_status.crl.der b/tests/client_auth_revocation/ee_crl_mismatched_idp_unknown_status.crl.der new file mode 100644 index 00000000..641db043 Binary files /dev/null and b/tests/client_auth_revocation/ee_crl_mismatched_idp_unknown_status.crl.der differ diff --git a/tests/client_auth_revocation/ee_crl_no_idp_unknown_status.crl.der b/tests/client_auth_revocation/ee_crl_no_idp_unknown_status.crl.der new file mode 100644 index 00000000..ffc4e9b6 Binary files /dev/null and b/tests/client_auth_revocation/ee_crl_no_idp_unknown_status.crl.der differ diff --git a/tests/client_auth_revocation/ee_dp_idp_match.crl.der b/tests/client_auth_revocation/ee_dp_idp_match.crl.der new file mode 100644 index 00000000..507ea06e Binary files /dev/null and b/tests/client_auth_revocation/ee_dp_idp_match.crl.der differ diff --git a/tests/client_auth_revocation/ee_dp_invalid.crl.der b/tests/client_auth_revocation/ee_dp_invalid.crl.der new file mode 100644 index 00000000..aedd5406 Binary files /dev/null and b/tests/client_auth_revocation/ee_dp_invalid.crl.der differ diff --git a/tests/client_auth_revocation/ee_indirect_dp_unknown_status.crl.der b/tests/client_auth_revocation/ee_indirect_dp_unknown_status.crl.der new file mode 100644 index 00000000..8efa0cda Binary files /dev/null and b/tests/client_auth_revocation/ee_indirect_dp_unknown_status.crl.der differ diff --git a/tests/client_auth_revocation/ee_no_dp_crl_idp.crl.der b/tests/client_auth_revocation/ee_no_dp_crl_idp.crl.der new file mode 100644 index 00000000..8cac9192 Binary files /dev/null and b/tests/client_auth_revocation/ee_no_dp_crl_idp.crl.der differ diff --git a/tests/client_auth_revocation/ee_nofullname_dp_unknown_status.crl.der b/tests/client_auth_revocation/ee_nofullname_dp_unknown_status.crl.der new file mode 100644 index 00000000..f2efb50c Binary files /dev/null and b/tests/client_auth_revocation/ee_nofullname_dp_unknown_status.crl.der differ diff --git a/tests/client_auth_revocation/ee_not_revoked_ee_depth.crl.der b/tests/client_auth_revocation/ee_not_revoked_ee_depth.crl.der index 359c3b8e..793a1021 100644 Binary files a/tests/client_auth_revocation/ee_not_revoked_ee_depth.crl.der and b/tests/client_auth_revocation/ee_not_revoked_ee_depth.crl.der differ diff --git a/tests/client_auth_revocation/ee_not_revoked_wrong_ku_ee_depth.crl.der b/tests/client_auth_revocation/ee_not_revoked_wrong_ku_ee_depth.crl.der index cf39b9bb..169c8dc4 100644 Binary files a/tests/client_auth_revocation/ee_not_revoked_wrong_ku_ee_depth.crl.der and b/tests/client_auth_revocation/ee_not_revoked_wrong_ku_ee_depth.crl.der differ diff --git a/tests/client_auth_revocation/ee_reasons_dp_unknown_status.crl.der b/tests/client_auth_revocation/ee_reasons_dp_unknown_status.crl.der new file mode 100644 index 00000000..b6679fc2 Binary files /dev/null and b/tests/client_auth_revocation/ee_reasons_dp_unknown_status.crl.der differ diff --git a/tests/client_auth_revocation/ee_revoked_badsig_ee_depth.crl.der b/tests/client_auth_revocation/ee_revoked_badsig_ee_depth.crl.der index 0db92cf2..d22c91dc 100644 Binary files a/tests/client_auth_revocation/ee_revoked_badsig_ee_depth.crl.der and b/tests/client_auth_revocation/ee_revoked_badsig_ee_depth.crl.der differ diff --git a/tests/client_auth_revocation/ee_revoked_chain_depth.crl.der b/tests/client_auth_revocation/ee_revoked_chain_depth.crl.der index 9ec24b26..982aef37 100644 Binary files a/tests/client_auth_revocation/ee_revoked_chain_depth.crl.der and b/tests/client_auth_revocation/ee_revoked_chain_depth.crl.der differ diff --git a/tests/client_auth_revocation/ee_revoked_crl_ku_ee_depth.crl.der b/tests/client_auth_revocation/ee_revoked_crl_ku_ee_depth.crl.der index b96e9041..a23f4aee 100644 Binary files a/tests/client_auth_revocation/ee_revoked_crl_ku_ee_depth.crl.der and b/tests/client_auth_revocation/ee_revoked_crl_ku_ee_depth.crl.der differ diff --git a/tests/client_auth_revocation/ee_revoked_no_ku_ee_depth.crl.der b/tests/client_auth_revocation/ee_revoked_no_ku_ee_depth.crl.der index 30197eac..cc2535ee 100644 Binary files a/tests/client_auth_revocation/ee_revoked_no_ku_ee_depth.crl.der and b/tests/client_auth_revocation/ee_revoked_no_ku_ee_depth.crl.der differ diff --git a/tests/client_auth_revocation/ee_revoked_wrong_ku_ee_depth.crl.der b/tests/client_auth_revocation/ee_revoked_wrong_ku_ee_depth.crl.der index 6ccc8299..97c5bd1e 100644 Binary files a/tests/client_auth_revocation/ee_revoked_wrong_ku_ee_depth.crl.der and b/tests/client_auth_revocation/ee_revoked_wrong_ku_ee_depth.crl.der differ diff --git a/tests/client_auth_revocation/ee_with_top_bit_set_serial_revoked.crl.der b/tests/client_auth_revocation/ee_with_top_bit_set_serial_revoked.crl.der index 48217fef..2736a41c 100644 Binary files a/tests/client_auth_revocation/ee_with_top_bit_set_serial_revoked.crl.der and b/tests/client_auth_revocation/ee_with_top_bit_set_serial_revoked.crl.der differ diff --git a/tests/client_auth_revocation/indirect_dp_chain.ee.der b/tests/client_auth_revocation/indirect_dp_chain.ee.der new file mode 100644 index 00000000..e6317e4e Binary files /dev/null and b/tests/client_auth_revocation/indirect_dp_chain.ee.der differ diff --git a/tests/client_auth_revocation/indirect_dp_chain.int.a.ca.der b/tests/client_auth_revocation/indirect_dp_chain.int.a.ca.der new file mode 100644 index 00000000..7b4db2a3 Binary files /dev/null and b/tests/client_auth_revocation/indirect_dp_chain.int.a.ca.der differ diff --git a/tests/client_auth_revocation/indirect_dp_chain.int.b.ca.der b/tests/client_auth_revocation/indirect_dp_chain.int.b.ca.der new file mode 100644 index 00000000..d1678fe2 Binary files /dev/null and b/tests/client_auth_revocation/indirect_dp_chain.int.b.ca.der differ diff --git a/tests/client_auth_revocation/indirect_dp_chain.root.ca.der b/tests/client_auth_revocation/indirect_dp_chain.root.ca.der new file mode 100644 index 00000000..18c4647a Binary files /dev/null and b/tests/client_auth_revocation/indirect_dp_chain.root.ca.der differ diff --git a/tests/client_auth_revocation/indirect_dp_chain.topbit.ee.der b/tests/client_auth_revocation/indirect_dp_chain.topbit.ee.der new file mode 100644 index 00000000..1d6d8461 Binary files /dev/null and b/tests/client_auth_revocation/indirect_dp_chain.topbit.ee.der differ diff --git a/tests/client_auth_revocation/int_not_revoked_chain_depth.crl.der b/tests/client_auth_revocation/int_not_revoked_chain_depth.crl.der index 82566acb..d5290bb7 100644 Binary files a/tests/client_auth_revocation/int_not_revoked_chain_depth.crl.der and b/tests/client_auth_revocation/int_not_revoked_chain_depth.crl.der differ diff --git a/tests/client_auth_revocation/int_revoked_badsig_chain_depth.crl.der b/tests/client_auth_revocation/int_revoked_badsig_chain_depth.crl.der index ca4e87bd..62d54c5f 100644 Binary files a/tests/client_auth_revocation/int_revoked_badsig_chain_depth.crl.der and b/tests/client_auth_revocation/int_revoked_badsig_chain_depth.crl.der differ diff --git a/tests/client_auth_revocation/int_revoked_crl_ku_chain_depth.crl.der b/tests/client_auth_revocation/int_revoked_crl_ku_chain_depth.crl.der index 4a747848..1ba27cfc 100644 Binary files a/tests/client_auth_revocation/int_revoked_crl_ku_chain_depth.crl.der and b/tests/client_auth_revocation/int_revoked_crl_ku_chain_depth.crl.der differ diff --git a/tests/client_auth_revocation/int_revoked_ee_depth.crl.der b/tests/client_auth_revocation/int_revoked_ee_depth.crl.der deleted file mode 100644 index 358b83b2..00000000 Binary files a/tests/client_auth_revocation/int_revoked_ee_depth.crl.der and /dev/null differ diff --git a/tests/client_auth_revocation/int_revoked_no_ku_chain_depth.crl.der b/tests/client_auth_revocation/int_revoked_no_ku_chain_depth.crl.der index f0e0888f..656f7b77 100644 Binary files a/tests/client_auth_revocation/int_revoked_no_ku_chain_depth.crl.der and b/tests/client_auth_revocation/int_revoked_no_ku_chain_depth.crl.der differ diff --git a/tests/client_auth_revocation/int_revoked_wrong_ku_chain_depth.crl.der b/tests/client_auth_revocation/int_revoked_wrong_ku_chain_depth.crl.der index 23de4f5e..39b63d99 100644 Binary files a/tests/client_auth_revocation/int_revoked_wrong_ku_chain_depth.crl.der and b/tests/client_auth_revocation/int_revoked_wrong_ku_chain_depth.crl.der differ diff --git a/tests/client_auth_revocation/invalid_dp_chain.ee.der b/tests/client_auth_revocation/invalid_dp_chain.ee.der new file mode 100644 index 00000000..3cdbb94d Binary files /dev/null and b/tests/client_auth_revocation/invalid_dp_chain.ee.der differ diff --git a/tests/client_auth_revocation/invalid_dp_chain.int.a.ca.der b/tests/client_auth_revocation/invalid_dp_chain.int.a.ca.der new file mode 100644 index 00000000..361378e0 Binary files /dev/null and b/tests/client_auth_revocation/invalid_dp_chain.int.a.ca.der differ diff --git a/tests/client_auth_revocation/invalid_dp_chain.int.b.ca.der b/tests/client_auth_revocation/invalid_dp_chain.int.b.ca.der new file mode 100644 index 00000000..7e933431 Binary files /dev/null and b/tests/client_auth_revocation/invalid_dp_chain.int.b.ca.der differ diff --git a/tests/client_auth_revocation/invalid_dp_chain.root.ca.der b/tests/client_auth_revocation/invalid_dp_chain.root.ca.der new file mode 100644 index 00000000..5ec74765 Binary files /dev/null and b/tests/client_auth_revocation/invalid_dp_chain.root.ca.der differ diff --git a/tests/client_auth_revocation/invalid_dp_chain.topbit.ee.der b/tests/client_auth_revocation/invalid_dp_chain.topbit.ee.der new file mode 100644 index 00000000..c284d262 Binary files /dev/null and b/tests/client_auth_revocation/invalid_dp_chain.topbit.ee.der differ diff --git a/tests/client_auth_revocation/ku_chain.ee.der b/tests/client_auth_revocation/ku_chain.ee.der index a864e257..d805764e 100644 Binary files a/tests/client_auth_revocation/ku_chain.ee.der and b/tests/client_auth_revocation/ku_chain.ee.der differ diff --git a/tests/client_auth_revocation/ku_chain.int.a.ca.der b/tests/client_auth_revocation/ku_chain.int.a.ca.der index 3da89d75..f37e5f7d 100644 Binary files a/tests/client_auth_revocation/ku_chain.int.a.ca.der and b/tests/client_auth_revocation/ku_chain.int.a.ca.der differ diff --git a/tests/client_auth_revocation/ku_chain.int.b.ca.der b/tests/client_auth_revocation/ku_chain.int.b.ca.der index f36d67e3..7f68d5ce 100644 Binary files a/tests/client_auth_revocation/ku_chain.int.b.ca.der and b/tests/client_auth_revocation/ku_chain.int.b.ca.der differ diff --git a/tests/client_auth_revocation/ku_chain.root.ca.der b/tests/client_auth_revocation/ku_chain.root.ca.der index b6f47163..43f9bb51 100644 Binary files a/tests/client_auth_revocation/ku_chain.root.ca.der and b/tests/client_auth_revocation/ku_chain.root.ca.der differ diff --git a/tests/client_auth_revocation/ku_chain.topbit.ee.der b/tests/client_auth_revocation/ku_chain.topbit.ee.der index c3d2dccd..3c326e62 100644 Binary files a/tests/client_auth_revocation/ku_chain.topbit.ee.der and b/tests/client_auth_revocation/ku_chain.topbit.ee.der differ diff --git a/tests/client_auth_revocation/no_crl_ku_chain.ee.der b/tests/client_auth_revocation/no_crl_ku_chain.ee.der index f6f4c7ee..9416bb40 100644 Binary files a/tests/client_auth_revocation/no_crl_ku_chain.ee.der and b/tests/client_auth_revocation/no_crl_ku_chain.ee.der differ diff --git a/tests/client_auth_revocation/no_crl_ku_chain.int.a.ca.der b/tests/client_auth_revocation/no_crl_ku_chain.int.a.ca.der index aa4ec2e6..930a3e1f 100644 Binary files a/tests/client_auth_revocation/no_crl_ku_chain.int.a.ca.der and b/tests/client_auth_revocation/no_crl_ku_chain.int.a.ca.der differ diff --git a/tests/client_auth_revocation/no_crl_ku_chain.int.b.ca.der b/tests/client_auth_revocation/no_crl_ku_chain.int.b.ca.der index 6180958f..8cbf239a 100644 Binary files a/tests/client_auth_revocation/no_crl_ku_chain.int.b.ca.der and b/tests/client_auth_revocation/no_crl_ku_chain.int.b.ca.der differ diff --git a/tests/client_auth_revocation/no_crl_ku_chain.root.ca.der b/tests/client_auth_revocation/no_crl_ku_chain.root.ca.der index fb6d6d16..d084e9af 100644 Binary files a/tests/client_auth_revocation/no_crl_ku_chain.root.ca.der and b/tests/client_auth_revocation/no_crl_ku_chain.root.ca.der differ diff --git a/tests/client_auth_revocation/no_crl_ku_chain.topbit.ee.der b/tests/client_auth_revocation/no_crl_ku_chain.topbit.ee.der index e01b9fd9..76177772 100644 Binary files a/tests/client_auth_revocation/no_crl_ku_chain.topbit.ee.der and b/tests/client_auth_revocation/no_crl_ku_chain.topbit.ee.der differ diff --git a/tests/client_auth_revocation/no_ku_chain.ee.der b/tests/client_auth_revocation/no_ku_chain.ee.der index 8698bee8..1c4eae34 100644 Binary files a/tests/client_auth_revocation/no_ku_chain.ee.der and b/tests/client_auth_revocation/no_ku_chain.ee.der differ diff --git a/tests/client_auth_revocation/no_ku_chain.int.a.ca.der b/tests/client_auth_revocation/no_ku_chain.int.a.ca.der index 0e5b66b3..e42ab4cc 100644 Binary files a/tests/client_auth_revocation/no_ku_chain.int.a.ca.der and b/tests/client_auth_revocation/no_ku_chain.int.a.ca.der differ diff --git a/tests/client_auth_revocation/no_ku_chain.int.b.ca.der b/tests/client_auth_revocation/no_ku_chain.int.b.ca.der index 859a164c..6f6893a9 100644 Binary files a/tests/client_auth_revocation/no_ku_chain.int.b.ca.der and b/tests/client_auth_revocation/no_ku_chain.int.b.ca.der differ diff --git a/tests/client_auth_revocation/no_ku_chain.root.ca.der b/tests/client_auth_revocation/no_ku_chain.root.ca.der index daca5c01..453a9220 100644 Binary files a/tests/client_auth_revocation/no_ku_chain.root.ca.der and b/tests/client_auth_revocation/no_ku_chain.root.ca.der differ diff --git a/tests/client_auth_revocation/no_ku_chain.topbit.ee.der b/tests/client_auth_revocation/no_ku_chain.topbit.ee.der index fd864e30..7c75e4c2 100644 Binary files a/tests/client_auth_revocation/no_ku_chain.topbit.ee.der and b/tests/client_auth_revocation/no_ku_chain.topbit.ee.der differ diff --git a/tests/client_auth_revocation/no_relevant_crl_chain_depth.crl.der b/tests/client_auth_revocation/no_relevant_crl_chain_depth.crl.der index 050f1020..831b4291 100644 Binary files a/tests/client_auth_revocation/no_relevant_crl_chain_depth.crl.der and b/tests/client_auth_revocation/no_relevant_crl_chain_depth.crl.der differ diff --git a/tests/client_auth_revocation/no_relevant_crl_ee_depth.crl.der b/tests/client_auth_revocation/no_relevant_crl_ee_depth.crl.der deleted file mode 100644 index 6870ad0a..00000000 Binary files a/tests/client_auth_revocation/no_relevant_crl_ee_depth.crl.der and /dev/null differ diff --git a/tests/client_auth_revocation/no_relevant_crl_ee_depth_allow_unknown.crl.der b/tests/client_auth_revocation/no_relevant_crl_ee_depth_allow_unknown.crl.der new file mode 100644 index 00000000..a5977445 Binary files /dev/null and b/tests/client_auth_revocation/no_relevant_crl_ee_depth_allow_unknown.crl.der differ diff --git a/tests/client_auth_revocation/nofullname_dp_chain.ee.der b/tests/client_auth_revocation/nofullname_dp_chain.ee.der new file mode 100644 index 00000000..2eb3f664 Binary files /dev/null and b/tests/client_auth_revocation/nofullname_dp_chain.ee.der differ diff --git a/tests/client_auth_revocation/nofullname_dp_chain.int.a.ca.der b/tests/client_auth_revocation/nofullname_dp_chain.int.a.ca.der new file mode 100644 index 00000000..ee008fc3 Binary files /dev/null and b/tests/client_auth_revocation/nofullname_dp_chain.int.a.ca.der differ diff --git a/tests/client_auth_revocation/nofullname_dp_chain.int.b.ca.der b/tests/client_auth_revocation/nofullname_dp_chain.int.b.ca.der new file mode 100644 index 00000000..33bc5218 Binary files /dev/null and b/tests/client_auth_revocation/nofullname_dp_chain.int.b.ca.der differ diff --git a/tests/client_auth_revocation/nofullname_dp_chain.root.ca.der b/tests/client_auth_revocation/nofullname_dp_chain.root.ca.der new file mode 100644 index 00000000..e69ed4d9 Binary files /dev/null and b/tests/client_auth_revocation/nofullname_dp_chain.root.ca.der differ diff --git a/tests/client_auth_revocation/nofullname_dp_chain.topbit.ee.der b/tests/client_auth_revocation/nofullname_dp_chain.topbit.ee.der new file mode 100644 index 00000000..e89361fa Binary files /dev/null and b/tests/client_auth_revocation/nofullname_dp_chain.topbit.ee.der differ diff --git a/tests/client_auth_revocation/reasons_dp_chain.ee.der b/tests/client_auth_revocation/reasons_dp_chain.ee.der new file mode 100644 index 00000000..63e652a2 Binary files /dev/null and b/tests/client_auth_revocation/reasons_dp_chain.ee.der differ diff --git a/tests/client_auth_revocation/reasons_dp_chain.int.a.ca.der b/tests/client_auth_revocation/reasons_dp_chain.int.a.ca.der new file mode 100644 index 00000000..d9c0cbe5 Binary files /dev/null and b/tests/client_auth_revocation/reasons_dp_chain.int.a.ca.der differ diff --git a/tests/client_auth_revocation/reasons_dp_chain.int.b.ca.der b/tests/client_auth_revocation/reasons_dp_chain.int.b.ca.der new file mode 100644 index 00000000..a78fed11 Binary files /dev/null and b/tests/client_auth_revocation/reasons_dp_chain.int.b.ca.der differ diff --git a/tests/client_auth_revocation/reasons_dp_chain.root.ca.der b/tests/client_auth_revocation/reasons_dp_chain.root.ca.der new file mode 100644 index 00000000..56cc0c31 Binary files /dev/null and b/tests/client_auth_revocation/reasons_dp_chain.root.ca.der differ diff --git a/tests/client_auth_revocation/reasons_dp_chain.topbit.ee.der b/tests/client_auth_revocation/reasons_dp_chain.topbit.ee.der new file mode 100644 index 00000000..68752898 Binary files /dev/null and b/tests/client_auth_revocation/reasons_dp_chain.topbit.ee.der differ diff --git a/tests/generate.py b/tests/generate.py index 17d34e2d..91b100f1 100755 --- a/tests/generate.py +++ b/tests/generate.py @@ -8,6 +8,7 @@ drops testcase data into subdirectories as required. """ import argparse +import enum import os from typing import TextIO, Optional, Union, Any, Callable, Iterable, List from pathlib import Path @@ -87,6 +88,7 @@ def end_entity_cert( sans: Optional[Iterable[x509.GeneralName]] = None, ekus: Optional[Iterable[x509.ObjectIdentifier]] = None, serial: Optional[int] = None, + cert_dps: Optional[x509.DistributionPoint] = None, ) -> x509.Certificate: subject_priv_key = key_or_generate(subject_key) subject_key_pub: ANY_PUB_KEY = subject_priv_key.public_key() @@ -108,6 +110,10 @@ def end_entity_cert( ee_builder = ee_builder.add_extension( x509.ExtendedKeyUsage(ekus), critical=False ) + if cert_dps: + ee_builder = ee_builder.add_extension( + x509.CRLDistributionPoints([cert_dps]), critical=False + ) ee_builder = ee_builder.add_extension( x509.BasicConstraints(ca=False, path_length=None), critical=True, @@ -146,6 +152,7 @@ def ca_cert( permitted_subtrees: Optional[Iterable[x509.GeneralName]] = None, excluded_subtrees: Optional[Iterable[x509.GeneralName]] = None, key_usage: Optional[x509.KeyUsage] = None, + cert_dps: Optional[x509.DistributionPoint] = None, ) -> x509.Certificate: subject_priv_key = key_or_generate(subject_key) subject_key_pub: ANY_PUB_KEY = subject_priv_key.public_key() @@ -170,6 +177,10 @@ def ca_cert( key_usage, critical=True, ) + if cert_dps: + ca_builder = ca_builder.add_extension( + x509.CRLDistributionPoints([cert_dps]), critical=False + ) return ca_builder.sign( private_key=issuer_key if issuer_key else subject_priv_key, @@ -892,8 +903,43 @@ def client_auth_revocation(force: bool) -> None: decipher_only=False, ) + # Cert CRL distribution point + valid_cert_crl_dp = x509.DistributionPoint( + full_name=[ + x509.DNSName("example.com"), + x509.UniformResourceIdentifier("http://example.com/another.crl"), + x509.UniformResourceIdentifier("http://example.com/valid.crl"), + ], + crl_issuer=None, + relative_name=None, + reasons=None, + ) + valid_crl_idp = x509.IssuingDistributionPoint( + full_name=[ + x509.UniformResourceIdentifier("http://example.com/yet.another.crl"), + x509.UniformResourceIdentifier("http://example.com/valid.crl"), + ], + indirect_crl=False, + only_contains_user_certs=False, + only_contains_ca_certs=False, + only_contains_attribute_certs=False, + only_some_reasons=None, + relative_name=None, + ) + + class ChainDepth(enum.Enum): + END_ENTITY = enum.auto() + CHAIN = enum.auto() + + class StatusRequirement(enum.Enum): + ALLOW_UNKNOWN = enum.auto() + FORBID_UNKNOWN = enum.auto() + def _chain( - *, chain_name: str, key_usage: Optional[x509.KeyUsage] + *, + chain_name: str, + key_usage: Optional[x509.KeyUsage], + cert_dps: Optional[x509.DistributionPoint], ) -> list[tuple[x509.Certificate, str, ANY_PRIV_KEY]]: """ Generate a short test certificate chain: @@ -904,10 +950,13 @@ def _chain( :param key_usage: the KeyUsage to include in the issuer certificates (both the intermediate and the root). + :param cert_dps: an optional CRL distribution point to include in each certificate. + :return: Return a list comprising the chain starting from the end entity and ending at the root trust anchor. Each entry in the list is a tuple of three values: the x509.Certificate object, the path the DER encoding was written to, and lastly the corresponding private key. """ + ee_subj: x509.Name = subject_name_for_test("test.example.com", chain_name) int_a_subj: x509.Name = issuer_name_for_test(f"int.a.{chain_name}") int_b_subj: x509.Name = issuer_name_for_test(f"int.b.{chain_name}") @@ -927,7 +976,10 @@ def _chain( # EE cert issued by intermediate. ee_cert: x509.Certificate = end_entity_cert( - subject_name=ee_subj, issuer_name=int_a_subj, issuer_key=int_a_key + subject_name=ee_subj, + issuer_name=int_a_subj, + issuer_key=int_a_key, + cert_dps=cert_dps, ) ee_cert_path: str = os.path.join(output_dir, f"{chain_name}.ee.der") write_der(ee_cert_path, ee_cert.public_bytes(Encoding.DER), force) @@ -938,6 +990,7 @@ def _chain( issuer_name=int_a_subj, issuer_key=int_a_key, serial=0x80DEADBEEFF00D, + cert_dps=cert_dps, ) ee_cert_topbit_path: str = os.path.join( output_dir, f"{chain_name}.topbit.ee.der" @@ -951,6 +1004,7 @@ def _chain( issuer_name=int_b_subj, issuer_key=int_b_key, key_usage=key_usage, + cert_dps=cert_dps, ) int_a_cert_path: str = os.path.join(output_dir, f"{chain_name}.int.a.ca.der") write_der(int_a_cert_path, int_a_cert.public_bytes(Encoding.DER), force) @@ -962,6 +1016,7 @@ def _chain( issuer_name=ca_subj, issuer_key=root_key, key_usage=key_usage, + cert_dps=cert_dps, ) int_b_cert_path: str = os.path.join(output_dir, f"{chain_name}.int.b.ca.der") write_der(int_b_cert_path, int_b_cert.public_bytes(Encoding.DER), force) @@ -971,6 +1026,7 @@ def _chain( subject_name=ca_subj, subject_key=root_key, key_usage=key_usage, + cert_dps=cert_dps, ) root_cert_path: str = os.path.join(output_dir, f"{chain_name}.root.ca.der") write_der(root_cert_path, root_cert.public_bytes(Encoding.DER), force) @@ -988,6 +1044,7 @@ def _crl( serials: Iterable[int], issuer_name: x509.Name, issuer_key: Optional[ANY_PRIV_KEY], + issuing_dp: Optional[x509.IssuingDistributionPoint] = None, ) -> x509.CertificateRevocationList: """ Generate a certificate revocation list. @@ -1015,6 +1072,8 @@ def _crl( crl_builder = crl_builder.add_revoked_certificate( revoked_cert_builder.build() ) + if issuing_dp is not None: + crl_builder = crl_builder.add_extension(issuing_dp, critical=True) crl_builder = crl_builder.add_extension( x509.CRLNumber(x509.random_serial_number()), critical=False ) @@ -1028,7 +1087,9 @@ def _revocation_test( *, test_name: str, chain: list[tuple[x509.Certificate, str, ANY_PRIV_KEY]], - crl_paths: Iterable[str], + crl_paths: list[str], + depth: ChainDepth, + policy: StatusRequirement, owned: bool, expected_error: Optional[str], ee_topbit_serial: bool = False, @@ -1065,7 +1126,24 @@ def _revocation_test( for path in crl_paths ] ) - crls: str = f"&[{crl_includes}]" + + if len(crl_paths) == 0: + revocation_setup = "let revocation = None;" + else: + revocation_setup = f""" + let crls = &[{crl_includes}]; + let builder = RevocationOptionsBuilder::new(crls).unwrap(); + """ + if depth == ChainDepth.END_ENTITY: + revocation_setup += """ + let builder = builder.with_depth(RevocationCheckDepth::EndEntity); + """ + if policy == StatusRequirement.ALLOW_UNKNOWN: + revocation_setup += """ + let builder = builder.allow_unknown_status(); + """ + revocation_setup += "let revocation = Some(builder.build());" + expected: str = ( f"Err(webpki::Error::{expected_error})" if expected_error else "Ok(())" ) @@ -1079,8 +1157,8 @@ def _revocation_test( let ee = include_bytes!("%(ee_cert_path)s"); let intermediates = %(intermediates_str)s; let ca = include_bytes!("%(root_cert_path)s"); - let crls = %(crls)s; - assert_eq!(check_cert(ee, intermediates, ca, crls), %(expected)s); + %(revocation_setup)s + assert_eq!(check_cert(ee, intermediates, ca, revocation), %(expected)s); } """ % locals(), @@ -1088,34 +1166,43 @@ def _revocation_test( ) # Build a simple certificate chain where the issuers don't have a key usage specified. - no_ku_chain = _chain(chain_name="no_ku_chain", key_usage=None) + no_ku_chain = _chain(chain_name="no_ku_chain", key_usage=None, cert_dps=None) # Build a simple certificate chain where the issuers have key usage specified, but don't include the # cRLSign bit. - no_crl_ku_chain = _chain(chain_name="no_crl_ku_chain", key_usage=no_crl_sign_ku) + no_crl_ku_chain = _chain( + chain_name="no_crl_ku_chain", key_usage=no_crl_sign_ku, cert_dps=None + ) # Build a simple certificate chain where the issuers have key usage specified, and include the cRLSign bit. - crl_ku_chain = _chain(chain_name="ku_chain", key_usage=crl_sign_ku) + crl_ku_chain = _chain(chain_name="ku_chain", key_usage=crl_sign_ku, cert_dps=None) - def _no_crls_test_ee_depth() -> None: + # Build a certificate chain where each certificate has a CRL distribution point ext. + dp_chain = _chain(chain_name="dp_chain", key_usage=None, cert_dps=valid_cert_crl_dp) + + def _no_crls_test() -> None: # Providing no CRLs means the EE cert should verify without err. _revocation_test( - test_name="no_crls_test_ee_depth", + test_name="no_crls_test", chain=no_ku_chain, crl_paths=[], + depth=ChainDepth.END_ENTITY, # unused + policy=StatusRequirement.ALLOW_UNKNOWN, # unused owned=False, expected_error=None, ) _revocation_test( - test_name="no_crls_test_ee_depth_owned", + test_name="no_crls_test_owned", chain=no_ku_chain, crl_paths=[], + depth=ChainDepth.END_ENTITY, # unused + policy=StatusRequirement.ALLOW_UNKNOWN, # unused owned=True, expected_error=None, ) - def _no_relevant_crl_ee_depth() -> None: - test_name = "no_relevant_crl_ee_depth" + def _no_relevant_crl_ee_depth_allow_unknown() -> None: + test_name = "no_relevant_crl_ee_depth_allow_unknown" # Generate a CRL that includes the EE cert's serial, but that is issued by an unknown issuer. ee_cert = no_ku_chain[0][0] no_match_crl = _crl( @@ -1126,11 +1213,14 @@ def _no_relevant_crl_ee_depth() -> None: no_match_crl_path = os.path.join(output_dir, f"{test_name}.crl.der") write_der(no_match_crl_path, no_match_crl.public_bytes(Encoding.DER), force) - # Providing no relevant CRL means the EE cert should verify without err. + # Providing no relevant CRL and allowing unknown status + # means the EE cert should verify without err. _revocation_test( test_name=test_name, chain=no_ku_chain, crl_paths=[no_match_crl_path], + depth=ChainDepth.END_ENTITY, + policy=StatusRequirement.ALLOW_UNKNOWN, owned=False, expected_error=None, ) @@ -1138,6 +1228,8 @@ def _no_relevant_crl_ee_depth() -> None: test_name=test_name + "_owned", chain=no_ku_chain, crl_paths=[no_match_crl_path], + depth=ChainDepth.END_ENTITY, + policy=StatusRequirement.ALLOW_UNKNOWN, owned=True, expected_error=None, ) @@ -1165,6 +1257,8 @@ def _ee_not_revoked_ee_depth() -> None: test_name=test_name, chain=no_ku_chain, crl_paths=[ee_not_revoked_crl_path], + depth=ChainDepth.END_ENTITY, + policy=StatusRequirement.ALLOW_UNKNOWN, owned=False, expected_error=None, ) @@ -1172,6 +1266,8 @@ def _ee_not_revoked_ee_depth() -> None: test_name=test_name + "_owned", chain=no_ku_chain, crl_paths=[ee_not_revoked_crl_path], + depth=ChainDepth.END_ENTITY, + policy=StatusRequirement.ALLOW_UNKNOWN, owned=True, expected_error=None, ) @@ -1199,6 +1295,8 @@ def _ee_revoked_badsig_ee_depth() -> None: test_name=test_name, chain=no_ku_chain, crl_paths=[ee_revoked_badsig_path], + depth=ChainDepth.END_ENTITY, + policy=StatusRequirement.ALLOW_UNKNOWN, owned=False, expected_error="InvalidCrlSignatureForPublicKey", ) @@ -1206,6 +1304,8 @@ def _ee_revoked_badsig_ee_depth() -> None: test_name=test_name + "_owned", chain=no_ku_chain, crl_paths=[ee_revoked_badsig_path], + depth=ChainDepth.END_ENTITY, + policy=StatusRequirement.ALLOW_UNKNOWN, owned=True, expected_error="InvalidCrlSignatureForPublicKey", ) @@ -1230,6 +1330,8 @@ def _ee_revoked_wrong_ku_ee_depth() -> None: test_name=test_name, chain=no_crl_ku_chain, crl_paths=[ee_revoked_crl_path], + depth=ChainDepth.END_ENTITY, + policy=StatusRequirement.ALLOW_UNKNOWN, owned=False, expected_error="IssuerNotCrlSigner", ) @@ -1237,6 +1339,8 @@ def _ee_revoked_wrong_ku_ee_depth() -> None: test_name=test_name + "_owned", chain=no_crl_ku_chain, crl_paths=[ee_revoked_crl_path], + depth=ChainDepth.END_ENTITY, + policy=StatusRequirement.ALLOW_UNKNOWN, owned=True, expected_error="IssuerNotCrlSigner", ) @@ -1264,6 +1368,8 @@ def _ee_not_revoked_wrong_ku_ee_depth() -> None: test_name=test_name, chain=no_crl_ku_chain, crl_paths=[ee_not_revoked_crl_path], + depth=ChainDepth.END_ENTITY, + policy=StatusRequirement.ALLOW_UNKNOWN, owned=False, expected_error="IssuerNotCrlSigner", ) @@ -1271,6 +1377,8 @@ def _ee_not_revoked_wrong_ku_ee_depth() -> None: test_name=test_name + "_owned", chain=no_crl_ku_chain, crl_paths=[ee_not_revoked_crl_path], + depth=ChainDepth.END_ENTITY, + policy=StatusRequirement.ALLOW_UNKNOWN, owned=True, expected_error="IssuerNotCrlSigner", ) @@ -1295,6 +1403,8 @@ def _ee_revoked_no_ku_ee_depth() -> None: test_name=test_name, chain=no_ku_chain, crl_paths=[ee_revoked_crl_path], + depth=ChainDepth.END_ENTITY, + policy=StatusRequirement.ALLOW_UNKNOWN, owned=False, expected_error="CertRevoked", ) @@ -1302,6 +1412,8 @@ def _ee_revoked_no_ku_ee_depth() -> None: test_name=test_name + "_owned", chain=no_ku_chain, crl_paths=[ee_revoked_crl_path], + depth=ChainDepth.END_ENTITY, + policy=StatusRequirement.ALLOW_UNKNOWN, owned=True, expected_error="CertRevoked", ) @@ -1326,6 +1438,8 @@ def _ee_revoked_crl_ku_ee_depth() -> None: test_name=test_name, chain=crl_ku_chain, crl_paths=[ee_revoked_crl_path], + depth=ChainDepth.END_ENTITY, + policy=StatusRequirement.ALLOW_UNKNOWN, owned=False, expected_error="CertRevoked", ) @@ -1333,6 +1447,8 @@ def _ee_revoked_crl_ku_ee_depth() -> None: test_name=test_name + "_owned", chain=crl_ku_chain, crl_paths=[ee_revoked_crl_path], + depth=ChainDepth.END_ENTITY, + policy=StatusRequirement.ALLOW_UNKNOWN, owned=True, expected_error="CertRevoked", ) @@ -1343,6 +1459,8 @@ def _no_crls_test_chain_depth() -> None: test_name="no_crls_test_chain_depth", chain=no_ku_chain, crl_paths=[], + depth=ChainDepth.END_ENTITY, # unused + policy=StatusRequirement.ALLOW_UNKNOWN, # unused owned=False, expected_error=None, ) @@ -1359,11 +1477,13 @@ def _no_relevant_crl_chain_depth() -> None: no_match_crl_path = os.path.join(output_dir, f"{test_name}.crl.der") write_der(no_match_crl_path, no_match_crl.public_bytes(Encoding.DER), force) - # Providing no relevant CRL means the chain should verify without err. + # Providing no relevant CRL, and allowing unknown status, means the chain should verify without err. _revocation_test( test_name=test_name, chain=no_ku_chain, crl_paths=[no_match_crl_path], + depth=ChainDepth.CHAIN, + policy=StatusRequirement.ALLOW_UNKNOWN, owned=False, expected_error=None, ) @@ -1371,6 +1491,8 @@ def _no_relevant_crl_chain_depth() -> None: test_name=test_name + "_owned", chain=no_ku_chain, crl_paths=[no_match_crl_path], + depth=ChainDepth.CHAIN, + policy=StatusRequirement.ALLOW_UNKNOWN, owned=True, expected_error=None, ) @@ -1398,6 +1520,8 @@ def _int_not_revoked_chain_depth() -> None: test_name=test_name, chain=no_ku_chain, crl_paths=[int_not_revoked_crl_path], + depth=ChainDepth.CHAIN, + policy=StatusRequirement.ALLOW_UNKNOWN, owned=False, expected_error=None, ) @@ -1405,6 +1529,8 @@ def _int_not_revoked_chain_depth() -> None: test_name=test_name + "_owned", chain=no_ku_chain, crl_paths=[int_not_revoked_crl_path], + depth=ChainDepth.CHAIN, + policy=StatusRequirement.ALLOW_UNKNOWN, owned=True, expected_error=None, ) @@ -1429,11 +1555,13 @@ def _int_revoked_badsig_chain_depth() -> None: force, ) - # Providing a relevant CRL that includes the EE cert serial but does not verify should error. + # Providing a relevant CRL that includes the intermediate cert's serial but does not verify should error. _revocation_test( test_name=test_name, chain=no_ku_chain, crl_paths=[int_revoked_badsig_path], + depth=ChainDepth.CHAIN, + policy=StatusRequirement.ALLOW_UNKNOWN, owned=False, expected_error="InvalidCrlSignatureForPublicKey", ) @@ -1441,6 +1569,8 @@ def _int_revoked_badsig_chain_depth() -> None: test_name=test_name + "_owned", chain=no_ku_chain, crl_paths=[int_revoked_badsig_path], + depth=ChainDepth.CHAIN, + policy=StatusRequirement.ALLOW_UNKNOWN, owned=True, expected_error="InvalidCrlSignatureForPublicKey", ) @@ -1467,6 +1597,8 @@ def _int_revoked_wrong_ku_chain_depth() -> None: test_name=test_name, chain=no_crl_ku_chain, crl_paths=[int_revoked_crl_path], + depth=ChainDepth.CHAIN, + policy=StatusRequirement.ALLOW_UNKNOWN, owned=False, expected_error="IssuerNotCrlSigner", ) @@ -1474,6 +1606,8 @@ def _int_revoked_wrong_ku_chain_depth() -> None: test_name=test_name + "_owned", chain=no_crl_ku_chain, crl_paths=[int_revoked_crl_path], + depth=ChainDepth.CHAIN, + policy=StatusRequirement.ALLOW_UNKNOWN, owned=True, expected_error="IssuerNotCrlSigner", ) @@ -1498,6 +1632,8 @@ def _ee_revoked_chain_depth() -> None: test_name=test_name, chain=no_ku_chain, crl_paths=[ee_revoked_crl_path], + depth=ChainDepth.CHAIN, + policy=StatusRequirement.ALLOW_UNKNOWN, owned=False, expected_error="CertRevoked", ) @@ -1505,6 +1641,8 @@ def _ee_revoked_chain_depth() -> None: test_name=test_name + "_owned", chain=no_ku_chain, crl_paths=[ee_revoked_crl_path], + depth=ChainDepth.CHAIN, + policy=StatusRequirement.ALLOW_UNKNOWN, owned=True, expected_error="CertRevoked", ) @@ -1531,6 +1669,8 @@ def _int_revoked_no_ku_chain_depth() -> None: test_name=test_name, chain=no_ku_chain, crl_paths=[int_revoked_crl_path], + depth=ChainDepth.CHAIN, + policy=StatusRequirement.ALLOW_UNKNOWN, owned=False, expected_error="CertRevoked", ) @@ -1538,6 +1678,8 @@ def _int_revoked_no_ku_chain_depth() -> None: test_name=test_name + "_owned", chain=no_ku_chain, crl_paths=[int_revoked_crl_path], + depth=ChainDepth.CHAIN, + policy=StatusRequirement.ALLOW_UNKNOWN, owned=True, expected_error="CertRevoked", ) @@ -1564,6 +1706,8 @@ def _int_revoked_crl_ku_chain_depth() -> None: test_name=test_name, chain=crl_ku_chain, crl_paths=[int_revoked_crl_path], + depth=ChainDepth.CHAIN, + policy=StatusRequirement.ALLOW_UNKNOWN, owned=False, expected_error="CertRevoked", ) @@ -1571,6 +1715,8 @@ def _int_revoked_crl_ku_chain_depth() -> None: test_name=test_name + "_owned", chain=crl_ku_chain, crl_paths=[int_revoked_crl_path], + depth=ChainDepth.CHAIN, + policy=StatusRequirement.ALLOW_UNKNOWN, owned=True, expected_error="CertRevoked", ) @@ -1593,6 +1739,8 @@ def _ee_with_top_bit_set_serial_revoked() -> None: test_name=test_name, chain=crl_ku_chain, crl_paths=[ee_revoked_crl_path], + depth=ChainDepth.CHAIN, + policy=StatusRequirement.ALLOW_UNKNOWN, owned=False, ee_topbit_serial=True, expected_error="CertRevoked", @@ -1601,14 +1749,423 @@ def _ee_with_top_bit_set_serial_revoked() -> None: test_name=test_name + "_owned", chain=crl_ku_chain, crl_paths=[ee_revoked_crl_path], + depth=ChainDepth.CHAIN, + policy=StatusRequirement.ALLOW_UNKNOWN, owned=True, ee_topbit_serial=True, expected_error="CertRevoked", ) + def _ee_no_dp_crl_idp() -> None: + test_name = "ee_no_dp_crl_idp" + # Use a chain that has no CRL distribution point in each cert. + ee_cert = no_ku_chain[0][0] + int_a_key = no_ku_chain[1][2] + # Generate a CRL that has a matching issuer, and an issuing distribution point. + ee_idp_crl = _crl( + serials=[0xFFFF], + issuer_name=ee_cert.issuer, + issuer_key=int_a_key, + issuing_dp=valid_crl_idp, + ) + ee_idp_crl_path = os.path.join(output_dir, f"{test_name}.crl.der") + write_der(ee_idp_crl_path, ee_idp_crl.public_bytes(Encoding.DER), force) + + # Checking revocation and not allowing unknown status shouldn't error - the CRL + # is relevant because the certs have no DP. + _revocation_test( + test_name=test_name, + chain=no_ku_chain, + crl_paths=[ee_idp_crl_path], + depth=ChainDepth.END_ENTITY, + policy=StatusRequirement.FORBID_UNKNOWN, + owned=False, + expected_error=None, + ) + _revocation_test( + test_name=test_name + "_owned", + chain=no_ku_chain, + crl_paths=[ee_idp_crl_path], + depth=ChainDepth.END_ENTITY, + policy=StatusRequirement.FORBID_UNKNOWN, + owned=True, + expected_error=None, + ) + + def _ee_crl_no_idp_unknown_status() -> None: + test_name = "ee_crl_no_idp_unknown_status" + # Use the chain that has a CRL distribution point in each cert. + ee_cert = dp_chain[0][0] + int_a_key = dp_chain[1][2] + # Generate a CRL that has a matching issuer, but no issuing distribution point. + ee_no_idp_crl = _crl( + serials=[0xFFFF], + issuer_name=ee_cert.issuer, + issuer_key=int_a_key, + ) + ee_no_idp_crl_path = os.path.join(output_dir, f"{test_name}.crl.der") + write_der(ee_no_idp_crl_path, ee_no_idp_crl.public_bytes(Encoding.DER), force) + + # Checking revocation and not allowing unknown status should error - the CRL + # isn't relevant because it's missing a CRL IDP to match the cert DP. + _revocation_test( + test_name=test_name, + chain=dp_chain, + crl_paths=[ee_no_idp_crl_path], + depth=ChainDepth.END_ENTITY, + policy=StatusRequirement.FORBID_UNKNOWN, + owned=False, + expected_error="UnknownRevocationStatus", + ) + _revocation_test( + test_name=test_name + "_owned", + chain=dp_chain, + crl_paths=[ee_no_idp_crl_path], + depth=ChainDepth.END_ENTITY, + policy=StatusRequirement.FORBID_UNKNOWN, + owned=True, + expected_error="UnknownRevocationStatus", + ) + + def _ee_crl_mismatched_idp_unknown_status() -> None: + test_name = "ee_crl_mismatched_idp_unknown_status" + # Use the chain that has a CRL distribution point in each cert. + ee_cert = dp_chain[0][0] + int_a_key = dp_chain[1][2] + # Generate a CRL that has a matching issuer, but no matching issuing distribution point. + ee_wrong_idp_crl = _crl( + serials=[0xFFFF], + issuer_name=ee_cert.issuer, + issuer_key=int_a_key, + issuing_dp=x509.IssuingDistributionPoint( + full_name=[ + x509.UniformResourceIdentifier("http://does.not.match.example.com") + ], + indirect_crl=False, + relative_name=None, + only_contains_attribute_certs=False, + only_contains_ca_certs=False, + only_contains_user_certs=False, + only_some_reasons=None, + ), + ) + ee_wrong_idp_crl_path = os.path.join(output_dir, f"{test_name}.crl.der") + write_der( + ee_wrong_idp_crl_path, ee_wrong_idp_crl.public_bytes(Encoding.DER), force + ) + + # Checking revocation and not allowing unknown status should error - the CRL + # isn't relevant because its CRL IDP doesn't match the cert DP. + _revocation_test( + test_name=test_name, + chain=dp_chain, + crl_paths=[ee_wrong_idp_crl_path], + depth=ChainDepth.END_ENTITY, + policy=StatusRequirement.FORBID_UNKNOWN, + owned=False, + expected_error="UnknownRevocationStatus", + ) + _revocation_test( + test_name=test_name + "_owned", + chain=dp_chain, + crl_paths=[ee_wrong_idp_crl_path], + depth=ChainDepth.END_ENTITY, + policy=StatusRequirement.FORBID_UNKNOWN, + owned=True, + expected_error="UnknownRevocationStatus", + ) + + def _ee_indirect_dp_unknown_status() -> None: + test_name = "ee_indirect_dp_unknown_status" + indirect_dp_chain = _chain( + chain_name="indirect_dp_chain", + key_usage=None, + cert_dps=x509.DistributionPoint( + full_name=valid_cert_crl_dp.full_name, + relative_name=None, + reasons=None, + crl_issuer=[x509.DNSName("indirect.example.com")], + ), + ) + # Use the chain that has an indirect CRL distribution point in each cert. + ee_cert = indirect_dp_chain[0][0] + int_a_key = indirect_dp_chain[1][2] + # Generate a CRL that has a matching issuer, and an issuing distribution point + # that would match if the DP wasn't for an indirect CRL. + ee_indirect_dp_unknown_status_crl = _crl( + serials=[0xFFFF], + issuer_name=ee_cert.issuer, + issuer_key=int_a_key, + issuing_dp=x509.IssuingDistributionPoint( + full_name=valid_cert_crl_dp.full_name, + indirect_crl=False, + relative_name=None, + only_contains_attribute_certs=False, + only_contains_ca_certs=False, + only_contains_user_certs=False, + only_some_reasons=None, + ), + ) + ee_indirect_dp_unknown_status_crl_path = os.path.join( + output_dir, f"{test_name}.crl.der" + ) + write_der( + ee_indirect_dp_unknown_status_crl_path, + ee_indirect_dp_unknown_status_crl.public_bytes(Encoding.DER), + force, + ) + + # Checking revocation and not allowing unknown status should error - the CRL + # isn't relevant because the cert DP requires an indirect CRL. + _revocation_test( + test_name=test_name, + chain=indirect_dp_chain, + crl_paths=[ee_indirect_dp_unknown_status_crl_path], + depth=ChainDepth.END_ENTITY, + policy=StatusRequirement.FORBID_UNKNOWN, + owned=False, + expected_error="UnknownRevocationStatus", + ) + _revocation_test( + test_name=test_name + "_owned", + chain=indirect_dp_chain, + crl_paths=[ee_indirect_dp_unknown_status_crl_path], + depth=ChainDepth.END_ENTITY, + policy=StatusRequirement.FORBID_UNKNOWN, + owned=True, + expected_error="UnknownRevocationStatus", + ) + + def _ee_reasons_dp_unknown_status() -> None: + test_name = "ee_reasons_dp_unknown_status" + reasons_dp_chain = _chain( + chain_name="reasons_dp_chain", + key_usage=None, + cert_dps=x509.DistributionPoint( + full_name=valid_cert_crl_dp.full_name, + relative_name=None, + reasons=frozenset([x509.ReasonFlags.key_compromise]), + crl_issuer=None, + ), + ) + # Use the chain that has a CRL distribution point in each cert that indicates + # sharding by revocation reason. + ee_cert = reasons_dp_chain[0][0] + int_a_key = reasons_dp_chain[1][2] + # Generate a CRL that has a matching issuer, and an issuing distribution point + # that would match if the DP wasn't for a reason-sharded CRL. + ee_reasons_dp_unknown_status_crl = _crl( + serials=[0xFFFF], + issuer_name=ee_cert.issuer, + issuer_key=int_a_key, + issuing_dp=x509.IssuingDistributionPoint( + full_name=valid_cert_crl_dp.full_name, + indirect_crl=False, + relative_name=None, + only_contains_attribute_certs=False, + only_contains_ca_certs=False, + only_contains_user_certs=False, + only_some_reasons=None, + ), + ) + ee_reasons_dp_unknown_status_crl_path = os.path.join( + output_dir, f"{test_name}.crl.der" + ) + write_der( + ee_reasons_dp_unknown_status_crl_path, + ee_reasons_dp_unknown_status_crl.public_bytes(Encoding.DER), + force, + ) + + # Checking revocation and not allowing unknown status should error - the CRL + # isn't relevant because the cert DP requires a CRL sharded by revocation reason. + _revocation_test( + test_name=test_name, + chain=reasons_dp_chain, + crl_paths=[ee_reasons_dp_unknown_status_crl_path], + depth=ChainDepth.END_ENTITY, + policy=StatusRequirement.FORBID_UNKNOWN, + owned=False, + expected_error="UnknownRevocationStatus", + ) + _revocation_test( + test_name=test_name + "_owned", + chain=reasons_dp_chain, + crl_paths=[ee_reasons_dp_unknown_status_crl_path], + depth=ChainDepth.END_ENTITY, + policy=StatusRequirement.FORBID_UNKNOWN, + owned=True, + expected_error="UnknownRevocationStatus", + ) + + def _ee_nofullname_dp_unknown_status() -> None: + test_name = "ee_nofullname_dp_unknown_status" + nofullname_dp_chain = _chain( + chain_name="nofullname_dp_chain", + key_usage=None, + cert_dps=x509.DistributionPoint( + full_name=None, + relative_name=x509.RelativeDistinguishedName( + [x509.NameAttribute(NameOID.COMMON_NAME, "example.com")] + ), + reasons=None, + crl_issuer=None, + ), + ) + # Use the chain that has a CRL distribution point in each cert that has no full name. + ee_cert = nofullname_dp_chain[0][0] + int_a_key = nofullname_dp_chain[1][2] + # Generate a CRL that has a matching issuer, and an issuing distribution point + # that would match if the DP wasn't for a relative-name CRL issuer. + ee_nofullname_dp_unknown_status_crl = _crl( + serials=[0xFFFF], + issuer_name=ee_cert.issuer, + issuer_key=int_a_key, + issuing_dp=x509.IssuingDistributionPoint( + full_name=valid_cert_crl_dp.full_name, + indirect_crl=False, + relative_name=None, + only_contains_attribute_certs=False, + only_contains_ca_certs=False, + only_contains_user_certs=False, + only_some_reasons=None, + ), + ) + ee_nofullname_dp_unknown_status_crl_path = os.path.join( + output_dir, f"{test_name}.crl.der" + ) + write_der( + ee_nofullname_dp_unknown_status_crl_path, + ee_nofullname_dp_unknown_status_crl.public_bytes(Encoding.DER), + force, + ) + + # Checking revocation and not allowing unknown status should error - the CRL + # isn't relevant because the cert DP requires a CRL with a name relative to an issuer. + _revocation_test( + test_name=test_name, + chain=nofullname_dp_chain, + crl_paths=[ee_nofullname_dp_unknown_status_crl_path], + depth=ChainDepth.END_ENTITY, + policy=StatusRequirement.FORBID_UNKNOWN, + owned=False, + expected_error="UnknownRevocationStatus", + ) + _revocation_test( + test_name=test_name + "_owned", + chain=nofullname_dp_chain, + crl_paths=[ee_nofullname_dp_unknown_status_crl_path], + depth=ChainDepth.END_ENTITY, + policy=StatusRequirement.FORBID_UNKNOWN, + owned=True, + expected_error="UnknownRevocationStatus", + ) + + def _ee_dp_idp_match() -> None: + test_name = "ee_dp_idp_match" + # Use the chain that has a CRL distribution point in each cert. + ee_cert = dp_chain[0][0] + int_a_key = dp_chain[1][2] + # Generate a CRL that has a matching issuer, and an issuing distribution point + # that matches too. + ee_dp_idp_match_crl = _crl( + serials=[0xFFFF], + issuer_name=ee_cert.issuer, + issuer_key=int_a_key, + issuing_dp=x509.IssuingDistributionPoint( + full_name=valid_cert_crl_dp.full_name, + indirect_crl=False, + relative_name=None, + only_contains_attribute_certs=False, + only_contains_ca_certs=False, + only_contains_user_certs=False, + only_some_reasons=None, + ), + ) + ee_dp_idp_match_crl_path = os.path.join(output_dir, f"{test_name}.crl.der") + write_der( + ee_dp_idp_match_crl_path, + ee_dp_idp_match_crl.public_bytes(Encoding.DER), + force, + ) + + # Checking revocation and not allowing unknown status shouldn't error - the CRL + # covers the cert, and it isn't revoked. + _revocation_test( + test_name=test_name, + chain=dp_chain, + crl_paths=[ee_dp_idp_match_crl_path], + depth=ChainDepth.END_ENTITY, + policy=StatusRequirement.FORBID_UNKNOWN, + owned=False, + expected_error=None, + ) + _revocation_test( + test_name=test_name + "_owned", + chain=dp_chain, + crl_paths=[ee_dp_idp_match_crl_path], + depth=ChainDepth.END_ENTITY, + policy=StatusRequirement.FORBID_UNKNOWN, + owned=True, + expected_error=None, + ) + + def _ee_dp_invalid() -> None: + test_name = "ee_dp_invalid" + bad_dp = x509.DistributionPoint( + full_name=valid_cert_crl_dp.full_name, + relative_name=None, + reasons=frozenset([x509.ReasonFlags.key_compromise]), + crl_issuer=None, + ) + # The __init__ constructor forbids omitting the full_name, relative_name and full_issuer, so + # patch it after construction to be in an invalid state. + bad_dp._full_name = None + invalid_dp_chain = _chain( + chain_name="invalid_dp_chain", + key_usage=None, + cert_dps=bad_dp, + ) + ee_cert = invalid_dp_chain[0][0] + int_a_key = invalid_dp_chain[1][2] + # Generate a CRL with an IDP extension. + invalid_dp_chain_crl = _crl( + serials=[0xFFFF], + issuer_name=ee_cert.issuer, + issuer_key=int_a_key, + issuing_dp=valid_crl_idp, + ) + invalid_dp_chain_crl_path = os.path.join(output_dir, f"{test_name}.crl.der") + write_der( + invalid_dp_chain_crl_path, + invalid_dp_chain_crl.public_bytes(Encoding.DER), + force, + ) + + # Checking revocation should result in an unknown revocation status - the certificate DP is invalid + # so we can't match it to any CRL IDP. + _revocation_test( + test_name=test_name, + chain=invalid_dp_chain, + crl_paths=[invalid_dp_chain_crl_path], + depth=ChainDepth.END_ENTITY, + policy=StatusRequirement.FORBID_UNKNOWN, + owned=False, + expected_error="UnknownRevocationStatus", + ) + _revocation_test( + test_name=test_name + "_owned", + chain=invalid_dp_chain, + crl_paths=[invalid_dp_chain_crl_path], + depth=ChainDepth.END_ENTITY, + policy=StatusRequirement.FORBID_UNKNOWN, + owned=True, + expected_error="UnknownRevocationStatus", + ) + with trim_top("client_auth_revocation.rs") as output: - _no_crls_test_ee_depth() - _no_relevant_crl_ee_depth() + _no_crls_test() + _no_relevant_crl_ee_depth_allow_unknown() _ee_not_revoked_ee_depth() _ee_revoked_badsig_ee_depth() _ee_revoked_wrong_ku_ee_depth() @@ -1624,6 +2181,14 @@ def _ee_with_top_bit_set_serial_revoked() -> None: _int_revoked_no_ku_chain_depth() _int_revoked_crl_ku_chain_depth() _ee_with_top_bit_set_serial_revoked() + _ee_no_dp_crl_idp() + _ee_crl_no_idp_unknown_status() + _ee_crl_mismatched_idp_unknown_status() + _ee_indirect_dp_unknown_status() + _ee_reasons_dp_unknown_status() + _ee_nofullname_dp_unknown_status() + _ee_dp_idp_match() + _ee_dp_invalid() if __name__ == "__main__":