1use core::ops::ControlFlow;
16
17use pki_types::{CertificateDer, SignatureVerificationAlgorithm, TrustAnchor, UnixTime};
18
19use crate::cert::Cert;
20use crate::crl::RevocationOptions;
21use crate::der::{self, FromDer};
22use crate::end_entity::EndEntityCert;
23use crate::error::Error;
24use crate::{public_values_eq, signed_data, subject_name};
25
26pub(crate) struct ChainOptions<'a, 'p> {
29 pub(crate) eku: KeyUsage,
30 pub(crate) supported_sig_algs: &'a [&'a dyn SignatureVerificationAlgorithm],
31 pub(crate) trust_anchors: &'p [TrustAnchor<'p>],
32 pub(crate) intermediate_certs: &'p [CertificateDer<'p>],
33 pub(crate) revocation: Option<RevocationOptions<'a>>,
34}
35
36impl<'a, 'p: 'a> ChainOptions<'a, 'p> {
37 pub(crate) fn build_chain(
38 &self,
39 end_entity: &'p EndEntityCert<'p>,
40 time: UnixTime,
41 verify_path: Option<&dyn Fn(&VerifiedPath<'_>) -> Result<(), Error>>,
42 ) -> Result<VerifiedPath<'p>, Error> {
43 let mut path = PartialPath::new(end_entity);
44 match self.build_chain_inner(&mut path, time, verify_path, 0, &mut Budget::default()) {
45 Ok(anchor) => Ok(VerifiedPath::new(end_entity, anchor, path)),
46 Err(ControlFlow::Break(err)) | Err(ControlFlow::Continue(err)) => Err(err),
47 }
48 }
49
50 fn build_chain_inner(
51 &self,
52 path: &mut PartialPath<'p>,
53 time: UnixTime,
54 verify_path: Option<&dyn Fn(&VerifiedPath<'_>) -> Result<(), Error>>,
55 sub_ca_count: usize,
56 budget: &mut Budget,
57 ) -> Result<&'p TrustAnchor<'p>, ControlFlow<Error, Error>> {
58 let role = path.node().role();
59
60 check_issuer_independent_properties(path.head(), time, role, sub_ca_count, self.eku.inner)?;
61
62 let result =
65 loop_while_non_fatal_error(Error::UnknownIssuer, self.trust_anchors, |trust_anchor| {
66 let trust_anchor_subject = untrusted::Input::from(trust_anchor.subject.as_ref());
67 if !public_values_eq(path.head().issuer, trust_anchor_subject) {
68 return Err(Error::UnknownIssuer.into());
69 }
70
71 let node = path.node();
74 self.check_signed_chain(&node, time, trust_anchor, budget)?;
75 check_signed_chain_name_constraints(&node, trust_anchor, budget)?;
76
77 let verify = match verify_path {
78 Some(verify) => verify,
79 None => return Ok(trust_anchor),
80 };
81
82 let candidate = VerifiedPath {
83 end_entity: path.end_entity,
84 intermediates: Intermediates::Borrowed(&path.intermediates[..path.used]),
85 anchor: trust_anchor,
86 };
87
88 match verify(&candidate) {
89 Ok(()) => Ok(trust_anchor),
90 Err(err) => Err(ControlFlow::Continue(err)),
91 }
92 });
93
94 let err = match result {
95 Ok(anchor) => return Ok(anchor),
96 res @ Err(ControlFlow::Break(_)) => return res,
98 Err(ControlFlow::Continue(err)) => err,
102 };
103
104 loop_while_non_fatal_error(err, self.intermediate_certs, |cert_der| {
105 let potential_issuer = Cert::from_der(untrusted::Input::from(cert_der))?;
106 if !public_values_eq(potential_issuer.subject, path.head().issuer) {
107 return Err(Error::UnknownIssuer.into());
108 }
109
110 if path.node().iter().any(|prev| {
112 public_values_eq(potential_issuer.spki, prev.cert.spki)
113 && public_values_eq(potential_issuer.subject, prev.cert.subject)
114 }) {
115 return Err(Error::UnknownIssuer.into());
116 }
117
118 let next_sub_ca_count = match role {
119 Role::EndEntity => sub_ca_count,
120 Role::Issuer => sub_ca_count + 1,
121 };
122
123 budget.consume_build_chain_call()?;
124 path.push(potential_issuer)?;
125 let result = self.build_chain_inner(path, time, verify_path, next_sub_ca_count, budget);
126 if result.is_err() {
127 path.pop();
128 }
129
130 result
131 })
132 }
133
134 fn check_signed_chain(
135 &self,
136 path: &PathNode<'_>,
137 time: UnixTime,
138 trust_anchor: &TrustAnchor<'_>,
139 budget: &mut Budget,
140 ) -> Result<(), ControlFlow<Error, Error>> {
141 let mut spki_value = untrusted::Input::from(trust_anchor.subject_public_key_info.as_ref());
142 let mut issuer_subject = untrusted::Input::from(trust_anchor.subject.as_ref());
143 let mut issuer_key_usage = None; for path in path.iter() {
145 signed_data::verify_signed_data(
146 self.supported_sig_algs,
147 spki_value,
148 &path.cert.signed_data,
149 budget,
150 )?;
151
152 if let Some(revocation_opts) = &self.revocation {
153 revocation_opts.check(
154 &path,
155 issuer_subject,
156 spki_value,
157 issuer_key_usage,
158 self.supported_sig_algs,
159 budget,
160 time,
161 )?;
162 }
163
164 spki_value = path.cert.spki;
165 issuer_subject = path.cert.subject;
166 issuer_key_usage = path.cert.key_usage;
167 }
168
169 Ok(())
170 }
171}
172
173pub struct VerifiedPath<'p> {
177 end_entity: &'p EndEntityCert<'p>,
178 intermediates: Intermediates<'p>,
179 anchor: &'p TrustAnchor<'p>,
180}
181
182impl<'p> VerifiedPath<'p> {
183 fn new(
184 end_entity: &'p EndEntityCert<'p>,
185 anchor: &'p TrustAnchor<'p>,
186 partial: PartialPath<'p>,
187 ) -> Self {
188 Self {
189 end_entity,
190 intermediates: Intermediates::Owned {
191 certs: partial.intermediates,
192 used: partial.used,
193 },
194 anchor,
195 }
196 }
197
198 pub fn intermediate_certificates(&'p self) -> IntermediateIterator<'p> {
200 IntermediateIterator {
201 intermediates: self.intermediates.as_ref(),
202 }
203 }
204
205 pub fn end_entity(&self) -> &'p EndEntityCert<'p> {
207 self.end_entity
208 }
209
210 pub fn anchor(&self) -> &'p TrustAnchor<'p> {
212 self.anchor
213 }
214}
215
216pub struct IntermediateIterator<'a> {
220 intermediates: &'a [Option<Cert<'a>>],
222}
223
224impl<'a> Iterator for IntermediateIterator<'a> {
225 type Item = &'a Cert<'a>;
226
227 fn next(&mut self) -> Option<Self::Item> {
228 match self.intermediates.split_first() {
229 Some((head, tail)) => {
230 self.intermediates = tail;
231 Some(head.as_ref().unwrap())
232 }
233 None => None,
234 }
235 }
236}
237
238impl DoubleEndedIterator for IntermediateIterator<'_> {
239 fn next_back(&mut self) -> Option<Self::Item> {
240 match self.intermediates.split_last() {
241 Some((head, tail)) => {
242 self.intermediates = tail;
243 Some(head.as_ref().unwrap())
244 }
245 None => None,
246 }
247 }
248}
249
250#[allow(clippy::large_enum_variant)]
251enum Intermediates<'a> {
252 Owned {
253 certs: [Option<Cert<'a>>; MAX_SUB_CA_COUNT],
254 used: usize,
255 },
256 Borrowed(&'a [Option<Cert<'a>>]),
257}
258
259impl<'a> AsRef<[Option<Cert<'a>>]> for Intermediates<'a> {
260 fn as_ref(&self) -> &[Option<Cert<'a>>] {
261 match self {
262 Intermediates::Owned { certs, used } => &certs[..*used],
263 Intermediates::Borrowed(certs) => certs,
264 }
265 }
266}
267
268fn check_signed_chain_name_constraints(
269 path: &PathNode<'_>,
270 trust_anchor: &TrustAnchor<'_>,
271 budget: &mut Budget,
272) -> Result<(), ControlFlow<Error, Error>> {
273 let mut name_constraints = trust_anchor
274 .name_constraints
275 .as_ref()
276 .map(|der| untrusted::Input::from(der.as_ref()));
277
278 for path in path.iter() {
279 untrusted::read_all_optional(name_constraints, Error::BadDer, |value| {
280 subject_name::check_name_constraints(value, &path, budget)
281 })?;
282
283 name_constraints = path.cert.name_constraints;
284 }
285
286 Ok(())
287}
288
289pub(crate) struct Budget {
290 signatures: usize,
291 build_chain_calls: usize,
292 name_constraint_comparisons: usize,
293}
294
295impl Budget {
296 #[inline]
297 pub(crate) fn consume_signature(&mut self) -> Result<(), Error> {
298 self.signatures = self
299 .signatures
300 .checked_sub(1)
301 .ok_or(Error::MaximumSignatureChecksExceeded)?;
302 Ok(())
303 }
304
305 #[inline]
306 fn consume_build_chain_call(&mut self) -> Result<(), Error> {
307 self.build_chain_calls = self
308 .build_chain_calls
309 .checked_sub(1)
310 .ok_or(Error::MaximumPathBuildCallsExceeded)?;
311 Ok(())
312 }
313
314 #[inline]
315 pub(crate) fn consume_name_constraint_comparison(&mut self) -> Result<(), Error> {
316 self.name_constraint_comparisons = self
317 .name_constraint_comparisons
318 .checked_sub(1)
319 .ok_or(Error::MaximumNameConstraintComparisonsExceeded)?;
320 Ok(())
321 }
322}
323
324impl Default for Budget {
325 fn default() -> Self {
326 Self {
327 signatures: 100,
332
333 build_chain_calls: 200_000,
336
337 name_constraint_comparisons: 250_000,
340 }
341 }
342}
343
344fn check_issuer_independent_properties(
345 cert: &Cert<'_>,
346 time: UnixTime,
347 role: Role,
348 sub_ca_count: usize,
349 eku: ExtendedKeyUsage,
350) -> Result<(), Error> {
351 cert.validity
363 .read_all(Error::BadDer, |value| check_validity(value, time))?;
364 untrusted::read_all_optional(cert.basic_constraints, Error::BadDer, |value| {
365 check_basic_constraints(value, role, sub_ca_count)
366 })?;
367 untrusted::read_all_optional(cert.eku, Error::BadDer, |value| eku.check(value))?;
368
369 Ok(())
370}
371
372fn check_validity(input: &mut untrusted::Reader<'_>, time: UnixTime) -> Result<(), Error> {
374 let not_before = UnixTime::from_der(input)?;
375 let not_after = UnixTime::from_der(input)?;
376
377 if not_before > not_after {
378 return Err(Error::InvalidCertValidity);
379 }
380 if time < not_before {
381 return Err(Error::CertNotValidYet { time, not_before });
382 }
383 if time > not_after {
384 return Err(Error::CertExpired { time, not_after });
385 }
386
387 Ok(())
392}
393
394fn check_basic_constraints(
396 input: Option<&mut untrusted::Reader<'_>>,
397 role: Role,
398 sub_ca_count: usize,
399) -> Result<(), Error> {
400 let (is_ca, path_len_constraint) = match input {
401 Some(input) => {
402 let is_ca = bool::from_der(input)?;
403
404 let path_len_constraint = if !input.at_end() {
409 Some(usize::from(u8::from_der(input)?))
410 } else {
411 None
412 };
413
414 (is_ca, path_len_constraint)
415 }
416 None => (false, None),
417 };
418
419 match (role, is_ca, path_len_constraint) {
420 (Role::EndEntity, true, _) => Err(Error::CaUsedAsEndEntity),
421 (Role::Issuer, false, _) => Err(Error::EndEntityUsedAsCa),
422 (Role::Issuer, true, Some(len)) if sub_ca_count > len => {
423 Err(Error::PathLenConstraintViolated)
424 }
425 _ => Ok(()),
426 }
427}
428
429#[derive(Clone, Copy)]
438pub struct KeyUsage {
439 inner: ExtendedKeyUsage,
440}
441
442impl KeyUsage {
443 pub const fn server_auth() -> Self {
447 Self::required_if_present(EKU_SERVER_AUTH)
448 }
449
450 pub const fn client_auth() -> Self {
454 Self::required_if_present(EKU_CLIENT_AUTH)
455 }
456
457 pub const fn required(oid: &'static [u8]) -> Self {
459 Self {
460 inner: ExtendedKeyUsage::Required(KeyPurposeId::new(oid)),
461 }
462 }
463
464 pub const fn required_if_present(oid: &'static [u8]) -> Self {
466 Self {
467 inner: ExtendedKeyUsage::RequiredIfPresent(KeyPurposeId::new(oid)),
468 }
469 }
470}
471
472#[derive(Clone, Copy)]
474enum ExtendedKeyUsage {
475 Required(KeyPurposeId),
477
478 RequiredIfPresent(KeyPurposeId),
480}
481
482impl ExtendedKeyUsage {
483 fn check(&self, input: Option<&mut untrusted::Reader<'_>>) -> Result<(), Error> {
485 let input = match (input, self) {
486 (Some(input), _) => input,
487 (None, Self::RequiredIfPresent(_)) => return Ok(()),
488 (None, Self::Required(_)) => return Err(Error::RequiredEkuNotFound),
489 };
490
491 loop {
492 let value = der::expect_tag(input, der::Tag::OID)?;
493 if self.key_purpose_id_equals(value) {
494 input.skip_to_end();
495 break;
496 }
497
498 if input.at_end() {
499 return Err(Error::RequiredEkuNotFound);
500 }
501 }
502
503 Ok(())
504 }
505
506 fn key_purpose_id_equals(&self, value: untrusted::Input<'_>) -> bool {
507 public_values_eq(
508 match self {
509 Self::Required(eku) => *eku,
510 Self::RequiredIfPresent(eku) => *eku,
511 }
512 .oid_value,
513 value,
514 )
515 }
516}
517
518#[derive(Clone, Copy)]
520struct KeyPurposeId {
521 oid_value: untrusted::Input<'static>,
522}
523
524impl KeyPurposeId {
525 const fn new(oid: &'static [u8]) -> Self {
529 Self {
530 oid_value: untrusted::Input::from(oid),
531 }
532 }
533}
534
535impl PartialEq<Self> for KeyPurposeId {
536 fn eq(&self, other: &Self) -> bool {
537 public_values_eq(self.oid_value, other.oid_value)
538 }
539}
540
541impl Eq for KeyPurposeId {}
542
543const EKU_SERVER_AUTH: &[u8] = &oid!(1, 3, 6, 1, 5, 5, 7, 3, 1);
548
549const EKU_CLIENT_AUTH: &[u8] = &oid!(1, 3, 6, 1, 5, 5, 7, 3, 2);
551
552fn loop_while_non_fatal_error<'a, V: IntoIterator + 'a>(
553 default_error: Error,
554 values: V,
555 mut f: impl FnMut(V::Item) -> Result<&'a TrustAnchor<'a>, ControlFlow<Error, Error>>,
556) -> Result<&'a TrustAnchor<'a>, ControlFlow<Error, Error>> {
557 let mut error = default_error;
558 for v in values {
559 match f(v) {
560 Ok(anchor) => return Ok(anchor),
561 res @ Err(ControlFlow::Break(_)) => return res,
563 Err(ControlFlow::Continue(new_error)) => error = error.most_specific(new_error),
566 }
567 }
568 Err(error.into())
569}
570
571pub(crate) struct PartialPath<'a> {
576 end_entity: &'a EndEntityCert<'a>,
577 intermediates: [Option<Cert<'a>>; MAX_SUB_CA_COUNT],
581 used: usize,
586}
587
588impl<'a> PartialPath<'a> {
589 pub(crate) fn new(end_entity: &'a EndEntityCert<'a>) -> Self {
590 Self {
591 end_entity,
592 intermediates: Default::default(),
593 used: 0,
594 }
595 }
596
597 pub(crate) fn push(&mut self, cert: Cert<'a>) -> Result<(), ControlFlow<Error, Error>> {
598 if self.used >= MAX_SUB_CA_COUNT {
599 return Err(Error::MaximumPathDepthExceeded.into());
600 }
601
602 self.intermediates[self.used] = Some(cert);
603 self.used += 1;
604 Ok(())
605 }
606
607 fn pop(&mut self) {
608 debug_assert!(self.used > 0);
609 if self.used == 0 {
610 return;
611 }
612
613 self.used -= 1;
614 self.intermediates[self.used] = None;
615 }
616
617 pub(crate) fn node(&self) -> PathNode<'_> {
618 PathNode {
619 path: self,
620 index: self.used,
621 cert: self.head(),
622 }
623 }
624
625 pub(crate) fn head(&self) -> &Cert<'a> {
627 self.get(self.used)
628 }
629
630 fn get(&self, idx: usize) -> &Cert<'a> {
635 match idx {
636 0 => self.end_entity,
637 _ => self.intermediates[idx - 1].as_ref().unwrap(),
638 }
639 }
640}
641
642const MAX_SUB_CA_COUNT: usize = 6;
643
644pub(crate) struct PathNode<'a> {
645 path: &'a PartialPath<'a>,
647 index: usize,
649 pub(crate) cert: &'a Cert<'a>,
651}
652
653impl<'a> PathNode<'a> {
654 pub(crate) fn iter(&self) -> PathIter<'a> {
655 PathIter {
656 path: self.path,
657 next: Some(self.index),
658 }
659 }
660
661 pub(crate) fn role(&self) -> Role {
662 match self.index {
663 0 => Role::EndEntity,
664 _ => Role::Issuer,
665 }
666 }
667}
668
669pub(crate) struct PathIter<'a> {
670 path: &'a PartialPath<'a>,
671 next: Option<usize>,
672}
673
674impl<'a> Iterator for PathIter<'a> {
675 type Item = PathNode<'a>;
676
677 fn next(&mut self) -> Option<Self::Item> {
678 let next = self.next?;
679 self.next = match next {
680 0 => None,
681 _ => Some(next - 1),
682 };
683
684 Some(PathNode {
685 path: self.path,
686 index: next,
687 cert: self.path.get(next),
688 })
689 }
690}
691
692#[derive(Clone, Copy, PartialEq)]
693pub(crate) enum Role {
694 Issuer,
695 EndEntity,
696}
697
698#[cfg(all(test, feature = "alloc", any(feature = "ring", feature = "aws-lc-rs")))]
699mod tests {
700 use super::*;
701 use crate::test_utils;
702 use crate::test_utils::{issuer_params, make_end_entity, make_issuer};
703 use crate::trust_anchor::anchor_from_trusted_cert;
704 use rcgen::{CertifiedKey, KeyPair};
705 use std::dbg;
706 use std::prelude::v1::*;
707
708 #[test]
709 fn eku_key_purpose_id() {
710 assert!(
711 ExtendedKeyUsage::RequiredIfPresent(KeyPurposeId::new(EKU_SERVER_AUTH))
712 .key_purpose_id_equals(KeyPurposeId::new(EKU_SERVER_AUTH).oid_value)
713 )
714 }
715
716 #[test]
717 fn test_too_many_signatures() {
718 assert!(matches!(
719 build_and_verify_degenerate_chain(5, ChainTrustAnchor::NotInChain),
720 ControlFlow::Break(Error::MaximumSignatureChecksExceeded)
721 ));
722 }
723
724 #[test]
725 fn test_too_many_path_calls() {
726 assert!(matches!(
727 dbg!(build_and_verify_degenerate_chain(
728 10,
729 ChainTrustAnchor::InChain
730 )),
731 ControlFlow::Break(Error::MaximumPathBuildCallsExceeded)
732 ));
733 }
734
735 #[test]
736 fn longest_allowed_path() {
737 assert!(build_and_verify_linear_chain(1).is_ok());
738 assert!(build_and_verify_linear_chain(2).is_ok());
739 assert!(build_and_verify_linear_chain(3).is_ok());
740 assert!(build_and_verify_linear_chain(4).is_ok());
741 assert!(build_and_verify_linear_chain(5).is_ok());
742 assert!(build_and_verify_linear_chain(6).is_ok());
743 }
744
745 #[test]
746 fn path_too_long() {
747 assert!(matches!(
748 build_and_verify_linear_chain(7),
749 Err(ControlFlow::Continue(Error::MaximumPathDepthExceeded))
750 ));
751 }
752
753 #[test]
754 fn name_constraint_budget() {
755 let mut ca_cert_params = issuer_params("Constrained Root");
758 ca_cert_params.name_constraints = Some(rcgen::NameConstraints {
759 permitted_subtrees: vec![rcgen::GeneralSubtree::DnsName(".com".into())],
760 excluded_subtrees: vec![],
761 });
762 let ca_key_pair = KeyPair::generate_for(test_utils::RCGEN_SIGNATURE_ALG).unwrap();
763 let ca_cert = ca_cert_params.self_signed(&ca_key_pair).unwrap();
764
765 let mut intermediates = Vec::with_capacity(5);
769 for i in 0..5 {
770 let intermediate = issuer_params(format!("Intermediate {i}"));
771 let intermediate_key_pair =
772 KeyPair::generate_for(test_utils::RCGEN_SIGNATURE_ALG).unwrap();
773 let intermediate = intermediate
775 .signed_by(&intermediate_key_pair, &ca_cert, &ca_key_pair)
776 .unwrap();
777 intermediates.push((intermediate, intermediate_key_pair));
778 }
779
780 let last_issuer = intermediates.last().unwrap();
782 let ee_cert = make_end_entity(&last_issuer.0, &last_issuer.1);
783 let ee_cert = EndEntityCert::try_from(ee_cert.cert.der()).unwrap();
784
785 let passing_budget = Budget {
789 name_constraint_comparisons: 3,
794 ..Budget::default()
795 };
796
797 let ca_cert_der = ca_cert.into();
798 let anchors = &[anchor_from_trusted_cert(&ca_cert_der).unwrap()];
799 let intermediates_der = intermediates
800 .iter()
801 .map(|(cert, _)| cert.der().clone())
802 .collect::<Vec<_>>();
803
804 let path = verify_chain(
808 anchors,
809 &intermediates_der,
810 &ee_cert,
811 None,
812 Some(passing_budget),
813 )
814 .unwrap();
815 assert_eq!(path.anchor().subject, anchors.first().unwrap().subject);
816
817 let failing_budget = Budget {
818 name_constraint_comparisons: 2,
820 ..Budget::default()
821 };
822 let result = verify_chain(
826 anchors,
827 &intermediates_der,
828 &ee_cert,
829 None,
830 Some(failing_budget),
831 );
832
833 assert!(matches!(
834 result,
835 Err(ControlFlow::Break(
836 Error::MaximumNameConstraintComparisonsExceeded
837 ))
838 ));
839 }
840
841 #[test]
842 fn test_reject_candidate_path() {
843 let trust_anchor = make_issuer("Trust Anchor");
880 let trust_anchor_cert =
881 Cert::from_der(untrusted::Input::from(trust_anchor.cert.der())).unwrap();
882 let trust_anchors = &[anchor_from_trusted_cert(trust_anchor.cert.der()).unwrap()];
883
884 let intermediate_a = issuer_params("Intermediate A");
885 let intermediate_a_kp = KeyPair::generate_for(test_utils::RCGEN_SIGNATURE_ALG).unwrap();
886 let intermediate_a = intermediate_a
887 .signed_by(
888 &intermediate_a_kp,
889 &trust_anchor.cert,
890 &trust_anchor.key_pair,
891 )
892 .unwrap();
893 let intermediate_a_cert =
894 Cert::from_der(untrusted::Input::from(intermediate_a.der())).unwrap();
895
896 let intermediate_c = issuer_params("Intermediate C");
897 let intermediate_c_kp = KeyPair::generate_for(test_utils::RCGEN_SIGNATURE_ALG).unwrap();
898 let intermediate_c = intermediate_c
899 .signed_by(
900 &intermediate_c_kp,
901 &trust_anchor.cert,
902 &trust_anchor.key_pair,
903 )
904 .unwrap();
905 let intermediate_c_cert =
906 Cert::from_der(untrusted::Input::from(intermediate_c.der())).unwrap();
907
908 let intermediate_b_key = KeyPair::generate_for(test_utils::RCGEN_SIGNATURE_ALG).unwrap();
911 let intermediate_b_params = issuer_params("Intermediate");
912 let intermediate_b_a = intermediate_b_params
913 .clone()
914 .signed_by(&intermediate_b_key, &intermediate_a, &intermediate_a_kp)
915 .unwrap();
916 let intermediate_b_c = intermediate_b_params
917 .signed_by(&intermediate_b_key, &intermediate_c, &intermediate_c_kp)
918 .unwrap();
919
920 let intermediates = &[
921 intermediate_a.der().clone(),
922 intermediate_c.der().clone(),
923 intermediate_b_a.der().clone(),
924 intermediate_b_c.der().clone(),
925 ];
926
927 let ee = make_end_entity(&intermediate_b_a, &intermediate_b_key);
929 let ee_cert = &EndEntityCert::try_from(ee.cert.der()).unwrap();
930
931 let path = verify_chain(trust_anchors, intermediates, ee_cert, None, None).unwrap();
933 let path_intermediates = path.intermediate_certificates().collect::<Vec<_>>();
934
935 assert_eq!(path_intermediates.len(), 2);
938 assert_eq!(
939 path_intermediates[0].issuer(),
940 intermediate_a_cert.subject()
941 );
942 assert_eq!(path_intermediates[1].issuer(), trust_anchor_cert.subject());
943
944 let expected_chain = |path: &VerifiedPath<'_>| {
946 for intermediate in path.intermediate_certificates() {
947 if intermediate.issuer() == intermediate_a_cert.subject() {
949 return Err(Error::UnknownIssuer);
950 }
951 }
952
953 Ok(())
954 };
955
956 let path = verify_chain(
958 trust_anchors,
959 intermediates,
960 ee_cert,
961 Some(&expected_chain),
962 None,
963 )
964 .unwrap();
965 let path_intermediates = path.intermediate_certificates().collect::<Vec<_>>();
966
967 assert_eq!(path_intermediates.len(), 2);
970 assert_eq!(
971 path_intermediates[0].issuer(),
972 intermediate_c_cert.subject()
973 );
974 assert_eq!(path_intermediates[1].issuer(), trust_anchor_cert.subject());
975 }
976
977 fn build_and_verify_degenerate_chain(
978 intermediate_count: usize,
979 trust_anchor: ChainTrustAnchor,
980 ) -> ControlFlow<Error, Error> {
981 let ca_cert = make_issuer("Bogus Subject");
982 let mut intermediate_chain = build_linear_chain(&ca_cert, intermediate_count, true);
983
984 let verify_trust_anchor = match trust_anchor {
985 ChainTrustAnchor::InChain => make_issuer("Bogus Trust Anchor"),
986 ChainTrustAnchor::NotInChain => ca_cert,
987 };
988
989 let ee_cert = make_end_entity(
990 &intermediate_chain.last_issuer.cert,
991 &intermediate_chain.last_issuer.key_pair,
992 );
993 let ee_cert = EndEntityCert::try_from(ee_cert.cert.der()).unwrap();
994 let trust_anchor_der: CertificateDer<'_> = verify_trust_anchor.cert.into();
995 let webpki_ta = anchor_from_trusted_cert(&trust_anchor_der).unwrap();
996 if matches!(trust_anchor, ChainTrustAnchor::InChain) {
997 intermediate_chain.chain.insert(0, trust_anchor_der.clone())
1000 }
1001
1002 verify_chain(
1003 &[webpki_ta],
1004 &intermediate_chain.chain,
1005 &ee_cert,
1006 None,
1007 None,
1008 )
1009 .map(|_| ())
1010 .unwrap_err()
1011 }
1012
1013 #[cfg(feature = "alloc")]
1014 enum ChainTrustAnchor {
1015 NotInChain,
1016 InChain,
1017 }
1018
1019 fn build_and_verify_linear_chain(chain_length: usize) -> Result<(), ControlFlow<Error, Error>> {
1020 let ca_cert = make_issuer(format!("Bogus Subject {chain_length}"));
1021 let intermediate_chain = build_linear_chain(&ca_cert, chain_length, false);
1022
1023 let ca_cert_der: CertificateDer<'_> = ca_cert.cert.into();
1024 let anchor = anchor_from_trusted_cert(&ca_cert_der).unwrap();
1025 let anchors = &[anchor.clone()];
1026
1027 let ee_cert = make_end_entity(
1028 &intermediate_chain.last_issuer.cert,
1029 &intermediate_chain.last_issuer.key_pair,
1030 );
1031 let ee_cert = EndEntityCert::try_from(ee_cert.cert.der()).unwrap();
1032
1033 let expected_chain = |path: &VerifiedPath<'_>| {
1034 assert_eq!(path.anchor().subject, anchor.subject);
1035 assert!(public_values_eq(path.end_entity().subject, ee_cert.subject));
1036 assert_eq!(path.intermediate_certificates().count(), chain_length);
1037
1038 let intermediate_certs = intermediate_chain
1039 .chain
1040 .iter()
1041 .map(|der| Cert::from_der(untrusted::Input::from(der)).unwrap())
1042 .collect::<Vec<_>>();
1043
1044 for (cert, expected) in path
1045 .intermediate_certificates()
1046 .rev()
1047 .zip(intermediate_certs.iter())
1048 {
1049 assert!(public_values_eq(cert.subject, expected.subject));
1050 assert_eq!(cert.der(), expected.der());
1051 }
1052
1053 for (cert, expected) in path
1054 .intermediate_certificates()
1055 .zip(intermediate_certs.iter().rev())
1056 {
1057 assert!(public_values_eq(cert.subject, expected.subject));
1058 assert_eq!(cert.der(), expected.der());
1059 }
1060
1061 Ok(())
1062 };
1063
1064 verify_chain(
1065 anchors,
1066 &intermediate_chain.chain,
1067 &ee_cert,
1068 Some(&expected_chain),
1069 None,
1070 )
1071 .map(|_| ())
1072 }
1073
1074 fn build_linear_chain(
1075 ca_cert: &CertifiedKey,
1076 chain_length: usize,
1077 all_same_subject: bool,
1078 ) -> IntermediateChain {
1079 let mut chain = Vec::with_capacity(chain_length);
1080
1081 let mut prev = None;
1082 for i in 0..chain_length {
1083 let issuer = match &prev {
1084 Some(prev) => prev,
1085 None => ca_cert,
1086 };
1087
1088 let intermediate = issuer_params(match all_same_subject {
1089 true => "Bogus Subject".to_string(),
1090 false => format!("Bogus Subject {i}"),
1091 });
1092
1093 let key_pair = KeyPair::generate_for(test_utils::RCGEN_SIGNATURE_ALG).unwrap();
1094 let cert = intermediate
1095 .signed_by(&key_pair, &issuer.cert, &issuer.key_pair)
1096 .unwrap();
1097
1098 chain.push(cert.der().clone());
1099 prev = Some(CertifiedKey { cert, key_pair });
1100 }
1101
1102 IntermediateChain {
1103 last_issuer: prev.unwrap(),
1104 chain,
1105 }
1106 }
1107
1108 struct IntermediateChain {
1109 last_issuer: CertifiedKey,
1110 chain: Vec<CertificateDer<'static>>,
1111 }
1112
1113 fn verify_chain<'a>(
1114 trust_anchors: &'a [TrustAnchor<'a>],
1115 intermediate_certs: &'a [CertificateDer<'a>],
1116 ee_cert: &'a EndEntityCert<'a>,
1117 verify_path: Option<&dyn Fn(&VerifiedPath<'_>) -> Result<(), Error>>,
1118 budget: Option<Budget>,
1119 ) -> Result<VerifiedPath<'a>, ControlFlow<Error, Error>> {
1120 use core::time::Duration;
1121
1122 let time = UnixTime::since_unix_epoch(Duration::from_secs(0x1fed_f00d));
1123 let mut path = PartialPath::new(ee_cert);
1124 let opts = ChainOptions {
1125 eku: KeyUsage::server_auth(),
1126 supported_sig_algs: crate::ALL_VERIFICATION_ALGS,
1127 trust_anchors,
1128 intermediate_certs,
1129 revocation: None,
1130 };
1131
1132 match opts.build_chain_inner(
1133 &mut path,
1134 time,
1135 verify_path,
1136 0,
1137 &mut budget.unwrap_or_default(),
1138 ) {
1139 Ok(anchor) => Ok(VerifiedPath::new(ee_cert, anchor, path)),
1140 Err(err) => Err(err),
1141 }
1142 }
1143}