use secure_network::cert_pin::*;
use security_events::kind::EventKind;
use security_events::sink::InMemorySink;
fn test_cert_der() -> Vec<u8> {
include_bytes!("testdata/test_cert.der").to_vec()
}
fn spki_hash_of(cert_der: &[u8]) -> [u8; 32] {
CertPinValidator::spki_hash(cert_der).expect("valid test cert")
}
#[test]
fn pinned_cert_matches_spki_hash() {
let cert_der = test_cert_der();
let hash = spki_hash_of(&cert_der);
let mut pin_set = PinSet::new();
pin_set.add_pin(hash);
let validator = CertPinValidator::new(pin_set);
assert_eq!(validator.validate_der(&cert_der), CertPinResult::Valid);
}
#[test]
fn pinned_cert_does_not_match() {
let cert_der = test_cert_der();
let wrong_hash = [0xFFu8; 32];
let mut pin_set = PinSet::new();
pin_set.add_pin(wrong_hash);
let validator = CertPinValidator::new(pin_set);
let sink = InMemorySink::new();
let result = validator.validate_der_and_emit(&cert_der, &sink);
assert_eq!(result, CertPinResult::PinMismatch);
let events = sink.events();
assert_eq!(events.len(), 1);
assert_eq!(events[0].kind, EventKind::CertPinFailure);
assert_eq!(events[0].reason_code, Some("cert_pin_mismatch"));
}
#[test]
fn multiple_pins_one_matches() {
let cert_der = test_cert_der();
let correct_hash = spki_hash_of(&cert_der);
let mut pin_set = PinSet::new();
pin_set.add_pin([0xAAu8; 32]);
pin_set.add_pin([0xBBu8; 32]);
pin_set.add_pin(correct_hash);
let validator = CertPinValidator::new(pin_set);
assert_eq!(validator.validate_der(&cert_der), CertPinResult::Valid);
}
#[test]
fn empty_pin_set_returns_no_pins_configured() {
let cert_der = test_cert_der();
let pin_set = PinSet::new();
let validator = CertPinValidator::new(pin_set);
assert_eq!(
validator.validate_der(&cert_der),
CertPinResult::NoPinsConfigured
);
}
#[test]
fn expired_cert_detected() {
let cert_der = test_cert_der();
let hash = spki_hash_of(&cert_der);
let mut pin_set = PinSet::new();
pin_set.add_pin(hash);
let validator = CertPinValidator::new(pin_set).with_expiry_check(true);
let far_future = time::OffsetDateTime::from_unix_timestamp(4_102_444_800).unwrap();
let sink = InMemorySink::new();
let result = validator.validate_der_at_and_emit(&cert_der, far_future, &sink);
assert_eq!(result, CertPinResult::Expired);
let events = sink.events();
assert_eq!(events.len(), 1);
assert_eq!(events[0].kind, EventKind::CertPinFailure);
assert_eq!(events[0].reason_code, Some("cert_expired"));
}
#[test]
fn certificate_chain_validation_with_pinned_leaf() {
let cert_der = test_cert_der();
let correct_hash = spki_hash_of(&cert_der);
let mut pin_set = PinSet::new();
pin_set.add_pin(correct_hash);
let validator = CertPinValidator::new(pin_set);
let chain: Vec<&[u8]> = vec![&cert_der];
assert_eq!(validator.validate_chain(&chain), CertPinResult::Valid);
}
#[test]
fn empty_chain_fails() {
let mut pin_set = PinSet::new();
pin_set.add_pin([0xAAu8; 32]);
let validator = CertPinValidator::new(pin_set);
let chain: Vec<&[u8]> = vec![];
assert_eq!(validator.validate_chain(&chain), CertPinResult::PinMismatch);
}
#[test]
fn pin_set_from_hex_hashes() {
let hex = "0102030405060708091011121314151617181920212223242526272829303132";
let pin_set = PinSet::from_hex_hashes(&[hex]).unwrap();
assert_eq!(pin_set.len(), 1);
}
#[test]
fn pin_set_from_invalid_hex_errors() {
let result = PinSet::from_hex_hashes(&["not-valid-hex"]);
assert!(result.is_err());
}
#[test]
fn no_event_on_valid_pin() {
let cert_der = test_cert_der();
let hash = spki_hash_of(&cert_der);
let mut pin_set = PinSet::new();
pin_set.add_pin(hash);
let validator = CertPinValidator::new(pin_set);
let sink = InMemorySink::new();
let result = validator.validate_der_and_emit(&cert_der, &sink);
assert_eq!(result, CertPinResult::Valid);
assert!(sink.events().is_empty());
}
#[test]
fn invalid_der_returns_pin_mismatch() {
let mut pin_set = PinSet::new();
pin_set.add_pin([0xAAu8; 32]);
let validator = CertPinValidator::new(pin_set);
assert_eq!(
validator.validate_der(b"not a valid cert"),
CertPinResult::PinMismatch
);
}
#[test]
fn spki_hash_utility() {
let cert_der = test_cert_der();
let hash = CertPinValidator::spki_hash(&cert_der).unwrap();
assert_eq!(hash.len(), 32);
let hash2 = CertPinValidator::spki_hash(&cert_der).unwrap();
assert_eq!(hash, hash2);
}
#[test]
fn spki_hash_invalid_der_errors() {
let result = CertPinValidator::spki_hash(b"invalid");
assert!(result.is_err());
}