use crate::der::read_element;
use crate::id::TrustAnchorId;
use crate::trust::{CaTrust, CosignerInfo};
use crate::{Error, Result, SignatureAlgorithm};
const MTC_CA_SHA256_EXTENSION_OID: &str = "1.3.6.1.5.5.7.1.38";
const TRUST_ANCHOR_ID_ATTRIBUTE_OID: &str = "1.3.6.1.5.5.7.25.3";
fn serial_bounds_ranges(min: u64, max: u64) -> Vec<core::ops::RangeInclusive<u64>> {
let mut ranges = Vec::new();
if min > 0 {
ranges.push(0..=min - 1);
}
if max < u64::MAX {
ranges.push(max + 1..=u64::MAX);
}
ranges
}
impl CaTrust {
pub fn from_ca_certificate(certificate_der: &[u8]) -> Result<Self> {
let (tbs, _, _) = crate::entry::certificate_elements(certificate_der)?;
let mut input = tbs.content;
if let Some((version, rest)) = read_element(input)
&& version.tag == 0xa0
{
input = rest;
}
let _serial = crate::der::next_element(&mut input, "serial")?;
let _tbs_signature = crate::der::next_element(&mut input, "signature")?;
let _issuer = crate::der::next_element(&mut input, "issuer")?;
let _validity = crate::der::next_element(&mut input, "validity")?;
let subject = crate::der::next_element(&mut input, "subject")?;
let spki = crate::der::next_element(&mut input, "subjectPublicKeyInfo")?;
if spki.tag != 0x30 {
return Err(Error::Malformed("subjectPublicKeyInfo"));
}
let ca_id = trust_anchor_id_from_name(subject.content)?;
let mut signature_algorithm = None;
let mut bounds = None;
for extension in extensions(input)? {
if extension.oid == MTC_CA_SHA256_EXTENSION_OID {
let (algorithm, min, max) = parse_mtc_ca_extension(&extension.value)?;
signature_algorithm = Some(algorithm);
bounds = Some((min, max));
}
}
let signature_algorithm =
signature_algorithm.ok_or(Error::Malformed("MTCCertificationAuthority extension"))?;
let (min, max) = bounds.ok_or(Error::Malformed("MTCCertificationAuthority"))?;
let mut trust = CaTrust::new(
ca_id.clone(),
CosignerInfo {
id: ca_id,
algorithm: signature_algorithm,
spki_der: spki.encoded.to_vec(),
},
);
for range in serial_bounds_ranges(min, max) {
trust.revoked_ranges.push(range);
}
Ok(trust)
}
}
pub(crate) fn trust_anchor_id_from_name(name_content: &[u8]) -> Result<TrustAnchorId> {
let (rdn, rest) = read_element(name_content).ok_or(Error::Malformed("issuer RDN"))?;
if rdn.tag != 0x31 || !rest.is_empty() {
return Err(Error::Malformed("issuer RDN"));
}
let (attribute, rest) =
read_element(rdn.content).ok_or(Error::Malformed("issuer attribute"))?;
if attribute.tag != 0x30 || !rest.is_empty() {
return Err(Error::Malformed("issuer attribute"));
}
let (oid, rest) = read_element(attribute.content).ok_or(Error::Malformed("attribute OID"))?;
if oid.tag != 0x06
|| crate::id::oid_content_to_dotted(oid.content)? != TRUST_ANCHOR_ID_ATTRIBUTE_OID
{
return Err(Error::Malformed("attribute OID"));
}
let (value, rest) = read_element(rest).ok_or(Error::Malformed("attribute value"))?;
if value.tag != 0x0d || !rest.is_empty() {
return Err(Error::Malformed("attribute value"));
}
TrustAnchorId::from_binary(value.content)
}
struct RawExtension {
oid: String,
value: Vec<u8>,
}
fn extensions(input: &[u8]) -> Result<Vec<RawExtension>> {
let mut result = Vec::new();
let mut rest = input;
while !rest.is_empty() {
let (element, next) = read_element(rest).ok_or(Error::Malformed("TBS trailing fields"))?;
rest = next;
if element.tag != 0xa3 {
continue;
}
let (sequence, tail) =
read_element(element.content).ok_or(Error::Malformed("extensions"))?;
if sequence.tag != 0x30 || !tail.is_empty() {
return Err(Error::Malformed("extensions"));
}
let mut list = sequence.content;
while !list.is_empty() {
let (extension, tail) = read_element(list).ok_or(Error::Malformed("extension"))?;
list = tail;
if extension.tag != 0x30 {
return Err(Error::Malformed("extension"));
}
let (oid, tail) =
read_element(extension.content).ok_or(Error::Malformed("extension OID"))?;
if oid.tag != 0x06 {
return Err(Error::Malformed("extension OID"));
}
let mut tail = tail;
let (peek, tail_after_peek) =
read_element(tail).ok_or(Error::Malformed("extension value"))?;
if peek.tag == 0x01 {
tail = tail_after_peek;
}
let (value, tail) = read_element(tail).ok_or(Error::Malformed("extnValue"))?;
if value.tag != 0x04 || !tail.is_empty() {
return Err(Error::Malformed("extnValue"));
}
result.push(RawExtension {
oid: crate::id::oid_content_to_dotted(oid.content)?,
value: value.content.to_vec(),
});
}
}
Ok(result)
}
fn parse_mtc_ca_extension(bytes: &[u8]) -> Result<(SignatureAlgorithm, u64, u64)> {
let parameters = crate::caext::parse_mtc_ca_parameters(bytes)?;
let algorithm = SignatureAlgorithm::from_algorithm_oid(¶meters.signature_algorithm_oid)
.ok_or(Error::UnsupportedKey("MTCCA signature algorithm"))?;
Ok((algorithm, parameters.min_serial, parameters.max_serial))
}