use {Error, TrustAnchor};
use cert::{certificate_serial_number, Cert, EndEntityOrCA, parse_cert_internal};
use std;
use super::der;
use untrusted;
pub fn cert_der_as_trust_anchor<'a>(cert_der: untrusted::Input<'a>)
-> Result<TrustAnchor<'a>, Error> {
match parse_cert_internal(cert_der, EndEntityOrCA::EndEntity,
possibly_invalid_certificate_serial_number) {
Ok(cert) => Ok(trust_anchor_from_cert(cert)),
Err(Error::BadDER) => parse_cert_v1(cert_der).or(Err(Error::BadDER)),
Err(err) => Err(err),
}
}
fn possibly_invalid_certificate_serial_number<'a>(
input: &mut untrusted::Reader<'a>) -> Result<(), Error> {
skip(input, der::Tag::Integer)
}
pub fn generate_code_for_trust_anchors(name: &str,
trust_anchors: &[TrustAnchor])
-> std::string::String {
let decl = format!("static {}: [TrustAnchor<'static>; {}] = ", name,
trust_anchors.len());
let value = str::replace(&format!("{:?};\n", trust_anchors), ": [", ": &[");
decl + &value
}
fn trust_anchor_from_cert<'a>(cert: Cert<'a>) -> TrustAnchor<'a> {
TrustAnchor {
subject: cert.subject.as_slice_less_safe(),
spki: cert.spki.as_slice_less_safe(),
name_constraints: cert.name_constraints
.map(|nc| nc.as_slice_less_safe())
}
}
fn parse_cert_v1<'a>(cert_der: untrusted::Input<'a>)
-> Result<TrustAnchor<'a>, Error> {
cert_der.read_all(Error::BadDER, |cert_der| {
der::nested(cert_der, der::Tag::Sequence, Error::BadDER, |cert_der| {
let anchor = der::nested(cert_der, der::Tag::Sequence,
Error::BadDER, |tbs| {
certificate_serial_number(tbs)?;
skip(tbs, der::Tag::Sequence)?; skip(tbs, der::Tag::Sequence)?; skip(tbs, der::Tag::Sequence)?; let subject =
der::expect_tag_and_get_value(tbs, der::Tag::Sequence)?;
let spki =
der::expect_tag_and_get_value(tbs, der::Tag::Sequence)?;
Ok(TrustAnchor {
subject: subject.as_slice_less_safe(),
spki: spki.as_slice_less_safe(),
name_constraints: None
})
});
skip(cert_der, der::Tag::Sequence)?;
skip(cert_der, der::Tag::BitString)?;
anchor
})
})
}
fn skip(input: &mut untrusted::Reader, tag: der::Tag) -> Result<(), Error> {
der::expect_tag_and_get_value(input, tag).map(|_| ())
}