Skip to content

Commit

Permalink
Implement iteration through certificate chain as an iterator.
Browse files Browse the repository at this point in the history
Factor out the boilerplate of navigating through the linked list.
  • Loading branch information
briansmith committed Feb 18, 2021
1 parent 1d5f4bd commit c24e693
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 53 deletions.
25 changes: 25 additions & 0 deletions src/cert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,31 @@ pub struct Cert<'a> {
pub subject_alt_name: Option<untrusted::Input<'a>>,
}

impl<'a> Cert<'a> {
/// Returns an iterator of all the certs in the chain so far.
///
/// The first item will be `self` and the last item will be the end-entity
/// certificate.
pub fn iter_from_self_through_end_entity(&'a self) -> impl Iterator<Item = &'a Cert<'a>> + 'a {
struct Iter<'c> {
next: Option<&'c Cert<'c>>,
}
impl<'c> Iterator for Iter<'c> {
type Item = &'c Cert<'c>;

fn next(&mut self) -> Option<Self::Item> {
let next_next = match self.next?.ee_or_ca {
EndEntityOrCA::EndEntity => None,
EndEntityOrCA::CA(c) => Some(c),
};
core::mem::replace(&mut self.next, next_next)
}
}

Iter { next: Some(self) }
}
}

pub fn parse_cert<'a>(
cert_der: untrusted::Input<'a>,
ee_or_ca: EndEntityOrCA<'a>,
Expand Down
36 changes: 17 additions & 19 deletions src/name/verify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,7 @@ use super::{
dns_name::{self, DnsNameRef},
ip_address,
};
use crate::{
cert::{Cert, EndEntityOrCA},
der, Error,
};
use crate::{cert::Cert, der, Error};

pub fn verify_cert_dns_name(
cert: &crate::EndEntityCert,
Expand Down Expand Up @@ -79,21 +76,22 @@ pub fn check_name_constraints(
let permitted_subtrees = parse_subtrees(input, der::Tag::ContextSpecificConstructed0)?;
let excluded_subtrees = parse_subtrees(input, der::Tag::ContextSpecificConstructed1)?;

let mut child = subordinate_certs;
loop {
iterate_names(child.subject, child.subject_alt_name, Ok(()), &|name| {
check_presented_id_conforms_to_constraints(name, permitted_subtrees, excluded_subtrees)
})?;

child = match child.ee_or_ca {
EndEntityOrCA::CA(child_cert) => child_cert,
EndEntityOrCA::EndEntity => {
break;
}
};
}

Ok(())
subordinate_certs
.iter_from_self_through_end_entity()
.try_for_each(|subordinate| {
iterate_names(
subordinate.subject,
subordinate.subject_alt_name,
Ok(()),
&|name| {
check_presented_id_conforms_to_constraints(
name,
permitted_subtrees,
excluded_subtrees,
)
},
)
})
}

fn check_presented_id_conforms_to_constraints(
Expand Down
46 changes: 12 additions & 34 deletions src/verify_cert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,21 +90,11 @@ pub fn build_chain(
}

// Prevent loops; see RFC 4158 section 5.2.
let mut prev = cert;
loop {
if potential_issuer.spki.value() == prev.spki.value()
&& potential_issuer.subject == prev.subject
{
return Err(Error::UnknownIssuer);
}
match &prev.ee_or_ca {
EndEntityOrCA::EndEntity => {
break;
}
EndEntityOrCA::CA(child_cert) => {
prev = child_cert;
}
}
if cert.iter_from_self_through_end_entity().any(|cert| {
potential_issuer.spki.value() == cert.spki.value()
&& potential_issuer.subject == cert.subject
}) {
return Err(Error::UnknownIssuer);
}

untrusted::read_all_optional(potential_issuer.name_constraints, Error::BadDER, |value| {
Expand Down Expand Up @@ -133,25 +123,13 @@ fn check_signatures(
cert_chain: &Cert,
trust_anchor_key: untrusted::Input,
) -> Result<(), Error> {
let mut spki_value = trust_anchor_key;
let mut cert = cert_chain;
loop {
signed_data::verify_signed_data(supported_sig_algs, spki_value, &cert.signed_data)?;

// TODO: check revocation

match &cert.ee_or_ca {
EndEntityOrCA::CA(child_cert) => {
spki_value = cert.spki.value();
cert = child_cert;
}
EndEntityOrCA::EndEntity => {
break;
}
}
}

Ok(())
cert_chain
.iter_from_self_through_end_entity()
.try_fold(trust_anchor_key, |spki_value, cert| {
signed_data::verify_signed_data(supported_sig_algs, spki_value, &cert.signed_data)?;
Ok(cert.spki.value())
})
.map(|_| ())
}

fn check_issuer_independent_properties(
Expand Down

0 comments on commit c24e693

Please sign in to comment.