use rpki::data_model::crl::{CrlDecodeError, CrlVerifyError, RpkixCrl}; use x509_parser::prelude::FromDer; use x509_parser::prelude::X509Certificate; const TEST_NO_CRLSIGN_CERT_DER_B64: &str = "MIIDATCCAemgAwIBAgIUCyQLQJn92+gyAzvIz22q1F/97OMwDQYJKoZIhvcNAQELBQAwGjEYMBYGA1UEAwwPVGVzdCBObyBDUkxTaWduMB4XDTI2MDEyNzAzNTk1OVoXDTM2MDEyNTAzNTk1OVowGjEYMBYGA1UEAwwPVGVzdCBObyBDUkxTaWduMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr/aoMU8J6cddkM2r6F2snd1rCdQPepgo2T2lrqWFcxnQJdcxBL1OYg3wFi95TJmZSeIHIOGauDaJ2abmjgyOUHOC4U68x66JRg4hLkmLxo1cf3uYHWl9Obph6g2qPRvN80ORq70JPuL6mAfUkNiO9hnwK6oQiTzc/rjCQGIFH8kTESBMXLfNCyUpGi+MNztYH6Ha6bKAQuXgd29OFwIkOlGQnYgGC2qBMvnp86eITvV1gTiuI8Ho9m9nZHCmaD7TylvkMDq8Hk5nkIpRcG0uO60SkR2BiMOYe/TNn5dTmHd6bsdbU2GOvgnq1SnqGq3FOWhKIe3ycUJde0uNfZOqRwIDAQABoz8wPTAOBgNVHQ8BAf8EBAMCBaAwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUFjyzfJCDNhFfKxVr06kjUkE23dMwDQYJKoZIhvcNAQELBQADggEBAK98n2gVlwKA3Ob1YeAm9f+8hm7pbvrt0tA8GW180CILjf09k7fKgiRlxqGdZ9ySXjU52+zCqu3MpBXVbI87ZC+zA6uK05n4y1F0n85MJ9hGR2UEiPcqou85X73LvioynnSOy/OV1PjKJXReUsqF3GgDtgcMyFssPJ9s/5DWuUCScUJY6pu0kuIGOLQ/oXUw4TvxUeyz73gOTiAJshVTQoLpHUhj0595S7lArjwi7oLI1b8m8guTknvhk0Sc3tJZmUqOcIvYIs0guHpaeC+sMoF4K+6UTrxxOBdX+fUEWNpUyYXWHjdZq25PbJdHwA/VAW2zYVojaVREligf0Qfo6F4="; fn test_no_crlsign_cert_der() -> Vec { use base64::{engine::general_purpose, Engine as _}; general_purpose::STANDARD .decode(TEST_NO_CRLSIGN_CERT_DER_B64) .expect("decode base64 cert") } #[test] fn verify_errors_are_reported() { let crl_der = std::fs::read( "tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/05FC9C5B88506F7C0D3F862C8895BED67E9F8EBA.crl", ) .expect("read CRL fixture"); let issuer_cert_der = std::fs::read( "tests/fixtures/repository/rpki.apnic.net/repository/B527EF581D6611E2BB468F7C72FD1FF2/BfycW4hQb3wNP4YsiJW-1n6fjro.cer", ) .expect("read issuer cert"); let mut crl = RpkixCrl::decode_der(&crl_der).expect("decode"); // IssuerSubjectMismatch. crl.issuer_dn = "CN=Not The Issuer".to_string(); let err = crl .verify_signature_with_issuer_certificate_der(&issuer_cert_der) .unwrap_err(); assert!(matches!(err, CrlVerifyError::IssuerSubjectMismatch { .. })); // AkiSkiMismatch (force issuer dn to match, then change AKI). let (_rem, issuer_cert) = X509Certificate::from_der(&issuer_cert_der).unwrap(); crl.issuer_dn = issuer_cert.subject().to_string(); crl.extensions.authority_key_identifier = vec![0u8; 20]; let err = crl .verify_signature_with_issuer_certificate_der(&issuer_cert_der) .unwrap_err(); assert!(matches!(err, CrlVerifyError::AkiSkiMismatch)); // IssuerKeyUsageMissingCrlSign (use a cert with KeyUsage present but without CRLSign). let no_crlsign_der = test_no_crlsign_cert_der(); let (_rem, no_crlsign_cert) = X509Certificate::from_der(&no_crlsign_der).unwrap(); crl.issuer_dn = no_crlsign_cert.subject().to_string(); let err = crl .verify_signature_with_issuer_certificate_der(&no_crlsign_der) .unwrap_err(); assert!(matches!(err, CrlVerifyError::IssuerKeyUsageMissingCrlSign)); // InvalidSignature: verify cryptographically with the wrong SPKI. let no_crlsign_spki_der = no_crlsign_cert.public_key().raw.to_vec(); let err = crl .verify_signature_with_issuer_spki_der(&no_crlsign_spki_der) .unwrap_err(); assert!(matches!(err, CrlVerifyError::InvalidSignature(_))); // IssuerCertificateParse / trailing bytes. let err = crl .verify_signature_with_issuer_certificate_der(b"not a cert") .unwrap_err(); assert!(matches!(err, CrlVerifyError::IssuerCertificateParse(_))); let mut bad = issuer_cert_der.clone(); bad.push(0); let err = crl .verify_signature_with_issuer_certificate_der(&bad) .unwrap_err(); assert!(matches!(err, CrlVerifyError::IssuerCertificateTrailingBytes(1))); } #[test] fn verify_signature_with_spki_der_paths() { let crl_der = std::fs::read( "tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/05FC9C5B88506F7C0D3F862C8895BED67E9F8EBA.crl", ) .expect("read CRL fixture"); let issuer_cert_der = std::fs::read( "tests/fixtures/repository/rpki.apnic.net/repository/B527EF581D6611E2BB468F7C72FD1FF2/BfycW4hQb3wNP4YsiJW-1n6fjro.cer", ) .expect("read issuer cert"); let crl = RpkixCrl::decode_der(&crl_der).expect("decode"); let (_rem, issuer_cert) = X509Certificate::from_der(&issuer_cert_der).unwrap(); let spki_der = issuer_cert.public_key().raw.to_vec(); crl.verify_signature_with_issuer_spki_der(&spki_der) .expect("verify with spki der"); let mut bad = spki_der; bad.push(0); let err = crl.verify_signature_with_issuer_spki_der(&bad).unwrap_err(); assert!(matches!(err, CrlVerifyError::IssuerSpkiTrailingBytes(1))); } #[test] fn decode_rejects_trailing_bytes() { let crl_der = std::fs::read( "tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/05FC9C5B88506F7C0D3F862C8895BED67E9F8EBA.crl", ) .expect("read CRL fixture"); let mut bad = crl_der.clone(); bad.push(0); let err = RpkixCrl::decode_der(&bad).unwrap_err(); assert!(matches!(err, CrlDecodeError::TrailingBytes(1))); } #[test] fn verify_rejects_crl_with_trailing_bytes_in_raw_der() { let crl_der = std::fs::read( "tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/05FC9C5B88506F7C0D3F862C8895BED67E9F8EBA.crl", ) .expect("read CRL fixture"); let issuer_cert_der = std::fs::read( "tests/fixtures/repository/rpki.apnic.net/repository/B527EF581D6611E2BB468F7C72FD1FF2/BfycW4hQb3wNP4YsiJW-1n6fjro.cer", ) .expect("read issuer cert"); let mut crl = RpkixCrl::decode_der(&crl_der).expect("decode"); crl.raw_der.push(0); let (_rem, issuer_cert) = X509Certificate::from_der(&issuer_cert_der).unwrap(); let spki_der = issuer_cert.public_key().raw.to_vec(); let err = crl.verify_signature_with_issuer_spki_der(&spki_der).unwrap_err(); assert!(matches!(err, CrlVerifyError::CrlTrailingBytes(1))); }