Skip to content

Commit c24e693

Browse files
committed
Implement iteration through certificate chain as an iterator.
Factor out the boilerplate of navigating through the linked list.
1 parent 1d5f4bd commit c24e693

File tree

3 files changed

+54
-53
lines changed

3 files changed

+54
-53
lines changed

src/cert.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,31 @@ pub struct Cert<'a> {
3434
pub subject_alt_name: Option<untrusted::Input<'a>>,
3535
}
3636

37+
impl<'a> Cert<'a> {
38+
/// Returns an iterator of all the certs in the chain so far.
39+
///
40+
/// The first item will be `self` and the last item will be the end-entity
41+
/// certificate.
42+
pub fn iter_from_self_through_end_entity(&'a self) -> impl Iterator<Item = &'a Cert<'a>> + 'a {
43+
struct Iter<'c> {
44+
next: Option<&'c Cert<'c>>,
45+
}
46+
impl<'c> Iterator for Iter<'c> {
47+
type Item = &'c Cert<'c>;
48+
49+
fn next(&mut self) -> Option<Self::Item> {
50+
let next_next = match self.next?.ee_or_ca {
51+
EndEntityOrCA::EndEntity => None,
52+
EndEntityOrCA::CA(c) => Some(c),
53+
};
54+
core::mem::replace(&mut self.next, next_next)
55+
}
56+
}
57+
58+
Iter { next: Some(self) }
59+
}
60+
}
61+
3762
pub fn parse_cert<'a>(
3863
cert_der: untrusted::Input<'a>,
3964
ee_or_ca: EndEntityOrCA<'a>,

src/name/verify.rs

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,7 @@ use super::{
1616
dns_name::{self, DnsNameRef},
1717
ip_address,
1818
};
19-
use crate::{
20-
cert::{Cert, EndEntityOrCA},
21-
der, Error,
22-
};
19+
use crate::{cert::Cert, der, Error};
2320

2421
pub fn verify_cert_dns_name(
2522
cert: &crate::EndEntityCert,
@@ -79,21 +76,22 @@ pub fn check_name_constraints(
7976
let permitted_subtrees = parse_subtrees(input, der::Tag::ContextSpecificConstructed0)?;
8077
let excluded_subtrees = parse_subtrees(input, der::Tag::ContextSpecificConstructed1)?;
8178

82-
let mut child = subordinate_certs;
83-
loop {
84-
iterate_names(child.subject, child.subject_alt_name, Ok(()), &|name| {
85-
check_presented_id_conforms_to_constraints(name, permitted_subtrees, excluded_subtrees)
86-
})?;
87-
88-
child = match child.ee_or_ca {
89-
EndEntityOrCA::CA(child_cert) => child_cert,
90-
EndEntityOrCA::EndEntity => {
91-
break;
92-
}
93-
};
94-
}
95-
96-
Ok(())
79+
subordinate_certs
80+
.iter_from_self_through_end_entity()
81+
.try_for_each(|subordinate| {
82+
iterate_names(
83+
subordinate.subject,
84+
subordinate.subject_alt_name,
85+
Ok(()),
86+
&|name| {
87+
check_presented_id_conforms_to_constraints(
88+
name,
89+
permitted_subtrees,
90+
excluded_subtrees,
91+
)
92+
},
93+
)
94+
})
9795
}
9896

9997
fn check_presented_id_conforms_to_constraints(

src/verify_cert.rs

Lines changed: 12 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -90,21 +90,11 @@ pub fn build_chain(
9090
}
9191

9292
// Prevent loops; see RFC 4158 section 5.2.
93-
let mut prev = cert;
94-
loop {
95-
if potential_issuer.spki.value() == prev.spki.value()
96-
&& potential_issuer.subject == prev.subject
97-
{
98-
return Err(Error::UnknownIssuer);
99-
}
100-
match &prev.ee_or_ca {
101-
EndEntityOrCA::EndEntity => {
102-
break;
103-
}
104-
EndEntityOrCA::CA(child_cert) => {
105-
prev = child_cert;
106-
}
107-
}
93+
if cert.iter_from_self_through_end_entity().any(|cert| {
94+
potential_issuer.spki.value() == cert.spki.value()
95+
&& potential_issuer.subject == cert.subject
96+
}) {
97+
return Err(Error::UnknownIssuer);
10898
}
10999

110100
untrusted::read_all_optional(potential_issuer.name_constraints, Error::BadDER, |value| {
@@ -133,25 +123,13 @@ fn check_signatures(
133123
cert_chain: &Cert,
134124
trust_anchor_key: untrusted::Input,
135125
) -> Result<(), Error> {
136-
let mut spki_value = trust_anchor_key;
137-
let mut cert = cert_chain;
138-
loop {
139-
signed_data::verify_signed_data(supported_sig_algs, spki_value, &cert.signed_data)?;
140-
141-
// TODO: check revocation
142-
143-
match &cert.ee_or_ca {
144-
EndEntityOrCA::CA(child_cert) => {
145-
spki_value = cert.spki.value();
146-
cert = child_cert;
147-
}
148-
EndEntityOrCA::EndEntity => {
149-
break;
150-
}
151-
}
152-
}
153-
154-
Ok(())
126+
cert_chain
127+
.iter_from_self_through_end_entity()
128+
.try_fold(trust_anchor_key, |spki_value, cert| {
129+
signed_data::verify_signed_data(supported_sig_algs, spki_value, &cert.signed_data)?;
130+
Ok(cert.spki.value())
131+
})
132+
.map(|_| ())
155133
}
156134

157135
fn check_issuer_independent_properties(

0 commit comments

Comments
 (0)