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> {
32 pub(crate) eku: KeyUsage,
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}
38
39impl<'a, 'p: 'a> ChainOptions<'a, 'p> {
40 pub(crate) fn build_chain(
41 &self,
42 end_entity: &'p EndEntityCert<'p>,
43 time: UnixTime,
44 verify_path: Option<&dyn Fn(&VerifiedPath<'_>) -> Result<(), Error>>,
45 ) -> Result<VerifiedPath<'p>, Error> {
46 let mut path = PartialPath::new(end_entity);
47 match self.build_chain_inner(&mut path, time, verify_path, 0, &mut Budget::default()) {
48 Ok(anchor) => Ok(VerifiedPath::new(end_entity, anchor, path)),
49 Err(ControlFlow::Break(err)) | Err(ControlFlow::Continue(err)) => Err(err),
50 }
51 }
52
53 fn build_chain_inner(
54 &self,
55 path: &mut PartialPath<'p>,
56 time: UnixTime,
57 verify_path: Option<&dyn Fn(&VerifiedPath<'_>) -> Result<(), Error>>,
58 sub_ca_count: usize,
59 budget: &mut Budget,
60 ) -> Result<&'p TrustAnchor<'p>, ControlFlow<Error, Error>> {
61 let role = path.node().role();
62
63 check_issuer_independent_properties(path.head(), time, role, sub_ca_count, self.eku.inner)?;
64
65 let result =
68 loop_while_non_fatal_error(Error::UnknownIssuer, self.trust_anchors, |trust_anchor| {
69 let trust_anchor_subject = untrusted::Input::from(trust_anchor.subject.as_ref());
70 if !public_values_eq(path.head().issuer, trust_anchor_subject) {
71 return Err(Error::UnknownIssuer.into());
72 }
73
74 let node = path.node();
77 self.check_signed_chain(&node, time, trust_anchor, budget)?;
78 check_signed_chain_name_constraints(&node, trust_anchor, budget)?;
79
80 let verify = match verify_path {
81 Some(verify) => verify,
82 None => return Ok(trust_anchor),
83 };
84
85 let candidate = VerifiedPath {
86 end_entity: path.end_entity,
87 intermediates: Intermediates::Borrowed(&path.intermediates[..path.used]),
88 anchor: trust_anchor,
89 };
90
91 match verify(&candidate) {
92 Ok(()) => Ok(trust_anchor),
93 Err(err) => Err(ControlFlow::Continue(err)),
94 }
95 });
96
97 let err = match result {
98 Ok(anchor) => return Ok(anchor),
99 res @ Err(ControlFlow::Break(_)) => return res,
101 Err(ControlFlow::Continue(err)) => err,
105 };
106
107 loop_while_non_fatal_error(err, self.intermediate_certs, |cert_der| {
108 let potential_issuer = Cert::from_der(untrusted::Input::from(cert_der))?;
109 if !public_values_eq(potential_issuer.subject, path.head().issuer) {
110 return Err(Error::UnknownIssuer.into());
111 }
112
113 if path.node().iter().any(|prev| {
115 public_values_eq(potential_issuer.spki, prev.cert.spki)
116 && public_values_eq(potential_issuer.subject, prev.cert.subject)
117 }) {
118 return Err(Error::UnknownIssuer.into());
119 }
120
121 let next_sub_ca_count = match role {
122 Role::EndEntity => sub_ca_count,
123 Role::Issuer => sub_ca_count + 1,
124 };
125
126 budget.consume_build_chain_call()?;
127 path.push(potential_issuer)?;
128 let result = self.build_chain_inner(path, time, verify_path, next_sub_ca_count, budget);
129 if result.is_err() {
130 path.pop();
131 }
132
133 result
134 })
135 }
136
137 fn check_signed_chain(
138 &self,
139 path: &PathNode<'_>,
140 time: UnixTime,
141 trust_anchor: &TrustAnchor<'_>,
142 budget: &mut Budget,
143 ) -> Result<(), ControlFlow<Error, Error>> {
144 let mut spki_value = untrusted::Input::from(trust_anchor.subject_public_key_info.as_ref());
145 let mut issuer_subject = untrusted::Input::from(trust_anchor.subject.as_ref());
146 let mut issuer_key_usage = None; for path in path.iter() {
148 signed_data::verify_signed_data(
149 self.supported_sig_algs,
150 spki_value,
151 &path.cert.signed_data,
152 budget,
153 )?;
154
155 if let Some(revocation_opts) = &self.revocation {
156 revocation_opts.check(
157 &path,
158 issuer_subject,
159 spki_value,
160 issuer_key_usage,
161 self.supported_sig_algs,
162 budget,
163 time,
164 )?;
165 }
166
167 spki_value = path.cert.spki;
168 issuer_subject = path.cert.subject;
169 issuer_key_usage = path.cert.key_usage;
170 }
171
172 Ok(())
173 }
174}
175
176pub struct VerifiedPath<'p> {
180 end_entity: &'p EndEntityCert<'p>,
181 intermediates: Intermediates<'p>,
182 anchor: &'p TrustAnchor<'p>,
183}
184
185impl<'p> VerifiedPath<'p> {
186 fn new(
187 end_entity: &'p EndEntityCert<'p>,
188 anchor: &'p TrustAnchor<'p>,
189 partial: PartialPath<'p>,
190 ) -> Self {
191 Self {
192 end_entity,
193 intermediates: Intermediates::Owned {
194 certs: partial.intermediates,
195 used: partial.used,
196 },
197 anchor,
198 }
199 }
200
201 pub fn intermediate_certificates(&'p self) -> IntermediateIterator<'p> {
203 IntermediateIterator {
204 intermediates: self.intermediates.as_ref(),
205 }
206 }
207
208 pub fn end_entity(&self) -> &'p EndEntityCert<'p> {
210 self.end_entity
211 }
212
213 pub fn anchor(&self) -> &'p TrustAnchor<'p> {
215 self.anchor
216 }
217}
218
219pub struct IntermediateIterator<'a> {
223 intermediates: &'a [Option<Cert<'a>>],
225}
226
227impl<'a> Iterator for IntermediateIterator<'a> {
228 type Item = &'a Cert<'a>;
229
230 fn next(&mut self) -> Option<Self::Item> {
231 match self.intermediates.split_first() {
232 Some((head, tail)) => {
233 self.intermediates = tail;
234 Some(head.as_ref().unwrap())
235 }
236 None => None,
237 }
238 }
239}
240
241impl DoubleEndedIterator for IntermediateIterator<'_> {
242 fn next_back(&mut self) -> Option<Self::Item> {
243 match self.intermediates.split_last() {
244 Some((head, tail)) => {
245 self.intermediates = tail;
246 Some(head.as_ref().unwrap())
247 }
248 None => None,
249 }
250 }
251}
252
253#[allow(clippy::large_enum_variant)]
254enum Intermediates<'a> {
255 Owned {
256 certs: [Option<Cert<'a>>; MAX_SUB_CA_COUNT],
257 used: usize,
258 },
259 Borrowed(&'a [Option<Cert<'a>>]),
260}
261
262impl<'a> AsRef<[Option<Cert<'a>>]> for Intermediates<'a> {
263 fn as_ref(&self) -> &[Option<Cert<'a>>] {
264 match self {
265 Intermediates::Owned { certs, used } => &certs[..*used],
266 Intermediates::Borrowed(certs) => certs,
267 }
268 }
269}
270
271fn check_signed_chain_name_constraints(
272 path: &PathNode<'_>,
273 trust_anchor: &TrustAnchor<'_>,
274 budget: &mut Budget,
275) -> Result<(), ControlFlow<Error, Error>> {
276 let mut name_constraints = trust_anchor
277 .name_constraints
278 .as_ref()
279 .map(|der| untrusted::Input::from(der.as_ref()));
280
281 for path in path.iter() {
282 untrusted::read_all_optional(name_constraints, Error::BadDer, |value| {
283 subject_name::check_name_constraints(value, &path, budget)
284 })?;
285
286 name_constraints = path.cert.name_constraints;
287 }
288
289 Ok(())
290}
291
292pub(crate) struct Budget {
293 signatures: usize,
294 build_chain_calls: usize,
295 name_constraint_comparisons: usize,
296}
297
298impl Budget {
299 #[inline]
300 pub(crate) fn consume_signature(&mut self) -> Result<(), Error> {
301 self.signatures = self
302 .signatures
303 .checked_sub(1)
304 .ok_or(Error::MaximumSignatureChecksExceeded)?;
305 Ok(())
306 }
307
308 #[inline]
309 fn consume_build_chain_call(&mut self) -> Result<(), Error> {
310 self.build_chain_calls = self
311 .build_chain_calls
312 .checked_sub(1)
313 .ok_or(Error::MaximumPathBuildCallsExceeded)?;
314 Ok(())
315 }
316
317 #[inline]
318 pub(crate) fn consume_name_constraint_comparison(&mut self) -> Result<(), Error> {
319 self.name_constraint_comparisons = self
320 .name_constraint_comparisons
321 .checked_sub(1)
322 .ok_or(Error::MaximumNameConstraintComparisonsExceeded)?;
323 Ok(())
324 }
325}
326
327impl Default for Budget {
328 fn default() -> Self {
329 Self {
330 signatures: 100,
335
336 build_chain_calls: 200_000,
339
340 name_constraint_comparisons: 250_000,
343 }
344 }
345}
346
347fn check_issuer_independent_properties(
348 cert: &Cert<'_>,
349 time: UnixTime,
350 role: Role,
351 sub_ca_count: usize,
352 eku: ExtendedKeyUsage,
353) -> Result<(), Error> {
354 cert.validity
366 .read_all(Error::BadDer, |value| check_validity(value, time))?;
367 untrusted::read_all_optional(cert.basic_constraints, Error::BadDer, |value| {
368 check_basic_constraints(value, role, sub_ca_count)
369 })?;
370 untrusted::read_all_optional(cert.eku, Error::BadDer, |value| eku.check(value))?;
371
372 Ok(())
373}
374
375fn check_validity(input: &mut untrusted::Reader<'_>, time: UnixTime) -> Result<(), Error> {
377 let not_before = UnixTime::from_der(input)?;
378 let not_after = UnixTime::from_der(input)?;
379
380 if not_before > not_after {
381 return Err(Error::InvalidCertValidity);
382 }
383 if time < not_before {
384 return Err(Error::CertNotValidYet { time, not_before });
385 }
386 if time > not_after {
387 return Err(Error::CertExpired { time, not_after });
388 }
389
390 Ok(())
395}
396
397fn check_basic_constraints(
399 input: Option<&mut untrusted::Reader<'_>>,
400 role: Role,
401 sub_ca_count: usize,
402) -> Result<(), Error> {
403 let (is_ca, path_len_constraint) = match input {
404 Some(input) => {
405 let is_ca = bool::from_der(input)?;
406
407 let path_len_constraint = if !input.at_end() {
412 Some(usize::from(u8::from_der(input)?))
413 } else {
414 None
415 };
416
417 (is_ca, path_len_constraint)
418 }
419 None => (false, None),
420 };
421
422 match (role, is_ca, path_len_constraint) {
423 (Role::EndEntity, true, _) => Err(Error::CaUsedAsEndEntity),
424 (Role::Issuer, false, _) => Err(Error::EndEntityUsedAsCa),
425 (Role::Issuer, true, Some(len)) if sub_ca_count > len => {
426 Err(Error::PathLenConstraintViolated)
427 }
428 _ => Ok(()),
429 }
430}
431
432#[derive(Clone, PartialEq, Eq)]
436pub struct RequiredEkuNotFoundContext {
437 #[cfg(feature = "alloc")]
439 pub required: KeyUsage,
440 #[cfg(feature = "alloc")]
442 pub present: Vec<Vec<usize>>,
443}
444
445impl fmt::Debug for RequiredEkuNotFoundContext {
446 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
447 let mut builder = f.debug_struct("RequiredEkuNotFoundContext");
448 #[cfg(feature = "alloc")]
449 builder.field(
450 "required",
451 match &self.required.inner {
452 ExtendedKeyUsage::Required(inner) => inner,
453 ExtendedKeyUsage::RequiredIfPresent(inner) => inner,
454 },
455 );
456 #[cfg(feature = "alloc")]
457 builder.field("present", &EkuListDebug(&self.present));
458 builder.finish()
459 }
460}
461
462#[cfg(feature = "alloc")]
463struct EkuListDebug<'a>(&'a [Vec<usize>]);
464
465#[cfg(feature = "alloc")]
466impl fmt::Debug for EkuListDebug<'_> {
467 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
468 write!(f, "[")?;
469 for (i, part) in self.0.iter().enumerate() {
470 if i > 0 {
471 write!(f, ", ")?;
472 }
473
474 write!(f, "KeyPurposeId(")?;
475 for (j, part) in part.iter().enumerate() {
476 if j > 0 {
477 write!(f, ".")?;
478 }
479 write!(f, "{part}")?;
480 }
481 write!(f, ")")?;
482 }
483 write!(f, "]")
484 }
485}
486
487#[derive(Clone, Copy, Debug, Eq, PartialEq)]
496pub struct KeyUsage {
497 inner: ExtendedKeyUsage,
498}
499
500impl KeyUsage {
501 pub const fn server_auth() -> Self {
505 Self::required_if_present(EKU_SERVER_AUTH)
506 }
507
508 pub const fn client_auth() -> Self {
512 Self::required_if_present(EKU_CLIENT_AUTH)
513 }
514
515 pub const fn required(oid: &'static [u8]) -> Self {
517 Self {
518 inner: ExtendedKeyUsage::Required(KeyPurposeId::new(oid)),
519 }
520 }
521
522 pub const fn required_if_present(oid: &'static [u8]) -> Self {
524 Self {
525 inner: ExtendedKeyUsage::RequiredIfPresent(KeyPurposeId::new(oid)),
526 }
527 }
528
529 pub fn oid_values(&self) -> impl Iterator<Item = usize> + '_ {
531 OidDecoder::new(
532 match &self.inner {
533 ExtendedKeyUsage::Required(eku) => eku,
534 ExtendedKeyUsage::RequiredIfPresent(eku) => eku,
535 }
536 .oid_value
537 .as_slice_less_safe(),
538 )
539 }
540
541 pub const SERVER_AUTH_REPR: &[usize] = &[1, 3, 6, 1, 5, 5, 7, 3, 1];
543 pub const CLIENT_AUTH_REPR: &[usize] = &[1, 3, 6, 1, 5, 5, 7, 3, 2];
545}
546
547#[derive(Clone, Copy, Debug, Eq, PartialEq)]
549enum ExtendedKeyUsage {
550 Required(KeyPurposeId<'static>),
552
553 RequiredIfPresent(KeyPurposeId<'static>),
555}
556
557impl ExtendedKeyUsage {
558 fn check(&self, input: Option<&mut untrusted::Reader<'_>>) -> Result<(), Error> {
560 let input = match (input, self) {
561 (Some(input), _) => input,
562 (None, Self::RequiredIfPresent(_)) => return Ok(()),
563 (None, Self::Required(_)) => {
564 return Err(Error::RequiredEkuNotFoundContext(
565 RequiredEkuNotFoundContext {
566 #[cfg(feature = "alloc")]
567 required: KeyUsage { inner: *self },
568 #[cfg(feature = "alloc")]
569 present: Vec::new(),
570 },
571 ));
572 }
573 };
574
575 #[cfg(feature = "alloc")]
576 let mut present = Vec::new();
577 loop {
578 let value = der::expect_tag(input, der::Tag::OID)?;
579 if self.key_purpose_id_equals(value) {
580 input.skip_to_end();
581 break;
582 }
583
584 #[cfg(feature = "alloc")]
585 present.push(OidDecoder::new(value.as_slice_less_safe()).collect());
586 if input.at_end() {
587 return Err(Error::RequiredEkuNotFoundContext(
588 RequiredEkuNotFoundContext {
589 #[cfg(feature = "alloc")]
590 required: KeyUsage { inner: *self },
591 #[cfg(feature = "alloc")]
592 present,
593 },
594 ));
595 }
596 }
597
598 Ok(())
599 }
600
601 fn key_purpose_id_equals(&self, value: untrusted::Input<'_>) -> bool {
602 public_values_eq(
603 match self {
604 Self::Required(eku) => *eku,
605 Self::RequiredIfPresent(eku) => *eku,
606 }
607 .oid_value,
608 value,
609 )
610 }
611}
612
613#[derive(Clone, Copy)]
615struct KeyPurposeId<'a> {
616 oid_value: untrusted::Input<'a>,
617}
618
619impl<'a> KeyPurposeId<'a> {
620 const fn new(oid: &'a [u8]) -> Self {
624 Self {
625 oid_value: untrusted::Input::from(oid),
626 }
627 }
628}
629
630impl fmt::Debug for KeyPurposeId<'_> {
631 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
632 write!(f, "KeyPurposeId(")?;
633 let decoder = OidDecoder::new(self.oid_value.as_slice_less_safe());
634 for (i, part) in decoder.enumerate() {
635 if i > 0 {
636 write!(f, ".")?;
637 }
638 write!(f, "{part}")?;
639 }
640 write!(f, ")")
641 }
642}
643
644impl PartialEq<Self> for KeyPurposeId<'_> {
645 fn eq(&self, other: &Self) -> bool {
646 public_values_eq(self.oid_value, other.oid_value)
647 }
648}
649
650impl Eq for KeyPurposeId<'_> {}
651
652const EKU_SERVER_AUTH: &[u8] = &oid!(1, 3, 6, 1, 5, 5, 7, 3, 1);
657
658const EKU_CLIENT_AUTH: &[u8] = &oid!(1, 3, 6, 1, 5, 5, 7, 3, 2);
660
661struct OidDecoder<'a> {
662 encoded: &'a [u8],
663 left: Option<usize>,
664 first: bool,
665}
666
667impl<'a> OidDecoder<'a> {
668 fn new(encoded: &'a [u8]) -> Self {
669 Self {
670 encoded,
671 left: None,
672 first: true,
673 }
674 }
675}
676
677impl Iterator for OidDecoder<'_> {
678 type Item = usize;
679
680 fn next(&mut self) -> Option<Self::Item> {
681 if let Some(next) = self.left.take() {
682 return Some(next);
683 }
684
685 let mut cur = 0;
686 for (i, &byte) in self.encoded.iter().enumerate() {
687 cur = (cur << 8) + usize::from(byte & 0x7f);
688 if byte & 0x80 > 0 {
689 continue;
690 }
691
692 if !self.first {
693 self.encoded = &self.encoded[i + 1..];
694 return Some(cur);
695 }
696
697 let (cur, next) = match cur {
698 ..=39 => (0, cur),
699 40..=79 => (1, cur - 40),
700 _ => (2, cur - 80),
701 };
702
703 self.encoded = &self.encoded[i + 1..];
704 self.first = false;
705 self.left = Some(next);
706 return Some(cur);
707 }
708
709 None
710 }
711}
712
713fn loop_while_non_fatal_error<'a, V: IntoIterator + 'a>(
714 default_error: Error,
715 values: V,
716 mut f: impl FnMut(V::Item) -> Result<&'a TrustAnchor<'a>, ControlFlow<Error, Error>>,
717) -> Result<&'a TrustAnchor<'a>, ControlFlow<Error, Error>> {
718 let mut error = default_error;
719 for v in values {
720 match f(v) {
721 Ok(anchor) => return Ok(anchor),
722 res @ Err(ControlFlow::Break(_)) => return res,
724 Err(ControlFlow::Continue(new_error)) => error = error.most_specific(new_error),
727 }
728 }
729 Err(error.into())
730}
731
732pub(crate) struct PartialPath<'a> {
737 end_entity: &'a EndEntityCert<'a>,
738 intermediates: [Option<Cert<'a>>; MAX_SUB_CA_COUNT],
742 used: usize,
747}
748
749impl<'a> PartialPath<'a> {
750 pub(crate) fn new(end_entity: &'a EndEntityCert<'a>) -> Self {
751 Self {
752 end_entity,
753 intermediates: Default::default(),
754 used: 0,
755 }
756 }
757
758 pub(crate) fn push(&mut self, cert: Cert<'a>) -> Result<(), ControlFlow<Error, Error>> {
759 if self.used >= MAX_SUB_CA_COUNT {
760 return Err(Error::MaximumPathDepthExceeded.into());
761 }
762
763 self.intermediates[self.used] = Some(cert);
764 self.used += 1;
765 Ok(())
766 }
767
768 fn pop(&mut self) {
769 debug_assert!(self.used > 0);
770 if self.used == 0 {
771 return;
772 }
773
774 self.used -= 1;
775 self.intermediates[self.used] = None;
776 }
777
778 pub(crate) fn node(&self) -> PathNode<'_> {
779 PathNode {
780 path: self,
781 index: self.used,
782 cert: self.head(),
783 }
784 }
785
786 pub(crate) fn head(&self) -> &Cert<'a> {
788 self.get(self.used)
789 }
790
791 fn get(&self, idx: usize) -> &Cert<'a> {
796 match idx {
797 0 => self.end_entity,
798 _ => self.intermediates[idx - 1].as_ref().unwrap(),
799 }
800 }
801}
802
803const MAX_SUB_CA_COUNT: usize = 6;
804
805pub(crate) struct PathNode<'a> {
806 path: &'a PartialPath<'a>,
808 index: usize,
810 pub(crate) cert: &'a Cert<'a>,
812}
813
814impl<'a> PathNode<'a> {
815 pub(crate) fn iter(&self) -> PathIter<'a> {
816 PathIter {
817 path: self.path,
818 next: Some(self.index),
819 }
820 }
821
822 pub(crate) fn role(&self) -> Role {
823 match self.index {
824 0 => Role::EndEntity,
825 _ => Role::Issuer,
826 }
827 }
828}
829
830pub(crate) struct PathIter<'a> {
831 path: &'a PartialPath<'a>,
832 next: Option<usize>,
833}
834
835impl<'a> Iterator for PathIter<'a> {
836 type Item = PathNode<'a>;
837
838 fn next(&mut self) -> Option<Self::Item> {
839 let next = self.next?;
840 self.next = match next {
841 0 => None,
842 _ => Some(next - 1),
843 };
844
845 Some(PathNode {
846 path: self.path,
847 index: next,
848 cert: self.path.get(next),
849 })
850 }
851}
852
853#[derive(Clone, Copy, PartialEq)]
854pub(crate) enum Role {
855 Issuer,
856 EndEntity,
857}
858
859#[cfg(all(test, feature = "alloc", any(feature = "ring", feature = "aws-lc-rs")))]
860mod tests {
861 use super::*;
862 use crate::test_utils;
863 use crate::test_utils::{issuer_params, make_end_entity, make_issuer};
864 use crate::trust_anchor::anchor_from_trusted_cert;
865 use rcgen::{CertifiedKey, KeyPair};
866 use std::dbg;
867 use std::prelude::v1::*;
868
869 #[test]
870 fn roundtrip() {
871 const ENCODED: &[u8] = &[0x84, 0x37, 0x3];
873 let decoded = OidDecoder::new(ENCODED);
874 assert_eq!(decoded.collect::<Vec<_>>(), [2, 999, 3]);
875 }
876
877 #[test]
878 fn oid_decoding() {
879 assert_eq!(
880 KeyUsage::server_auth().oid_values().collect::<Vec<_>>(),
881 KeyUsage::SERVER_AUTH_REPR
882 );
883 assert_eq!(
884 KeyUsage::client_auth().oid_values().collect::<Vec<_>>(),
885 KeyUsage::CLIENT_AUTH_REPR
886 );
887 }
888
889 #[test]
890 fn eku_fail_empty() {
891 let err = ExtendedKeyUsage::Required(KeyPurposeId::new(EKU_SERVER_AUTH))
892 .check(None)
893 .unwrap_err();
894 assert_eq!(
895 err,
896 Error::RequiredEkuNotFoundContext(RequiredEkuNotFoundContext {
897 #[cfg(feature = "alloc")]
898 required: dbg!(KeyUsage::required(EKU_SERVER_AUTH)), #[cfg(feature = "alloc")]
900 present: Vec::new(),
901 })
902 );
903 }
904
905 #[test]
906 fn eku_key_purpose_id() {
907 assert!(
908 ExtendedKeyUsage::RequiredIfPresent(KeyPurposeId::new(EKU_SERVER_AUTH))
909 .key_purpose_id_equals(KeyPurposeId::new(EKU_SERVER_AUTH).oid_value)
910 )
911 }
912
913 #[test]
914 fn test_too_many_signatures() {
915 assert!(matches!(
916 build_and_verify_degenerate_chain(5, ChainTrustAnchor::NotInChain),
917 ControlFlow::Break(Error::MaximumSignatureChecksExceeded)
918 ));
919 }
920
921 #[test]
922 fn test_too_many_path_calls() {
923 assert!(matches!(
924 dbg!(build_and_verify_degenerate_chain(
925 10,
926 ChainTrustAnchor::InChain
927 )),
928 ControlFlow::Break(Error::MaximumPathBuildCallsExceeded)
929 ));
930 }
931
932 #[test]
933 fn longest_allowed_path() {
934 assert!(build_and_verify_linear_chain(1).is_ok());
935 assert!(build_and_verify_linear_chain(2).is_ok());
936 assert!(build_and_verify_linear_chain(3).is_ok());
937 assert!(build_and_verify_linear_chain(4).is_ok());
938 assert!(build_and_verify_linear_chain(5).is_ok());
939 assert!(build_and_verify_linear_chain(6).is_ok());
940 }
941
942 #[test]
943 fn path_too_long() {
944 assert!(matches!(
945 build_and_verify_linear_chain(7),
946 Err(ControlFlow::Continue(Error::MaximumPathDepthExceeded))
947 ));
948 }
949
950 #[test]
951 fn name_constraint_budget() {
952 let mut ca_cert_params = issuer_params("Constrained Root");
955 ca_cert_params.name_constraints = Some(rcgen::NameConstraints {
956 permitted_subtrees: vec![rcgen::GeneralSubtree::DnsName(".com".into())],
957 excluded_subtrees: vec![],
958 });
959 let ca_key_pair = KeyPair::generate_for(test_utils::RCGEN_SIGNATURE_ALG).unwrap();
960 let ca_cert = ca_cert_params.self_signed(&ca_key_pair).unwrap();
961
962 let mut intermediates = Vec::with_capacity(5);
966 for i in 0..5 {
967 let intermediate = issuer_params(format!("Intermediate {i}"));
968 let intermediate_key_pair =
969 KeyPair::generate_for(test_utils::RCGEN_SIGNATURE_ALG).unwrap();
970 let intermediate = intermediate
972 .signed_by(&intermediate_key_pair, &ca_cert, &ca_key_pair)
973 .unwrap();
974 intermediates.push((intermediate, intermediate_key_pair));
975 }
976
977 let last_issuer = intermediates.last().unwrap();
979 let ee_cert = make_end_entity(&last_issuer.0, &last_issuer.1);
980 let ee_cert = EndEntityCert::try_from(ee_cert.cert.der()).unwrap();
981
982 let passing_budget = Budget {
986 name_constraint_comparisons: 3,
991 ..Budget::default()
992 };
993
994 let ca_cert_der = ca_cert.into();
995 let anchors = &[anchor_from_trusted_cert(&ca_cert_der).unwrap()];
996 let intermediates_der = intermediates
997 .iter()
998 .map(|(cert, _)| cert.der().clone())
999 .collect::<Vec<_>>();
1000
1001 let path = verify_chain(
1005 anchors,
1006 &intermediates_der,
1007 &ee_cert,
1008 None,
1009 Some(passing_budget),
1010 )
1011 .unwrap();
1012 assert_eq!(path.anchor().subject, anchors.first().unwrap().subject);
1013
1014 let failing_budget = Budget {
1015 name_constraint_comparisons: 2,
1017 ..Budget::default()
1018 };
1019 let result = verify_chain(
1023 anchors,
1024 &intermediates_der,
1025 &ee_cert,
1026 None,
1027 Some(failing_budget),
1028 );
1029
1030 assert!(matches!(
1031 result,
1032 Err(ControlFlow::Break(
1033 Error::MaximumNameConstraintComparisonsExceeded
1034 ))
1035 ));
1036 }
1037
1038 #[test]
1039 fn test_reject_candidate_path() {
1040 let trust_anchor = make_issuer("Trust Anchor");
1077 let trust_anchor_cert =
1078 Cert::from_der(untrusted::Input::from(trust_anchor.cert.der())).unwrap();
1079 let trust_anchors = &[anchor_from_trusted_cert(trust_anchor.cert.der()).unwrap()];
1080
1081 let intermediate_a = issuer_params("Intermediate A");
1082 let intermediate_a_kp = KeyPair::generate_for(test_utils::RCGEN_SIGNATURE_ALG).unwrap();
1083 let intermediate_a = intermediate_a
1084 .signed_by(
1085 &intermediate_a_kp,
1086 &trust_anchor.cert,
1087 &trust_anchor.key_pair,
1088 )
1089 .unwrap();
1090 let intermediate_a_cert =
1091 Cert::from_der(untrusted::Input::from(intermediate_a.der())).unwrap();
1092
1093 let intermediate_c = issuer_params("Intermediate C");
1094 let intermediate_c_kp = KeyPair::generate_for(test_utils::RCGEN_SIGNATURE_ALG).unwrap();
1095 let intermediate_c = intermediate_c
1096 .signed_by(
1097 &intermediate_c_kp,
1098 &trust_anchor.cert,
1099 &trust_anchor.key_pair,
1100 )
1101 .unwrap();
1102 let intermediate_c_cert =
1103 Cert::from_der(untrusted::Input::from(intermediate_c.der())).unwrap();
1104
1105 let intermediate_b_key = KeyPair::generate_for(test_utils::RCGEN_SIGNATURE_ALG).unwrap();
1108 let intermediate_b_params = issuer_params("Intermediate");
1109 let intermediate_b_a = intermediate_b_params
1110 .clone()
1111 .signed_by(&intermediate_b_key, &intermediate_a, &intermediate_a_kp)
1112 .unwrap();
1113 let intermediate_b_c = intermediate_b_params
1114 .signed_by(&intermediate_b_key, &intermediate_c, &intermediate_c_kp)
1115 .unwrap();
1116
1117 let intermediates = &[
1118 intermediate_a.der().clone(),
1119 intermediate_c.der().clone(),
1120 intermediate_b_a.der().clone(),
1121 intermediate_b_c.der().clone(),
1122 ];
1123
1124 let ee = make_end_entity(&intermediate_b_a, &intermediate_b_key);
1126 let ee_cert = &EndEntityCert::try_from(ee.cert.der()).unwrap();
1127
1128 let path = verify_chain(trust_anchors, intermediates, ee_cert, None, None).unwrap();
1130 let path_intermediates = path.intermediate_certificates().collect::<Vec<_>>();
1131
1132 assert_eq!(path_intermediates.len(), 2);
1135 assert_eq!(
1136 path_intermediates[0].issuer(),
1137 intermediate_a_cert.subject()
1138 );
1139 assert_eq!(path_intermediates[1].issuer(), trust_anchor_cert.subject());
1140
1141 let expected_chain = |path: &VerifiedPath<'_>| {
1143 for intermediate in path.intermediate_certificates() {
1144 if intermediate.issuer() == intermediate_a_cert.subject() {
1146 return Err(Error::UnknownIssuer);
1147 }
1148 }
1149
1150 Ok(())
1151 };
1152
1153 let path = verify_chain(
1155 trust_anchors,
1156 intermediates,
1157 ee_cert,
1158 Some(&expected_chain),
1159 None,
1160 )
1161 .unwrap();
1162 let path_intermediates = path.intermediate_certificates().collect::<Vec<_>>();
1163
1164 assert_eq!(path_intermediates.len(), 2);
1167 assert_eq!(
1168 path_intermediates[0].issuer(),
1169 intermediate_c_cert.subject()
1170 );
1171 assert_eq!(path_intermediates[1].issuer(), trust_anchor_cert.subject());
1172 }
1173
1174 fn build_and_verify_degenerate_chain(
1175 intermediate_count: usize,
1176 trust_anchor: ChainTrustAnchor,
1177 ) -> ControlFlow<Error, Error> {
1178 let ca_cert = make_issuer("Bogus Subject");
1179 let mut intermediate_chain = build_linear_chain(&ca_cert, intermediate_count, true);
1180
1181 let verify_trust_anchor = match trust_anchor {
1182 ChainTrustAnchor::InChain => make_issuer("Bogus Trust Anchor"),
1183 ChainTrustAnchor::NotInChain => ca_cert,
1184 };
1185
1186 let ee_cert = make_end_entity(
1187 &intermediate_chain.last_issuer.cert,
1188 &intermediate_chain.last_issuer.key_pair,
1189 );
1190 let ee_cert = EndEntityCert::try_from(ee_cert.cert.der()).unwrap();
1191 let trust_anchor_der: CertificateDer<'_> = verify_trust_anchor.cert.into();
1192 let webpki_ta = anchor_from_trusted_cert(&trust_anchor_der).unwrap();
1193 if matches!(trust_anchor, ChainTrustAnchor::InChain) {
1194 intermediate_chain.chain.insert(0, trust_anchor_der.clone())
1197 }
1198
1199 verify_chain(
1200 &[webpki_ta],
1201 &intermediate_chain.chain,
1202 &ee_cert,
1203 None,
1204 None,
1205 )
1206 .map(|_| ())
1207 .unwrap_err()
1208 }
1209
1210 #[cfg(feature = "alloc")]
1211 enum ChainTrustAnchor {
1212 NotInChain,
1213 InChain,
1214 }
1215
1216 fn build_and_verify_linear_chain(chain_length: usize) -> Result<(), ControlFlow<Error, Error>> {
1217 let ca_cert = make_issuer(format!("Bogus Subject {chain_length}"));
1218 let intermediate_chain = build_linear_chain(&ca_cert, chain_length, false);
1219
1220 let ca_cert_der: CertificateDer<'_> = ca_cert.cert.into();
1221 let anchor = anchor_from_trusted_cert(&ca_cert_der).unwrap();
1222 let anchors = &[anchor.clone()];
1223
1224 let ee_cert = make_end_entity(
1225 &intermediate_chain.last_issuer.cert,
1226 &intermediate_chain.last_issuer.key_pair,
1227 );
1228 let ee_cert = EndEntityCert::try_from(ee_cert.cert.der()).unwrap();
1229
1230 let expected_chain = |path: &VerifiedPath<'_>| {
1231 assert_eq!(path.anchor().subject, anchor.subject);
1232 assert!(public_values_eq(path.end_entity().subject, ee_cert.subject));
1233 assert_eq!(path.intermediate_certificates().count(), chain_length);
1234
1235 let intermediate_certs = intermediate_chain
1236 .chain
1237 .iter()
1238 .map(|der| Cert::from_der(untrusted::Input::from(der)).unwrap())
1239 .collect::<Vec<_>>();
1240
1241 for (cert, expected) in path
1242 .intermediate_certificates()
1243 .rev()
1244 .zip(intermediate_certs.iter())
1245 {
1246 assert!(public_values_eq(cert.subject, expected.subject));
1247 assert_eq!(cert.der(), expected.der());
1248 }
1249
1250 for (cert, expected) in path
1251 .intermediate_certificates()
1252 .zip(intermediate_certs.iter().rev())
1253 {
1254 assert!(public_values_eq(cert.subject, expected.subject));
1255 assert_eq!(cert.der(), expected.der());
1256 }
1257
1258 Ok(())
1259 };
1260
1261 verify_chain(
1262 anchors,
1263 &intermediate_chain.chain,
1264 &ee_cert,
1265 Some(&expected_chain),
1266 None,
1267 )
1268 .map(|_| ())
1269 }
1270
1271 fn build_linear_chain(
1272 ca_cert: &CertifiedKey,
1273 chain_length: usize,
1274 all_same_subject: bool,
1275 ) -> IntermediateChain {
1276 let mut chain = Vec::with_capacity(chain_length);
1277
1278 let mut prev = None;
1279 for i in 0..chain_length {
1280 let issuer = match &prev {
1281 Some(prev) => prev,
1282 None => ca_cert,
1283 };
1284
1285 let intermediate = issuer_params(match all_same_subject {
1286 true => "Bogus Subject".to_string(),
1287 false => format!("Bogus Subject {i}"),
1288 });
1289
1290 let key_pair = KeyPair::generate_for(test_utils::RCGEN_SIGNATURE_ALG).unwrap();
1291 let cert = intermediate
1292 .signed_by(&key_pair, &issuer.cert, &issuer.key_pair)
1293 .unwrap();
1294
1295 chain.push(cert.der().clone());
1296 prev = Some(CertifiedKey { cert, key_pair });
1297 }
1298
1299 IntermediateChain {
1300 last_issuer: prev.unwrap(),
1301 chain,
1302 }
1303 }
1304
1305 struct IntermediateChain {
1306 last_issuer: CertifiedKey,
1307 chain: Vec<CertificateDer<'static>>,
1308 }
1309
1310 fn verify_chain<'a>(
1311 trust_anchors: &'a [TrustAnchor<'a>],
1312 intermediate_certs: &'a [CertificateDer<'a>],
1313 ee_cert: &'a EndEntityCert<'a>,
1314 verify_path: Option<&dyn Fn(&VerifiedPath<'_>) -> Result<(), Error>>,
1315 budget: Option<Budget>,
1316 ) -> Result<VerifiedPath<'a>, ControlFlow<Error, Error>> {
1317 use core::time::Duration;
1318
1319 let time = UnixTime::since_unix_epoch(Duration::from_secs(0x1fed_f00d));
1320 let mut path = PartialPath::new(ee_cert);
1321 let opts = ChainOptions {
1322 eku: KeyUsage::server_auth(),
1323 supported_sig_algs: crate::ALL_VERIFICATION_ALGS,
1324 trust_anchors,
1325 intermediate_certs,
1326 revocation: None,
1327 };
1328
1329 match opts.build_chain_inner(
1330 &mut path,
1331 time,
1332 verify_path,
1333 0,
1334 &mut budget.unwrap_or_default(),
1335 ) {
1336 Ok(anchor) => Ok(VerifiedPath::new(ee_cert, anchor, path)),
1337 Err(err) => Err(err),
1338 }
1339 }
1340}