Files
firewall/core/tests/mitm.rs
ian-at-strixandIan Graham Martinez a2e6d3f72f Sign an empty CRL and point leaves at it (#8)
schannel's revocation check, which cargo enables, fails closed on a leaf
without a reachable CRL. The CA gains cRLSign, which rcgen needs to sign
one, and leaves carry a distribution point when the platform serves it.

Co-authored-by: Ian Graham Martinez <[email protected]>
2026-10-13 11:11:25 -04:00

53 lines
2.0 KiB
Rust

use firewall::mitm;
use rcgen::KeyPair;
fn signer() -> KeyPair {
KeyPair::generate().expect("generate a key")
}
/// The name constraint is what scopes a machine-wide trust anchor, and only if critical.
#[test]
fn minted_ca_is_name_constrained() {
let hosts = ["registry.npmjs.org", "pypi.org"];
let ca = mitm::CertificateAuthority::generate(&hosts, &signer()).expect("mint a ca");
let der = ca.crt.to_der().expect("re-encode the certificate");
// SEQUENCE { OID 2.5.29.30, BOOLEAN TRUE, ... }
let critical_name_constraints = [0x06, 0x03, 0x55, 0x1d, 0x1e, 0x01, 0x01, 0xff];
assert!(der.windows(8).any(|w| w == critical_name_constraints));
for host in hosts {
assert!(der.windows(host.len()).any(|w| w == host.as_bytes()), "{host} missing");
}
}
/// A stored CA must survive a restart, but never be reused for a different host set.
#[test]
fn stored_ca_round_trips_and_rejects_a_changed_host_set() {
let hosts = ["registry.npmjs.org", "pypi.org"];
let signer = signer();
let ca = mitm::CertificateAuthority::generate(&hosts, &signer);
let blob = ca.expect("mint a ca").to_blob(&hosts);
let restored = mitm::CertificateAuthority::from_blob(&blob, &hosts, &signer);
assert_eq!(restored.expect("restore the ca").to_blob(&hosts), blob);
assert!(mitm::CertificateAuthority::from_blob(&blob, &["npmjs.org"], &signer).is_none());
}
/// Leaves signed by a different key would not verify against the stored certificate.
#[test]
fn stored_ca_is_rejected_when_the_signing_key_changed() {
let hosts = ["registry.npmjs.org", "pypi.org"];
let ca = mitm::CertificateAuthority::generate(&hosts, &signer());
let blob = ca.expect("mint a ca").to_blob(&hosts);
assert!(mitm::CertificateAuthority::from_blob(&blob, &hosts, &signer()).is_none());
}
/// rcgen signs a CRL only for a CA with cRLSign, and schannel wants one for every leaf.
#[test]
fn ca_signs_an_empty_crl() {
let crl = mitm::crl(&["registry.npmjs.org", "pypi.org"], &signer()).expect("sign a crl");
assert_eq!(crl[0], 0x30, "a DER SEQUENCE");
}