use super::CertificateCount;
use crate::error::ErrorCode;
use crate::fixtures::{
boolean, context, extension, extension_error, implicit, int, octets, seq, tlv, with_extension,
};
use crate::general_name::GeneralName;
use crate::oid;
#[test]
fn an_authority_is_read_with_the_depth_it_allows() {
let value = seq(&[boolean(true), int(3)]);
with_extension(extension(oid::BASIC_CONSTRAINTS, true, &value), |list| {
let constraints = list.basic_constraints(list.memory()).unwrap().unwrap();
assert!(constraints.is_authority());
assert_eq!(
constraints.path_length(),
Some(CertificateCount::Certificates(3))
);
});
}
#[test]
fn an_empty_basic_constraints_says_not_an_authority() {
with_extension(extension(oid::BASIC_CONSTRAINTS, true, &seq(&[])), |list| {
let constraints = list.basic_constraints(list.memory()).unwrap().unwrap();
assert!(!constraints.is_authority());
assert_eq!(constraints.path_length(), None);
});
}
#[test]
fn a_depth_written_without_the_flag_is_refused() {
let error = extension_error!(
extension(oid::BASIC_CONSTRAINTS, true, &seq(&[int(2)])),
basic_constraints
);
assert_eq!(error.code(), ErrorCode::UnexpectedField);
}
#[test]
fn a_depth_that_is_not_a_count_is_refused() {
let value = seq(&[boolean(true), tlv(0x02, &[0xff])]);
let error = extension_error!(
extension(oid::BASIC_CONSTRAINTS, true, &value),
basic_constraints
);
assert_eq!(error.code(), ErrorCode::MalformedValue);
assert_eq!(error.field(), "extensions.basicConstraints");
}
#[test]
fn a_depth_wider_than_the_counter_is_a_bound_nothing_reaches() {
let value = seq(&[
boolean(true),
tlv(0x02, &[0x01, 0x00, 0x00, 0x00, 0x00, 0x00]),
]);
with_extension(extension(oid::BASIC_CONSTRAINTS, true, &value), |list| {
let constraints = list.basic_constraints(list.memory()).unwrap().unwrap();
assert_eq!(
constraints.path_length(),
Some(CertificateCount::BeyondAnyPath)
);
assert_eq!(
constraints
.path_length()
.and_then(CertificateCount::certificates),
None
);
});
}
#[test]
fn name_constraints_are_read_as_the_regions_they_name() {
let permitted = context(0, &[seq(&[implicit(2, b"example.ua")])]);
let excluded = context(1, &[seq(&[implicit(2, b"forbidden.example.ua")])]);
with_extension(
extension(oid::NAME_CONSTRAINTS, true, &seq(&[permitted, excluded])),
|list| {
let constraints = list.name_constraints(list.memory()).unwrap().unwrap();
assert_eq!(constraints.permitted().len(), 1);
assert_eq!(constraints.excluded().len(), 1);
assert!(matches!(
constraints.permitted()[0].base(),
GeneralName::Dns("example.ua")
));
},
);
}
#[test]
fn a_domain_constraint_written_with_a_leading_period_is_read() {
let permitted = context(0, &[seq(&[implicit(2, b".example.ua")])]);
with_extension(
extension(oid::NAME_CONSTRAINTS, true, &seq(&[permitted])),
|list| {
let constraints = list.name_constraints(list.memory()).unwrap().unwrap();
assert!(matches!(
constraints.permitted()[0].base(),
GeneralName::Dns(".example.ua")
));
},
);
let der = seq(&[implicit(2, b".example.ua")]);
let parser = structured_asn1::Parser::der(crate::fixtures::memory());
let mut reader = parser.read(&der, 0).unwrap();
let element = reader.next_element().unwrap().unwrap();
assert!(crate::general_name::read_all(&reader, &element, "test").is_err());
let permitted = context(0, &[seq(&[implicit(2, b".")])]);
let error = extension_error!(
extension(oid::NAME_CONSTRAINTS, true, &seq(&[permitted])),
name_constraints
);
assert_eq!(error.code(), ErrorCode::MalformedValue);
}
#[test]
fn a_constraint_that_constrains_nothing_is_refused() {
let error = extension_error!(
extension(oid::NAME_CONSTRAINTS, true, &seq(&[])),
name_constraints
);
assert_eq!(error.code(), ErrorCode::MalformedValue);
}
#[test]
fn policy_constraints_are_read_as_the_counts_they_carry() {
let value = seq(&[implicit(0, &[0x00]), implicit(1, &[0x02])]);
with_extension(extension(oid::POLICY_CONSTRAINTS, true, &value), |list| {
let constraints = list.policy_constraints(list.memory()).unwrap().unwrap();
assert_eq!(
constraints.require_explicit_policy(),
Some(CertificateCount::Certificates(0))
);
assert_eq!(
constraints.inhibit_policy_mapping(),
Some(CertificateCount::Certificates(2))
);
});
}
#[test]
fn policy_constraints_with_neither_count_are_refused() {
let error = extension_error!(
extension(oid::POLICY_CONSTRAINTS, true, &seq(&[])),
policy_constraints
);
assert_eq!(error.code(), ErrorCode::MalformedValue);
}
#[test]
fn the_count_that_stops_the_any_policy_identifier_is_read() {
with_extension(extension(oid::INHIBIT_ANY_POLICY, true, &int(1)), |list| {
let inhibit = list.inhibit_any_policy(list.memory()).unwrap().unwrap();
assert_eq!(inhibit.skip(), CertificateCount::Certificates(1));
});
}
#[test]
fn a_count_that_is_not_an_integer_is_refused() {
let error = extension_error!(
extension(oid::INHIBIT_ANY_POLICY, true, &octets(&[0x01])),
inhibit_any_policy
);
assert_eq!(
error.code(),
ErrorCode::Encoding(structured_asn1::ErrorCode::UnexpectedTag)
);
}
#[test]
fn a_field_of_another_tag_class_is_not_a_policy_constraint() {
let error = extension_error!(
extension(oid::POLICY_CONSTRAINTS, true, &seq(&[tlv(0xc0, &[0x00])])),
policy_constraints
);
assert_eq!(error.code(), ErrorCode::UnexpectedField);
}
#[test]
fn a_subtree_address_must_carry_the_mask_beside_it() {
let error = extension_error!(
extension(
oid::NAME_CONSTRAINTS,
true,
&seq(&[context(0, &[seq(&[implicit(7, &[192, 0, 2, 1])])])]),
),
name_constraints
);
assert_eq!(error.code(), ErrorCode::MalformedValue);
let paired = [192, 0, 2, 0, 255, 255, 255, 0];
with_extension(
extension(
oid::NAME_CONSTRAINTS,
true,
&seq(&[context(0, &[seq(&[implicit(7, &paired)])])]),
),
|list| assert!(list.name_constraints(list.memory()).unwrap().is_some()),
);
}
#[test]
fn a_nonzero_subtree_minimum_is_refused() {
let subtree = seq(&[implicit(2, b"example.ua"), implicit(0, &[0x01])]);
let error = extension_error!(
extension(oid::NAME_CONSTRAINTS, true, &seq(&[context(0, &[subtree])])),
name_constraints
);
assert_eq!(error.code(), ErrorCode::MalformedValue);
}
#[test]
fn a_subtree_maximum_distance_is_refused() {
let subtree = seq(&[implicit(2, b"example.ua"), implicit(1, &[0x02])]);
let error = extension_error!(
extension(oid::NAME_CONSTRAINTS, true, &seq(&[context(0, &[subtree])])),
name_constraints
);
assert_eq!(error.code(), ErrorCode::UnexpectedField);
}
#[test]
fn a_subtree_mask_that_is_not_contiguous_is_refused() {
let holed = [192, 0, 2, 0, 255, 0, 255, 0];
let error = extension_error!(
extension(
oid::NAME_CONSTRAINTS,
true,
&seq(&[context(0, &[seq(&[implicit(7, &holed)])])]),
),
name_constraints
);
assert_eq!(error.code(), ErrorCode::MalformedValue);
}
#[test]
fn constraint_fields_written_backwards_are_refused() {
let backwards_subtrees = seq(&[
context(1, &[seq(&[implicit(2, b"forbidden.example.ua")])]),
context(0, &[seq(&[implicit(2, b"example.ua")])]),
]);
let error = extension_error!(
extension(oid::NAME_CONSTRAINTS, true, &backwards_subtrees),
name_constraints
);
assert_eq!(error.code(), ErrorCode::UnexpectedField);
let backwards_policy = seq(&[implicit(1, &[0x02]), implicit(0, &[0x00])]);
let error = extension_error!(
extension(oid::POLICY_CONSTRAINTS, true, &backwards_policy),
policy_constraints
);
assert_eq!(error.code(), ErrorCode::UnexpectedField);
}
#[test]
fn a_subtree_maximum_before_its_minimum_is_refused() {
let subtree = seq(&[
implicit(2, b"example.ua"),
implicit(1, &[0x02]),
implicit(0, &[0x00]),
]);
let error = extension_error!(
extension(oid::NAME_CONSTRAINTS, true, &seq(&[context(0, &[subtree])])),
name_constraints
);
assert_eq!(error.code(), ErrorCode::UnexpectedField);
}
#[test]
fn a_spelled_out_default_constraint_is_refused_under_der() {
let error = extension_error!(
extension(oid::BASIC_CONSTRAINTS, true, &seq(&[boolean(false)])),
basic_constraints
);
assert_eq!(error.code(), ErrorCode::MalformedValue);
let subtree = seq(&[implicit(2, b"example.ua"), implicit(0, &[0x00])]);
let error = extension_error!(
extension(oid::NAME_CONSTRAINTS, true, &seq(&[context(0, &[subtree])])),
name_constraints
);
assert_eq!(error.code(), ErrorCode::MalformedValue);
}
#[test]
fn an_empty_directory_subtree_base_is_the_root() {
let base = context(4, &[seq(&[])]);
let value = seq(&[context(1, &[seq(&[base])])]);
with_extension(extension(oid::NAME_CONSTRAINTS, true, &value), |list| {
let constraints = list.name_constraints(list.memory()).unwrap().unwrap();
assert_eq!(constraints.excluded().len(), 1);
});
}