#![cfg(test)]
use super::*;
#[test]
fn a_delegation_for_another_origin_is_refused_though_it_is_internally_perfect() {
let key = root();
let elsewhere = sign_delegation(&key, &claim_for(OTHER_ORIGIN)).unwrap();
verify_delegation(&elsewhere, &key.public_key_bytes(), DOMAIN, OTHER_ORIGIN).unwrap();
assert!(matches!(
verify_delegation(&elsewhere, &key.public_key_bytes(), DOMAIN, ORIGIN),
Err(TrustError::DelegationVerification)
));
let mut refused = 0;
for near_miss in [
"example.tes",
"example.test.",
"Example.Test",
"sub.example.test",
" example.test",
] {
let cose = sign_delegation(&key, &claim_for(near_miss)).unwrap();
assert!(
verify_delegation(&cose, &key.public_key_bytes(), DOMAIN, ORIGIN).is_err(),
"origin {near_miss:?} must not satisfy {ORIGIN:?}"
);
refused += 1;
}
assert_eq!(refused, 5, "every near-miss origin must have been tried");
}
#[test]
fn origin_comparison_is_raw_utf8_byte_equality() {
let key = root();
let nfc = "caf\u{e9}.test";
let nfd = "cafe\u{301}.test";
assert_ne!(nfc.as_bytes(), nfd.as_bytes());
let cose = sign_delegation(&key, &claim_for(nfc)).unwrap();
verify_delegation(&cose, &key.public_key_bytes(), DOMAIN, nfc).unwrap();
assert!(verify_delegation(&cose, &key.public_key_bytes(), DOMAIN, nfd).is_err());
let cose_nfd = sign_delegation(&key, &claim_for(nfd)).unwrap();
verify_delegation(&cose_nfd, &key.public_key_bytes(), DOMAIN, nfd).unwrap();
assert!(verify_delegation(&cose_nfd, &key.public_key_bytes(), DOMAIN, nfc).is_err());
}
#[test]
fn the_two_subject_kinds_do_not_interchange_even_at_the_same_subject_value() {
let key = root();
let expected = key.public_key_bytes();
let domain = sign_delegation(&key, &claim_for(ORIGIN)).unwrap();
let seat = sign_delegation(&key, &seat_claim_for(ORIGIN)).unwrap();
assert_eq!(
Delegation::from_cose_bytes(&domain)
.unwrap()
.claim
.subject_value,
Delegation::from_cose_bytes(&seat)
.unwrap()
.claim
.subject_value,
"the two artifacts must name the same subject VALUE for this test to be \
about the KIND"
);
assert_ne!(domain, seat, "and they must still be different artifacts");
let ok_domain = verify_delegation(&domain, &expected, DOMAIN, ORIGIN).unwrap();
assert_eq!(ok_domain.claim.subject_kind, DelegationSubjectKind::Domain);
assert_eq!(ok_domain.claim.role, DelegationRole::Operational);
let ok_seat = verify_delegation(&seat, &expected, SEAT, ORIGIN).unwrap();
assert_eq!(ok_seat.claim.subject_kind, DelegationSubjectKind::Seat);
assert_eq!(ok_seat.claim.role, DelegationRole::SpeaksFor);
let mut refused = 0;
for (name, artifact, kind) in [
("a seat delegation at a domain verifier", &seat, DOMAIN),
("a domain delegation at a seat verifier", &domain, SEAT),
] {
assert!(
matches!(
verify_delegation(artifact, &expected, kind, ORIGIN),
Err(TrustError::DelegationVerification)
),
"{name} was accepted"
);
refused += 1;
}
assert_eq!(refused, 2, "both directions must have been tried");
}
#[test]
fn a_pair_outside_the_table_is_refused_though_its_signature_is_valid() {
let key = root();
let expected = key.public_key_bytes();
let canonical = encoding::payload_bytes(&claim());
assert_eq!(&canonical[..3], &[0xa6, 0x01, 0x01], "kind at index 2");
let role_at = role_offset(&canonical);
let cases = [
(
0x01u8,
0x03u8,
"domain + speaks-for: both values valid, pair is not",
),
(
0x02,
0x02,
"seat + operational: both values valid, pair is not",
),
];
let mut refused = 0;
for (kind, role, why) in cases {
let kind_enum = DelegationSubjectKind::from_wire(u64::from(kind)).expect("kind decodes");
let role_enum = DelegationRole::from_wire(u64::from(role)).expect("role decodes");
assert!(!kind_enum.permits(role_enum), "{why}");
let mut payload = canonical.clone();
payload[2] = kind;
payload[role_at + 1] = role;
assert_eq!(payload.len(), canonical.len(), "a repair, not a resize");
let mutant = signed_envelope(&protected_for(&key), &payload, &key);
Ed25519Identity::verify(
&expected,
&cbor::sig_structure_bytes(&protected_for(&key), &payload),
&mutant[mutant.len() - 64..],
)
.unwrap();
for kind_expected in [DOMAIN, SEAT] {
assert!(
matches!(
verify_delegation(&mutant, &expected, kind_expected, ORIGIN),
Err(TrustError::DelegationVerification)
),
"({kind}, {role}) was accepted — {why}"
);
}
refused += 1;
}
assert_eq!(refused, 2, "both clause-3 pairs must have been tried");
let mut accepted = 0;
for (kind, role, kind_expected) in [(0x01u8, 0x02u8, DOMAIN), (0x02, 0x03, SEAT)] {
let mut payload = canonical.clone();
payload[2] = kind;
payload[role_at + 1] = role;
let ok = signed_envelope(&protected_for(&key), &payload, &key);
verify_delegation(&ok, &expected, kind_expected, ORIGIN).unwrap();
accepted += 1;
}
assert_eq!(
accepted, 2,
"both valid pairs must have been controlled for"
);
}
#[test]
fn an_unusable_delegated_key_is_refused_at_verification_too() {
let key = root();
let canonical = encoding::payload_bytes(&claim());
let delegated = operational().public_key_bytes();
let at = canonical
.windows(32)
.position(|w| w == delegated)
.expect("the delegated key is in the payload");
let mut identity_point = [0u8; 32];
identity_point[0] = 1;
let mut refused = 0;
for bad_key in [[0u8; 32], [0xffu8; 32], identity_point] {
let mut payload = canonical.clone();
payload[at..at + 32].copy_from_slice(&bad_key);
let mutant = signed_envelope(&protected_for(&key), &payload, &key);
assert!(
matches!(
verify_delegation(&mutant, &key.public_key_bytes(), DOMAIN, ORIGIN),
Err(TrustError::DelegationVerification)
),
"a delegation naming an unusable key was accepted"
);
refused += 1;
}
assert_eq!(refused, 3, "every unusable key shape must have been tried");
let ok = signed_envelope(&protected_for(&key), &canonical, &key);
verify_delegation(&ok, &key.public_key_bytes(), DOMAIN, ORIGIN).unwrap();
}
#[test]
fn an_empty_subject_value_is_refused_at_verification_too() {
let key = root();
let mut payload = vec![0xa6, 0x01, 0x01, 0x02, 0x60, 0x03, 0x58, 0x20];
payload.extend_from_slice(&operational().public_key_bytes());
payload.extend_from_slice(&[0x04, 0x02, 0x05, 0x1b]);
payload.extend_from_slice(&1_700_000_000_000u64.to_be_bytes());
payload.extend_from_slice(&[0x06, 0x19, 0x01, 0x2c]);
let mutant = signed_envelope(&protected_for(&key), &payload, &key);
assert!(matches!(
verify_delegation(&mutant, &key.public_key_bytes(), DOMAIN, ""),
Err(TrustError::DelegationVerification)
));
assert!(verify_delegation(&mutant, &key.public_key_bytes(), DOMAIN, ORIGIN).is_err());
}