1#[cfg(feature = "alloc")]
16use alloc::vec::Vec;
17use core::fmt;
18use core::ops::ControlFlow;
19
20use pki_types::{CertificateDer, SignatureVerificationAlgorithm, TrustAnchor, UnixTime};
21
22use crate::cert::Cert;
23use crate::crl::RevocationOptions;
24use crate::der::{self, FromDer};
25use crate::end_entity::EndEntityCert;
26use crate::error::Error;
27use crate::{public_values_eq, signed_data, subject_name};
28
29pub(crate) struct ChainOptions<'a, 'p, V> {
32 pub(crate) eku: V,
33 pub(crate) supported_sig_algs: &'a [&'a dyn SignatureVerificationAlgorithm],
34 pub(crate) trust_anchors: &'p [TrustAnchor<'p>],
35 pub(crate) intermediate_certs: &'p [CertificateDer<'p>],
36 pub(crate) revocation: Option<RevocationOptions<'a>>,
37 pub(crate) distrusted_spkis: &'a [&'a [u8]],
38}
39
40impl<'a, 'p: 'a, V: ExtendedKeyUsageValidator> ChainOptions<'a, 'p, V> {
41 pub(crate) fn build_chain(
42 &self,
43 end_entity: &'p EndEntityCert<'p>,
44 time: UnixTime,
45 verify_path: Option<&dyn Fn(&VerifiedPath<'_>) -> Result<(), Error>>,
46 ) -> Result<VerifiedPath<'p>, Error> {
47 let mut path = PartialPath::new(end_entity);
48 match self.build_chain_inner(&mut path, time, verify_path, 0, &mut Budget::default()) {
49 Ok(anchor) => Ok(VerifiedPath::new(end_entity, anchor, path)),
50 Err(ControlFlow::Break(err)) | Err(ControlFlow::Continue(err)) => Err(err),
51 }
52 }
53
54 fn build_chain_inner(
55 &self,
56 path: &mut PartialPath<'p>,
57 time: UnixTime,
58 verify_path: Option<&dyn Fn(&VerifiedPath<'_>) -> Result<(), Error>>,
59 sub_ca_count: usize,
60 budget: &mut Budget,
61 ) -> Result<&'p TrustAnchor<'p>, ControlFlow<Error, Error>> {
62 if self
63 .distrusted_spkis
64 .contains(&path.head().spki.as_slice_less_safe())
65 {
66 return Err(Error::CertDistrusted.into());
67 }
68
69 let role = path.node().role();
70
71 check_issuer_independent_properties(path.head(), time, role, sub_ca_count, &self.eku)?;
72
73 let result =
76 loop_while_non_fatal_error(Error::UnknownIssuer, self.trust_anchors, |trust_anchor| {
77 let trust_anchor_subject = untrusted::Input::from(trust_anchor.subject.as_ref());
78 if !public_values_eq(path.head().issuer, trust_anchor_subject) {
79 return Err(Error::UnknownIssuer.into());
80 }
81
82 if self
83 .distrusted_spkis
84 .contains(&trust_anchor.subject_public_key_info.as_ref())
85 {
86 return Err(Error::CertDistrusted.into());
87 }
88
89 let node = path.node();
90 self.check_signed_chain(&node, time, trust_anchor, budget)?;
91 check_signed_chain_name_constraints(&node, trust_anchor, budget)?;
92
93 let verify = match verify_path {
94 Some(verify) => verify,
95 None => return Ok(trust_anchor),
96 };
97
98 let candidate = VerifiedPath {
99 end_entity: path.end_entity,
100 intermediates: Intermediates::Borrowed(&path.intermediates[..path.used]),
101 anchor: trust_anchor,
102 };
103
104 match verify(&candidate) {
105 Ok(()) => Ok(trust_anchor),
106 Err(err) => Err(ControlFlow::Continue(err)),
107 }
108 });
109
110 let err = match result {
111 Ok(anchor) => return Ok(anchor),
112 res @ Err(ControlFlow::Break(_)) => return res,
114 Err(ControlFlow::Continue(err)) => err,
118 };
119
120 loop_while_non_fatal_error(err, self.intermediate_certs, |cert_der| {
121 let potential_issuer = Cert::from_der(untrusted::Input::from(cert_der))?;
122 if !public_values_eq(potential_issuer.subject, path.head().issuer) {
123 return Err(Error::UnknownIssuer.into());
124 }
125
126 if path.node().iter().any(|prev| {
128 public_values_eq(potential_issuer.spki, prev.cert.spki)
129 && public_values_eq(potential_issuer.subject, prev.cert.subject)
130 }) {
131 return Err(Error::UnknownIssuer.into());
132 }
133
134 let next_sub_ca_count = match role {
135 Role::EndEntity => sub_ca_count,
136 Role::Issuer => sub_ca_count + 1,
137 };
138
139 budget.consume_build_chain_call()?;
140 path.push(potential_issuer)?;
141 let result = self.build_chain_inner(path, time, verify_path, next_sub_ca_count, budget);
142 if result.is_err() {
143 path.pop();
144 }
145
146 result
147 })
148 }
149
150 fn check_signed_chain(
151 &self,
152 path: &PathNode<'_>,
153 time: UnixTime,
154 trust_anchor: &TrustAnchor<'_>,
155 budget: &mut Budget,
156 ) -> Result<(), ControlFlow<Error, Error>> {
157 let mut spki_value = untrusted::Input::from(trust_anchor.subject_public_key_info.as_ref());
158 let mut issuer_subject = untrusted::Input::from(trust_anchor.subject.as_ref());
159 let mut issuer_key_usage = None; for path in path.iter() {
161 signed_data::verify_signed_data(
162 self.supported_sig_algs,
163 spki_value,
164 &path.cert.signed_data,
165 budget,
166 )?;
167
168 if let Some(revocation_opts) = &self.revocation {
169 revocation_opts.check(
170 &path,
171 issuer_subject,
172 spki_value,
173 issuer_key_usage,
174 self.supported_sig_algs,
175 budget,
176 time,
177 )?;
178 }
179
180 spki_value = path.cert.spki;
181 issuer_subject = path.cert.subject;
182 issuer_key_usage = path.cert.key_usage;
183 }
184
185 Ok(())
186 }
187}
188
189pub struct VerifiedPath<'p> {
193 end_entity: &'p EndEntityCert<'p>,
194 intermediates: Intermediates<'p>,
195 anchor: &'p TrustAnchor<'p>,
196}
197
198impl<'p> VerifiedPath<'p> {
199 fn new(
200 end_entity: &'p EndEntityCert<'p>,
201 anchor: &'p TrustAnchor<'p>,
202 partial: PartialPath<'p>,
203 ) -> Self {
204 Self {
205 end_entity,
206 intermediates: Intermediates::Owned {
207 certs: partial.intermediates,
208 used: partial.used,
209 },
210 anchor,
211 }
212 }
213
214 pub fn intermediate_certificates(&'p self) -> IntermediateIterator<'p> {
216 IntermediateIterator {
217 intermediates: self.intermediates.as_ref(),
218 }
219 }
220
221 pub fn end_entity(&self) -> &'p EndEntityCert<'p> {
223 self.end_entity
224 }
225
226 pub fn anchor(&self) -> &'p TrustAnchor<'p> {
228 self.anchor
229 }
230}
231
232pub struct IntermediateIterator<'a> {
236 intermediates: &'a [Option<Cert<'a>>],
238}
239
240impl<'a> Iterator for IntermediateIterator<'a> {
241 type Item = &'a Cert<'a>;
242
243 fn next(&mut self) -> Option<Self::Item> {
244 match self.intermediates.split_first() {
245 Some((head, tail)) => {
246 self.intermediates = tail;
247 Some(head.as_ref().unwrap())
248 }
249 None => None,
250 }
251 }
252}
253
254impl DoubleEndedIterator for IntermediateIterator<'_> {
255 fn next_back(&mut self) -> Option<Self::Item> {
256 match self.intermediates.split_last() {
257 Some((head, tail)) => {
258 self.intermediates = tail;
259 Some(head.as_ref().unwrap())
260 }
261 None => None,
262 }
263 }
264}
265
266#[allow(clippy::large_enum_variant)]
267enum Intermediates<'a> {
268 Owned {
269 certs: [Option<Cert<'a>>; MAX_SUB_CA_COUNT],
270 used: usize,
271 },
272 Borrowed(&'a [Option<Cert<'a>>]),
273}
274
275impl<'a> AsRef<[Option<Cert<'a>>]> for Intermediates<'a> {
276 fn as_ref(&self) -> &[Option<Cert<'a>>] {
277 match self {
278 Intermediates::Owned { certs, used } => &certs[..*used],
279 Intermediates::Borrowed(certs) => certs,
280 }
281 }
282}
283
284fn check_signed_chain_name_constraints(
285 path: &PathNode<'_>,
286 trust_anchor: &TrustAnchor<'_>,
287 budget: &mut Budget,
288) -> Result<(), ControlFlow<Error, Error>> {
289 let mut name_constraints = trust_anchor
290 .name_constraints
291 .as_ref()
292 .map(|der| untrusted::Input::from(der.as_ref()));
293
294 for path in path.iter() {
295 untrusted::read_all_optional(name_constraints, Error::BadDer, |value| {
296 subject_name::check_name_constraints(value, &path, budget)
297 })?;
298
299 name_constraints = path.cert.name_constraints;
300 }
301
302 Ok(())
303}
304
305pub(crate) struct Budget {
306 signatures: usize,
307 build_chain_calls: usize,
308 name_constraint_comparisons: usize,
309}
310
311impl Budget {
312 #[inline]
313 pub(crate) fn consume_signature(&mut self) -> Result<(), Error> {
314 self.signatures = self
315 .signatures
316 .checked_sub(1)
317 .ok_or(Error::MaximumSignatureChecksExceeded)?;
318 Ok(())
319 }
320
321 #[inline]
322 fn consume_build_chain_call(&mut self) -> Result<(), Error> {
323 self.build_chain_calls = self
324 .build_chain_calls
325 .checked_sub(1)
326 .ok_or(Error::MaximumPathBuildCallsExceeded)?;
327 Ok(())
328 }
329
330 #[inline]
331 pub(crate) fn consume_name_constraint_comparison(&mut self) -> Result<(), Error> {
332 self.name_constraint_comparisons = self
333 .name_constraint_comparisons
334 .checked_sub(1)
335 .ok_or(Error::MaximumNameConstraintComparisonsExceeded)?;
336 Ok(())
337 }
338}
339
340impl Default for Budget {
341 fn default() -> Self {
342 Self {
343 signatures: 100,
348
349 build_chain_calls: 200_000,
352
353 name_constraint_comparisons: 250_000,
356 }
357 }
358}
359
360fn check_issuer_independent_properties(
361 cert: &Cert<'_>,
362 time: UnixTime,
363 role: Role,
364 sub_ca_count: usize,
365 eku: &impl ExtendedKeyUsageValidator,
366) -> Result<(), Error> {
367 cert.validity
379 .read_all(Error::BadDer, |value| check_validity(value, time))?;
380 untrusted::read_all_optional(cert.basic_constraints, Error::BadDer, |value| {
381 check_basic_constraints(value, role, sub_ca_count)
382 })?;
383 untrusted::read_all_optional(cert.eku, Error::BadDer, |input| check_eku(input, eku))?;
384
385 Ok(())
386}
387
388fn check_eku(
389 input: Option<&mut untrusted::Reader<'_>>,
390 eku: &impl ExtendedKeyUsageValidator,
391) -> Result<(), Error> {
392 match input {
393 Some(input) if input.at_end() => Err(Error::EmptyEkuExtension),
394 Some(input) => eku.validate(KeyPurposeIdIter { input }),
395 None => eku.validate(KeyPurposeIdIter {
396 input: &mut untrusted::Reader::new(untrusted::Input::from(&[])),
397 }),
398 }
399}
400
401fn check_validity(input: &mut untrusted::Reader<'_>, time: UnixTime) -> Result<(), Error> {
403 let not_before = UnixTime::from_der(input)?;
404 let not_after = UnixTime::from_der(input)?;
405
406 if not_before > not_after {
407 return Err(Error::InvalidCertValidity);
408 }
409 if time < not_before {
410 return Err(Error::CertNotValidYet { time, not_before });
411 }
412 if time > not_after {
413 return Err(Error::CertExpired { time, not_after });
414 }
415
416 Ok(())
421}
422
423fn check_basic_constraints(
425 input: Option<&mut untrusted::Reader<'_>>,
426 role: Role,
427 sub_ca_count: usize,
428) -> Result<(), Error> {
429 let (is_ca, path_len_constraint) = match input {
430 Some(input) => {
431 let is_ca = bool::from_der(input)?;
432
433 let path_len_constraint = if !input.at_end() {
438 Some(usize::from(u8::from_der(input)?))
439 } else {
440 None
441 };
442
443 (is_ca, path_len_constraint)
444 }
445 None => (false, None),
446 };
447
448 match (role, is_ca, path_len_constraint) {
449 (Role::EndEntity, true, _) => Err(Error::CaUsedAsEndEntity),
450 (Role::Issuer, false, _) => Err(Error::EndEntityUsedAsCa),
451 (Role::Issuer, true, Some(len)) if sub_ca_count > len => {
452 Err(Error::PathLenConstraintViolated)
453 }
454 _ => Ok(()),
455 }
456}
457
458#[derive(Clone, PartialEq, Eq)]
462pub struct RequiredEkuNotFoundContext {
463 #[cfg(feature = "alloc")]
465 pub required: KeyUsage,
466 #[cfg(feature = "alloc")]
468 pub present: Vec<Vec<usize>>,
469}
470
471impl fmt::Debug for RequiredEkuNotFoundContext {
472 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
473 let mut builder = f.debug_struct("RequiredEkuNotFoundContext");
474 #[cfg(feature = "alloc")]
475 builder.field(
476 "required",
477 match &self.required.inner {
478 ExtendedKeyUsage::Required(inner) => inner,
479 ExtendedKeyUsage::RequiredIfPresent(inner) => inner,
480 },
481 );
482 #[cfg(feature = "alloc")]
483 builder.field("present", &EkuListDebug(&self.present));
484 builder.finish()
485 }
486}
487
488#[cfg(feature = "alloc")]
489struct EkuListDebug<'a>(&'a [Vec<usize>]);
490
491#[cfg(feature = "alloc")]
492impl fmt::Debug for EkuListDebug<'_> {
493 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
494 write!(f, "[")?;
495 for (i, part) in self.0.iter().enumerate() {
496 if i > 0 {
497 write!(f, ", ")?;
498 }
499
500 write!(f, "KeyPurposeId(")?;
501 for (j, part) in part.iter().enumerate() {
502 if j > 0 {
503 write!(f, ".")?;
504 }
505 write!(f, "{part}")?;
506 }
507 write!(f, ")")?;
508 }
509 write!(f, "]")
510 }
511}
512
513#[derive(Clone, Copy, Debug, Eq, PartialEq)]
522pub struct KeyUsage {
523 inner: ExtendedKeyUsage,
524}
525
526impl KeyUsage {
527 pub const fn server_auth() -> Self {
531 Self::required_if_present(EKU_SERVER_AUTH)
532 }
533
534 pub const fn client_auth() -> Self {
538 Self::required_if_present(EKU_CLIENT_AUTH)
539 }
540
541 pub const fn required(oid: &'static [u8]) -> Self {
543 Self {
544 inner: ExtendedKeyUsage::Required(KeyPurposeId::new(oid)),
545 }
546 }
547
548 pub const fn required_if_present(oid: &'static [u8]) -> Self {
550 Self {
551 inner: ExtendedKeyUsage::RequiredIfPresent(KeyPurposeId::new(oid)),
552 }
553 }
554
555 pub fn oid_values(&self) -> impl Iterator<Item = usize> + '_ {
557 OidDecoder::new(
558 match &self.inner {
559 ExtendedKeyUsage::Required(eku) => eku,
560 ExtendedKeyUsage::RequiredIfPresent(eku) => eku,
561 }
562 .oid_value
563 .as_slice_less_safe(),
564 )
565 }
566
567 pub const SERVER_AUTH_REPR: &[usize] = &[1, 3, 6, 1, 5, 5, 7, 3, 1];
569 pub const CLIENT_AUTH_REPR: &[usize] = &[1, 3, 6, 1, 5, 5, 7, 3, 2];
571}
572
573impl ExtendedKeyUsageValidator for KeyUsage {
574 fn validate(&self, iter: KeyPurposeIdIter<'_, '_>) -> Result<(), Error> {
576 let mut empty = true;
577 #[cfg(feature = "alloc")]
578 let mut present = Vec::new();
579
580 for id in iter {
581 empty = false;
582 let id = id?;
583 if self.inner.id() == id {
584 return Ok(());
585 }
586
587 #[cfg(feature = "alloc")]
588 present.push(id.to_decoded_oid());
589 }
590
591 match (empty, self.inner) {
592 (true, ExtendedKeyUsage::RequiredIfPresent(_)) => Ok(()),
593 _ => Err(Error::RequiredEkuNotFoundContext(
594 RequiredEkuNotFoundContext {
595 #[cfg(feature = "alloc")]
596 required: Self { inner: self.inner },
597 #[cfg(feature = "alloc")]
598 present,
599 },
600 )),
601 }
602 }
603}
604
605impl<V: ExtendedKeyUsageValidator> ExtendedKeyUsageValidator for &V {
606 fn validate(&self, iter: KeyPurposeIdIter<'_, '_>) -> Result<(), Error> {
607 (*self).validate(iter)
608 }
609}
610
611pub trait ExtendedKeyUsageValidator {
613 fn validate(&self, iter: KeyPurposeIdIter<'_, '_>) -> Result<(), Error>;
620}
621
622#[derive(Clone, Copy, Debug, Eq, PartialEq)]
624enum ExtendedKeyUsage {
625 Required(KeyPurposeId<'static>),
627
628 RequiredIfPresent(KeyPurposeId<'static>),
630}
631
632impl ExtendedKeyUsage {
633 fn id(&self) -> KeyPurposeId<'static> {
634 match self {
635 Self::Required(id) => *id,
636 Self::RequiredIfPresent(id) => *id,
637 }
638 }
639}
640
641pub struct KeyPurposeIdIter<'a, 'r> {
643 input: &'r mut untrusted::Reader<'a>,
644}
645
646impl<'a, 'r> Iterator for KeyPurposeIdIter<'a, 'r> {
647 type Item = Result<KeyPurposeId<'a>, Error>;
648
649 fn next(&mut self) -> Option<Self::Item> {
650 if self.input.at_end() {
651 return None;
652 }
653
654 Some(der::expect_tag(self.input, der::Tag::OID).map(|oid_value| KeyPurposeId { oid_value }))
655 }
656}
657
658impl Drop for KeyPurposeIdIter<'_, '_> {
659 fn drop(&mut self) {
660 self.input.skip_to_end();
661 }
662}
663
664#[derive(Clone, Copy)]
666pub struct KeyPurposeId<'a> {
667 oid_value: untrusted::Input<'a>,
668}
669
670impl<'a> KeyPurposeId<'a> {
671 pub const fn new(oid: &'a [u8]) -> Self {
675 Self {
676 oid_value: untrusted::Input::from(oid),
677 }
678 }
679
680 #[cfg(feature = "alloc")]
682 pub fn to_decoded_oid(&self) -> Vec<usize> {
683 OidDecoder::new(self.oid_value.as_slice_less_safe()).collect()
684 }
685}
686
687impl fmt::Debug for KeyPurposeId<'_> {
688 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
689 write!(f, "KeyPurposeId(")?;
690 let decoder = OidDecoder::new(self.oid_value.as_slice_less_safe());
691 for (i, part) in decoder.enumerate() {
692 if i > 0 {
693 write!(f, ".")?;
694 }
695 write!(f, "{part}")?;
696 }
697 write!(f, ")")
698 }
699}
700
701impl PartialEq<Self> for KeyPurposeId<'_> {
702 fn eq(&self, other: &Self) -> bool {
703 public_values_eq(self.oid_value, other.oid_value)
704 }
705}
706
707impl Eq for KeyPurposeId<'_> {}
708
709const EKU_SERVER_AUTH: &[u8] = &oid!(1, 3, 6, 1, 5, 5, 7, 3, 1);
714
715const EKU_CLIENT_AUTH: &[u8] = &oid!(1, 3, 6, 1, 5, 5, 7, 3, 2);
717
718struct OidDecoder<'a> {
719 encoded: &'a [u8],
720 left: Option<usize>,
721 first: bool,
722}
723
724impl<'a> OidDecoder<'a> {
725 fn new(encoded: &'a [u8]) -> Self {
726 Self {
727 encoded,
728 left: None,
729 first: true,
730 }
731 }
732}
733
734impl Iterator for OidDecoder<'_> {
735 type Item = usize;
736
737 fn next(&mut self) -> Option<Self::Item> {
738 if let Some(next) = self.left.take() {
739 return Some(next);
740 }
741
742 let mut cur = 0;
743 for (i, &byte) in self.encoded.iter().enumerate() {
744 cur = (cur << 8) + usize::from(byte & 0x7f);
745 if byte & 0x80 > 0 {
746 continue;
747 }
748
749 if !self.first {
750 self.encoded = &self.encoded[i + 1..];
751 return Some(cur);
752 }
753
754 let (cur, next) = match cur {
755 ..=39 => (0, cur),
756 40..=79 => (1, cur - 40),
757 _ => (2, cur - 80),
758 };
759
760 self.encoded = &self.encoded[i + 1..];
761 self.first = false;
762 self.left = Some(next);
763 return Some(cur);
764 }
765
766 None
767 }
768}
769
770fn loop_while_non_fatal_error<'a, V: IntoIterator + 'a>(
771 default_error: Error,
772 values: V,
773 mut f: impl FnMut(V::Item) -> Result<&'a TrustAnchor<'a>, ControlFlow<Error, Error>>,
774) -> Result<&'a TrustAnchor<'a>, ControlFlow<Error, Error>> {
775 let mut error = default_error;
776 for v in values {
777 match f(v) {
778 Ok(anchor) => return Ok(anchor),
779 res @ Err(ControlFlow::Break(_)) => return res,
781 Err(ControlFlow::Continue(new_error)) => error = error.most_specific(new_error),
784 }
785 }
786 Err(error.into())
787}
788
789pub(crate) struct PartialPath<'a> {
794 end_entity: &'a EndEntityCert<'a>,
795 intermediates: [Option<Cert<'a>>; MAX_SUB_CA_COUNT],
799 used: usize,
804}
805
806impl<'a> PartialPath<'a> {
807 pub(crate) fn new(end_entity: &'a EndEntityCert<'a>) -> Self {
808 Self {
809 end_entity,
810 intermediates: Default::default(),
811 used: 0,
812 }
813 }
814
815 pub(crate) fn push(&mut self, cert: Cert<'a>) -> Result<(), ControlFlow<Error, Error>> {
816 if self.used >= MAX_SUB_CA_COUNT {
817 return Err(Error::MaximumPathDepthExceeded.into());
818 }
819
820 self.intermediates[self.used] = Some(cert);
821 self.used += 1;
822 Ok(())
823 }
824
825 fn pop(&mut self) {
826 debug_assert!(self.used > 0);
827 if self.used == 0 {
828 return;
829 }
830
831 self.used -= 1;
832 self.intermediates[self.used] = None;
833 }
834
835 pub(crate) fn node(&self) -> PathNode<'_> {
836 PathNode {
837 path: self,
838 index: self.used,
839 cert: self.head(),
840 }
841 }
842
843 pub(crate) fn head(&self) -> &Cert<'a> {
845 self.get(self.used)
846 }
847
848 fn get(&self, idx: usize) -> &Cert<'a> {
853 match idx {
854 0 => self.end_entity,
855 _ => self.intermediates[idx - 1].as_ref().unwrap(),
856 }
857 }
858}
859
860const MAX_SUB_CA_COUNT: usize = 6;
861
862pub(crate) struct PathNode<'a> {
863 path: &'a PartialPath<'a>,
865 index: usize,
867 pub(crate) cert: &'a Cert<'a>,
869}
870
871impl<'a> PathNode<'a> {
872 pub(crate) fn iter(&self) -> PathIter<'a> {
873 PathIter {
874 path: self.path,
875 next: Some(self.index),
876 }
877 }
878
879 pub(crate) fn role(&self) -> Role {
880 match self.index {
881 0 => Role::EndEntity,
882 _ => Role::Issuer,
883 }
884 }
885}
886
887pub(crate) struct PathIter<'a> {
888 path: &'a PartialPath<'a>,
889 next: Option<usize>,
890}
891
892impl<'a> Iterator for PathIter<'a> {
893 type Item = PathNode<'a>;
894
895 fn next(&mut self) -> Option<Self::Item> {
896 let next = self.next?;
897 self.next = match next {
898 0 => None,
899 _ => Some(next - 1),
900 };
901
902 Some(PathNode {
903 path: self.path,
904 index: next,
905 cert: self.path.get(next),
906 })
907 }
908}
909
910#[derive(Clone, Copy, PartialEq)]
911pub(crate) enum Role {
912 Issuer,
913 EndEntity,
914}
915
916pub(crate) const DISTRUSTED_SPKIS: &[&[u8]] = &[
918 include_bytes!("data/distrusted/EMDVTLSCAG3B.spki.der"),
919 include_bytes!("data/distrusted/EMDVTLSCAG3C.spki.der"),
920 include_bytes!("data/distrusted/EMEVTLSCAG3B.spki.der"),
921 include_bytes!("data/distrusted/EMEVTLSCAG3C.spki.der"),
922 include_bytes!("data/distrusted/EMOVTLSCAG3B.spki.der"),
923 include_bytes!("data/distrusted/EMOVTLSCAG3C.spki.der"),
924 include_bytes!("data/distrusted/EMOVCSCAG3B.spki.der"),
925 include_bytes!("data/distrusted/EMOVCSCAG3C.spki.der"),
926];
927
928#[cfg(all(test, feature = "alloc", any(feature = "ring", feature = "aws-lc-rs")))]
929mod tests {
930 use alloc::borrow::ToOwned;
931 use alloc::string::{String, ToString};
932 use std::dbg;
933 use std::slice;
934
935 use super::*;
936 use crate::test_utils;
937 use crate::test_utils::{issuer_params, make_end_entity, make_issuer};
938 use crate::trust_anchor::anchor_from_trusted_cert;
939 use rcgen::{CertifiedIssuer, Issuer, KeyPair, SigningKey};
940
941 #[test]
942 fn roundtrip() {
943 const ENCODED: &[u8] = &[0x84, 0x37, 0x3];
945 let decoded = OidDecoder::new(ENCODED);
946 assert_eq!(decoded.collect::<Vec<_>>(), [2, 999, 3]);
947 }
948
949 #[test]
950 fn oid_decoding() {
951 assert_eq!(
952 KeyUsage::server_auth().oid_values().collect::<Vec<_>>(),
953 KeyUsage::SERVER_AUTH_REPR
954 );
955 assert_eq!(
956 KeyUsage::client_auth().oid_values().collect::<Vec<_>>(),
957 KeyUsage::CLIENT_AUTH_REPR
958 );
959 }
960
961 #[test]
962 fn eku_fail_empty() {
963 let err = KeyUsage::required(EKU_SERVER_AUTH)
964 .validate(KeyPurposeIdIter {
965 input: &mut untrusted::Reader::new(untrusted::Input::from(&[])),
966 })
967 .unwrap_err();
968 assert_eq!(
969 err,
970 Error::RequiredEkuNotFoundContext(RequiredEkuNotFoundContext {
971 #[cfg(feature = "alloc")]
972 required: dbg!(KeyUsage::required(EKU_SERVER_AUTH)), #[cfg(feature = "alloc")]
974 present: Vec::new(),
975 })
976 );
977 }
978
979 #[test]
980 fn eku_fail_empty_with_optional() {
981 let mut empty_eku = untrusted::Reader::new(untrusted::Input::from(&[]));
982 let validator = KeyUsage::required_if_present(EKU_SERVER_AUTH);
983 assert_eq!(
984 check_eku(Some(&mut empty_eku), &validator).unwrap_err(),
985 Error::EmptyEkuExtension,
986 );
987 }
988
989 #[test]
990 fn eku_key_purpose_id() {
991 assert!(
992 ExtendedKeyUsage::RequiredIfPresent(KeyPurposeId::new(EKU_SERVER_AUTH)).id()
993 == KeyPurposeId::new(EKU_SERVER_AUTH)
994 )
995 }
996
997 #[test]
998 fn test_too_many_signatures() {
999 assert!(matches!(
1000 build_and_verify_degenerate_chain(5, ChainTrustAnchor::NotInChain),
1001 ControlFlow::Break(Error::MaximumSignatureChecksExceeded)
1002 ));
1003 }
1004
1005 #[test]
1006 fn test_too_many_path_calls() {
1007 assert!(matches!(
1008 dbg!(build_and_verify_degenerate_chain(
1009 10,
1010 ChainTrustAnchor::InChain
1011 )),
1012 ControlFlow::Break(Error::MaximumPathBuildCallsExceeded)
1013 ));
1014 }
1015
1016 #[test]
1017 fn longest_allowed_path() {
1018 assert!(build_and_verify_linear_chain(1).is_ok());
1019 assert!(build_and_verify_linear_chain(2).is_ok());
1020 assert!(build_and_verify_linear_chain(3).is_ok());
1021 assert!(build_and_verify_linear_chain(4).is_ok());
1022 assert!(build_and_verify_linear_chain(5).is_ok());
1023 assert!(build_and_verify_linear_chain(6).is_ok());
1024 }
1025
1026 #[test]
1027 fn path_too_long() {
1028 assert!(matches!(
1029 build_and_verify_linear_chain(7),
1030 Err(ControlFlow::Continue(Error::MaximumPathDepthExceeded))
1031 ));
1032 }
1033
1034 #[test]
1035 fn name_constraint_budget() {
1036 let mut ca_cert_params = issuer_params("Constrained Root");
1039 ca_cert_params.name_constraints = Some(rcgen::NameConstraints {
1040 permitted_subtrees: vec![rcgen::GeneralSubtree::DnsName(".com".into())],
1041 excluded_subtrees: vec![],
1042 });
1043 let ca_key_pair = KeyPair::generate_for(test_utils::RCGEN_SIGNATURE_ALG).unwrap();
1044 let ca = CertifiedIssuer::self_signed(ca_cert_params, ca_key_pair).unwrap();
1045
1046 let mut intermediates = Vec::with_capacity(5);
1050 for i in 0..5 {
1051 let intermediate = issuer_params(format!("Intermediate {i}"));
1052 let intermediate_key_pair =
1053 KeyPair::generate_for(test_utils::RCGEN_SIGNATURE_ALG).unwrap();
1054 intermediates.push(
1056 CertifiedIssuer::signed_by(intermediate, intermediate_key_pair, &ca).unwrap(),
1057 );
1058 }
1059
1060 let ee_cert = make_end_entity(intermediates.last().unwrap());
1062 let ee_cert = EndEntityCert::try_from(ee_cert.cert.der()).unwrap();
1063
1064 let passing_budget = Budget {
1068 name_constraint_comparisons: 3,
1073 ..Budget::default()
1074 };
1075
1076 let anchors = &[anchor_from_trusted_cert(ca.der()).unwrap()];
1077 let intermediates_der = intermediates
1078 .iter()
1079 .map(|issuer| issuer.der().clone())
1080 .collect::<Vec<_>>();
1081
1082 let path = verify_chain(
1086 anchors,
1087 &intermediates_der,
1088 &ee_cert,
1089 None,
1090 Some(passing_budget),
1091 )
1092 .unwrap();
1093 assert_eq!(path.anchor().subject, anchors.first().unwrap().subject);
1094
1095 let failing_budget = Budget {
1096 name_constraint_comparisons: 2,
1098 ..Budget::default()
1099 };
1100 let result = verify_chain(
1104 anchors,
1105 &intermediates_der,
1106 &ee_cert,
1107 None,
1108 Some(failing_budget),
1109 );
1110
1111 assert!(matches!(
1112 result,
1113 Err(ControlFlow::Break(
1114 Error::MaximumNameConstraintComparisonsExceeded
1115 ))
1116 ));
1117 }
1118
1119 #[test]
1151 fn test_reject_candidate_path() {
1152 let trust_anchor = make_issuer("Trust Anchor");
1155 let trust_anchor_cert = Cert::from_der(untrusted::Input::from(trust_anchor.der())).unwrap();
1156 let trust_anchors = &[anchor_from_trusted_cert(trust_anchor.der()).unwrap()];
1157
1158 let intermediate_a = make_intermediate("Intermediate A", &trust_anchor);
1159 let intermediate_c = make_intermediate("Intermediate C", &trust_anchor);
1160
1161 let (intermediate_b, intermediate_b_a_cert, intermediate_b_c_cert) = {
1164 let key = KeyPair::generate_for(test_utils::RCGEN_SIGNATURE_ALG).unwrap();
1165 let params = issuer_params("Intermediate");
1166 let intermediate_b_a_cert = params.signed_by(&key, &intermediate_a).unwrap();
1167 let intermediate_b_c_cert = params.signed_by(&key, &intermediate_c).unwrap();
1168 let issuer = Issuer::new(params, key);
1169 (issuer, intermediate_b_a_cert, intermediate_b_c_cert)
1170 };
1171
1172 let intermediates = &[
1173 intermediate_a.der().clone(),
1174 intermediate_c.der().clone(),
1175 intermediate_b_a_cert.der().clone(),
1176 intermediate_b_c_cert.der().clone(),
1177 ];
1178
1179 let ee = make_end_entity(&intermediate_b);
1181 let ee_cert = &EndEntityCert::try_from(ee.cert.der()).unwrap();
1182
1183 let path = verify_chain(trust_anchors, intermediates, ee_cert, None, None).unwrap();
1185 let path_intermediates = path.intermediate_certificates().collect::<Vec<_>>();
1186
1187 let intermediate_a_cert =
1190 Cert::from_der(untrusted::Input::from(intermediate_a.der())).unwrap();
1191 assert_eq!(path_intermediates.len(), 2);
1192 assert_eq!(
1193 path_intermediates[0].issuer(),
1194 intermediate_a_cert.subject()
1195 );
1196 assert_eq!(path_intermediates[1].issuer(), trust_anchor_cert.subject());
1197
1198 let expected_chain = |path: &VerifiedPath<'_>| {
1200 for intermediate in path.intermediate_certificates() {
1201 if intermediate.issuer() == intermediate_a_cert.subject() {
1203 return Err(Error::UnknownIssuer);
1204 }
1205 }
1206
1207 Ok(())
1208 };
1209
1210 let path = verify_chain(
1212 trust_anchors,
1213 intermediates,
1214 ee_cert,
1215 Some(&expected_chain),
1216 None,
1217 )
1218 .unwrap();
1219 let path_intermediates = path.intermediate_certificates().collect::<Vec<_>>();
1220
1221 let intermediate_c_cert =
1224 Cert::from_der(untrusted::Input::from(intermediate_c.der())).unwrap();
1225 assert_eq!(path_intermediates.len(), 2);
1226 assert_eq!(
1227 path_intermediates[0].issuer(),
1228 intermediate_c_cert.subject()
1229 );
1230 assert_eq!(path_intermediates[1].issuer(), trust_anchor_cert.subject());
1231 }
1232
1233 #[test]
1234 fn distrusted_spki() {
1235 fn verify(
1236 ee_cert: &EndEntityCert<'_>,
1237 intermediates: &[CertificateDer<'_>],
1238 trust_anchors: &[TrustAnchor<'_>],
1239 distrusted_spkis: &[&[u8]],
1240 ) -> Result<usize, Error> {
1241 use core::time::Duration;
1242
1243 ChainOptions {
1244 eku: KeyUsage::server_auth(),
1245 supported_sig_algs: crate::ALL_VERIFICATION_ALGS,
1246 trust_anchors,
1247 intermediate_certs: intermediates,
1248 revocation: None,
1249 distrusted_spkis,
1250 }
1251 .build_chain(
1252 ee_cert,
1253 UnixTime::since_unix_epoch(Duration::from_secs(0x1fed_f00d)),
1254 None,
1255 )
1256 .map(|path| path.intermediate_certificates().count())
1257 }
1258
1259 let root = make_issuer("Root");
1260 let trust_anchors = &[anchor_from_trusted_cert(root.der()).unwrap()];
1261 let issuing_intermediate = make_intermediate("Issuing Intermediate", &root);
1262 let unrelated = make_intermediate("Intermediate", &root);
1263
1264 let params = issuer_params("Intermediate");
1265 let key = KeyPair::generate_for(test_utils::RCGEN_SIGNATURE_ALG).unwrap();
1266 let intermediate = params.signed_by(&key, &issuing_intermediate).unwrap();
1268 let cross_signed = params.signed_by(&key, &root).unwrap();
1269 let ee = make_end_entity(&Issuer::new(params, key));
1270 let ee_cert = EndEntityCert::try_from(ee.cert.der()).unwrap();
1271 let intermediates = &[
1272 unrelated.der().clone(),
1273 intermediate.der().clone(),
1274 issuing_intermediate.der().clone(),
1275 ];
1276 assert_eq!(
1277 verify(&ee_cert, intermediates, trust_anchors, DISTRUSTED_SPKIS),
1278 Ok(2)
1279 );
1280
1281 for cert in [
1283 root.der(),
1284 issuing_intermediate.der(),
1285 intermediate.der(),
1286 ee.cert.der(),
1287 ] {
1288 assert_eq!(
1289 verify(
1290 &ee_cert,
1291 intermediates,
1292 trust_anchors,
1293 &[anchor_from_trusted_cert(cert)
1294 .unwrap()
1295 .subject_public_key_info
1296 .as_ref()]
1297 ),
1298 Err(Error::CertDistrusted)
1299 );
1300 }
1301
1302 assert_eq!(
1304 verify(
1305 &ee_cert,
1306 intermediates,
1307 trust_anchors,
1308 &[anchor_from_trusted_cert(unrelated.der())
1309 .unwrap()
1310 .subject_public_key_info
1311 .as_ref()]
1312 ),
1313 Ok(2)
1314 );
1315
1316 let intermediates = &[
1318 intermediate.der().clone(),
1319 issuing_intermediate.der().clone(),
1320 cross_signed.der().clone(),
1321 ];
1322 let issuer_spki = anchor_from_trusted_cert(issuing_intermediate.der()).unwrap();
1323 assert_eq!(
1324 verify(
1325 &ee_cert,
1326 intermediates,
1327 trust_anchors,
1328 &[issuer_spki.subject_public_key_info.as_ref()]
1329 ),
1330 Ok(1)
1331 );
1332
1333 let intermediate_spki = anchor_from_trusted_cert(intermediate.der()).unwrap();
1335 assert_eq!(
1336 verify(
1337 &ee_cert,
1338 intermediates,
1339 trust_anchors,
1340 &[intermediate_spki.subject_public_key_info.as_ref()]
1341 ),
1342 Err(Error::CertDistrusted)
1343 );
1344
1345 assert_eq!(
1347 verify(
1348 &ee_cert,
1349 &[intermediate.der().clone()],
1350 &[],
1351 &[intermediate_spki.subject_public_key_info.as_ref()]
1352 ),
1353 Err(Error::CertDistrusted)
1354 );
1355 }
1356
1357 fn make_intermediate(
1358 org_name: impl Into<String>,
1359 issuer: &Issuer<'_, impl SigningKey>,
1360 ) -> CertifiedIssuer<'static, KeyPair> {
1361 let params = issuer_params(org_name);
1362 let key = KeyPair::generate_for(test_utils::RCGEN_SIGNATURE_ALG).unwrap();
1363 CertifiedIssuer::signed_by(params, key, issuer).unwrap()
1364 }
1365
1366 fn build_and_verify_degenerate_chain(
1367 intermediate_count: usize,
1368 trust_anchor: ChainTrustAnchor,
1369 ) -> ControlFlow<Error, Error> {
1370 let ca = make_issuer("Bogus Subject");
1371 let mut intermediate_chain = IntermediateChain::new(intermediate_count, true, &ca);
1372
1373 let verify_trust_anchor = match trust_anchor {
1374 ChainTrustAnchor::InChain => make_issuer("Bogus Trust Anchor"),
1375 ChainTrustAnchor::NotInChain => ca,
1376 };
1377
1378 let ee_cert = make_end_entity(&intermediate_chain.last_issuer);
1379 let ee_cert = EndEntityCert::try_from(ee_cert.cert.der()).unwrap();
1380 let webpki_ta = anchor_from_trusted_cert(verify_trust_anchor.der()).unwrap();
1381 if matches!(trust_anchor, ChainTrustAnchor::InChain) {
1382 intermediate_chain
1385 .chain
1386 .insert(0, verify_trust_anchor.der().to_owned())
1387 }
1388
1389 verify_chain(
1390 &[webpki_ta],
1391 &intermediate_chain.chain,
1392 &ee_cert,
1393 None,
1394 None,
1395 )
1396 .map(|_| ())
1397 .unwrap_err()
1398 }
1399
1400 #[cfg(feature = "alloc")]
1401 enum ChainTrustAnchor {
1402 NotInChain,
1403 InChain,
1404 }
1405
1406 fn build_and_verify_linear_chain(chain_length: usize) -> Result<(), ControlFlow<Error, Error>> {
1407 let ca = make_issuer(format!("Bogus Subject {chain_length}"));
1408 let intermediate_chain = IntermediateChain::new(chain_length, false, &ca);
1409
1410 let anchor = anchor_from_trusted_cert(ca.der()).unwrap();
1411 let anchors = slice::from_ref(&anchor);
1412
1413 let ee_cert = make_end_entity(&intermediate_chain.last_issuer);
1414 let ee_cert = EndEntityCert::try_from(ee_cert.cert.der()).unwrap();
1415
1416 let expected_chain = |path: &VerifiedPath<'_>| {
1417 assert_eq!(path.anchor().subject, anchor.subject);
1418 assert!(public_values_eq(path.end_entity().subject, ee_cert.subject));
1419 assert_eq!(path.intermediate_certificates().count(), chain_length);
1420
1421 let intermediate_certs = intermediate_chain
1422 .chain
1423 .iter()
1424 .map(|der| Cert::from_der(untrusted::Input::from(der)).unwrap())
1425 .collect::<Vec<_>>();
1426
1427 for (cert, expected) in path
1428 .intermediate_certificates()
1429 .rev()
1430 .zip(intermediate_certs.iter())
1431 {
1432 assert!(public_values_eq(cert.subject, expected.subject));
1433 assert_eq!(cert.der(), expected.der());
1434 }
1435
1436 for (cert, expected) in path
1437 .intermediate_certificates()
1438 .zip(intermediate_certs.iter().rev())
1439 {
1440 assert!(public_values_eq(cert.subject, expected.subject));
1441 assert_eq!(cert.der(), expected.der());
1442 }
1443
1444 Ok(())
1445 };
1446
1447 verify_chain(
1448 anchors,
1449 &intermediate_chain.chain,
1450 &ee_cert,
1451 Some(&expected_chain),
1452 None,
1453 )
1454 .map(|_| ())
1455 }
1456
1457 struct IntermediateChain {
1458 last_issuer: Issuer<'static, KeyPair>,
1459 chain: Vec<CertificateDer<'static>>,
1460 }
1461
1462 impl IntermediateChain {
1463 fn new(chain_length: usize, all_same_subject: bool, ca_cert: &Issuer<'_, KeyPair>) -> Self {
1464 let mut chain = Vec::with_capacity(chain_length);
1465
1466 let mut prev = None;
1467 for i in 0..chain_length {
1468 let issuer = match &prev {
1469 Some(prev) => prev,
1470 None => ca_cert,
1471 };
1472
1473 let intermediate = issuer_params(match all_same_subject {
1474 true => "Bogus Subject".to_string(),
1475 false => format!("Bogus Subject {i}"),
1476 });
1477
1478 let key_pair = KeyPair::generate_for(test_utils::RCGEN_SIGNATURE_ALG).unwrap();
1479 let cert = intermediate.signed_by(&key_pair, issuer).unwrap();
1480
1481 chain.push(cert.der().clone());
1482 prev = Some(Issuer::new(intermediate, key_pair));
1483 }
1484
1485 Self {
1486 last_issuer: prev.unwrap(),
1487 chain,
1488 }
1489 }
1490 }
1491
1492 fn verify_chain<'a>(
1493 trust_anchors: &'a [TrustAnchor<'a>],
1494 intermediate_certs: &'a [CertificateDer<'a>],
1495 ee_cert: &'a EndEntityCert<'a>,
1496 verify_path: Option<&dyn Fn(&VerifiedPath<'_>) -> Result<(), Error>>,
1497 budget: Option<Budget>,
1498 ) -> Result<VerifiedPath<'a>, ControlFlow<Error, Error>> {
1499 use core::time::Duration;
1500
1501 let time = UnixTime::since_unix_epoch(Duration::from_secs(0x1fed_f00d));
1502 let mut path = PartialPath::new(ee_cert);
1503 let opts = ChainOptions {
1504 eku: KeyUsage::server_auth(),
1505 supported_sig_algs: crate::ALL_VERIFICATION_ALGS,
1506 trust_anchors,
1507 intermediate_certs,
1508 revocation: None,
1509 distrusted_spkis: DISTRUSTED_SPKIS,
1510 };
1511
1512 match opts.build_chain_inner(
1513 &mut path,
1514 time,
1515 verify_path,
1516 0,
1517 &mut budget.unwrap_or_default(),
1518 ) {
1519 Ok(anchor) => Ok(VerifiedPath::new(ee_cert, anchor, path)),
1520 Err(err) => Err(err),
1521 }
1522 }
1523}