Coverage Report

Created: 2026-01-09 06:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/rustls-webpki-0.103.8/src/verify_cert.rs
Line
Count
Source
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")]
16
use alloc::vec::Vec;
17
use core::fmt;
18
use core::ops::ControlFlow;
19
20
use pki_types::{CertificateDer, SignatureVerificationAlgorithm, TrustAnchor, UnixTime};
21
22
use crate::cert::Cert;
23
use crate::crl::RevocationOptions;
24
use crate::der::{self, FromDer};
25
use crate::end_entity::EndEntityCert;
26
use crate::error::Error;
27
use 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`.
31
pub(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
39
impl<'a, 'p: 'a, V: ExtendedKeyUsageValidator> ChainOptions<'a, 'p, V> {
40
0
    pub(crate) fn build_chain(
41
0
        &self,
42
0
        end_entity: &'p EndEntityCert<'p>,
43
0
        time: UnixTime,
44
0
        verify_path: Option<&dyn Fn(&VerifiedPath<'_>) -> Result<(), Error>>,
45
0
    ) -> Result<VerifiedPath<'p>, Error> {
46
0
        let mut path = PartialPath::new(end_entity);
47
0
        match self.build_chain_inner(&mut path, time, verify_path, 0, &mut Budget::default()) {
48
0
            Ok(anchor) => Ok(VerifiedPath::new(end_entity, anchor, path)),
49
0
            Err(ControlFlow::Break(err)) | Err(ControlFlow::Continue(err)) => Err(err),
50
        }
51
0
    }
Unexecuted instantiation: <webpki::verify_cert::ChainOptions<spdmlib::crypto::spdm_ring::cert_operation_impl::SpdmResponderEkuValidator>>::build_chain
Unexecuted instantiation: <webpki::verify_cert::ChainOptions<_>>::build_chain
52
53
0
    fn build_chain_inner(
54
0
        &self,
55
0
        path: &mut PartialPath<'p>,
56
0
        time: UnixTime,
57
0
        verify_path: Option<&dyn Fn(&VerifiedPath<'_>) -> Result<(), Error>>,
58
0
        sub_ca_count: usize,
59
0
        budget: &mut Budget,
60
0
    ) -> Result<&'p TrustAnchor<'p>, ControlFlow<Error, Error>> {
61
0
        let role = path.node().role();
62
63
0
        check_issuer_independent_properties(path.head(), time, role, sub_ca_count, &self.eku)?;
64
65
        // TODO: HPKP checks.
66
67
0
        let result =
68
0
            loop_while_non_fatal_error(Error::UnknownIssuer, self.trust_anchors, |trust_anchor| {
69
0
                let trust_anchor_subject = untrusted::Input::from(trust_anchor.subject.as_ref());
70
0
                if !public_values_eq(path.head().issuer, trust_anchor_subject) {
71
0
                    return Err(Error::UnknownIssuer.into());
72
0
                }
73
74
                // TODO: check_distrust(trust_anchor_subject, trust_anchor_spki)?;
75
76
0
                let node = path.node();
77
0
                self.check_signed_chain(&node, time, trust_anchor, budget)?;
78
0
                check_signed_chain_name_constraints(&node, trust_anchor, budget)?;
79
80
0
                let verify = match verify_path {
81
0
                    Some(verify) => verify,
82
0
                    None => return Ok(trust_anchor),
83
                };
84
85
0
                let candidate = VerifiedPath {
86
0
                    end_entity: path.end_entity,
87
0
                    intermediates: Intermediates::Borrowed(&path.intermediates[..path.used]),
88
0
                    anchor: trust_anchor,
89
0
                };
90
91
0
                match verify(&candidate) {
92
0
                    Ok(()) => Ok(trust_anchor),
93
0
                    Err(err) => Err(ControlFlow::Continue(err)),
94
                }
95
0
            });
Unexecuted instantiation: <webpki::verify_cert::ChainOptions<spdmlib::crypto::spdm_ring::cert_operation_impl::SpdmResponderEkuValidator>>::build_chain_inner::{closure#0}
Unexecuted instantiation: <webpki::verify_cert::ChainOptions<_>>::build_chain_inner::{closure#0}
96
97
0
        let err = match result {
98
0
            Ok(anchor) => return Ok(anchor),
99
            // Fatal errors should halt further path building.
100
0
            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
0
            Err(ControlFlow::Continue(err)) => err,
105
        };
106
107
0
        loop_while_non_fatal_error(err, self.intermediate_certs, |cert_der| {
108
0
            let potential_issuer = Cert::from_der(untrusted::Input::from(cert_der))?;
109
0
            if !public_values_eq(potential_issuer.subject, path.head().issuer) {
110
0
                return Err(Error::UnknownIssuer.into());
111
0
            }
112
113
            // Prevent loops; see RFC 4158 section 5.2.
114
0
            if path.node().iter().any(|prev| {
115
0
                public_values_eq(potential_issuer.spki, prev.cert.spki)
116
0
                    && public_values_eq(potential_issuer.subject, prev.cert.subject)
117
0
            }) {
Unexecuted instantiation: <webpki::verify_cert::ChainOptions<spdmlib::crypto::spdm_ring::cert_operation_impl::SpdmResponderEkuValidator>>::build_chain_inner::{closure#1}::{closure#0}
Unexecuted instantiation: <webpki::verify_cert::ChainOptions<_>>::build_chain_inner::{closure#1}::{closure#0}
118
0
                return Err(Error::UnknownIssuer.into());
119
0
            }
120
121
0
            let next_sub_ca_count = match role {
122
0
                Role::EndEntity => sub_ca_count,
123
0
                Role::Issuer => sub_ca_count + 1,
124
            };
125
126
0
            budget.consume_build_chain_call()?;
127
0
            path.push(potential_issuer)?;
128
0
            let result = self.build_chain_inner(path, time, verify_path, next_sub_ca_count, budget);
129
0
            if result.is_err() {
130
0
                path.pop();
131
0
            }
132
133
0
            result
134
0
        })
Unexecuted instantiation: <webpki::verify_cert::ChainOptions<spdmlib::crypto::spdm_ring::cert_operation_impl::SpdmResponderEkuValidator>>::build_chain_inner::{closure#1}
Unexecuted instantiation: <webpki::verify_cert::ChainOptions<_>>::build_chain_inner::{closure#1}
135
0
    }
Unexecuted instantiation: <webpki::verify_cert::ChainOptions<spdmlib::crypto::spdm_ring::cert_operation_impl::SpdmResponderEkuValidator>>::build_chain_inner
Unexecuted instantiation: <webpki::verify_cert::ChainOptions<_>>::build_chain_inner
136
137
0
    fn check_signed_chain(
138
0
        &self,
139
0
        path: &PathNode<'_>,
140
0
        time: UnixTime,
141
0
        trust_anchor: &TrustAnchor<'_>,
142
0
        budget: &mut Budget,
143
0
    ) -> Result<(), ControlFlow<Error, Error>> {
144
0
        let mut spki_value = untrusted::Input::from(trust_anchor.subject_public_key_info.as_ref());
145
0
        let mut issuer_subject = untrusted::Input::from(trust_anchor.subject.as_ref());
146
0
        let mut issuer_key_usage = None; // TODO(XXX): Consider whether to track TrustAnchor KU.
147
0
        for path in path.iter() {
148
0
            signed_data::verify_signed_data(
149
0
                self.supported_sig_algs,
150
0
                spki_value,
151
0
                &path.cert.signed_data,
152
0
                budget,
153
0
            )?;
154
155
0
            if let Some(revocation_opts) = &self.revocation {
156
0
                revocation_opts.check(
157
0
                    &path,
158
0
                    issuer_subject,
159
0
                    spki_value,
160
0
                    issuer_key_usage,
161
0
                    self.supported_sig_algs,
162
0
                    budget,
163
0
                    time,
164
0
                )?;
165
0
            }
166
167
0
            spki_value = path.cert.spki;
168
0
            issuer_subject = path.cert.subject;
169
0
            issuer_key_usage = path.cert.key_usage;
170
        }
171
172
0
        Ok(())
173
0
    }
Unexecuted instantiation: <webpki::verify_cert::ChainOptions<spdmlib::crypto::spdm_ring::cert_operation_impl::SpdmResponderEkuValidator>>::check_signed_chain
Unexecuted instantiation: <webpki::verify_cert::ChainOptions<_>>::check_signed_chain
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.
179
pub struct VerifiedPath<'p> {
180
    end_entity: &'p EndEntityCert<'p>,
181
    intermediates: Intermediates<'p>,
182
    anchor: &'p TrustAnchor<'p>,
183
}
184
185
impl<'p> VerifiedPath<'p> {
186
0
    fn new(
187
0
        end_entity: &'p EndEntityCert<'p>,
188
0
        anchor: &'p TrustAnchor<'p>,
189
0
        partial: PartialPath<'p>,
190
0
    ) -> Self {
191
0
        Self {
192
0
            end_entity,
193
0
            intermediates: Intermediates::Owned {
194
0
                certs: partial.intermediates,
195
0
                used: partial.used,
196
0
            },
197
0
            anchor,
198
0
        }
199
0
    }
200
201
    /// Yields a (double-ended) iterator over the intermediate certificates in this path.
202
0
    pub fn intermediate_certificates(&'p self) -> IntermediateIterator<'p> {
203
0
        IntermediateIterator {
204
0
            intermediates: self.intermediates.as_ref(),
205
0
        }
206
0
    }
207
208
    /// Yields the end-entity certificate for this path.
209
0
    pub fn end_entity(&self) -> &'p EndEntityCert<'p> {
210
0
        self.end_entity
211
0
    }
212
213
    /// Yields the trust anchor for this path.
214
0
    pub fn anchor(&self) -> &'p TrustAnchor<'p> {
215
0
        self.anchor
216
0
    }
217
}
218
219
/// Iterator over a path's intermediate certificates.
220
///
221
/// Implements [`DoubleEndedIterator`] so it can be traversed in both directions.
222
pub struct IntermediateIterator<'a> {
223
    /// Invariant: all of these `Option`s are `Some`.
224
    intermediates: &'a [Option<Cert<'a>>],
225
}
226
227
impl<'a> Iterator for IntermediateIterator<'a> {
228
    type Item = &'a Cert<'a>;
229
230
0
    fn next(&mut self) -> Option<Self::Item> {
231
0
        match self.intermediates.split_first() {
232
0
            Some((head, tail)) => {
233
0
                self.intermediates = tail;
234
0
                Some(head.as_ref().unwrap())
235
            }
236
0
            None => None,
237
        }
238
0
    }
239
}
240
241
impl DoubleEndedIterator for IntermediateIterator<'_> {
242
0
    fn next_back(&mut self) -> Option<Self::Item> {
243
0
        match self.intermediates.split_last() {
244
0
            Some((head, tail)) => {
245
0
                self.intermediates = tail;
246
0
                Some(head.as_ref().unwrap())
247
            }
248
0
            None => None,
249
        }
250
0
    }
251
}
252
253
#[allow(clippy::large_enum_variant)]
254
enum 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
262
impl<'a> AsRef<[Option<Cert<'a>>]> for Intermediates<'a> {
263
0
    fn as_ref(&self) -> &[Option<Cert<'a>>] {
264
0
        match self {
265
0
            Intermediates::Owned { certs, used } => &certs[..*used],
266
0
            Intermediates::Borrowed(certs) => certs,
267
        }
268
0
    }
269
}
270
271
0
fn check_signed_chain_name_constraints(
272
0
    path: &PathNode<'_>,
273
0
    trust_anchor: &TrustAnchor<'_>,
274
0
    budget: &mut Budget,
275
0
) -> Result<(), ControlFlow<Error, Error>> {
276
0
    let mut name_constraints = trust_anchor
277
0
        .name_constraints
278
0
        .as_ref()
279
0
        .map(|der| untrusted::Input::from(der.as_ref()));
280
281
0
    for path in path.iter() {
282
0
        untrusted::read_all_optional(name_constraints, Error::BadDer, |value| {
283
0
            subject_name::check_name_constraints(value, &path, budget)
284
0
        })?;
285
286
0
        name_constraints = path.cert.name_constraints;
287
    }
288
289
0
    Ok(())
290
0
}
291
292
pub(crate) struct Budget {
293
    signatures: usize,
294
    build_chain_calls: usize,
295
    name_constraint_comparisons: usize,
296
}
297
298
impl Budget {
299
    #[inline]
300
0
    pub(crate) fn consume_signature(&mut self) -> Result<(), Error> {
301
0
        self.signatures = self
302
0
            .signatures
303
0
            .checked_sub(1)
304
0
            .ok_or(Error::MaximumSignatureChecksExceeded)?;
305
0
        Ok(())
306
0
    }
307
308
    #[inline]
309
0
    fn consume_build_chain_call(&mut self) -> Result<(), Error> {
310
0
        self.build_chain_calls = self
311
0
            .build_chain_calls
312
0
            .checked_sub(1)
313
0
            .ok_or(Error::MaximumPathBuildCallsExceeded)?;
314
0
        Ok(())
315
0
    }
Unexecuted instantiation: <webpki::verify_cert::Budget>::consume_build_chain_call
Unexecuted instantiation: <webpki::verify_cert::Budget>::consume_build_chain_call
316
317
    #[inline]
318
0
    pub(crate) fn consume_name_constraint_comparison(&mut self) -> Result<(), Error> {
319
0
        self.name_constraint_comparisons = self
320
0
            .name_constraint_comparisons
321
0
            .checked_sub(1)
322
0
            .ok_or(Error::MaximumNameConstraintComparisonsExceeded)?;
323
0
        Ok(())
324
0
    }
325
}
326
327
impl Default for Budget {
328
0
    fn default() -> Self {
329
0
        Self {
330
0
            // This limit is taken from the remediation for golang CVE-2018-16875.  However,
331
0
            // note that golang subsequently implemented AKID matching due to this limit
332
0
            // being hit in real applications (see <https://github.com/spiffe/spire/issues/1004>).
333
0
            // So this may actually be too aggressive.
334
0
            signatures: 100,
335
0
336
0
            // This limit is taken from mozilla::pkix, see:
337
0
            // <https://github.com/nss-dev/nss/blob/bb4a1d38dd9e92923525ac6b5ed0288479f3f3fc/lib/mozpkix/lib/pkixbuild.cpp#L381-L393>
338
0
            build_chain_calls: 200_000,
339
0
340
0
            // This limit is taken from golang crypto/x509's default, see:
341
0
            // <https://github.com/golang/go/blob/ac17bb6f13979f2ab9fcd45f0758b43ed72d0973/src/crypto/x509/verify.go#L588-L592>
342
0
            name_constraint_comparisons: 250_000,
343
0
        }
344
0
    }
345
}
346
347
0
fn check_issuer_independent_properties(
348
0
    cert: &Cert<'_>,
349
0
    time: UnixTime,
350
0
    role: Role,
351
0
    sub_ca_count: usize,
352
0
    eku: &impl ExtendedKeyUsageValidator,
353
0
) -> 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
0
    cert.validity
366
0
        .read_all(Error::BadDer, |value| check_validity(value, time))?;
Unexecuted instantiation: webpki::verify_cert::check_issuer_independent_properties::<spdmlib::crypto::spdm_ring::cert_operation_impl::SpdmResponderEkuValidator>::{closure#0}
Unexecuted instantiation: webpki::verify_cert::check_issuer_independent_properties::<_>::{closure#0}
367
0
    untrusted::read_all_optional(cert.basic_constraints, Error::BadDer, |value| {
368
0
        check_basic_constraints(value, role, sub_ca_count)
369
0
    })?;
Unexecuted instantiation: webpki::verify_cert::check_issuer_independent_properties::<spdmlib::crypto::spdm_ring::cert_operation_impl::SpdmResponderEkuValidator>::{closure#1}
Unexecuted instantiation: webpki::verify_cert::check_issuer_independent_properties::<_>::{closure#1}
370
0
    untrusted::read_all_optional(cert.eku, Error::BadDer, |input| check_eku(input, eku))?;
Unexecuted instantiation: webpki::verify_cert::check_issuer_independent_properties::<spdmlib::crypto::spdm_ring::cert_operation_impl::SpdmResponderEkuValidator>::{closure#2}
Unexecuted instantiation: webpki::verify_cert::check_issuer_independent_properties::<_>::{closure#2}
371
372
0
    Ok(())
373
0
}
Unexecuted instantiation: webpki::verify_cert::check_issuer_independent_properties::<spdmlib::crypto::spdm_ring::cert_operation_impl::SpdmResponderEkuValidator>
Unexecuted instantiation: webpki::verify_cert::check_issuer_independent_properties::<_>
374
375
0
fn check_eku(
376
0
    input: Option<&mut untrusted::Reader<'_>>,
377
0
    eku: &impl ExtendedKeyUsageValidator,
378
0
) -> Result<(), Error> {
379
0
    match input {
380
0
        Some(input) if input.at_end() => Err(Error::EmptyEkuExtension),
381
0
        Some(input) => eku.validate(KeyPurposeIdIter { input }),
382
0
        None => eku.validate(KeyPurposeIdIter {
383
0
            input: &mut untrusted::Reader::new(untrusted::Input::from(&[])),
384
0
        }),
385
    }
386
0
}
Unexecuted instantiation: webpki::verify_cert::check_eku::<spdmlib::crypto::spdm_ring::cert_operation_impl::SpdmResponderEkuValidator>
Unexecuted instantiation: webpki::verify_cert::check_eku::<_>
387
388
// https://tools.ietf.org/html/rfc5280#section-4.1.2.5
389
0
fn check_validity(input: &mut untrusted::Reader<'_>, time: UnixTime) -> Result<(), Error> {
390
0
    let not_before = UnixTime::from_der(input)?;
391
0
    let not_after = UnixTime::from_der(input)?;
392
393
0
    if not_before > not_after {
394
0
        return Err(Error::InvalidCertValidity);
395
0
    }
396
0
    if time < not_before {
397
0
        return Err(Error::CertNotValidYet { time, not_before });
398
0
    }
399
0
    if time > not_after {
400
0
        return Err(Error::CertExpired { time, not_after });
401
0
    }
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
0
    Ok(())
408
0
}
409
410
// https://tools.ietf.org/html/rfc5280#section-4.2.1.9
411
0
fn check_basic_constraints(
412
0
    input: Option<&mut untrusted::Reader<'_>>,
413
0
    role: Role,
414
0
    sub_ca_count: usize,
415
0
) -> Result<(), Error> {
416
0
    let (is_ca, path_len_constraint) = match input {
417
0
        Some(input) => {
418
0
            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
0
            let path_len_constraint = if !input.at_end() {
425
0
                Some(usize::from(u8::from_der(input)?))
426
            } else {
427
0
                None
428
            };
429
430
0
            (is_ca, path_len_constraint)
431
        }
432
0
        None => (false, None),
433
    };
434
435
0
    match (role, is_ca, path_len_constraint) {
436
0
        (Role::EndEntity, true, _) => Err(Error::CaUsedAsEndEntity),
437
0
        (Role::Issuer, false, _) => Err(Error::EndEntityUsedAsCa),
438
0
        (Role::Issuer, true, Some(len)) if sub_ca_count > len => {
439
0
            Err(Error::PathLenConstraintViolated)
440
        }
441
0
        _ => Ok(()),
442
    }
443
0
}
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)]
449
pub 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
458
impl fmt::Debug for RequiredEkuNotFoundContext {
459
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
460
0
        let mut builder = f.debug_struct("RequiredEkuNotFoundContext");
461
        #[cfg(feature = "alloc")]
462
0
        builder.field(
463
0
            "required",
464
0
            match &self.required.inner {
465
0
                ExtendedKeyUsage::Required(inner) => inner,
466
0
                ExtendedKeyUsage::RequiredIfPresent(inner) => inner,
467
            },
468
        );
469
        #[cfg(feature = "alloc")]
470
0
        builder.field("present", &EkuListDebug(&self.present));
471
0
        builder.finish()
472
0
    }
473
}
474
475
#[cfg(feature = "alloc")]
476
struct EkuListDebug<'a>(&'a [Vec<usize>]);
477
478
#[cfg(feature = "alloc")]
479
impl fmt::Debug for EkuListDebug<'_> {
480
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
481
0
        write!(f, "[")?;
482
0
        for (i, part) in self.0.iter().enumerate() {
483
0
            if i > 0 {
484
0
                write!(f, ", ")?;
485
0
            }
486
487
0
            write!(f, "KeyPurposeId(")?;
488
0
            for (j, part) in part.iter().enumerate() {
489
0
                if j > 0 {
490
0
                    write!(f, ".")?;
491
0
                }
492
0
                write!(f, "{part}")?;
493
            }
494
0
            write!(f, ")")?;
495
        }
496
0
        write!(f, "]")
497
0
    }
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)]
509
pub struct KeyUsage {
510
    inner: ExtendedKeyUsage,
511
}
512
513
impl 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
0
    pub const fn server_auth() -> Self {
518
0
        Self::required_if_present(EKU_SERVER_AUTH)
519
0
    }
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
0
    pub const fn client_auth() -> Self {
525
0
        Self::required_if_present(EKU_CLIENT_AUTH)
526
0
    }
527
528
    /// Construct a new [`KeyUsage`] requiring a certificate to support the specified OID.
529
0
    pub const fn required(oid: &'static [u8]) -> Self {
530
0
        Self {
531
0
            inner: ExtendedKeyUsage::Required(KeyPurposeId::new(oid)),
532
0
        }
533
0
    }
534
535
    /// Construct a new [`KeyUsage`] requiring a certificate to support the specified OID, if the certificate has EKUs.
536
0
    pub const fn required_if_present(oid: &'static [u8]) -> Self {
537
0
        Self {
538
0
            inner: ExtendedKeyUsage::RequiredIfPresent(KeyPurposeId::new(oid)),
539
0
        }
540
0
    }
541
542
    /// Yield the OID values of the required extended key usage.
543
0
    pub fn oid_values(&self) -> impl Iterator<Item = usize> + '_ {
544
0
        OidDecoder::new(
545
0
            match &self.inner {
546
0
                ExtendedKeyUsage::Required(eku) => eku,
547
0
                ExtendedKeyUsage::RequiredIfPresent(eku) => eku,
548
            }
549
            .oid_value
550
0
            .as_slice_less_safe(),
551
        )
552
0
    }
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
560
impl ExtendedKeyUsageValidator for KeyUsage {
561
    // https://tools.ietf.org/html/rfc5280#section-4.2.1.12
562
0
    fn validate(&self, iter: KeyPurposeIdIter<'_, '_>) -> Result<(), Error> {
563
0
        let mut empty = true;
564
        #[cfg(feature = "alloc")]
565
0
        let mut present = Vec::new();
566
567
0
        for id in iter {
568
0
            empty = false;
569
0
            let id = id?;
570
0
            if self.inner.id() == id {
571
0
                return Ok(());
572
0
            }
573
574
            #[cfg(feature = "alloc")]
575
0
            present.push(id.to_decoded_oid());
576
        }
577
578
0
        match (empty, self.inner) {
579
0
            (true, ExtendedKeyUsage::RequiredIfPresent(_)) => Ok(()),
580
0
            _ => Err(Error::RequiredEkuNotFoundContext(
581
0
                RequiredEkuNotFoundContext {
582
0
                    #[cfg(feature = "alloc")]
583
0
                    required: Self { inner: self.inner },
584
0
                    #[cfg(feature = "alloc")]
585
0
                    present,
586
0
                },
587
0
            )),
588
        }
589
0
    }
590
}
591
592
impl<V: ExtendedKeyUsageValidator> ExtendedKeyUsageValidator for &V {
593
0
    fn validate(&self, iter: KeyPurposeIdIter<'_, '_>) -> Result<(), Error> {
594
0
        (*self).validate(iter)
595
0
    }
596
}
597
598
/// A trait for validating the Extended Key Usage (EKU) extensions of a certificate.
599
pub 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)]
611
enum 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
619
impl ExtendedKeyUsage {
620
0
    fn id(&self) -> KeyPurposeId<'static> {
621
0
        match self {
622
0
            Self::Required(id) => *id,
623
0
            Self::RequiredIfPresent(id) => *id,
624
        }
625
0
    }
626
}
627
628
/// Iterator over [`KeyPurposeId`]s, for use in [`ExtendedKeyUsageValidator`].
629
pub struct KeyPurposeIdIter<'a, 'r> {
630
    input: &'r mut untrusted::Reader<'a>,
631
}
632
633
impl<'a, 'r> Iterator for KeyPurposeIdIter<'a, 'r> {
634
    type Item = Result<KeyPurposeId<'a>, Error>;
635
636
0
    fn next(&mut self) -> Option<Self::Item> {
637
0
        if self.input.at_end() {
638
0
            return None;
639
0
        }
640
641
0
        Some(der::expect_tag(self.input, der::Tag::OID).map(|oid_value| KeyPurposeId { oid_value }))
642
0
    }
643
}
644
645
impl Drop for KeyPurposeIdIter<'_, '_> {
646
0
    fn drop(&mut self) {
647
0
        self.input.skip_to_end();
648
0
    }
649
}
650
651
/// An OID value indicating an Extended Key Usage (EKU) key purpose.
652
#[derive(Clone, Copy)]
653
pub struct KeyPurposeId<'a> {
654
    oid_value: untrusted::Input<'a>,
655
}
656
657
impl<'a> KeyPurposeId<'a> {
658
    /// Construct a new [`KeyPurposeId`].
659
    ///
660
    /// `oid` is the OBJECT IDENTIFIER in bytes.
661
0
    pub const fn new(oid: &'a [u8]) -> Self {
662
0
        Self {
663
0
            oid_value: untrusted::Input::from(oid),
664
0
        }
665
0
    }
666
667
    /// Yield the OID value as a sequence of `usize` components.
668
    #[cfg(feature = "alloc")]
669
0
    pub fn to_decoded_oid(&self) -> Vec<usize> {
670
0
        OidDecoder::new(self.oid_value.as_slice_less_safe()).collect()
671
0
    }
672
}
673
674
impl fmt::Debug for KeyPurposeId<'_> {
675
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
676
0
        write!(f, "KeyPurposeId(")?;
677
0
        let decoder = OidDecoder::new(self.oid_value.as_slice_less_safe());
678
0
        for (i, part) in decoder.enumerate() {
679
0
            if i > 0 {
680
0
                write!(f, ".")?;
681
0
            }
682
0
            write!(f, "{part}")?;
683
        }
684
0
        write!(f, ")")
685
0
    }
686
}
687
688
impl PartialEq<Self> for KeyPurposeId<'_> {
689
0
    fn eq(&self, other: &Self) -> bool {
690
0
        public_values_eq(self.oid_value, other.oid_value)
691
0
    }
692
}
693
694
impl 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 }
700
const EKU_SERVER_AUTH: &[u8] = &oid!(1, 3, 6, 1, 5, 5, 7, 3, 1);
701
702
// id-kp-clientAuth   OBJECT IDENTIFIER ::= { id-kp 2 }
703
const EKU_CLIENT_AUTH: &[u8] = &oid!(1, 3, 6, 1, 5, 5, 7, 3, 2);
704
705
struct OidDecoder<'a> {
706
    encoded: &'a [u8],
707
    left: Option<usize>,
708
    first: bool,
709
}
710
711
impl<'a> OidDecoder<'a> {
712
0
    fn new(encoded: &'a [u8]) -> Self {
713
0
        Self {
714
0
            encoded,
715
0
            left: None,
716
0
            first: true,
717
0
        }
718
0
    }
719
}
720
721
impl Iterator for OidDecoder<'_> {
722
    type Item = usize;
723
724
0
    fn next(&mut self) -> Option<Self::Item> {
725
0
        if let Some(next) = self.left.take() {
726
0
            return Some(next);
727
0
        }
728
729
0
        let mut cur = 0;
730
0
        for (i, &byte) in self.encoded.iter().enumerate() {
731
0
            cur = (cur << 8) + usize::from(byte & 0x7f);
732
0
            if byte & 0x80 > 0 {
733
0
                continue;
734
0
            }
735
736
0
            if !self.first {
737
0
                self.encoded = &self.encoded[i + 1..];
738
0
                return Some(cur);
739
0
            }
740
741
0
            let (cur, next) = match cur {
742
0
                ..=39 => (0, cur),
743
0
                40..=79 => (1, cur - 40),
744
0
                _ => (2, cur - 80),
745
            };
746
747
0
            self.encoded = &self.encoded[i + 1..];
748
0
            self.first = false;
749
0
            self.left = Some(next);
750
0
            return Some(cur);
751
        }
752
753
0
        None
754
0
    }
755
}
756
757
0
fn loop_while_non_fatal_error<'a, V: IntoIterator + 'a>(
758
0
    default_error: Error,
759
0
    values: V,
760
0
    mut f: impl FnMut(V::Item) -> Result<&'a TrustAnchor<'a>, ControlFlow<Error, Error>>,
761
0
) -> Result<&'a TrustAnchor<'a>, ControlFlow<Error, Error>> {
762
0
    let mut error = default_error;
763
0
    for v in values {
764
0
        match f(v) {
765
0
            Ok(anchor) => return Ok(anchor),
766
            // Fatal errors should halt further looping.
767
0
            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
0
            Err(ControlFlow::Continue(new_error)) => error = error.most_specific(new_error),
771
        }
772
    }
773
0
    Err(error.into())
774
0
}
Unexecuted instantiation: webpki::verify_cert::loop_while_non_fatal_error::<&[rustls_pki_types::TrustAnchor], <webpki::verify_cert::ChainOptions<spdmlib::crypto::spdm_ring::cert_operation_impl::SpdmResponderEkuValidator>>::build_chain_inner::{closure#0}>
Unexecuted instantiation: webpki::verify_cert::loop_while_non_fatal_error::<&[rustls_pki_types::CertificateDer], <webpki::verify_cert::ChainOptions<spdmlib::crypto::spdm_ring::cert_operation_impl::SpdmResponderEkuValidator>>::build_chain_inner::{closure#1}>
Unexecuted instantiation: webpki::verify_cert::loop_while_non_fatal_error::<_, _>
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.
780
pub(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
793
impl<'a> PartialPath<'a> {
794
0
    pub(crate) fn new(end_entity: &'a EndEntityCert<'a>) -> Self {
795
0
        Self {
796
0
            end_entity,
797
0
            intermediates: Default::default(),
798
0
            used: 0,
799
0
        }
800
0
    }
801
802
0
    pub(crate) fn push(&mut self, cert: Cert<'a>) -> Result<(), ControlFlow<Error, Error>> {
803
0
        if self.used >= MAX_SUB_CA_COUNT {
804
0
            return Err(Error::MaximumPathDepthExceeded.into());
805
0
        }
806
807
0
        self.intermediates[self.used] = Some(cert);
808
0
        self.used += 1;
809
0
        Ok(())
810
0
    }
811
812
0
    fn pop(&mut self) {
813
0
        debug_assert!(self.used > 0);
814
0
        if self.used == 0 {
815
0
            return;
816
0
        }
817
818
0
        self.used -= 1;
819
0
        self.intermediates[self.used] = None;
820
0
    }
821
822
0
    pub(crate) fn node(&self) -> PathNode<'_> {
823
0
        PathNode {
824
0
            path: self,
825
0
            index: self.used,
826
0
            cert: self.head(),
827
0
        }
828
0
    }
829
830
    /// Current head of the path.
831
0
    pub(crate) fn head(&self) -> &Cert<'a> {
832
0
        self.get(self.used)
833
0
    }
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
0
    fn get(&self, idx: usize) -> &Cert<'a> {
840
0
        match idx {
841
0
            0 => self.end_entity,
842
0
            _ => self.intermediates[idx - 1].as_ref().unwrap(),
843
        }
844
0
    }
845
}
846
847
const MAX_SUB_CA_COUNT: usize = 6;
848
849
pub(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
858
impl<'a> PathNode<'a> {
859
0
    pub(crate) fn iter(&self) -> PathIter<'a> {
860
0
        PathIter {
861
0
            path: self.path,
862
0
            next: Some(self.index),
863
0
        }
864
0
    }
865
866
0
    pub(crate) fn role(&self) -> Role {
867
0
        match self.index {
868
0
            0 => Role::EndEntity,
869
0
            _ => Role::Issuer,
870
        }
871
0
    }
872
}
873
874
pub(crate) struct PathIter<'a> {
875
    path: &'a PartialPath<'a>,
876
    next: Option<usize>,
877
}
878
879
impl<'a> Iterator for PathIter<'a> {
880
    type Item = PathNode<'a>;
881
882
0
    fn next(&mut self) -> Option<Self::Item> {
883
0
        let next = self.next?;
884
0
        self.next = match next {
885
0
            0 => None,
886
0
            _ => Some(next - 1),
887
        };
888
889
0
        Some(PathNode {
890
0
            path: self.path,
891
0
            index: next,
892
0
            cert: self.path.get(next),
893
0
        })
894
0
    }
895
}
896
897
#[derive(Clone, Copy, PartialEq)]
898
pub(crate) enum Role {
899
    Issuer,
900
    EndEntity,
901
}
902
903
#[cfg(all(test, feature = "alloc", any(feature = "ring", feature = "aws-lc-rs")))]
904
mod 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
}