Skip to main content

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    pub(crate) distrusted_spkis: &'a [&'a [u8]],
38}
39
40impl<'a, 'p: 'a, V: ExtendedKeyUsageValidator> ChainOptions<'a, 'p, V> {
41    pub(crate) fn build_chain(
42        &self,
43        end_entity: &'p EndEntityCert<'p>,
44        time: UnixTime,
45        verify_path: Option<&dyn Fn(&VerifiedPath<'_>) -> Result<(), Error>>,
46    ) -> Result<VerifiedPath<'p>, Error> {
47        let mut path = PartialPath::new(end_entity);
48        match self.build_chain_inner(&mut path, time, verify_path, 0, &mut Budget::default()) {
49            Ok(anchor) => Ok(VerifiedPath::new(end_entity, anchor, path)),
50            Err(ControlFlow::Break(err)) | Err(ControlFlow::Continue(err)) => Err(err),
51        }
52    }
53
54    fn build_chain_inner(
55        &self,
56        path: &mut PartialPath<'p>,
57        time: UnixTime,
58        verify_path: Option<&dyn Fn(&VerifiedPath<'_>) -> Result<(), Error>>,
59        sub_ca_count: usize,
60        budget: &mut Budget,
61    ) -> Result<&'p TrustAnchor<'p>, ControlFlow<Error, Error>> {
62        if self
63            .distrusted_spkis
64            .contains(&path.head().spki.as_slice_less_safe())
65        {
66            return Err(Error::CertDistrusted.into());
67        }
68
69        let role = path.node().role();
70
71        check_issuer_independent_properties(path.head(), time, role, sub_ca_count, &self.eku)?;
72
73        // TODO: HPKP checks.
74
75        let result =
76            loop_while_non_fatal_error(Error::UnknownIssuer, self.trust_anchors, |trust_anchor| {
77                let trust_anchor_subject = untrusted::Input::from(trust_anchor.subject.as_ref());
78                if !public_values_eq(path.head().issuer, trust_anchor_subject) {
79                    return Err(Error::UnknownIssuer.into());
80                }
81
82                if self
83                    .distrusted_spkis
84                    .contains(&trust_anchor.subject_public_key_info.as_ref())
85                {
86                    return Err(Error::CertDistrusted.into());
87                }
88
89                let node = path.node();
90                self.check_signed_chain(&node, time, trust_anchor, budget)?;
91                check_signed_chain_name_constraints(&node, trust_anchor, budget)?;
92
93                let verify = match verify_path {
94                    Some(verify) => verify,
95                    None => return Ok(trust_anchor),
96                };
97
98                let candidate = VerifiedPath {
99                    end_entity: path.end_entity,
100                    intermediates: Intermediates::Borrowed(&path.intermediates[..path.used]),
101                    anchor: trust_anchor,
102                };
103
104                match verify(&candidate) {
105                    Ok(()) => Ok(trust_anchor),
106                    Err(err) => Err(ControlFlow::Continue(err)),
107                }
108            });
109
110        let err = match result {
111            Ok(anchor) => return Ok(anchor),
112            // Fatal errors should halt further path building.
113            res @ Err(ControlFlow::Break(_)) => return res,
114            // Non-fatal errors should be carried forward as the default_error for subsequent
115            // loop_while_non_fatal_error processing and only returned once all other path-building
116            // options have been exhausted.
117            Err(ControlFlow::Continue(err)) => err,
118        };
119
120        loop_while_non_fatal_error(err, self.intermediate_certs, |cert_der| {
121            let potential_issuer = Cert::from_der(untrusted::Input::from(cert_der))?;
122            if !public_values_eq(potential_issuer.subject, path.head().issuer) {
123                return Err(Error::UnknownIssuer.into());
124            }
125
126            // Prevent loops; see RFC 4158 section 5.2.
127            if path.node().iter().any(|prev| {
128                public_values_eq(potential_issuer.spki, prev.cert.spki)
129                    && public_values_eq(potential_issuer.subject, prev.cert.subject)
130            }) {
131                return Err(Error::UnknownIssuer.into());
132            }
133
134            let next_sub_ca_count = match role {
135                Role::EndEntity => sub_ca_count,
136                Role::Issuer => sub_ca_count + 1,
137            };
138
139            budget.consume_build_chain_call()?;
140            path.push(potential_issuer)?;
141            let result = self.build_chain_inner(path, time, verify_path, next_sub_ca_count, budget);
142            if result.is_err() {
143                path.pop();
144            }
145
146            result
147        })
148    }
149
150    fn check_signed_chain(
151        &self,
152        path: &PathNode<'_>,
153        time: UnixTime,
154        trust_anchor: &TrustAnchor<'_>,
155        budget: &mut Budget,
156    ) -> Result<(), ControlFlow<Error, Error>> {
157        let mut spki_value = untrusted::Input::from(trust_anchor.subject_public_key_info.as_ref());
158        let mut issuer_subject = untrusted::Input::from(trust_anchor.subject.as_ref());
159        let mut issuer_key_usage = None; // TODO(XXX): Consider whether to track TrustAnchor KU.
160        for path in path.iter() {
161            signed_data::verify_signed_data(
162                self.supported_sig_algs,
163                spki_value,
164                &path.cert.signed_data,
165                budget,
166            )?;
167
168            if let Some(revocation_opts) = &self.revocation {
169                revocation_opts.check(
170                    &path,
171                    issuer_subject,
172                    spki_value,
173                    issuer_key_usage,
174                    self.supported_sig_algs,
175                    budget,
176                    time,
177                )?;
178            }
179
180            spki_value = path.cert.spki;
181            issuer_subject = path.cert.subject;
182            issuer_key_usage = path.cert.key_usage;
183        }
184
185        Ok(())
186    }
187}
188
189/// Path from end-entity certificate to trust anchor that's been verified.
190///
191/// See [`EndEntityCert::verify_for_usage()`] for more details on what verification entails.
192pub struct VerifiedPath<'p> {
193    end_entity: &'p EndEntityCert<'p>,
194    intermediates: Intermediates<'p>,
195    anchor: &'p TrustAnchor<'p>,
196}
197
198impl<'p> VerifiedPath<'p> {
199    fn new(
200        end_entity: &'p EndEntityCert<'p>,
201        anchor: &'p TrustAnchor<'p>,
202        partial: PartialPath<'p>,
203    ) -> Self {
204        Self {
205            end_entity,
206            intermediates: Intermediates::Owned {
207                certs: partial.intermediates,
208                used: partial.used,
209            },
210            anchor,
211        }
212    }
213
214    /// Yields a (double-ended) iterator over the intermediate certificates in this path.
215    pub fn intermediate_certificates(&'p self) -> IntermediateIterator<'p> {
216        IntermediateIterator {
217            intermediates: self.intermediates.as_ref(),
218        }
219    }
220
221    /// Yields the end-entity certificate for this path.
222    pub fn end_entity(&self) -> &'p EndEntityCert<'p> {
223        self.end_entity
224    }
225
226    /// Yields the trust anchor for this path.
227    pub fn anchor(&self) -> &'p TrustAnchor<'p> {
228        self.anchor
229    }
230}
231
232/// Iterator over a path's intermediate certificates.
233///
234/// Implements [`DoubleEndedIterator`] so it can be traversed in both directions.
235pub struct IntermediateIterator<'a> {
236    /// Invariant: all of these `Option`s are `Some`.
237    intermediates: &'a [Option<Cert<'a>>],
238}
239
240impl<'a> Iterator for IntermediateIterator<'a> {
241    type Item = &'a Cert<'a>;
242
243    fn next(&mut self) -> Option<Self::Item> {
244        match self.intermediates.split_first() {
245            Some((head, tail)) => {
246                self.intermediates = tail;
247                Some(head.as_ref().unwrap())
248            }
249            None => None,
250        }
251    }
252}
253
254impl DoubleEndedIterator for IntermediateIterator<'_> {
255    fn next_back(&mut self) -> Option<Self::Item> {
256        match self.intermediates.split_last() {
257            Some((head, tail)) => {
258                self.intermediates = tail;
259                Some(head.as_ref().unwrap())
260            }
261            None => None,
262        }
263    }
264}
265
266#[allow(clippy::large_enum_variant)]
267enum Intermediates<'a> {
268    Owned {
269        certs: [Option<Cert<'a>>; MAX_SUB_CA_COUNT],
270        used: usize,
271    },
272    Borrowed(&'a [Option<Cert<'a>>]),
273}
274
275impl<'a> AsRef<[Option<Cert<'a>>]> for Intermediates<'a> {
276    fn as_ref(&self) -> &[Option<Cert<'a>>] {
277        match self {
278            Intermediates::Owned { certs, used } => &certs[..*used],
279            Intermediates::Borrowed(certs) => certs,
280        }
281    }
282}
283
284fn check_signed_chain_name_constraints(
285    path: &PathNode<'_>,
286    trust_anchor: &TrustAnchor<'_>,
287    budget: &mut Budget,
288) -> Result<(), ControlFlow<Error, Error>> {
289    let mut name_constraints = trust_anchor
290        .name_constraints
291        .as_ref()
292        .map(|der| untrusted::Input::from(der.as_ref()));
293
294    for path in path.iter() {
295        untrusted::read_all_optional(name_constraints, Error::BadDer, |value| {
296            subject_name::check_name_constraints(value, &path, budget)
297        })?;
298
299        name_constraints = path.cert.name_constraints;
300    }
301
302    Ok(())
303}
304
305pub(crate) struct Budget {
306    signatures: usize,
307    build_chain_calls: usize,
308    name_constraint_comparisons: usize,
309}
310
311impl Budget {
312    #[inline]
313    pub(crate) fn consume_signature(&mut self) -> Result<(), Error> {
314        self.signatures = self
315            .signatures
316            .checked_sub(1)
317            .ok_or(Error::MaximumSignatureChecksExceeded)?;
318        Ok(())
319    }
320
321    #[inline]
322    fn consume_build_chain_call(&mut self) -> Result<(), Error> {
323        self.build_chain_calls = self
324            .build_chain_calls
325            .checked_sub(1)
326            .ok_or(Error::MaximumPathBuildCallsExceeded)?;
327        Ok(())
328    }
329
330    #[inline]
331    pub(crate) fn consume_name_constraint_comparison(&mut self) -> Result<(), Error> {
332        self.name_constraint_comparisons = self
333            .name_constraint_comparisons
334            .checked_sub(1)
335            .ok_or(Error::MaximumNameConstraintComparisonsExceeded)?;
336        Ok(())
337    }
338}
339
340impl Default for Budget {
341    fn default() -> Self {
342        Self {
343            // This limit is taken from the remediation for golang CVE-2018-16875.  However,
344            // note that golang subsequently implemented AKID matching due to this limit
345            // being hit in real applications (see <https://github.com/spiffe/spire/issues/1004>).
346            // So this may actually be too aggressive.
347            signatures: 100,
348
349            // This limit is taken from mozilla::pkix, see:
350            // <https://github.com/nss-dev/nss/blob/bb4a1d38dd9e92923525ac6b5ed0288479f3f3fc/lib/mozpkix/lib/pkixbuild.cpp#L381-L393>
351            build_chain_calls: 200_000,
352
353            // This limit is taken from golang crypto/x509's default, see:
354            // <https://github.com/golang/go/blob/ac17bb6f13979f2ab9fcd45f0758b43ed72d0973/src/crypto/x509/verify.go#L588-L592>
355            name_constraint_comparisons: 250_000,
356        }
357    }
358}
359
360fn check_issuer_independent_properties(
361    cert: &Cert<'_>,
362    time: UnixTime,
363    role: Role,
364    sub_ca_count: usize,
365    eku: &impl ExtendedKeyUsageValidator,
366) -> Result<(), Error> {
367    // TODO: check_distrust(trust_anchor_subject, trust_anchor_spki)?;
368    // TODO: Check signature algorithm like mozilla::pkix.
369    // TODO: Check SPKI like mozilla::pkix.
370    // TODO: check for active distrust like mozilla::pkix.
371
372    // For cert validation, we ignore the KeyUsage extension. For CA
373    // certificates, BasicConstraints.cA makes KeyUsage redundant. Firefox
374    // and other common browsers do not check KeyUsage for end-entities,
375    // though it would be kind of nice to ensure that a KeyUsage without
376    // the keyEncipherment bit could not be used for RSA key exchange.
377
378    cert.validity
379        .read_all(Error::BadDer, |value| check_validity(value, time))?;
380    untrusted::read_all_optional(cert.basic_constraints, Error::BadDer, |value| {
381        check_basic_constraints(value, role, sub_ca_count)
382    })?;
383    untrusted::read_all_optional(cert.eku, Error::BadDer, |input| check_eku(input, eku))?;
384
385    Ok(())
386}
387
388fn check_eku(
389    input: Option<&mut untrusted::Reader<'_>>,
390    eku: &impl ExtendedKeyUsageValidator,
391) -> Result<(), Error> {
392    match input {
393        Some(input) if input.at_end() => Err(Error::EmptyEkuExtension),
394        Some(input) => eku.validate(KeyPurposeIdIter { input }),
395        None => eku.validate(KeyPurposeIdIter {
396            input: &mut untrusted::Reader::new(untrusted::Input::from(&[])),
397        }),
398    }
399}
400
401// https://tools.ietf.org/html/rfc5280#section-4.1.2.5
402fn check_validity(input: &mut untrusted::Reader<'_>, time: UnixTime) -> Result<(), Error> {
403    let not_before = UnixTime::from_der(input)?;
404    let not_after = UnixTime::from_der(input)?;
405
406    if not_before > not_after {
407        return Err(Error::InvalidCertValidity);
408    }
409    if time < not_before {
410        return Err(Error::CertNotValidYet { time, not_before });
411    }
412    if time > not_after {
413        return Err(Error::CertExpired { time, not_after });
414    }
415
416    // TODO: mozilla::pkix allows the TrustDomain to check not_before and
417    // not_after, to enforce things like a maximum validity period. We should
418    // do something similar.
419
420    Ok(())
421}
422
423// https://tools.ietf.org/html/rfc5280#section-4.2.1.9
424fn check_basic_constraints(
425    input: Option<&mut untrusted::Reader<'_>>,
426    role: Role,
427    sub_ca_count: usize,
428) -> Result<(), Error> {
429    let (is_ca, path_len_constraint) = match input {
430        Some(input) => {
431            let is_ca = bool::from_der(input)?;
432
433            // https://bugzilla.mozilla.org/show_bug.cgi?id=985025: RFC 5280
434            // says that a certificate must not have pathLenConstraint unless
435            // it is a CA certificate, but some real-world end-entity
436            // certificates have pathLenConstraint.
437            let path_len_constraint = if !input.at_end() {
438                Some(usize::from(u8::from_der(input)?))
439            } else {
440                None
441            };
442
443            (is_ca, path_len_constraint)
444        }
445        None => (false, None),
446    };
447
448    match (role, is_ca, path_len_constraint) {
449        (Role::EndEntity, true, _) => Err(Error::CaUsedAsEndEntity),
450        (Role::Issuer, false, _) => Err(Error::EndEntityUsedAsCa),
451        (Role::Issuer, true, Some(len)) if sub_ca_count > len => {
452            Err(Error::PathLenConstraintViolated)
453        }
454        _ => Ok(()),
455    }
456}
457
458/// Additional context for the `RequiredEkuNotFoundContext` error variant.
459///
460/// The contents of this type depend on whether the `alloc` feature is enabled.
461#[derive(Clone, PartialEq, Eq)]
462pub struct RequiredEkuNotFoundContext {
463    /// The required ExtendedKeyUsage.
464    #[cfg(feature = "alloc")]
465    pub required: KeyUsage,
466    /// The ExtendedKeyUsage OIDs present in the certificate.
467    #[cfg(feature = "alloc")]
468    pub present: Vec<Vec<usize>>,
469}
470
471impl fmt::Debug for RequiredEkuNotFoundContext {
472    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
473        let mut builder = f.debug_struct("RequiredEkuNotFoundContext");
474        #[cfg(feature = "alloc")]
475        builder.field(
476            "required",
477            match &self.required.inner {
478                ExtendedKeyUsage::Required(inner) => inner,
479                ExtendedKeyUsage::RequiredIfPresent(inner) => inner,
480            },
481        );
482        #[cfg(feature = "alloc")]
483        builder.field("present", &EkuListDebug(&self.present));
484        builder.finish()
485    }
486}
487
488#[cfg(feature = "alloc")]
489struct EkuListDebug<'a>(&'a [Vec<usize>]);
490
491#[cfg(feature = "alloc")]
492impl fmt::Debug for EkuListDebug<'_> {
493    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
494        write!(f, "[")?;
495        for (i, part) in self.0.iter().enumerate() {
496            if i > 0 {
497                write!(f, ", ")?;
498            }
499
500            write!(f, "KeyPurposeId(")?;
501            for (j, part) in part.iter().enumerate() {
502                if j > 0 {
503                    write!(f, ".")?;
504                }
505                write!(f, "{part}")?;
506            }
507            write!(f, ")")?;
508        }
509        write!(f, "]")
510    }
511}
512
513/// The expected key usage of a certificate.
514///
515/// This type represents the expected key usage of an end entity certificate. Although for most
516/// kinds of certificates the extended key usage extension is optional (and so certificates
517/// not carrying a particular value in the EKU extension are acceptable). If the extension
518/// is present, the certificate MUST only be used for one of the purposes indicated.
519///
520/// <https://www.rfc-editor.org/rfc/rfc5280#section-4.2.1.12>
521#[derive(Clone, Copy, Debug, Eq, PartialEq)]
522pub struct KeyUsage {
523    inner: ExtendedKeyUsage,
524}
525
526impl KeyUsage {
527    /// Construct a new [`KeyUsage`] as appropriate for server certificate authentication.
528    ///
529    /// 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.
530    pub const fn server_auth() -> Self {
531        Self::required_if_present(EKU_SERVER_AUTH)
532    }
533
534    /// Construct a new [`KeyUsage`] as appropriate for client certificate authentication.
535    ///
536    /// As specified in <>, this does not require the certificate to specify the eKU extension.
537    pub const fn client_auth() -> Self {
538        Self::required_if_present(EKU_CLIENT_AUTH)
539    }
540
541    /// Construct a new [`KeyUsage`] requiring a certificate to support the specified OID.
542    pub const fn required(oid: &'static [u8]) -> Self {
543        Self {
544            inner: ExtendedKeyUsage::Required(KeyPurposeId::new(oid)),
545        }
546    }
547
548    /// Construct a new [`KeyUsage`] requiring a certificate to support the specified OID, if the certificate has EKUs.
549    pub const fn required_if_present(oid: &'static [u8]) -> Self {
550        Self {
551            inner: ExtendedKeyUsage::RequiredIfPresent(KeyPurposeId::new(oid)),
552        }
553    }
554
555    /// Yield the OID values of the required extended key usage.
556    pub fn oid_values(&self) -> impl Iterator<Item = usize> + '_ {
557        OidDecoder::new(
558            match &self.inner {
559                ExtendedKeyUsage::Required(eku) => eku,
560                ExtendedKeyUsage::RequiredIfPresent(eku) => eku,
561            }
562            .oid_value
563            .as_slice_less_safe(),
564        )
565    }
566
567    /// Human-readable representation of the server authentication OID.
568    pub const SERVER_AUTH_REPR: &[usize] = &[1, 3, 6, 1, 5, 5, 7, 3, 1];
569    /// Human-readable representation of the client authentication OID.
570    pub const CLIENT_AUTH_REPR: &[usize] = &[1, 3, 6, 1, 5, 5, 7, 3, 2];
571}
572
573impl ExtendedKeyUsageValidator for KeyUsage {
574    // https://tools.ietf.org/html/rfc5280#section-4.2.1.12
575    fn validate(&self, iter: KeyPurposeIdIter<'_, '_>) -> Result<(), Error> {
576        let mut empty = true;
577        #[cfg(feature = "alloc")]
578        let mut present = Vec::new();
579
580        for id in iter {
581            empty = false;
582            let id = id?;
583            if self.inner.id() == id {
584                return Ok(());
585            }
586
587            #[cfg(feature = "alloc")]
588            present.push(id.to_decoded_oid());
589        }
590
591        match (empty, self.inner) {
592            (true, ExtendedKeyUsage::RequiredIfPresent(_)) => Ok(()),
593            _ => Err(Error::RequiredEkuNotFoundContext(
594                RequiredEkuNotFoundContext {
595                    #[cfg(feature = "alloc")]
596                    required: Self { inner: self.inner },
597                    #[cfg(feature = "alloc")]
598                    present,
599                },
600            )),
601        }
602    }
603}
604
605impl<V: ExtendedKeyUsageValidator> ExtendedKeyUsageValidator for &V {
606    fn validate(&self, iter: KeyPurposeIdIter<'_, '_>) -> Result<(), Error> {
607        (*self).validate(iter)
608    }
609}
610
611/// A trait for validating the Extended Key Usage (EKU) extensions of a certificate.
612pub trait ExtendedKeyUsageValidator {
613    /// Validate the EKU values in a certificate.
614    ///
615    /// `iter` yields the EKU OIDs in the certificate, or an error if the EKU extension
616    /// is malformed. `validate()` should yield `Ok(())` if the EKU values match the
617    /// required policy, or an `Error` if they do not. Ideally the `Error` should be
618    /// `Error::RequiredEkuNotFoundContext` if the policy is not met.
619    fn validate(&self, iter: KeyPurposeIdIter<'_, '_>) -> Result<(), Error>;
620}
621
622/// Extended Key Usage (EKU) of a certificate.
623#[derive(Clone, Copy, Debug, Eq, PartialEq)]
624enum ExtendedKeyUsage {
625    /// The certificate must contain the specified [`KeyPurposeId`] as EKU.
626    Required(KeyPurposeId<'static>),
627
628    /// If the certificate has EKUs, then the specified [`KeyPurposeId`] must be included.
629    RequiredIfPresent(KeyPurposeId<'static>),
630}
631
632impl ExtendedKeyUsage {
633    fn id(&self) -> KeyPurposeId<'static> {
634        match self {
635            Self::Required(id) => *id,
636            Self::RequiredIfPresent(id) => *id,
637        }
638    }
639}
640
641/// Iterator over [`KeyPurposeId`]s, for use in [`ExtendedKeyUsageValidator`].
642pub struct KeyPurposeIdIter<'a, 'r> {
643    input: &'r mut untrusted::Reader<'a>,
644}
645
646impl<'a, 'r> Iterator for KeyPurposeIdIter<'a, 'r> {
647    type Item = Result<KeyPurposeId<'a>, Error>;
648
649    fn next(&mut self) -> Option<Self::Item> {
650        if self.input.at_end() {
651            return None;
652        }
653
654        Some(der::expect_tag(self.input, der::Tag::OID).map(|oid_value| KeyPurposeId { oid_value }))
655    }
656}
657
658impl Drop for KeyPurposeIdIter<'_, '_> {
659    fn drop(&mut self) {
660        self.input.skip_to_end();
661    }
662}
663
664/// An OID value indicating an Extended Key Usage (EKU) key purpose.
665#[derive(Clone, Copy)]
666pub struct KeyPurposeId<'a> {
667    oid_value: untrusted::Input<'a>,
668}
669
670impl<'a> KeyPurposeId<'a> {
671    /// Construct a new [`KeyPurposeId`].
672    ///
673    /// `oid` is the OBJECT IDENTIFIER in bytes.
674    pub const fn new(oid: &'a [u8]) -> Self {
675        Self {
676            oid_value: untrusted::Input::from(oid),
677        }
678    }
679
680    /// Yield the OID value as a sequence of `usize` components.
681    #[cfg(feature = "alloc")]
682    pub fn to_decoded_oid(&self) -> Vec<usize> {
683        OidDecoder::new(self.oid_value.as_slice_less_safe()).collect()
684    }
685}
686
687impl fmt::Debug for KeyPurposeId<'_> {
688    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
689        write!(f, "KeyPurposeId(")?;
690        let decoder = OidDecoder::new(self.oid_value.as_slice_less_safe());
691        for (i, part) in decoder.enumerate() {
692            if i > 0 {
693                write!(f, ".")?;
694            }
695            write!(f, "{part}")?;
696        }
697        write!(f, ")")
698    }
699}
700
701impl PartialEq<Self> for KeyPurposeId<'_> {
702    fn eq(&self, other: &Self) -> bool {
703        public_values_eq(self.oid_value, other.oid_value)
704    }
705}
706
707impl Eq for KeyPurposeId<'_> {}
708
709// id-pkix            OBJECT IDENTIFIER ::= { 1 3 6 1 5 5 7 }
710// id-kp              OBJECT IDENTIFIER ::= { id-pkix 3 }
711
712// id-kp-serverAuth   OBJECT IDENTIFIER ::= { id-kp 1 }
713const EKU_SERVER_AUTH: &[u8] = &oid!(1, 3, 6, 1, 5, 5, 7, 3, 1);
714
715// id-kp-clientAuth   OBJECT IDENTIFIER ::= { id-kp 2 }
716const EKU_CLIENT_AUTH: &[u8] = &oid!(1, 3, 6, 1, 5, 5, 7, 3, 2);
717
718struct OidDecoder<'a> {
719    encoded: &'a [u8],
720    left: Option<usize>,
721    first: bool,
722}
723
724impl<'a> OidDecoder<'a> {
725    fn new(encoded: &'a [u8]) -> Self {
726        Self {
727            encoded,
728            left: None,
729            first: true,
730        }
731    }
732}
733
734impl Iterator for OidDecoder<'_> {
735    type Item = usize;
736
737    fn next(&mut self) -> Option<Self::Item> {
738        if let Some(next) = self.left.take() {
739            return Some(next);
740        }
741
742        let mut cur = 0;
743        for (i, &byte) in self.encoded.iter().enumerate() {
744            cur = (cur << 8) + usize::from(byte & 0x7f);
745            if byte & 0x80 > 0 {
746                continue;
747            }
748
749            if !self.first {
750                self.encoded = &self.encoded[i + 1..];
751                return Some(cur);
752            }
753
754            let (cur, next) = match cur {
755                ..=39 => (0, cur),
756                40..=79 => (1, cur - 40),
757                _ => (2, cur - 80),
758            };
759
760            self.encoded = &self.encoded[i + 1..];
761            self.first = false;
762            self.left = Some(next);
763            return Some(cur);
764        }
765
766        None
767    }
768}
769
770fn loop_while_non_fatal_error<'a, V: IntoIterator + 'a>(
771    default_error: Error,
772    values: V,
773    mut f: impl FnMut(V::Item) -> Result<&'a TrustAnchor<'a>, ControlFlow<Error, Error>>,
774) -> Result<&'a TrustAnchor<'a>, ControlFlow<Error, Error>> {
775    let mut error = default_error;
776    for v in values {
777        match f(v) {
778            Ok(anchor) => return Ok(anchor),
779            // Fatal errors should halt further looping.
780            res @ Err(ControlFlow::Break(_)) => return res,
781            // Non-fatal errors should be ranked by specificity and only returned
782            // once all other path-building options have been exhausted.
783            Err(ControlFlow::Continue(new_error)) => error = error.most_specific(new_error),
784        }
785    }
786    Err(error.into())
787}
788
789/// A path for consideration in path building.
790///
791/// This represents a partial path because it does not yet contain the trust anchor. It stores
792/// the end-entity certificates, and an array of intermediate certificates.
793pub(crate) struct PartialPath<'a> {
794    end_entity: &'a EndEntityCert<'a>,
795    /// Intermediate certificates, in order from end-entity to trust anchor.
796    ///
797    /// Invariant: all values below `used` are `Some`.
798    intermediates: [Option<Cert<'a>>; MAX_SUB_CA_COUNT],
799    /// The number of `Some` values in `intermediates`.
800    ///
801    /// The next `Cert` passed to `push()` will be placed at `intermediates[used]`.
802    /// If this value is 0, the path contains only the end-entity certificate.
803    used: usize,
804}
805
806impl<'a> PartialPath<'a> {
807    pub(crate) fn new(end_entity: &'a EndEntityCert<'a>) -> Self {
808        Self {
809            end_entity,
810            intermediates: Default::default(),
811            used: 0,
812        }
813    }
814
815    pub(crate) fn push(&mut self, cert: Cert<'a>) -> Result<(), ControlFlow<Error, Error>> {
816        if self.used >= MAX_SUB_CA_COUNT {
817            return Err(Error::MaximumPathDepthExceeded.into());
818        }
819
820        self.intermediates[self.used] = Some(cert);
821        self.used += 1;
822        Ok(())
823    }
824
825    fn pop(&mut self) {
826        debug_assert!(self.used > 0);
827        if self.used == 0 {
828            return;
829        }
830
831        self.used -= 1;
832        self.intermediates[self.used] = None;
833    }
834
835    pub(crate) fn node(&self) -> PathNode<'_> {
836        PathNode {
837            path: self,
838            index: self.used,
839            cert: self.head(),
840        }
841    }
842
843    /// Current head of the path.
844    pub(crate) fn head(&self) -> &Cert<'a> {
845        self.get(self.used)
846    }
847
848    /// Get the certificate at index `idx` in the path.
849    ///
850    // `idx` must be in the range `0..=self.used`; `idx` 0 thus yields the `end_entity`,
851    // while subsequent indexes yield the intermediate at `self.intermediates[idx - 1]`.
852    fn get(&self, idx: usize) -> &Cert<'a> {
853        match idx {
854            0 => self.end_entity,
855            _ => self.intermediates[idx - 1].as_ref().unwrap(),
856        }
857    }
858}
859
860const MAX_SUB_CA_COUNT: usize = 6;
861
862pub(crate) struct PathNode<'a> {
863    /// The path we're iterating.
864    path: &'a PartialPath<'a>,
865    /// The index of the current node in the path (input for `path.get()`).
866    index: usize,
867    /// The [`Cert`] at `index`.
868    pub(crate) cert: &'a Cert<'a>,
869}
870
871impl<'a> PathNode<'a> {
872    pub(crate) fn iter(&self) -> PathIter<'a> {
873        PathIter {
874            path: self.path,
875            next: Some(self.index),
876        }
877    }
878
879    pub(crate) fn role(&self) -> Role {
880        match self.index {
881            0 => Role::EndEntity,
882            _ => Role::Issuer,
883        }
884    }
885}
886
887pub(crate) struct PathIter<'a> {
888    path: &'a PartialPath<'a>,
889    next: Option<usize>,
890}
891
892impl<'a> Iterator for PathIter<'a> {
893    type Item = PathNode<'a>;
894
895    fn next(&mut self) -> Option<Self::Item> {
896        let next = self.next?;
897        self.next = match next {
898            0 => None,
899            _ => Some(next - 1),
900        };
901
902        Some(PathNode {
903            path: self.path,
904            index: next,
905            cert: self.path.get(next),
906        })
907    }
908}
909
910#[derive(Clone, Copy, PartialEq)]
911pub(crate) enum Role {
912    Issuer,
913    EndEntity,
914}
915
916// SPKI SEQUENCE contents (without tag/length) that should invalidate any path containing them.
917pub(crate) const DISTRUSTED_SPKIS: &[&[u8]] = &[
918    include_bytes!("data/distrusted/EMDVTLSCAG3B.spki.der"),
919    include_bytes!("data/distrusted/EMDVTLSCAG3C.spki.der"),
920    include_bytes!("data/distrusted/EMEVTLSCAG3B.spki.der"),
921    include_bytes!("data/distrusted/EMEVTLSCAG3C.spki.der"),
922    include_bytes!("data/distrusted/EMOVTLSCAG3B.spki.der"),
923    include_bytes!("data/distrusted/EMOVTLSCAG3C.spki.der"),
924    include_bytes!("data/distrusted/EMOVCSCAG3B.spki.der"),
925    include_bytes!("data/distrusted/EMOVCSCAG3C.spki.der"),
926];
927
928#[cfg(all(test, feature = "alloc", any(feature = "ring", feature = "aws-lc-rs")))]
929mod tests {
930    use alloc::borrow::ToOwned;
931    use alloc::string::{String, ToString};
932    use std::dbg;
933    use std::slice;
934
935    use super::*;
936    use crate::test_utils;
937    use crate::test_utils::{issuer_params, make_end_entity, make_issuer};
938    use crate::trust_anchor::anchor_from_trusted_cert;
939    use rcgen::{CertifiedIssuer, Issuer, KeyPair, SigningKey};
940
941    #[test]
942    fn roundtrip() {
943        // 2.999.3 -> 1079.3 -> [0x84, 0x37, 0x3]
944        const ENCODED: &[u8] = &[0x84, 0x37, 0x3];
945        let decoded = OidDecoder::new(ENCODED);
946        assert_eq!(decoded.collect::<Vec<_>>(), [2, 999, 3]);
947    }
948
949    #[test]
950    fn oid_decoding() {
951        assert_eq!(
952            KeyUsage::server_auth().oid_values().collect::<Vec<_>>(),
953            KeyUsage::SERVER_AUTH_REPR
954        );
955        assert_eq!(
956            KeyUsage::client_auth().oid_values().collect::<Vec<_>>(),
957            KeyUsage::CLIENT_AUTH_REPR
958        );
959    }
960
961    #[test]
962    fn eku_fail_empty() {
963        let err = KeyUsage::required(EKU_SERVER_AUTH)
964            .validate(KeyPurposeIdIter {
965                input: &mut untrusted::Reader::new(untrusted::Input::from(&[])),
966            })
967            .unwrap_err();
968        assert_eq!(
969            err,
970            Error::RequiredEkuNotFoundContext(RequiredEkuNotFoundContext {
971                #[cfg(feature = "alloc")]
972                required: dbg!(KeyUsage::required(EKU_SERVER_AUTH)), // Cover Debug impl
973                #[cfg(feature = "alloc")]
974                present: Vec::new(),
975            })
976        );
977    }
978
979    #[test]
980    fn eku_fail_empty_with_optional() {
981        let mut empty_eku = untrusted::Reader::new(untrusted::Input::from(&[]));
982        let validator = KeyUsage::required_if_present(EKU_SERVER_AUTH);
983        assert_eq!(
984            check_eku(Some(&mut empty_eku), &validator).unwrap_err(),
985            Error::EmptyEkuExtension,
986        );
987    }
988
989    #[test]
990    fn eku_key_purpose_id() {
991        assert!(
992            ExtendedKeyUsage::RequiredIfPresent(KeyPurposeId::new(EKU_SERVER_AUTH)).id()
993                == KeyPurposeId::new(EKU_SERVER_AUTH)
994        )
995    }
996
997    #[test]
998    fn test_too_many_signatures() {
999        assert!(matches!(
1000            build_and_verify_degenerate_chain(5, ChainTrustAnchor::NotInChain),
1001            ControlFlow::Break(Error::MaximumSignatureChecksExceeded)
1002        ));
1003    }
1004
1005    #[test]
1006    fn test_too_many_path_calls() {
1007        assert!(matches!(
1008            dbg!(build_and_verify_degenerate_chain(
1009                10,
1010                ChainTrustAnchor::InChain
1011            )),
1012            ControlFlow::Break(Error::MaximumPathBuildCallsExceeded)
1013        ));
1014    }
1015
1016    #[test]
1017    fn longest_allowed_path() {
1018        assert!(build_and_verify_linear_chain(1).is_ok());
1019        assert!(build_and_verify_linear_chain(2).is_ok());
1020        assert!(build_and_verify_linear_chain(3).is_ok());
1021        assert!(build_and_verify_linear_chain(4).is_ok());
1022        assert!(build_and_verify_linear_chain(5).is_ok());
1023        assert!(build_and_verify_linear_chain(6).is_ok());
1024    }
1025
1026    #[test]
1027    fn path_too_long() {
1028        assert!(matches!(
1029            build_and_verify_linear_chain(7),
1030            Err(ControlFlow::Continue(Error::MaximumPathDepthExceeded))
1031        ));
1032    }
1033
1034    #[test]
1035    fn name_constraint_budget() {
1036        // Issue a trust anchor that imposes name constraints. The constraint should match
1037        // the end entity certificate SAN.
1038        let mut ca_cert_params = issuer_params("Constrained Root");
1039        ca_cert_params.name_constraints = Some(rcgen::NameConstraints {
1040            permitted_subtrees: vec![rcgen::GeneralSubtree::DnsName(".com".into())],
1041            excluded_subtrees: vec![],
1042        });
1043        let ca_key_pair = KeyPair::generate_for(test_utils::RCGEN_SIGNATURE_ALG).unwrap();
1044        let ca = CertifiedIssuer::self_signed(ca_cert_params, ca_key_pair).unwrap();
1045
1046        // Create a series of intermediate issuers. We'll only use one in the actual built path,
1047        // helping demonstrate that the name constraint budget is not expended checking certificates
1048        // that are not part of the path we compute.
1049        let mut intermediates = Vec::with_capacity(5);
1050        for i in 0..5 {
1051            let intermediate = issuer_params(format!("Intermediate {i}"));
1052            let intermediate_key_pair =
1053                KeyPair::generate_for(test_utils::RCGEN_SIGNATURE_ALG).unwrap();
1054            // Each intermediate should be issued by the trust anchor.
1055            intermediates.push(
1056                CertifiedIssuer::signed_by(intermediate, intermediate_key_pair, &ca).unwrap(),
1057            );
1058        }
1059
1060        // Create an end-entity cert that is issued by the last of the intermediates.
1061        let ee_cert = make_end_entity(intermediates.last().unwrap());
1062        let ee_cert = EndEntityCert::try_from(ee_cert.cert.der()).unwrap();
1063
1064        // We use a custom budget to make it easier to write a test, otherwise it is tricky to
1065        // stuff enough names/constraints into the potential chains while staying within the path
1066        // depth limit and the build chain call limit.
1067        let passing_budget = Budget {
1068            // One comparison against the intermediate's distinguished name.
1069            // One comparison against the EE's distinguished name.
1070            // One comparison against the EE's SAN.
1071            //  = 3 total comparisons.
1072            name_constraint_comparisons: 3,
1073            ..Budget::default()
1074        };
1075
1076        let anchors = &[anchor_from_trusted_cert(ca.der()).unwrap()];
1077        let intermediates_der = intermediates
1078            .iter()
1079            .map(|issuer| issuer.der().clone())
1080            .collect::<Vec<_>>();
1081
1082        // Validation should succeed with the name constraint comparison budget allocated above.
1083        // This shows that we're not consuming budget on unused intermediates: we didn't budget
1084        // enough comparisons for that to pass the overall chain building.
1085        let path = verify_chain(
1086            anchors,
1087            &intermediates_der,
1088            &ee_cert,
1089            None,
1090            Some(passing_budget),
1091        )
1092        .unwrap();
1093        assert_eq!(path.anchor().subject, anchors.first().unwrap().subject);
1094
1095        let failing_budget = Budget {
1096            // See passing_budget: 2 comparisons is not sufficient.
1097            name_constraint_comparisons: 2,
1098            ..Budget::default()
1099        };
1100        // Validation should fail when the budget is smaller than the number of comparisons performed
1101        // on the validated path. This demonstrates we properly fail path building when too many
1102        // name constraint comparisons occur.
1103        let result = verify_chain(
1104            anchors,
1105            &intermediates_der,
1106            &ee_cert,
1107            None,
1108            Some(failing_budget),
1109        );
1110
1111        assert!(matches!(
1112            result,
1113            Err(ControlFlow::Break(
1114                Error::MaximumNameConstraintComparisonsExceeded
1115            ))
1116        ));
1117    }
1118
1119    /// This test builds a PKI like the following diagram depicts. We first verify
1120    /// that we can build a path EE -> B -> A -> TA. Next we supply a custom path verification
1121    /// function that rejects the B->A path, and verify that we build a path EE -> B -> C -> TA.
1122    ///
1123    ///        ┌───────────┐
1124    ///        │           │
1125    ///        │     TA    │
1126    ///        │           │
1127    ///        └───┬───┬───┘
1128    ///            │   │
1129    ///            │   │
1130    /// ┌────────┐◄┘   └──►┌────────┐
1131    /// │        │         │        │
1132    /// │   A    │         │   C    │
1133    /// │        │         │        │
1134    /// └────┬───┘         └───┬────┘
1135    ///      │                 │
1136    ///      │                 │
1137    ///      │   ┌─────────┐   │
1138    ///      └──►│         │◄──┘
1139    ///          │    B    │
1140    ///          │         │
1141    ///          └────┬────┘
1142    ///               │
1143    ///               │
1144    ///               │
1145    ///          ┌────▼────┐
1146    ///          │         │
1147    ///          │    EE   │
1148    ///          │         │
1149    ///          └─────────┘
1150    #[test]
1151    fn test_reject_candidate_path() {
1152        // Create a trust anchor, and use it to issue two distinct intermediate certificates, each
1153        // with a unique subject and keypair.
1154        let trust_anchor = make_issuer("Trust Anchor");
1155        let trust_anchor_cert = Cert::from_der(untrusted::Input::from(trust_anchor.der())).unwrap();
1156        let trust_anchors = &[anchor_from_trusted_cert(trust_anchor.der()).unwrap()];
1157
1158        let intermediate_a = make_intermediate("Intermediate A", &trust_anchor);
1159        let intermediate_c = make_intermediate("Intermediate C", &trust_anchor);
1160
1161        // Next, create an intermediate that is issued by both of the intermediates above.
1162        // Both should share the same subject, and key pair, but will differ in the issuer.
1163        let (intermediate_b, intermediate_b_a_cert, intermediate_b_c_cert) = {
1164            let key = KeyPair::generate_for(test_utils::RCGEN_SIGNATURE_ALG).unwrap();
1165            let params = issuer_params("Intermediate");
1166            let intermediate_b_a_cert = params.signed_by(&key, &intermediate_a).unwrap();
1167            let intermediate_b_c_cert = params.signed_by(&key, &intermediate_c).unwrap();
1168            let issuer = Issuer::new(params, key);
1169            (issuer, intermediate_b_a_cert, intermediate_b_c_cert)
1170        };
1171
1172        let intermediates = &[
1173            intermediate_a.der().clone(),
1174            intermediate_c.der().clone(),
1175            intermediate_b_a_cert.der().clone(),
1176            intermediate_b_c_cert.der().clone(),
1177        ];
1178
1179        // Create an end entity certificate signed by the keypair of the intermediates created above.
1180        let ee = make_end_entity(&intermediate_b);
1181        let ee_cert = &EndEntityCert::try_from(ee.cert.der()).unwrap();
1182
1183        // We should be able to create a valid path from EE to trust anchor.
1184        let path = verify_chain(trust_anchors, intermediates, ee_cert, None, None).unwrap();
1185        let path_intermediates = path.intermediate_certificates().collect::<Vec<_>>();
1186
1187        // We expect that without applying any additional constraints, that the path will be
1188        // EE -> intermediate_b_a -> intermediate_a -> trust_anchor.
1189        let intermediate_a_cert =
1190            Cert::from_der(untrusted::Input::from(intermediate_a.der())).unwrap();
1191        assert_eq!(path_intermediates.len(), 2);
1192        assert_eq!(
1193            path_intermediates[0].issuer(),
1194            intermediate_a_cert.subject()
1195        );
1196        assert_eq!(path_intermediates[1].issuer(), trust_anchor_cert.subject());
1197
1198        // Now, we'll create a function that will reject the intermediate_b_a path.
1199        let expected_chain = |path: &VerifiedPath<'_>| {
1200            for intermediate in path.intermediate_certificates() {
1201                // Reject any intermediates issued by intermediate A.
1202                if intermediate.issuer() == intermediate_a_cert.subject() {
1203                    return Err(Error::UnknownIssuer);
1204                }
1205            }
1206
1207            Ok(())
1208        };
1209
1210        // We should still be able to build a valid path.
1211        let path = verify_chain(
1212            trust_anchors,
1213            intermediates,
1214            ee_cert,
1215            Some(&expected_chain),
1216            None,
1217        )
1218        .unwrap();
1219        let path_intermediates = path.intermediate_certificates().collect::<Vec<_>>();
1220
1221        // We expect that the path will now be
1222        // EE -> intermediate_b_c -> intermediate_c -> trust_anchor.
1223        let intermediate_c_cert =
1224            Cert::from_der(untrusted::Input::from(intermediate_c.der())).unwrap();
1225        assert_eq!(path_intermediates.len(), 2);
1226        assert_eq!(
1227            path_intermediates[0].issuer(),
1228            intermediate_c_cert.subject()
1229        );
1230        assert_eq!(path_intermediates[1].issuer(), trust_anchor_cert.subject());
1231    }
1232
1233    #[test]
1234    fn distrusted_spki() {
1235        fn verify(
1236            ee_cert: &EndEntityCert<'_>,
1237            intermediates: &[CertificateDer<'_>],
1238            trust_anchors: &[TrustAnchor<'_>],
1239            distrusted_spkis: &[&[u8]],
1240        ) -> Result<usize, Error> {
1241            use core::time::Duration;
1242
1243            ChainOptions {
1244                eku: KeyUsage::server_auth(),
1245                supported_sig_algs: crate::ALL_VERIFICATION_ALGS,
1246                trust_anchors,
1247                intermediate_certs: intermediates,
1248                revocation: None,
1249                distrusted_spkis,
1250            }
1251            .build_chain(
1252                ee_cert,
1253                UnixTime::since_unix_epoch(Duration::from_secs(0x1fed_f00d)),
1254                None,
1255            )
1256            .map(|path| path.intermediate_certificates().count())
1257        }
1258
1259        let root = make_issuer("Root");
1260        let trust_anchors = &[anchor_from_trusted_cert(root.der()).unwrap()];
1261        let issuing_intermediate = make_intermediate("Issuing Intermediate", &root);
1262        let unrelated = make_intermediate("Intermediate", &root);
1263
1264        let params = issuer_params("Intermediate");
1265        let key = KeyPair::generate_for(test_utils::RCGEN_SIGNATURE_ALG).unwrap();
1266        // Issue the same SPKI under two different issuers to test cross-signing.
1267        let intermediate = params.signed_by(&key, &issuing_intermediate).unwrap();
1268        let cross_signed = params.signed_by(&key, &root).unwrap();
1269        let ee = make_end_entity(&Issuer::new(params, key));
1270        let ee_cert = EndEntityCert::try_from(ee.cert.der()).unwrap();
1271        let intermediates = &[
1272            unrelated.der().clone(),
1273            intermediate.der().clone(),
1274            issuing_intermediate.der().clone(),
1275        ];
1276        assert_eq!(
1277            verify(&ee_cert, intermediates, trust_anchors, DISTRUSTED_SPKIS),
1278            Ok(2)
1279        );
1280
1281        // Distrusting any certificate in the path, including the root or leaf, rejects the chain.
1282        for cert in [
1283            root.der(),
1284            issuing_intermediate.der(),
1285            intermediate.der(),
1286            ee.cert.der(),
1287        ] {
1288            assert_eq!(
1289                verify(
1290                    &ee_cert,
1291                    intermediates,
1292                    trust_anchors,
1293                    &[anchor_from_trusted_cert(cert)
1294                        .unwrap()
1295                        .subject_public_key_info
1296                        .as_ref()]
1297                ),
1298                Err(Error::CertDistrusted)
1299            );
1300        }
1301
1302        // Distrusting an unused intermediate leaves the valid path usable.
1303        assert_eq!(
1304            verify(
1305                &ee_cert,
1306                intermediates,
1307                trust_anchors,
1308                &[anchor_from_trusted_cert(unrelated.der())
1309                    .unwrap()
1310                    .subject_public_key_info
1311                    .as_ref()]
1312            ),
1313            Ok(2)
1314        );
1315
1316        // A different cross-sign provides a valid path around the distrusted issuer.
1317        let intermediates = &[
1318            intermediate.der().clone(),
1319            issuing_intermediate.der().clone(),
1320            cross_signed.der().clone(),
1321        ];
1322        let issuer_spki = anchor_from_trusted_cert(issuing_intermediate.der()).unwrap();
1323        assert_eq!(
1324            verify(
1325                &ee_cert,
1326                intermediates,
1327                trust_anchors,
1328                &[issuer_spki.subject_public_key_info.as_ref()]
1329            ),
1330            Ok(1)
1331        );
1332
1333        // Distrusting the shared SPKI rejects the original certificate and its cross-sign.
1334        let intermediate_spki = anchor_from_trusted_cert(intermediate.der()).unwrap();
1335        assert_eq!(
1336            verify(
1337                &ee_cert,
1338                intermediates,
1339                trust_anchors,
1340                &[intermediate_spki.subject_public_key_info.as_ref()]
1341            ),
1342            Err(Error::CertDistrusted)
1343        );
1344
1345        // Reject a distrusted intermediate before searching for its issuer.
1346        assert_eq!(
1347            verify(
1348                &ee_cert,
1349                &[intermediate.der().clone()],
1350                &[],
1351                &[intermediate_spki.subject_public_key_info.as_ref()]
1352            ),
1353            Err(Error::CertDistrusted)
1354        );
1355    }
1356
1357    fn make_intermediate(
1358        org_name: impl Into<String>,
1359        issuer: &Issuer<'_, impl SigningKey>,
1360    ) -> CertifiedIssuer<'static, KeyPair> {
1361        let params = issuer_params(org_name);
1362        let key = KeyPair::generate_for(test_utils::RCGEN_SIGNATURE_ALG).unwrap();
1363        CertifiedIssuer::signed_by(params, key, issuer).unwrap()
1364    }
1365
1366    fn build_and_verify_degenerate_chain(
1367        intermediate_count: usize,
1368        trust_anchor: ChainTrustAnchor,
1369    ) -> ControlFlow<Error, Error> {
1370        let ca = make_issuer("Bogus Subject");
1371        let mut intermediate_chain = IntermediateChain::new(intermediate_count, true, &ca);
1372
1373        let verify_trust_anchor = match trust_anchor {
1374            ChainTrustAnchor::InChain => make_issuer("Bogus Trust Anchor"),
1375            ChainTrustAnchor::NotInChain => ca,
1376        };
1377
1378        let ee_cert = make_end_entity(&intermediate_chain.last_issuer);
1379        let ee_cert = EndEntityCert::try_from(ee_cert.cert.der()).unwrap();
1380        let webpki_ta = anchor_from_trusted_cert(verify_trust_anchor.der()).unwrap();
1381        if matches!(trust_anchor, ChainTrustAnchor::InChain) {
1382            // Note: we clone the trust anchor DER here because we can't move it into the chain
1383            // as it's loaned to webpki_ta above.
1384            intermediate_chain
1385                .chain
1386                .insert(0, verify_trust_anchor.der().to_owned())
1387        }
1388
1389        verify_chain(
1390            &[webpki_ta],
1391            &intermediate_chain.chain,
1392            &ee_cert,
1393            None,
1394            None,
1395        )
1396        .map(|_| ())
1397        .unwrap_err()
1398    }
1399
1400    #[cfg(feature = "alloc")]
1401    enum ChainTrustAnchor {
1402        NotInChain,
1403        InChain,
1404    }
1405
1406    fn build_and_verify_linear_chain(chain_length: usize) -> Result<(), ControlFlow<Error, Error>> {
1407        let ca = make_issuer(format!("Bogus Subject {chain_length}"));
1408        let intermediate_chain = IntermediateChain::new(chain_length, false, &ca);
1409
1410        let anchor = anchor_from_trusted_cert(ca.der()).unwrap();
1411        let anchors = slice::from_ref(&anchor);
1412
1413        let ee_cert = make_end_entity(&intermediate_chain.last_issuer);
1414        let ee_cert = EndEntityCert::try_from(ee_cert.cert.der()).unwrap();
1415
1416        let expected_chain = |path: &VerifiedPath<'_>| {
1417            assert_eq!(path.anchor().subject, anchor.subject);
1418            assert!(public_values_eq(path.end_entity().subject, ee_cert.subject));
1419            assert_eq!(path.intermediate_certificates().count(), chain_length);
1420
1421            let intermediate_certs = intermediate_chain
1422                .chain
1423                .iter()
1424                .map(|der| Cert::from_der(untrusted::Input::from(der)).unwrap())
1425                .collect::<Vec<_>>();
1426
1427            for (cert, expected) in path
1428                .intermediate_certificates()
1429                .rev()
1430                .zip(intermediate_certs.iter())
1431            {
1432                assert!(public_values_eq(cert.subject, expected.subject));
1433                assert_eq!(cert.der(), expected.der());
1434            }
1435
1436            for (cert, expected) in path
1437                .intermediate_certificates()
1438                .zip(intermediate_certs.iter().rev())
1439            {
1440                assert!(public_values_eq(cert.subject, expected.subject));
1441                assert_eq!(cert.der(), expected.der());
1442            }
1443
1444            Ok(())
1445        };
1446
1447        verify_chain(
1448            anchors,
1449            &intermediate_chain.chain,
1450            &ee_cert,
1451            Some(&expected_chain),
1452            None,
1453        )
1454        .map(|_| ())
1455    }
1456
1457    struct IntermediateChain {
1458        last_issuer: Issuer<'static, KeyPair>,
1459        chain: Vec<CertificateDer<'static>>,
1460    }
1461
1462    impl IntermediateChain {
1463        fn new(chain_length: usize, all_same_subject: bool, ca_cert: &Issuer<'_, KeyPair>) -> Self {
1464            let mut chain = Vec::with_capacity(chain_length);
1465
1466            let mut prev = None;
1467            for i in 0..chain_length {
1468                let issuer = match &prev {
1469                    Some(prev) => prev,
1470                    None => ca_cert,
1471                };
1472
1473                let intermediate = issuer_params(match all_same_subject {
1474                    true => "Bogus Subject".to_string(),
1475                    false => format!("Bogus Subject {i}"),
1476                });
1477
1478                let key_pair = KeyPair::generate_for(test_utils::RCGEN_SIGNATURE_ALG).unwrap();
1479                let cert = intermediate.signed_by(&key_pair, issuer).unwrap();
1480
1481                chain.push(cert.der().clone());
1482                prev = Some(Issuer::new(intermediate, key_pair));
1483            }
1484
1485            Self {
1486                last_issuer: prev.unwrap(),
1487                chain,
1488            }
1489        }
1490    }
1491
1492    fn verify_chain<'a>(
1493        trust_anchors: &'a [TrustAnchor<'a>],
1494        intermediate_certs: &'a [CertificateDer<'a>],
1495        ee_cert: &'a EndEntityCert<'a>,
1496        verify_path: Option<&dyn Fn(&VerifiedPath<'_>) -> Result<(), Error>>,
1497        budget: Option<Budget>,
1498    ) -> Result<VerifiedPath<'a>, ControlFlow<Error, Error>> {
1499        use core::time::Duration;
1500
1501        let time = UnixTime::since_unix_epoch(Duration::from_secs(0x1fed_f00d));
1502        let mut path = PartialPath::new(ee_cert);
1503        let opts = ChainOptions {
1504            eku: KeyUsage::server_auth(),
1505            supported_sig_algs: crate::ALL_VERIFICATION_ALGS,
1506            trust_anchors,
1507            intermediate_certs,
1508            revocation: None,
1509            distrusted_spkis: DISTRUSTED_SPKIS,
1510        };
1511
1512        match opts.build_chain_inner(
1513            &mut path,
1514            time,
1515            verify_path,
1516            0,
1517            &mut budget.unwrap_or_default(),
1518        ) {
1519            Ok(anchor) => Ok(VerifiedPath::new(ee_cert, anchor, path)),
1520            Err(err) => Err(err),
1521        }
1522    }
1523}