webpki/
verify_cert.rs

1// Copyright 2015 Brian Smith.
2//
3// Permission to use, copy, modify, and/or distribute this software for any
4// purpose with or without fee is hereby granted, provided that the above
5// copyright notice and this permission notice appear in all copies.
6//
7// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
8// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
10// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
13// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14
15#[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
29// Use `'a` for lifetimes that we don't care about, `'p` for lifetimes that become a part of
30// the `VerifiedPath`.
31pub(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        // TODO: HPKP checks.
66
67        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                // TODO: check_distrust(trust_anchor_subject, trust_anchor_spki)?;
75
76                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            // Fatal errors should halt further path building.
100            res @ Err(ControlFlow::Break(_)) => return res,
101            // Non-fatal errors should be carried forward as the default_error for subsequent
102            // loop_while_non_fatal_error processing and only returned once all other path-building
103            // options have been exhausted.
104            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            // Prevent loops; see RFC 4158 section 5.2.
114            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; // TODO(XXX): Consider whether to track TrustAnchor KU.
147        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
176/// Path from end-entity certificate to trust anchor that's been verified.
177///
178/// See [`EndEntityCert::verify_for_usage()`] for more details on what verification entails.
179pub 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    /// Yields a (double-ended) iterator over the intermediate certificates in this path.
202    pub fn intermediate_certificates(&'p self) -> IntermediateIterator<'p> {
203        IntermediateIterator {
204            intermediates: self.intermediates.as_ref(),
205        }
206    }
207
208    /// Yields the end-entity certificate for this path.
209    pub fn end_entity(&self) -> &'p EndEntityCert<'p> {
210        self.end_entity
211    }
212
213    /// Yields the trust anchor for this path.
214    pub fn anchor(&self) -> &'p TrustAnchor<'p> {
215        self.anchor
216    }
217}
218
219/// Iterator over a path's intermediate certificates.
220///
221/// Implements [`DoubleEndedIterator`] so it can be traversed in both directions.
222pub struct IntermediateIterator<'a> {
223    /// Invariant: all of these `Option`s are `Some`.
224    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            // This limit is taken from the remediation for golang CVE-2018-16875.  However,
331            // note that golang subsequently implemented AKID matching due to this limit
332            // being hit in real applications (see <https://github.com/spiffe/spire/issues/1004>).
333            // So this may actually be too aggressive.
334            signatures: 100,
335
336            // This limit is taken from mozilla::pkix, see:
337            // <https://github.com/nss-dev/nss/blob/bb4a1d38dd9e92923525ac6b5ed0288479f3f3fc/lib/mozpkix/lib/pkixbuild.cpp#L381-L393>
338            build_chain_calls: 200_000,
339
340            // This limit is taken from golang crypto/x509's default, see:
341            // <https://github.com/golang/go/blob/ac17bb6f13979f2ab9fcd45f0758b43ed72d0973/src/crypto/x509/verify.go#L588-L592>
342            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    // TODO: check_distrust(trust_anchor_subject, trust_anchor_spki)?;
355    // TODO: Check signature algorithm like mozilla::pkix.
356    // TODO: Check SPKI like mozilla::pkix.
357    // TODO: check for active distrust like mozilla::pkix.
358
359    // For cert validation, we ignore the KeyUsage extension. For CA
360    // certificates, BasicConstraints.cA makes KeyUsage redundant. Firefox
361    // and other common browsers do not check KeyUsage for end-entities,
362    // though it would be kind of nice to ensure that a KeyUsage without
363    // the keyEncipherment bit could not be used for RSA key exchange.
364
365    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
388// https://tools.ietf.org/html/rfc5280#section-4.1.2.5
389fn 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    // TODO: mozilla::pkix allows the TrustDomain to check not_before and
404    // not_after, to enforce things like a maximum validity period. We should
405    // do something similar.
406
407    Ok(())
408}
409
410// https://tools.ietf.org/html/rfc5280#section-4.2.1.9
411fn 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            // https://bugzilla.mozilla.org/show_bug.cgi?id=985025: RFC 5280
421            // says that a certificate must not have pathLenConstraint unless
422            // it is a CA certificate, but some real-world end-entity
423            // certificates have pathLenConstraint.
424            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/// Additional context for the `RequiredEkuNotFoundContext` error variant.
446///
447/// The contents of this type depend on whether the `alloc` feature is enabled.
448#[derive(Clone, PartialEq, Eq)]
449pub struct RequiredEkuNotFoundContext {
450    /// The required ExtendedKeyUsage.
451    #[cfg(feature = "alloc")]
452    pub required: KeyUsage,
453    /// The ExtendedKeyUsage OIDs present in the certificate.
454    #[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/// The expected key usage of a certificate.
501///
502/// This type represents the expected key usage of an end entity certificate. Although for most
503/// kinds of certificates the extended key usage extension is optional (and so certificates
504/// not carrying a particular value in the EKU extension are acceptable). If the extension
505/// is present, the certificate MUST only be used for one of the purposes indicated.
506///
507/// <https://www.rfc-editor.org/rfc/rfc5280#section-4.2.1.12>
508#[derive(Clone, Copy, Debug, Eq, PartialEq)]
509pub struct KeyUsage {
510    inner: ExtendedKeyUsage,
511}
512
513impl KeyUsage {
514    /// Construct a new [`KeyUsage`] as appropriate for server certificate authentication.
515    ///
516    /// As specified in <https://www.rfc-editor.org/rfc/rfc5280#section-4.2.1.12>, this does not require the certificate to specify the eKU extension.
517    pub const fn server_auth() -> Self {
518        Self::required_if_present(EKU_SERVER_AUTH)
519    }
520
521    /// Construct a new [`KeyUsage`] as appropriate for client certificate authentication.
522    ///
523    /// As specified in <>, this does not require the certificate to specify the eKU extension.
524    pub const fn client_auth() -> Self {
525        Self::required_if_present(EKU_CLIENT_AUTH)
526    }
527
528    /// Construct a new [`KeyUsage`] requiring a certificate to support the specified OID.
529    pub const fn required(oid: &'static [u8]) -> Self {
530        Self {
531            inner: ExtendedKeyUsage::Required(KeyPurposeId::new(oid)),
532        }
533    }
534
535    /// Construct a new [`KeyUsage`] requiring a certificate to support the specified OID, if the certificate has EKUs.
536    pub const fn required_if_present(oid: &'static [u8]) -> Self {
537        Self {
538            inner: ExtendedKeyUsage::RequiredIfPresent(KeyPurposeId::new(oid)),
539        }
540    }
541
542    /// Yield the OID values of the required extended key usage.
543    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    /// Human-readable representation of the server authentication OID.
555    pub const SERVER_AUTH_REPR: &[usize] = &[1, 3, 6, 1, 5, 5, 7, 3, 1];
556    /// Human-readable representation of the client authentication OID.
557    pub const CLIENT_AUTH_REPR: &[usize] = &[1, 3, 6, 1, 5, 5, 7, 3, 2];
558}
559
560impl ExtendedKeyUsageValidator for KeyUsage {
561    // https://tools.ietf.org/html/rfc5280#section-4.2.1.12
562    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
598/// A trait for validating the Extended Key Usage (EKU) extensions of a certificate.
599pub trait ExtendedKeyUsageValidator {
600    /// Validate the EKU values in a certificate.
601    ///
602    /// `iter` yields the EKU OIDs in the certificate, or an error if the EKU extension
603    /// is malformed. `validate()` should yield `Ok(())` if the EKU values match the
604    /// required policy, or an `Error` if they do not. Ideally the `Error` should be
605    /// `Error::RequiredEkuNotFoundContext` if the policy is not met.
606    fn validate(&self, iter: KeyPurposeIdIter<'_, '_>) -> Result<(), Error>;
607}
608
609/// Extended Key Usage (EKU) of a certificate.
610#[derive(Clone, Copy, Debug, Eq, PartialEq)]
611enum ExtendedKeyUsage {
612    /// The certificate must contain the specified [`KeyPurposeId`] as EKU.
613    Required(KeyPurposeId<'static>),
614
615    /// If the certificate has EKUs, then the specified [`KeyPurposeId`] must be included.
616    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
628/// Iterator over [`KeyPurposeId`]s, for use in [`ExtendedKeyUsageValidator`].
629pub 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/// An OID value indicating an Extended Key Usage (EKU) key purpose.
652#[derive(Clone, Copy)]
653pub struct KeyPurposeId<'a> {
654    oid_value: untrusted::Input<'a>,
655}
656
657impl<'a> KeyPurposeId<'a> {
658    /// Construct a new [`KeyPurposeId`].
659    ///
660    /// `oid` is the OBJECT IDENTIFIER in bytes.
661    pub const fn new(oid: &'a [u8]) -> Self {
662        Self {
663            oid_value: untrusted::Input::from(oid),
664        }
665    }
666
667    /// Yield the OID value as a sequence of `usize` components.
668    #[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
696// id-pkix            OBJECT IDENTIFIER ::= { 1 3 6 1 5 5 7 }
697// id-kp              OBJECT IDENTIFIER ::= { id-pkix 3 }
698
699// id-kp-serverAuth   OBJECT IDENTIFIER ::= { id-kp 1 }
700const EKU_SERVER_AUTH: &[u8] = &oid!(1, 3, 6, 1, 5, 5, 7, 3, 1);
701
702// id-kp-clientAuth   OBJECT IDENTIFIER ::= { id-kp 2 }
703const 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            // Fatal errors should halt further looping.
767            res @ Err(ControlFlow::Break(_)) => return res,
768            // Non-fatal errors should be ranked by specificity and only returned
769            // once all other path-building options have been exhausted.
770            Err(ControlFlow::Continue(new_error)) => error = error.most_specific(new_error),
771        }
772    }
773    Err(error.into())
774}
775
776/// A path for consideration in path building.
777///
778/// This represents a partial path because it does not yet contain the trust anchor. It stores
779/// the end-entity certificates, and an array of intermediate certificates.
780pub(crate) struct PartialPath<'a> {
781    end_entity: &'a EndEntityCert<'a>,
782    /// Intermediate certificates, in order from end-entity to trust anchor.
783    ///
784    /// Invariant: all values below `used` are `Some`.
785    intermediates: [Option<Cert<'a>>; MAX_SUB_CA_COUNT],
786    /// The number of `Some` values in `intermediates`.
787    ///
788    /// The next `Cert` passed to `push()` will be placed at `intermediates[used]`.
789    /// If this value is 0, the path contains only the end-entity certificate.
790    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    /// Current head of the path.
831    pub(crate) fn head(&self) -> &Cert<'a> {
832        self.get(self.used)
833    }
834
835    /// Get the certificate at index `idx` in the path.
836    ///
837    // `idx` must be in the range `0..=self.used`; `idx` 0 thus yields the `end_entity`,
838    // while subsequent indexes yield the intermediate at `self.intermediates[idx - 1]`.
839    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    /// The path we're iterating.
851    path: &'a PartialPath<'a>,
852    /// The index of the current node in the path (input for `path.get()`).
853    index: usize,
854    /// The [`Cert`] at `index`.
855    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        // 2.999.3 -> 1079.3 -> [0x84, 0x37, 0x3]
917        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)), // Cover Debug impl
946                #[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        // Issue a trust anchor that imposes name constraints. The constraint should match
1010        // the end entity certificate SAN.
1011        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        // Create a series of intermediate issuers. We'll only use one in the actual built path,
1020        // helping demonstrate that the name constraint budget is not expended checking certificates
1021        // that are not part of the path we compute.
1022        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            // Each intermediate should be issued by the trust anchor.
1028            intermediates.push(
1029                CertifiedIssuer::signed_by(intermediate, intermediate_key_pair, &ca).unwrap(),
1030            );
1031        }
1032
1033        // Create an end-entity cert that is issued by the last of the intermediates.
1034        let ee_cert = make_end_entity(intermediates.last().unwrap());
1035        let ee_cert = EndEntityCert::try_from(ee_cert.cert.der()).unwrap();
1036
1037        // We use a custom budget to make it easier to write a test, otherwise it is tricky to
1038        // stuff enough names/constraints into the potential chains while staying within the path
1039        // depth limit and the build chain call limit.
1040        let passing_budget = Budget {
1041            // One comparison against the intermediate's distinguished name.
1042            // One comparison against the EE's distinguished name.
1043            // One comparison against the EE's SAN.
1044            //  = 3 total comparisons.
1045            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        // Validation should succeed with the name constraint comparison budget allocated above.
1056        // This shows that we're not consuming budget on unused intermediates: we didn't budget
1057        // enough comparisons for that to pass the overall chain building.
1058        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            // See passing_budget: 2 comparisons is not sufficient.
1070            name_constraint_comparisons: 2,
1071            ..Budget::default()
1072        };
1073        // Validation should fail when the budget is smaller than the number of comparisons performed
1074        // on the validated path. This demonstrates we properly fail path building when too many
1075        // name constraint comparisons occur.
1076        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    /// This test builds a PKI like the following diagram depicts. We first verify
1093    /// that we can build a path EE -> B -> A -> TA. Next we supply a custom path verification
1094    /// function that rejects the B->A path, and verify that we build a path EE -> B -> C -> TA.
1095    ///
1096    ///        ┌───────────┐
1097    ///        │           │
1098    ///        │     TA    │
1099    ///        │           │
1100    ///        └───┬───┬───┘
1101    ///            │   │
1102    ///            │   │
1103    /// ┌────────┐◄┘   └──►┌────────┐
1104    /// │        │         │        │
1105    /// │   A    │         │   C    │
1106    /// │        │         │        │
1107    /// └────┬───┘         └───┬────┘
1108    ///      │                 │
1109    ///      │                 │
1110    ///      │   ┌─────────┐   │
1111    ///      └──►│         │◄──┘
1112    ///          │    B    │
1113    ///          │         │
1114    ///          └────┬────┘
1115    ///               │
1116    ///               │
1117    ///               │
1118    ///          ┌────▼────┐
1119    ///          │         │
1120    ///          │    EE   │
1121    ///          │         │
1122    ///          └─────────┘
1123    #[test]
1124    fn test_reject_candidate_path() {
1125        // Create a trust anchor, and use it to issue two distinct intermediate certificates, each
1126        // with a unique subject and keypair.
1127        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        // Next, create an intermediate that is issued by both of the intermediates above.
1135        // Both should share the same subject, and key pair, but will differ in the issuer.
1136        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        // Create an end entity certificate signed by the keypair of the intermediates created above.
1153        let ee = make_end_entity(&intermediate_b);
1154        let ee_cert = &EndEntityCert::try_from(ee.cert.der()).unwrap();
1155
1156        // We should be able to create a valid path from EE to trust anchor.
1157        let path = verify_chain(trust_anchors, intermediates, ee_cert, None, None).unwrap();
1158        let path_intermediates = path.intermediate_certificates().collect::<Vec<_>>();
1159
1160        // We expect that without applying any additional constraints, that the path will be
1161        // EE -> intermediate_b_a -> intermediate_a -> trust_anchor.
1162        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        // Now, we'll create a function that will reject the intermediate_b_a path.
1172        let expected_chain = |path: &VerifiedPath<'_>| {
1173            for intermediate in path.intermediate_certificates() {
1174                // Reject any intermediates issued by intermediate A.
1175                if intermediate.issuer() == intermediate_a_cert.subject() {
1176                    return Err(Error::UnknownIssuer);
1177                }
1178            }
1179
1180            Ok(())
1181        };
1182
1183        // We should still be able to build a valid path.
1184        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        // We expect that the path will now be
1195        // EE -> intermediate_b_c -> intermediate_c -> trust_anchor.
1196        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            // Note: we clone the trust anchor DER here because we can't move it into the chain
1232            // as it's loaned to webpki_ta above.
1233            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}