use super::{ExtendedKeyUsage, KeyUsage};
use crate::error::ErrorCode;
use crate::fixtures::{
bits, extension, extension_error, int, oid as oid_of, seq, tlv, with_extension,
};
use crate::oid;
#[test]
fn the_bits_of_a_key_usage_are_read_by_what_they_mean() {
with_extension(
extension(oid::KEY_USAGE, true, &tlv(0x03, &[0x02, 0x44])),
|list| {
let usage = list.key_usage(list.memory()).unwrap().unwrap();
assert!(!usage.digital_signature());
assert!(usage.content_commitment());
assert!(usage.key_cert_sign());
assert!(!usage.crl_sign());
assert!(!usage.decipher_only());
},
);
}
#[test]
fn a_usage_that_permits_nothing_is_refused() {
for value in [&[0x00][..], &[0x01, 0x00][..]] {
let error = extension_error!(
extension(oid::KEY_USAGE, true, &tlv(0x03, value)),
key_usage
);
assert_eq!(error.code(), ErrorCode::MalformedValue, "{value:02x?}");
assert_eq!(error.field(), "extensions.keyUsage");
}
}
#[test]
fn an_extension_that_cannot_be_read_is_not_a_certificate_that_cannot_be_read() {
with_extension(extension(oid::KEY_USAGE, true, &int(3)), |list| {
assert_eq!(list.len(), 1);
let error = list.key_usage(list.memory()).unwrap_err();
assert_eq!(
error.code(),
ErrorCode::Encoding(structured_asn1::ErrorCode::UnexpectedTag)
);
});
}
#[test]
fn an_absent_extension_is_absent_rather_than_broken() {
with_extension(
extension(
oid::SUBJECT_KEY_IDENTIFIER,
false,
&crate::fixtures::octets(&[0x01]),
),
|list| {
assert!(list.key_usage(list.memory()).unwrap().is_none());
assert!(list.extended_key_usage(list.memory()).unwrap().is_none());
},
);
}
#[test]
fn extended_purposes_are_read_as_identifiers() {
let value = seq(&[oid_of(oid::TIME_STAMPING), oid_of(oid::OCSP_SIGNING)]);
with_extension(extension(oid::EXT_KEY_USAGE, false, &value), |list| {
let purposes = list.extended_key_usage(list.memory()).unwrap().unwrap();
assert_eq!(purposes.purposes().len(), 2);
assert!(purposes.has(oid::TIME_STAMPING, list.memory()).unwrap());
assert!(!purposes.has(oid::SERVER_AUTH, list.memory()).unwrap());
assert!(
!purposes
.has(oid::ANY_EXTENDED_KEY_USAGE, list.memory())
.unwrap()
);
});
}
#[test]
fn a_list_of_no_purposes_is_refused() {
let error = extension_error!(
extension(oid::EXT_KEY_USAGE, false, &seq(&[])),
extended_key_usage
);
assert_eq!(error.code(), ErrorCode::EmptySequence);
}
#[test]
fn a_second_structure_after_the_value_is_refused() {
let mut value = bits(&[0x80]);
value.extend_from_slice(&bits(&[0x40]));
let error = extension_error!(extension(oid::KEY_USAGE, true, &value), key_usage);
assert_eq!(error.code(), ErrorCode::TrailingData);
}
#[test]
fn reading_goes_through_the_list_the_certificate_carries() {
with_extension(
extension(oid::KEY_USAGE, true, &tlv(0x03, &[0x07, 0x80])),
|list| {
let found = list.get(oid::KEY_USAGE, list.memory()).unwrap().unwrap();
let direct = KeyUsage::read(found, list.memory()).unwrap();
let through = list.key_usage(list.memory()).unwrap().unwrap();
assert_eq!(direct.bits().as_bytes(), through.bits().as_bytes());
assert!(ExtendedKeyUsage::read(found, list.memory()).is_err());
},
);
}
#[test]
fn a_key_usage_with_trailing_zero_bits_is_refused_under_der() {
let padded = tlv(0x03, &[0x00, 0x04, 0x00]);
let error = extension_error!(extension(oid::KEY_USAGE, true, &padded), key_usage);
assert_eq!(error.code(), ErrorCode::MalformedValue);
let overlong = tlv(0x03, &[0x06, 0x04, 0x40]);
let error = extension_error!(extension(oid::KEY_USAGE, true, &overlong), key_usage);
assert_eq!(error.code(), ErrorCode::MalformedValue);
for value in [tlv(0x03, &[0x02, 0x04]), tlv(0x03, &[0x07, 0xff, 0x80])] {
with_extension(extension(oid::KEY_USAGE, true, &value), |list| {
assert!(list.key_usage(list.memory()).unwrap().is_some());
});
}
}