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}
38
39impl<'a, 'p: 'a, V: ExtendedKeyUsageValidator> ChainOptions<'a, 'p, V> {
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)?;
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: &impl ExtendedKeyUsageValidator,
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, |input| check_eku(input, eku))?;
371
372 Ok(())
373}
374
375fn check_eku(
376 input: Option<&mut untrusted::Reader<'_>>,
377 eku: &impl ExtendedKeyUsageValidator,
378) -> Result<(), Error> {
379 match input {
380 Some(input) if input.at_end() => Err(Error::EmptyEkuExtension),
381 Some(input) => eku.validate(KeyPurposeIdIter { input }),
382 None => eku.validate(KeyPurposeIdIter {
383 input: &mut untrusted::Reader::new(untrusted::Input::from(&[])),
384 }),
385 }
386}
387
388fn check_validity(input: &mut untrusted::Reader<'_>, time: UnixTime) -> Result<(), Error> {
390 let not_before = UnixTime::from_der(input)?;
391 let not_after = UnixTime::from_der(input)?;
392
393 if not_before > not_after {
394 return Err(Error::InvalidCertValidity);
395 }
396 if time < not_before {
397 return Err(Error::CertNotValidYet { time, not_before });
398 }
399 if time > not_after {
400 return Err(Error::CertExpired { time, not_after });
401 }
402
403 Ok(())
408}
409
410fn check_basic_constraints(
412 input: Option<&mut untrusted::Reader<'_>>,
413 role: Role,
414 sub_ca_count: usize,
415) -> Result<(), Error> {
416 let (is_ca, path_len_constraint) = match input {
417 Some(input) => {
418 let is_ca = bool::from_der(input)?;
419
420 let path_len_constraint = if !input.at_end() {
425 Some(usize::from(u8::from_der(input)?))
426 } else {
427 None
428 };
429
430 (is_ca, path_len_constraint)
431 }
432 None => (false, None),
433 };
434
435 match (role, is_ca, path_len_constraint) {
436 (Role::EndEntity, true, _) => Err(Error::CaUsedAsEndEntity),
437 (Role::Issuer, false, _) => Err(Error::EndEntityUsedAsCa),
438 (Role::Issuer, true, Some(len)) if sub_ca_count > len => {
439 Err(Error::PathLenConstraintViolated)
440 }
441 _ => Ok(()),
442 }
443}
444
445#[derive(Clone, PartialEq, Eq)]
449pub struct RequiredEkuNotFoundContext {
450 #[cfg(feature = "alloc")]
452 pub required: KeyUsage,
453 #[cfg(feature = "alloc")]
455 pub present: Vec<Vec<usize>>,
456}
457
458impl fmt::Debug for RequiredEkuNotFoundContext {
459 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
460 let mut builder = f.debug_struct("RequiredEkuNotFoundContext");
461 #[cfg(feature = "alloc")]
462 builder.field(
463 "required",
464 match &self.required.inner {
465 ExtendedKeyUsage::Required(inner) => inner,
466 ExtendedKeyUsage::RequiredIfPresent(inner) => inner,
467 },
468 );
469 #[cfg(feature = "alloc")]
470 builder.field("present", &EkuListDebug(&self.present));
471 builder.finish()
472 }
473}
474
475#[cfg(feature = "alloc")]
476struct EkuListDebug<'a>(&'a [Vec<usize>]);
477
478#[cfg(feature = "alloc")]
479impl fmt::Debug for EkuListDebug<'_> {
480 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
481 write!(f, "[")?;
482 for (i, part) in self.0.iter().enumerate() {
483 if i > 0 {
484 write!(f, ", ")?;
485 }
486
487 write!(f, "KeyPurposeId(")?;
488 for (j, part) in part.iter().enumerate() {
489 if j > 0 {
490 write!(f, ".")?;
491 }
492 write!(f, "{part}")?;
493 }
494 write!(f, ")")?;
495 }
496 write!(f, "]")
497 }
498}
499
500#[derive(Clone, Copy, Debug, Eq, PartialEq)]
509pub struct KeyUsage {
510 inner: ExtendedKeyUsage,
511}
512
513impl KeyUsage {
514 pub const fn server_auth() -> Self {
518 Self::required_if_present(EKU_SERVER_AUTH)
519 }
520
521 pub const fn client_auth() -> Self {
525 Self::required_if_present(EKU_CLIENT_AUTH)
526 }
527
528 pub const fn required(oid: &'static [u8]) -> Self {
530 Self {
531 inner: ExtendedKeyUsage::Required(KeyPurposeId::new(oid)),
532 }
533 }
534
535 pub const fn required_if_present(oid: &'static [u8]) -> Self {
537 Self {
538 inner: ExtendedKeyUsage::RequiredIfPresent(KeyPurposeId::new(oid)),
539 }
540 }
541
542 pub fn oid_values(&self) -> impl Iterator<Item = usize> + '_ {
544 OidDecoder::new(
545 match &self.inner {
546 ExtendedKeyUsage::Required(eku) => eku,
547 ExtendedKeyUsage::RequiredIfPresent(eku) => eku,
548 }
549 .oid_value
550 .as_slice_less_safe(),
551 )
552 }
553
554 pub const SERVER_AUTH_REPR: &[usize] = &[1, 3, 6, 1, 5, 5, 7, 3, 1];
556 pub const CLIENT_AUTH_REPR: &[usize] = &[1, 3, 6, 1, 5, 5, 7, 3, 2];
558}
559
560impl ExtendedKeyUsageValidator for KeyUsage {
561 fn validate(&self, iter: KeyPurposeIdIter<'_, '_>) -> Result<(), Error> {
563 let mut empty = true;
564 #[cfg(feature = "alloc")]
565 let mut present = Vec::new();
566
567 for id in iter {
568 empty = false;
569 let id = id?;
570 if self.inner.id() == id {
571 return Ok(());
572 }
573
574 #[cfg(feature = "alloc")]
575 present.push(id.to_decoded_oid());
576 }
577
578 match (empty, self.inner) {
579 (true, ExtendedKeyUsage::RequiredIfPresent(_)) => Ok(()),
580 _ => Err(Error::RequiredEkuNotFoundContext(
581 RequiredEkuNotFoundContext {
582 #[cfg(feature = "alloc")]
583 required: Self { inner: self.inner },
584 #[cfg(feature = "alloc")]
585 present,
586 },
587 )),
588 }
589 }
590}
591
592impl<V: ExtendedKeyUsageValidator> ExtendedKeyUsageValidator for &V {
593 fn validate(&self, iter: KeyPurposeIdIter<'_, '_>) -> Result<(), Error> {
594 (*self).validate(iter)
595 }
596}
597
598pub trait ExtendedKeyUsageValidator {
600 fn validate(&self, iter: KeyPurposeIdIter<'_, '_>) -> Result<(), Error>;
607}
608
609#[derive(Clone, Copy, Debug, Eq, PartialEq)]
611enum ExtendedKeyUsage {
612 Required(KeyPurposeId<'static>),
614
615 RequiredIfPresent(KeyPurposeId<'static>),
617}
618
619impl ExtendedKeyUsage {
620 fn id(&self) -> KeyPurposeId<'static> {
621 match self {
622 Self::Required(id) => *id,
623 Self::RequiredIfPresent(id) => *id,
624 }
625 }
626}
627
628pub struct KeyPurposeIdIter<'a, 'r> {
630 input: &'r mut untrusted::Reader<'a>,
631}
632
633impl<'a, 'r> Iterator for KeyPurposeIdIter<'a, 'r> {
634 type Item = Result<KeyPurposeId<'a>, Error>;
635
636 fn next(&mut self) -> Option<Self::Item> {
637 if self.input.at_end() {
638 return None;
639 }
640
641 Some(der::expect_tag(self.input, der::Tag::OID).map(|oid_value| KeyPurposeId { oid_value }))
642 }
643}
644
645impl Drop for KeyPurposeIdIter<'_, '_> {
646 fn drop(&mut self) {
647 self.input.skip_to_end();
648 }
649}
650
651#[derive(Clone, Copy)]
653pub struct KeyPurposeId<'a> {
654 oid_value: untrusted::Input<'a>,
655}
656
657impl<'a> KeyPurposeId<'a> {
658 pub const fn new(oid: &'a [u8]) -> Self {
662 Self {
663 oid_value: untrusted::Input::from(oid),
664 }
665 }
666
667 #[cfg(feature = "alloc")]
669 pub fn to_decoded_oid(&self) -> Vec<usize> {
670 OidDecoder::new(self.oid_value.as_slice_less_safe()).collect()
671 }
672}
673
674impl fmt::Debug for KeyPurposeId<'_> {
675 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
676 write!(f, "KeyPurposeId(")?;
677 let decoder = OidDecoder::new(self.oid_value.as_slice_less_safe());
678 for (i, part) in decoder.enumerate() {
679 if i > 0 {
680 write!(f, ".")?;
681 }
682 write!(f, "{part}")?;
683 }
684 write!(f, ")")
685 }
686}
687
688impl PartialEq<Self> for KeyPurposeId<'_> {
689 fn eq(&self, other: &Self) -> bool {
690 public_values_eq(self.oid_value, other.oid_value)
691 }
692}
693
694impl Eq for KeyPurposeId<'_> {}
695
696const EKU_SERVER_AUTH: &[u8] = &oid!(1, 3, 6, 1, 5, 5, 7, 3, 1);
701
702const EKU_CLIENT_AUTH: &[u8] = &oid!(1, 3, 6, 1, 5, 5, 7, 3, 2);
704
705struct OidDecoder<'a> {
706 encoded: &'a [u8],
707 left: Option<usize>,
708 first: bool,
709}
710
711impl<'a> OidDecoder<'a> {
712 fn new(encoded: &'a [u8]) -> Self {
713 Self {
714 encoded,
715 left: None,
716 first: true,
717 }
718 }
719}
720
721impl Iterator for OidDecoder<'_> {
722 type Item = usize;
723
724 fn next(&mut self) -> Option<Self::Item> {
725 if let Some(next) = self.left.take() {
726 return Some(next);
727 }
728
729 let mut cur = 0;
730 for (i, &byte) in self.encoded.iter().enumerate() {
731 cur = (cur << 8) + usize::from(byte & 0x7f);
732 if byte & 0x80 > 0 {
733 continue;
734 }
735
736 if !self.first {
737 self.encoded = &self.encoded[i + 1..];
738 return Some(cur);
739 }
740
741 let (cur, next) = match cur {
742 ..=39 => (0, cur),
743 40..=79 => (1, cur - 40),
744 _ => (2, cur - 80),
745 };
746
747 self.encoded = &self.encoded[i + 1..];
748 self.first = false;
749 self.left = Some(next);
750 return Some(cur);
751 }
752
753 None
754 }
755}
756
757fn loop_while_non_fatal_error<'a, V: IntoIterator + 'a>(
758 default_error: Error,
759 values: V,
760 mut f: impl FnMut(V::Item) -> Result<&'a TrustAnchor<'a>, ControlFlow<Error, Error>>,
761) -> Result<&'a TrustAnchor<'a>, ControlFlow<Error, Error>> {
762 let mut error = default_error;
763 for v in values {
764 match f(v) {
765 Ok(anchor) => return Ok(anchor),
766 res @ Err(ControlFlow::Break(_)) => return res,
768 Err(ControlFlow::Continue(new_error)) => error = error.most_specific(new_error),
771 }
772 }
773 Err(error.into())
774}
775
776pub(crate) struct PartialPath<'a> {
781 end_entity: &'a EndEntityCert<'a>,
782 intermediates: [Option<Cert<'a>>; MAX_SUB_CA_COUNT],
786 used: usize,
791}
792
793impl<'a> PartialPath<'a> {
794 pub(crate) fn new(end_entity: &'a EndEntityCert<'a>) -> Self {
795 Self {
796 end_entity,
797 intermediates: Default::default(),
798 used: 0,
799 }
800 }
801
802 pub(crate) fn push(&mut self, cert: Cert<'a>) -> Result<(), ControlFlow<Error, Error>> {
803 if self.used >= MAX_SUB_CA_COUNT {
804 return Err(Error::MaximumPathDepthExceeded.into());
805 }
806
807 self.intermediates[self.used] = Some(cert);
808 self.used += 1;
809 Ok(())
810 }
811
812 fn pop(&mut self) {
813 debug_assert!(self.used > 0);
814 if self.used == 0 {
815 return;
816 }
817
818 self.used -= 1;
819 self.intermediates[self.used] = None;
820 }
821
822 pub(crate) fn node(&self) -> PathNode<'_> {
823 PathNode {
824 path: self,
825 index: self.used,
826 cert: self.head(),
827 }
828 }
829
830 pub(crate) fn head(&self) -> &Cert<'a> {
832 self.get(self.used)
833 }
834
835 fn get(&self, idx: usize) -> &Cert<'a> {
840 match idx {
841 0 => self.end_entity,
842 _ => self.intermediates[idx - 1].as_ref().unwrap(),
843 }
844 }
845}
846
847const MAX_SUB_CA_COUNT: usize = 6;
848
849pub(crate) struct PathNode<'a> {
850 path: &'a PartialPath<'a>,
852 index: usize,
854 pub(crate) cert: &'a Cert<'a>,
856}
857
858impl<'a> PathNode<'a> {
859 pub(crate) fn iter(&self) -> PathIter<'a> {
860 PathIter {
861 path: self.path,
862 next: Some(self.index),
863 }
864 }
865
866 pub(crate) fn role(&self) -> Role {
867 match self.index {
868 0 => Role::EndEntity,
869 _ => Role::Issuer,
870 }
871 }
872}
873
874pub(crate) struct PathIter<'a> {
875 path: &'a PartialPath<'a>,
876 next: Option<usize>,
877}
878
879impl<'a> Iterator for PathIter<'a> {
880 type Item = PathNode<'a>;
881
882 fn next(&mut self) -> Option<Self::Item> {
883 let next = self.next?;
884 self.next = match next {
885 0 => None,
886 _ => Some(next - 1),
887 };
888
889 Some(PathNode {
890 path: self.path,
891 index: next,
892 cert: self.path.get(next),
893 })
894 }
895}
896
897#[derive(Clone, Copy, PartialEq)]
898pub(crate) enum Role {
899 Issuer,
900 EndEntity,
901}
902
903#[cfg(all(test, feature = "alloc", any(feature = "ring", feature = "aws-lc-rs")))]
904mod tests {
905 use super::*;
906 use crate::test_utils;
907 use crate::test_utils::{issuer_params, make_end_entity, make_issuer};
908 use crate::trust_anchor::anchor_from_trusted_cert;
909 use rcgen::{CertifiedIssuer, Issuer, KeyPair, SigningKey};
910 use std::dbg;
911 use std::prelude::v1::*;
912 use std::slice;
913
914 #[test]
915 fn roundtrip() {
916 const ENCODED: &[u8] = &[0x84, 0x37, 0x3];
918 let decoded = OidDecoder::new(ENCODED);
919 assert_eq!(decoded.collect::<Vec<_>>(), [2, 999, 3]);
920 }
921
922 #[test]
923 fn oid_decoding() {
924 assert_eq!(
925 KeyUsage::server_auth().oid_values().collect::<Vec<_>>(),
926 KeyUsage::SERVER_AUTH_REPR
927 );
928 assert_eq!(
929 KeyUsage::client_auth().oid_values().collect::<Vec<_>>(),
930 KeyUsage::CLIENT_AUTH_REPR
931 );
932 }
933
934 #[test]
935 fn eku_fail_empty() {
936 let err = KeyUsage::required(EKU_SERVER_AUTH)
937 .validate(KeyPurposeIdIter {
938 input: &mut untrusted::Reader::new(untrusted::Input::from(&[])),
939 })
940 .unwrap_err();
941 assert_eq!(
942 err,
943 Error::RequiredEkuNotFoundContext(RequiredEkuNotFoundContext {
944 #[cfg(feature = "alloc")]
945 required: dbg!(KeyUsage::required(EKU_SERVER_AUTH)), #[cfg(feature = "alloc")]
947 present: Vec::new(),
948 })
949 );
950 }
951
952 #[test]
953 fn eku_fail_empty_with_optional() {
954 let mut empty_eku = untrusted::Reader::new(untrusted::Input::from(&[]));
955 let validator = KeyUsage::required_if_present(EKU_SERVER_AUTH);
956 assert_eq!(
957 check_eku(Some(&mut empty_eku), &validator).unwrap_err(),
958 Error::EmptyEkuExtension,
959 );
960 }
961
962 #[test]
963 fn eku_key_purpose_id() {
964 assert!(
965 ExtendedKeyUsage::RequiredIfPresent(KeyPurposeId::new(EKU_SERVER_AUTH)).id()
966 == KeyPurposeId::new(EKU_SERVER_AUTH)
967 )
968 }
969
970 #[test]
971 fn test_too_many_signatures() {
972 assert!(matches!(
973 build_and_verify_degenerate_chain(5, ChainTrustAnchor::NotInChain),
974 ControlFlow::Break(Error::MaximumSignatureChecksExceeded)
975 ));
976 }
977
978 #[test]
979 fn test_too_many_path_calls() {
980 assert!(matches!(
981 dbg!(build_and_verify_degenerate_chain(
982 10,
983 ChainTrustAnchor::InChain
984 )),
985 ControlFlow::Break(Error::MaximumPathBuildCallsExceeded)
986 ));
987 }
988
989 #[test]
990 fn longest_allowed_path() {
991 assert!(build_and_verify_linear_chain(1).is_ok());
992 assert!(build_and_verify_linear_chain(2).is_ok());
993 assert!(build_and_verify_linear_chain(3).is_ok());
994 assert!(build_and_verify_linear_chain(4).is_ok());
995 assert!(build_and_verify_linear_chain(5).is_ok());
996 assert!(build_and_verify_linear_chain(6).is_ok());
997 }
998
999 #[test]
1000 fn path_too_long() {
1001 assert!(matches!(
1002 build_and_verify_linear_chain(7),
1003 Err(ControlFlow::Continue(Error::MaximumPathDepthExceeded))
1004 ));
1005 }
1006
1007 #[test]
1008 fn name_constraint_budget() {
1009 let mut ca_cert_params = issuer_params("Constrained Root");
1012 ca_cert_params.name_constraints = Some(rcgen::NameConstraints {
1013 permitted_subtrees: vec![rcgen::GeneralSubtree::DnsName(".com".into())],
1014 excluded_subtrees: vec![],
1015 });
1016 let ca_key_pair = KeyPair::generate_for(test_utils::RCGEN_SIGNATURE_ALG).unwrap();
1017 let ca = CertifiedIssuer::self_signed(ca_cert_params, ca_key_pair).unwrap();
1018
1019 let mut intermediates = Vec::with_capacity(5);
1023 for i in 0..5 {
1024 let intermediate = issuer_params(format!("Intermediate {i}"));
1025 let intermediate_key_pair =
1026 KeyPair::generate_for(test_utils::RCGEN_SIGNATURE_ALG).unwrap();
1027 intermediates.push(
1029 CertifiedIssuer::signed_by(intermediate, intermediate_key_pair, &ca).unwrap(),
1030 );
1031 }
1032
1033 let ee_cert = make_end_entity(intermediates.last().unwrap());
1035 let ee_cert = EndEntityCert::try_from(ee_cert.cert.der()).unwrap();
1036
1037 let passing_budget = Budget {
1041 name_constraint_comparisons: 3,
1046 ..Budget::default()
1047 };
1048
1049 let anchors = &[anchor_from_trusted_cert(ca.der()).unwrap()];
1050 let intermediates_der = intermediates
1051 .iter()
1052 .map(|issuer| issuer.der().clone())
1053 .collect::<Vec<_>>();
1054
1055 let path = verify_chain(
1059 anchors,
1060 &intermediates_der,
1061 &ee_cert,
1062 None,
1063 Some(passing_budget),
1064 )
1065 .unwrap();
1066 assert_eq!(path.anchor().subject, anchors.first().unwrap().subject);
1067
1068 let failing_budget = Budget {
1069 name_constraint_comparisons: 2,
1071 ..Budget::default()
1072 };
1073 let result = verify_chain(
1077 anchors,
1078 &intermediates_der,
1079 &ee_cert,
1080 None,
1081 Some(failing_budget),
1082 );
1083
1084 assert!(matches!(
1085 result,
1086 Err(ControlFlow::Break(
1087 Error::MaximumNameConstraintComparisonsExceeded
1088 ))
1089 ));
1090 }
1091
1092 #[test]
1124 fn test_reject_candidate_path() {
1125 let trust_anchor = make_issuer("Trust Anchor");
1128 let trust_anchor_cert = Cert::from_der(untrusted::Input::from(trust_anchor.der())).unwrap();
1129 let trust_anchors = &[anchor_from_trusted_cert(trust_anchor.der()).unwrap()];
1130
1131 let intermediate_a = make_intermediate("Intermediate A", &trust_anchor);
1132 let intermediate_c = make_intermediate("Intermediate C", &trust_anchor);
1133
1134 let (intermediate_b, intermediate_b_a_cert, intermediate_b_c_cert) = {
1137 let key = KeyPair::generate_for(test_utils::RCGEN_SIGNATURE_ALG).unwrap();
1138 let params = issuer_params("Intermediate");
1139 let intermediate_b_a_cert = params.signed_by(&key, &intermediate_a).unwrap();
1140 let intermediate_b_c_cert = params.signed_by(&key, &intermediate_c).unwrap();
1141 let issuer = Issuer::new(params, key);
1142 (issuer, intermediate_b_a_cert, intermediate_b_c_cert)
1143 };
1144
1145 let intermediates = &[
1146 intermediate_a.der().clone(),
1147 intermediate_c.der().clone(),
1148 intermediate_b_a_cert.der().clone(),
1149 intermediate_b_c_cert.der().clone(),
1150 ];
1151
1152 let ee = make_end_entity(&intermediate_b);
1154 let ee_cert = &EndEntityCert::try_from(ee.cert.der()).unwrap();
1155
1156 let path = verify_chain(trust_anchors, intermediates, ee_cert, None, None).unwrap();
1158 let path_intermediates = path.intermediate_certificates().collect::<Vec<_>>();
1159
1160 let intermediate_a_cert =
1163 Cert::from_der(untrusted::Input::from(intermediate_a.der())).unwrap();
1164 assert_eq!(path_intermediates.len(), 2);
1165 assert_eq!(
1166 path_intermediates[0].issuer(),
1167 intermediate_a_cert.subject()
1168 );
1169 assert_eq!(path_intermediates[1].issuer(), trust_anchor_cert.subject());
1170
1171 let expected_chain = |path: &VerifiedPath<'_>| {
1173 for intermediate in path.intermediate_certificates() {
1174 if intermediate.issuer() == intermediate_a_cert.subject() {
1176 return Err(Error::UnknownIssuer);
1177 }
1178 }
1179
1180 Ok(())
1181 };
1182
1183 let path = verify_chain(
1185 trust_anchors,
1186 intermediates,
1187 ee_cert,
1188 Some(&expected_chain),
1189 None,
1190 )
1191 .unwrap();
1192 let path_intermediates = path.intermediate_certificates().collect::<Vec<_>>();
1193
1194 let intermediate_c_cert =
1197 Cert::from_der(untrusted::Input::from(intermediate_c.der())).unwrap();
1198 assert_eq!(path_intermediates.len(), 2);
1199 assert_eq!(
1200 path_intermediates[0].issuer(),
1201 intermediate_c_cert.subject()
1202 );
1203 assert_eq!(path_intermediates[1].issuer(), trust_anchor_cert.subject());
1204 }
1205
1206 fn make_intermediate(
1207 org_name: impl Into<String>,
1208 issuer: &Issuer<'_, impl SigningKey>,
1209 ) -> CertifiedIssuer<'static, KeyPair> {
1210 let params = issuer_params(org_name);
1211 let key = KeyPair::generate_for(test_utils::RCGEN_SIGNATURE_ALG).unwrap();
1212 CertifiedIssuer::signed_by(params, key, issuer).unwrap()
1213 }
1214
1215 fn build_and_verify_degenerate_chain(
1216 intermediate_count: usize,
1217 trust_anchor: ChainTrustAnchor,
1218 ) -> ControlFlow<Error, Error> {
1219 let ca = make_issuer("Bogus Subject");
1220 let mut intermediate_chain = IntermediateChain::new(intermediate_count, true, &ca);
1221
1222 let verify_trust_anchor = match trust_anchor {
1223 ChainTrustAnchor::InChain => make_issuer("Bogus Trust Anchor"),
1224 ChainTrustAnchor::NotInChain => ca,
1225 };
1226
1227 let ee_cert = make_end_entity(&intermediate_chain.last_issuer);
1228 let ee_cert = EndEntityCert::try_from(ee_cert.cert.der()).unwrap();
1229 let webpki_ta = anchor_from_trusted_cert(verify_trust_anchor.der()).unwrap();
1230 if matches!(trust_anchor, ChainTrustAnchor::InChain) {
1231 intermediate_chain
1234 .chain
1235 .insert(0, verify_trust_anchor.der().to_owned())
1236 }
1237
1238 verify_chain(
1239 &[webpki_ta],
1240 &intermediate_chain.chain,
1241 &ee_cert,
1242 None,
1243 None,
1244 )
1245 .map(|_| ())
1246 .unwrap_err()
1247 }
1248
1249 #[cfg(feature = "alloc")]
1250 enum ChainTrustAnchor {
1251 NotInChain,
1252 InChain,
1253 }
1254
1255 fn build_and_verify_linear_chain(chain_length: usize) -> Result<(), ControlFlow<Error, Error>> {
1256 let ca = make_issuer(format!("Bogus Subject {chain_length}"));
1257 let intermediate_chain = IntermediateChain::new(chain_length, false, &ca);
1258
1259 let anchor = anchor_from_trusted_cert(ca.der()).unwrap();
1260 let anchors = slice::from_ref(&anchor);
1261
1262 let ee_cert = make_end_entity(&intermediate_chain.last_issuer);
1263 let ee_cert = EndEntityCert::try_from(ee_cert.cert.der()).unwrap();
1264
1265 let expected_chain = |path: &VerifiedPath<'_>| {
1266 assert_eq!(path.anchor().subject, anchor.subject);
1267 assert!(public_values_eq(path.end_entity().subject, ee_cert.subject));
1268 assert_eq!(path.intermediate_certificates().count(), chain_length);
1269
1270 let intermediate_certs = intermediate_chain
1271 .chain
1272 .iter()
1273 .map(|der| Cert::from_der(untrusted::Input::from(der)).unwrap())
1274 .collect::<Vec<_>>();
1275
1276 for (cert, expected) in path
1277 .intermediate_certificates()
1278 .rev()
1279 .zip(intermediate_certs.iter())
1280 {
1281 assert!(public_values_eq(cert.subject, expected.subject));
1282 assert_eq!(cert.der(), expected.der());
1283 }
1284
1285 for (cert, expected) in path
1286 .intermediate_certificates()
1287 .zip(intermediate_certs.iter().rev())
1288 {
1289 assert!(public_values_eq(cert.subject, expected.subject));
1290 assert_eq!(cert.der(), expected.der());
1291 }
1292
1293 Ok(())
1294 };
1295
1296 verify_chain(
1297 anchors,
1298 &intermediate_chain.chain,
1299 &ee_cert,
1300 Some(&expected_chain),
1301 None,
1302 )
1303 .map(|_| ())
1304 }
1305
1306 struct IntermediateChain {
1307 last_issuer: Issuer<'static, KeyPair>,
1308 chain: Vec<CertificateDer<'static>>,
1309 }
1310
1311 impl IntermediateChain {
1312 fn new(chain_length: usize, all_same_subject: bool, ca_cert: &Issuer<'_, KeyPair>) -> Self {
1313 let mut chain = Vec::with_capacity(chain_length);
1314
1315 let mut prev = None;
1316 for i in 0..chain_length {
1317 let issuer = match &prev {
1318 Some(prev) => prev,
1319 None => ca_cert,
1320 };
1321
1322 let intermediate = issuer_params(match all_same_subject {
1323 true => "Bogus Subject".to_string(),
1324 false => format!("Bogus Subject {i}"),
1325 });
1326
1327 let key_pair = KeyPair::generate_for(test_utils::RCGEN_SIGNATURE_ALG).unwrap();
1328 let cert = intermediate.signed_by(&key_pair, issuer).unwrap();
1329
1330 chain.push(cert.der().clone());
1331 prev = Some(Issuer::new(intermediate, key_pair));
1332 }
1333
1334 Self {
1335 last_issuer: prev.unwrap(),
1336 chain,
1337 }
1338 }
1339 }
1340
1341 fn verify_chain<'a>(
1342 trust_anchors: &'a [TrustAnchor<'a>],
1343 intermediate_certs: &'a [CertificateDer<'a>],
1344 ee_cert: &'a EndEntityCert<'a>,
1345 verify_path: Option<&dyn Fn(&VerifiedPath<'_>) -> Result<(), Error>>,
1346 budget: Option<Budget>,
1347 ) -> Result<VerifiedPath<'a>, ControlFlow<Error, Error>> {
1348 use core::time::Duration;
1349
1350 let time = UnixTime::since_unix_epoch(Duration::from_secs(0x1fed_f00d));
1351 let mut path = PartialPath::new(ee_cert);
1352 let opts = ChainOptions {
1353 eku: KeyUsage::server_auth(),
1354 supported_sig_algs: crate::ALL_VERIFICATION_ALGS,
1355 trust_anchors,
1356 intermediate_certs,
1357 revocation: None,
1358 };
1359
1360 match opts.build_chain_inner(
1361 &mut path,
1362 time,
1363 verify_path,
1364 0,
1365 &mut budget.unwrap_or_default(),
1366 ) {
1367 Ok(anchor) => Ok(VerifiedPath::new(ee_cert, anchor, path)),
1368 Err(err) => Err(err),
1369 }
1370 }
1371}