Coverage Report

Created: 2025-11-16 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/rustls-webpki-0.102.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
use core::ops::ControlFlow;
16
17
use pki_types::{CertificateDer, SignatureVerificationAlgorithm, TrustAnchor, UnixTime};
18
19
use crate::cert::Cert;
20
use crate::crl::RevocationOptions;
21
use crate::der::{self, FromDer};
22
use crate::end_entity::EndEntityCert;
23
use crate::error::Error;
24
use crate::{public_values_eq, signed_data, subject_name};
25
26
// Use `'a` for lifetimes that we don't care about, `'p` for lifetimes that become a part of
27
// the `VerifiedPath`.
28
pub(crate) struct ChainOptions<'a, 'p> {
29
    pub(crate) eku: KeyUsage,
30
    pub(crate) supported_sig_algs: &'a [&'a dyn SignatureVerificationAlgorithm],
31
    pub(crate) trust_anchors: &'p [TrustAnchor<'p>],
32
    pub(crate) intermediate_certs: &'p [CertificateDer<'p>],
33
    pub(crate) revocation: Option<RevocationOptions<'a>>,
34
}
35
36
impl<'a, 'p: 'a> ChainOptions<'a, 'p> {
37
0
    pub(crate) fn build_chain(
38
0
        &self,
39
0
        end_entity: &'p EndEntityCert<'p>,
40
0
        time: UnixTime,
41
0
        verify_path: Option<&dyn Fn(&VerifiedPath<'_>) -> Result<(), Error>>,
42
0
    ) -> Result<VerifiedPath<'p>, Error> {
43
0
        let mut path = PartialPath::new(end_entity);
44
0
        match self.build_chain_inner(&mut path, time, verify_path, 0, &mut Budget::default()) {
45
0
            Ok(anchor) => Ok(VerifiedPath::new(end_entity, anchor, path)),
46
0
            Err(ControlFlow::Break(err)) | Err(ControlFlow::Continue(err)) => Err(err),
47
        }
48
0
    }
49
50
0
    fn build_chain_inner(
51
0
        &self,
52
0
        path: &mut PartialPath<'p>,
53
0
        time: UnixTime,
54
0
        verify_path: Option<&dyn Fn(&VerifiedPath<'_>) -> Result<(), Error>>,
55
0
        sub_ca_count: usize,
56
0
        budget: &mut Budget,
57
0
    ) -> Result<&'p TrustAnchor<'p>, ControlFlow<Error, Error>> {
58
0
        let role = path.node().role();
59
60
0
        check_issuer_independent_properties(path.head(), time, role, sub_ca_count, self.eku.inner)?;
61
62
        // TODO: HPKP checks.
63
64
0
        let result =
65
0
            loop_while_non_fatal_error(Error::UnknownIssuer, self.trust_anchors, |trust_anchor| {
66
0
                let trust_anchor_subject = untrusted::Input::from(trust_anchor.subject.as_ref());
67
0
                if !public_values_eq(path.head().issuer, trust_anchor_subject) {
68
0
                    return Err(Error::UnknownIssuer.into());
69
0
                }
70
71
                // TODO: check_distrust(trust_anchor_subject, trust_anchor_spki)?;
72
73
0
                let node = path.node();
74
0
                self.check_signed_chain(&node, time, trust_anchor, budget)?;
75
0
                check_signed_chain_name_constraints(&node, trust_anchor, budget)?;
76
77
0
                let verify = match verify_path {
78
0
                    Some(verify) => verify,
79
0
                    None => return Ok(trust_anchor),
80
                };
81
82
0
                let candidate = VerifiedPath {
83
0
                    end_entity: path.end_entity,
84
0
                    intermediates: Intermediates::Borrowed(&path.intermediates[..path.used]),
85
0
                    anchor: trust_anchor,
86
0
                };
87
88
0
                match verify(&candidate) {
89
0
                    Ok(()) => Ok(trust_anchor),
90
0
                    Err(err) => Err(ControlFlow::Continue(err)),
91
                }
92
0
            });
93
94
0
        let err = match result {
95
0
            Ok(anchor) => return Ok(anchor),
96
            // Fatal errors should halt further path building.
97
0
            res @ Err(ControlFlow::Break(_)) => return res,
98
            // Non-fatal errors should be carried forward as the default_error for subsequent
99
            // loop_while_non_fatal_error processing and only returned once all other path-building
100
            // options have been exhausted.
101
0
            Err(ControlFlow::Continue(err)) => err,
102
        };
103
104
0
        loop_while_non_fatal_error(err, self.intermediate_certs, |cert_der| {
105
0
            let potential_issuer = Cert::from_der(untrusted::Input::from(cert_der))?;
106
0
            if !public_values_eq(potential_issuer.subject, path.head().issuer) {
107
0
                return Err(Error::UnknownIssuer.into());
108
0
            }
109
110
            // Prevent loops; see RFC 4158 section 5.2.
111
0
            if path.node().iter().any(|prev| {
112
0
                public_values_eq(potential_issuer.spki, prev.cert.spki)
113
0
                    && public_values_eq(potential_issuer.subject, prev.cert.subject)
114
0
            }) {
115
0
                return Err(Error::UnknownIssuer.into());
116
0
            }
117
118
0
            let next_sub_ca_count = match role {
119
0
                Role::EndEntity => sub_ca_count,
120
0
                Role::Issuer => sub_ca_count + 1,
121
            };
122
123
0
            budget.consume_build_chain_call()?;
124
0
            path.push(potential_issuer)?;
125
0
            let result = self.build_chain_inner(path, time, verify_path, next_sub_ca_count, budget);
126
0
            if result.is_err() {
127
0
                path.pop();
128
0
            }
129
130
0
            result
131
0
        })
132
0
    }
133
134
0
    fn check_signed_chain(
135
0
        &self,
136
0
        path: &PathNode<'_>,
137
0
        time: UnixTime,
138
0
        trust_anchor: &TrustAnchor<'_>,
139
0
        budget: &mut Budget,
140
0
    ) -> Result<(), ControlFlow<Error, Error>> {
141
0
        let mut spki_value = untrusted::Input::from(trust_anchor.subject_public_key_info.as_ref());
142
0
        let mut issuer_subject = untrusted::Input::from(trust_anchor.subject.as_ref());
143
0
        let mut issuer_key_usage = None; // TODO(XXX): Consider whether to track TrustAnchor KU.
144
0
        for path in path.iter() {
145
0
            signed_data::verify_signed_data(
146
0
                self.supported_sig_algs,
147
0
                spki_value,
148
0
                &path.cert.signed_data,
149
0
                budget,
150
0
            )?;
151
152
0
            if let Some(revocation_opts) = &self.revocation {
153
0
                revocation_opts.check(
154
0
                    &path,
155
0
                    issuer_subject,
156
0
                    spki_value,
157
0
                    issuer_key_usage,
158
0
                    self.supported_sig_algs,
159
0
                    budget,
160
0
                    time,
161
0
                )?;
162
0
            }
163
164
0
            spki_value = path.cert.spki;
165
0
            issuer_subject = path.cert.subject;
166
0
            issuer_key_usage = path.cert.key_usage;
167
        }
168
169
0
        Ok(())
170
0
    }
171
}
172
173
/// Path from end-entity certificate to trust anchor that's been verified.
174
///
175
/// See [`EndEntityCert::verify_for_usage()`] for more details on what verification entails.
176
pub struct VerifiedPath<'p> {
177
    end_entity: &'p EndEntityCert<'p>,
178
    intermediates: Intermediates<'p>,
179
    anchor: &'p TrustAnchor<'p>,
180
}
181
182
impl<'p> VerifiedPath<'p> {
183
0
    fn new(
184
0
        end_entity: &'p EndEntityCert<'p>,
185
0
        anchor: &'p TrustAnchor<'p>,
186
0
        partial: PartialPath<'p>,
187
0
    ) -> Self {
188
0
        Self {
189
0
            end_entity,
190
0
            intermediates: Intermediates::Owned {
191
0
                certs: partial.intermediates,
192
0
                used: partial.used,
193
0
            },
194
0
            anchor,
195
0
        }
196
0
    }
197
198
    /// Yields a (double-ended) iterator over the intermediate certificates in this path.
199
0
    pub fn intermediate_certificates(&'p self) -> IntermediateIterator<'p> {
200
0
        IntermediateIterator {
201
0
            intermediates: self.intermediates.as_ref(),
202
0
        }
203
0
    }
204
205
    /// Yields the end-entity certificate for this path.
206
0
    pub fn end_entity(&self) -> &'p EndEntityCert<'p> {
207
0
        self.end_entity
208
0
    }
209
210
    /// Yields the trust anchor for this path.
211
0
    pub fn anchor(&self) -> &'p TrustAnchor<'p> {
212
0
        self.anchor
213
0
    }
214
}
215
216
/// Iterator over a path's intermediate certificates.
217
///
218
/// Implements [`DoubleEndedIterator`] so it can be traversed in both directions.
219
pub struct IntermediateIterator<'a> {
220
    /// Invariant: all of these `Option`s are `Some`.
221
    intermediates: &'a [Option<Cert<'a>>],
222
}
223
224
impl<'a> Iterator for IntermediateIterator<'a> {
225
    type Item = &'a Cert<'a>;
226
227
0
    fn next(&mut self) -> Option<Self::Item> {
228
0
        match self.intermediates.split_first() {
229
0
            Some((head, tail)) => {
230
0
                self.intermediates = tail;
231
0
                Some(head.as_ref().unwrap())
232
            }
233
0
            None => None,
234
        }
235
0
    }
236
}
237
238
impl<'a> DoubleEndedIterator for IntermediateIterator<'a> {
239
0
    fn next_back(&mut self) -> Option<Self::Item> {
240
0
        match self.intermediates.split_last() {
241
0
            Some((head, tail)) => {
242
0
                self.intermediates = tail;
243
0
                Some(head.as_ref().unwrap())
244
            }
245
0
            None => None,
246
        }
247
0
    }
248
}
249
250
#[allow(clippy::large_enum_variant)]
251
enum Intermediates<'a> {
252
    Owned {
253
        certs: [Option<Cert<'a>>; MAX_SUB_CA_COUNT],
254
        used: usize,
255
    },
256
    Borrowed(&'a [Option<Cert<'a>>]),
257
}
258
259
impl<'a> AsRef<[Option<Cert<'a>>]> for Intermediates<'a> {
260
0
    fn as_ref(&self) -> &[Option<Cert<'a>>] {
261
0
        match self {
262
0
            Intermediates::Owned { certs, used } => &certs[..*used],
263
0
            Intermediates::Borrowed(certs) => certs,
264
        }
265
0
    }
266
}
267
268
0
fn check_signed_chain_name_constraints(
269
0
    path: &PathNode<'_>,
270
0
    trust_anchor: &TrustAnchor<'_>,
271
0
    budget: &mut Budget,
272
0
) -> Result<(), ControlFlow<Error, Error>> {
273
0
    let mut name_constraints = trust_anchor
274
0
        .name_constraints
275
0
        .as_ref()
276
0
        .map(|der| untrusted::Input::from(der.as_ref()));
277
278
0
    for path in path.iter() {
279
0
        untrusted::read_all_optional(name_constraints, Error::BadDer, |value| {
280
0
            subject_name::check_name_constraints(value, &path, budget)
281
0
        })?;
282
283
0
        name_constraints = path.cert.name_constraints;
284
    }
285
286
0
    Ok(())
287
0
}
288
289
pub(crate) struct Budget {
290
    signatures: usize,
291
    build_chain_calls: usize,
292
    name_constraint_comparisons: usize,
293
}
294
295
impl Budget {
296
    #[inline]
297
0
    pub(crate) fn consume_signature(&mut self) -> Result<(), Error> {
298
0
        self.signatures = self
299
0
            .signatures
300
0
            .checked_sub(1)
301
0
            .ok_or(Error::MaximumSignatureChecksExceeded)?;
302
0
        Ok(())
303
0
    }
304
305
    #[inline]
306
0
    fn consume_build_chain_call(&mut self) -> Result<(), Error> {
307
0
        self.build_chain_calls = self
308
0
            .build_chain_calls
309
0
            .checked_sub(1)
310
0
            .ok_or(Error::MaximumPathBuildCallsExceeded)?;
311
0
        Ok(())
312
0
    }
313
314
    #[inline]
315
0
    pub(crate) fn consume_name_constraint_comparison(&mut self) -> Result<(), Error> {
316
0
        self.name_constraint_comparisons = self
317
0
            .name_constraint_comparisons
318
0
            .checked_sub(1)
319
0
            .ok_or(Error::MaximumNameConstraintComparisonsExceeded)?;
320
0
        Ok(())
321
0
    }
322
}
323
324
impl Default for Budget {
325
0
    fn default() -> Self {
326
0
        Self {
327
0
            // This limit is taken from the remediation for golang CVE-2018-16875.  However,
328
0
            // note that golang subsequently implemented AKID matching due to this limit
329
0
            // being hit in real applications (see <https://github.com/spiffe/spire/issues/1004>).
330
0
            // So this may actually be too aggressive.
331
0
            signatures: 100,
332
0
333
0
            // This limit is taken from mozilla::pkix, see:
334
0
            // <https://github.com/nss-dev/nss/blob/bb4a1d38dd9e92923525ac6b5ed0288479f3f3fc/lib/mozpkix/lib/pkixbuild.cpp#L381-L393>
335
0
            build_chain_calls: 200_000,
336
0
337
0
            // This limit is taken from golang crypto/x509's default, see:
338
0
            // <https://github.com/golang/go/blob/ac17bb6f13979f2ab9fcd45f0758b43ed72d0973/src/crypto/x509/verify.go#L588-L592>
339
0
            name_constraint_comparisons: 250_000,
340
0
        }
341
0
    }
342
}
343
344
0
fn check_issuer_independent_properties(
345
0
    cert: &Cert<'_>,
346
0
    time: UnixTime,
347
0
    role: Role,
348
0
    sub_ca_count: usize,
349
0
    eku: ExtendedKeyUsage,
350
0
) -> Result<(), Error> {
351
    // TODO: check_distrust(trust_anchor_subject, trust_anchor_spki)?;
352
    // TODO: Check signature algorithm like mozilla::pkix.
353
    // TODO: Check SPKI like mozilla::pkix.
354
    // TODO: check for active distrust like mozilla::pkix.
355
356
    // For cert validation, we ignore the KeyUsage extension. For CA
357
    // certificates, BasicConstraints.cA makes KeyUsage redundant. Firefox
358
    // and other common browsers do not check KeyUsage for end-entities,
359
    // though it would be kind of nice to ensure that a KeyUsage without
360
    // the keyEncipherment bit could not be used for RSA key exchange.
361
362
0
    cert.validity
363
0
        .read_all(Error::BadDer, |value| check_validity(value, time))?;
364
0
    untrusted::read_all_optional(cert.basic_constraints, Error::BadDer, |value| {
365
0
        check_basic_constraints(value, role, sub_ca_count)
366
0
    })?;
367
0
    untrusted::read_all_optional(cert.eku, Error::BadDer, |value| eku.check(value))?;
368
369
0
    Ok(())
370
0
}
371
372
// https://tools.ietf.org/html/rfc5280#section-4.1.2.5
373
0
fn check_validity(input: &mut untrusted::Reader<'_>, time: UnixTime) -> Result<(), Error> {
374
0
    let not_before = UnixTime::from_der(input)?;
375
0
    let not_after = UnixTime::from_der(input)?;
376
377
0
    if not_before > not_after {
378
0
        return Err(Error::InvalidCertValidity);
379
0
    }
380
0
    if time < not_before {
381
0
        return Err(Error::CertNotValidYet);
382
0
    }
383
0
    if time > not_after {
384
0
        return Err(Error::CertExpired);
385
0
    }
386
387
    // TODO: mozilla::pkix allows the TrustDomain to check not_before and
388
    // not_after, to enforce things like a maximum validity period. We should
389
    // do something similar.
390
391
0
    Ok(())
392
0
}
393
394
// https://tools.ietf.org/html/rfc5280#section-4.2.1.9
395
0
fn check_basic_constraints(
396
0
    input: Option<&mut untrusted::Reader<'_>>,
397
0
    role: Role,
398
0
    sub_ca_count: usize,
399
0
) -> Result<(), Error> {
400
0
    let (is_ca, path_len_constraint) = match input {
401
0
        Some(input) => {
402
0
            let is_ca = bool::from_der(input)?;
403
404
            // https://bugzilla.mozilla.org/show_bug.cgi?id=985025: RFC 5280
405
            // says that a certificate must not have pathLenConstraint unless
406
            // it is a CA certificate, but some real-world end-entity
407
            // certificates have pathLenConstraint.
408
0
            let path_len_constraint = if !input.at_end() {
409
0
                Some(usize::from(u8::from_der(input)?))
410
            } else {
411
0
                None
412
            };
413
414
0
            (is_ca, path_len_constraint)
415
        }
416
0
        None => (false, None),
417
    };
418
419
0
    match (role, is_ca, path_len_constraint) {
420
0
        (Role::EndEntity, true, _) => Err(Error::CaUsedAsEndEntity),
421
0
        (Role::Issuer, false, _) => Err(Error::EndEntityUsedAsCa),
422
0
        (Role::Issuer, true, Some(len)) if sub_ca_count > len => {
423
0
            Err(Error::PathLenConstraintViolated)
424
        }
425
0
        _ => Ok(()),
426
    }
427
0
}
428
429
/// The expected key usage of a certificate.
430
///
431
/// This type represents the expected key usage of an end entity certificate. Although for most
432
/// kinds of certificates the extended key usage extension is optional (and so certificates
433
/// not carrying a particular value in the EKU extension are acceptable). If the extension
434
/// is present, the certificate MUST only be used for one of the purposes indicated.
435
///
436
/// <https://www.rfc-editor.org/rfc/rfc5280#section-4.2.1.12>
437
#[derive(Clone, Copy)]
438
pub struct KeyUsage {
439
    inner: ExtendedKeyUsage,
440
}
441
442
impl KeyUsage {
443
    /// Construct a new [`KeyUsage`] as appropriate for server certificate authentication.
444
    ///
445
    /// 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.
446
0
    pub const fn server_auth() -> Self {
447
0
        Self::required_if_present(EKU_SERVER_AUTH)
448
0
    }
449
450
    /// Construct a new [`KeyUsage`] as appropriate for client certificate authentication.
451
    ///
452
    /// As specified in <>, this does not require the certificate to specify the eKU extension.
453
0
    pub const fn client_auth() -> Self {
454
0
        Self::required_if_present(EKU_CLIENT_AUTH)
455
0
    }
456
457
    /// Construct a new [`KeyUsage`] requiring a certificate to support the specified OID.
458
0
    pub const fn required(oid: &'static [u8]) -> Self {
459
0
        Self {
460
0
            inner: ExtendedKeyUsage::Required(KeyPurposeId::new(oid)),
461
0
        }
462
0
    }
463
464
    /// Construct a new [`KeyUsage`] requiring a certificate to support the specified OID, if the certificate has EKUs.
465
0
    pub const fn required_if_present(oid: &'static [u8]) -> Self {
466
0
        Self {
467
0
            inner: ExtendedKeyUsage::RequiredIfPresent(KeyPurposeId::new(oid)),
468
0
        }
469
0
    }
470
}
471
472
/// Extended Key Usage (EKU) of a certificate.
473
#[derive(Clone, Copy)]
474
enum ExtendedKeyUsage {
475
    /// The certificate must contain the specified [`KeyPurposeId`] as EKU.
476
    Required(KeyPurposeId),
477
478
    /// If the certificate has EKUs, then the specified [`KeyPurposeId`] must be included.
479
    RequiredIfPresent(KeyPurposeId),
480
}
481
482
impl ExtendedKeyUsage {
483
    // https://tools.ietf.org/html/rfc5280#section-4.2.1.12
484
0
    fn check(&self, input: Option<&mut untrusted::Reader<'_>>) -> Result<(), Error> {
485
0
        let input = match (input, self) {
486
0
            (Some(input), _) => input,
487
0
            (None, Self::RequiredIfPresent(_)) => return Ok(()),
488
0
            (None, Self::Required(_)) => return Err(Error::RequiredEkuNotFound),
489
        };
490
491
        loop {
492
0
            let value = der::expect_tag(input, der::Tag::OID)?;
493
0
            if self.key_purpose_id_equals(value) {
494
0
                input.skip_to_end();
495
0
                break;
496
0
            }
497
498
0
            if input.at_end() {
499
0
                return Err(Error::RequiredEkuNotFound);
500
0
            }
501
        }
502
503
0
        Ok(())
504
0
    }
505
506
0
    fn key_purpose_id_equals(&self, value: untrusted::Input<'_>) -> bool {
507
0
        public_values_eq(
508
0
            match self {
509
0
                Self::Required(eku) => *eku,
510
0
                Self::RequiredIfPresent(eku) => *eku,
511
            }
512
            .oid_value,
513
0
            value,
514
        )
515
0
    }
516
}
517
518
/// An OID value indicating an Extended Key Usage (EKU) key purpose.
519
#[derive(Clone, Copy)]
520
struct KeyPurposeId {
521
    oid_value: untrusted::Input<'static>,
522
}
523
524
impl KeyPurposeId {
525
    /// Construct a new [`KeyPurposeId`].
526
    ///
527
    /// `oid` is the OBJECT IDENTIFIER in bytes.
528
0
    const fn new(oid: &'static [u8]) -> Self {
529
0
        Self {
530
0
            oid_value: untrusted::Input::from(oid),
531
0
        }
532
0
    }
533
}
534
535
impl PartialEq<Self> for KeyPurposeId {
536
0
    fn eq(&self, other: &Self) -> bool {
537
0
        public_values_eq(self.oid_value, other.oid_value)
538
0
    }
539
}
540
541
impl Eq for KeyPurposeId {}
542
543
// id-pkix            OBJECT IDENTIFIER ::= { 1 3 6 1 5 5 7 }
544
// id-kp              OBJECT IDENTIFIER ::= { id-pkix 3 }
545
546
// id-kp-serverAuth   OBJECT IDENTIFIER ::= { id-kp 1 }
547
const EKU_SERVER_AUTH: &[u8] = &oid!(1, 3, 6, 1, 5, 5, 7, 3, 1);
548
549
// id-kp-clientAuth   OBJECT IDENTIFIER ::= { id-kp 2 }
550
const EKU_CLIENT_AUTH: &[u8] = &oid!(1, 3, 6, 1, 5, 5, 7, 3, 2);
551
552
0
fn loop_while_non_fatal_error<'a, V: IntoIterator + 'a>(
553
0
    default_error: Error,
554
0
    values: V,
555
0
    mut f: impl FnMut(V::Item) -> Result<&'a TrustAnchor<'a>, ControlFlow<Error, Error>>,
556
0
) -> Result<&'a TrustAnchor<'a>, ControlFlow<Error, Error>> {
557
0
    let mut error = default_error;
558
0
    for v in values {
559
0
        match f(v) {
560
0
            Ok(anchor) => return Ok(anchor),
561
            // Fatal errors should halt further looping.
562
0
            res @ Err(ControlFlow::Break(_)) => return res,
563
            // Non-fatal errors should be ranked by specificity and only returned
564
            // once all other path-building options have been exhausted.
565
0
            Err(ControlFlow::Continue(new_error)) => error = error.most_specific(new_error),
566
        }
567
    }
568
0
    Err(error.into())
569
0
}
Unexecuted instantiation: webpki::verify_cert::loop_while_non_fatal_error::<&[rustls_pki_types::TrustAnchor], <webpki::verify_cert::ChainOptions>::build_chain_inner::{closure#0}>
Unexecuted instantiation: webpki::verify_cert::loop_while_non_fatal_error::<&[rustls_pki_types::CertificateDer], <webpki::verify_cert::ChainOptions>::build_chain_inner::{closure#1}>
570
571
/// A path for consideration in path building.
572
///
573
/// This represents a partial path because it does not yet contain the trust anchor. It stores
574
/// the end-entity certificates, and an array of intermediate certificates.
575
pub(crate) struct PartialPath<'a> {
576
    end_entity: &'a EndEntityCert<'a>,
577
    /// Intermediate certificates, in order from end-entity to trust anchor.
578
    ///
579
    /// Invariant: all values below `used` are `Some`.
580
    intermediates: [Option<Cert<'a>>; MAX_SUB_CA_COUNT],
581
    /// The number of `Some` values in `intermediates`.
582
    ///
583
    /// The next `Cert` passed to `push()` will be placed at `intermediates[used]`.
584
    /// If this value is 0, the path contains only the end-entity certificate.
585
    used: usize,
586
}
587
588
impl<'a> PartialPath<'a> {
589
0
    pub(crate) fn new(end_entity: &'a EndEntityCert<'a>) -> Self {
590
0
        Self {
591
0
            end_entity,
592
0
            intermediates: Default::default(),
593
0
            used: 0,
594
0
        }
595
0
    }
596
597
0
    pub(crate) fn push(&mut self, cert: Cert<'a>) -> Result<(), ControlFlow<Error, Error>> {
598
0
        if self.used >= MAX_SUB_CA_COUNT {
599
0
            return Err(Error::MaximumPathDepthExceeded.into());
600
0
        }
601
602
0
        self.intermediates[self.used] = Some(cert);
603
0
        self.used += 1;
604
0
        Ok(())
605
0
    }
606
607
0
    fn pop(&mut self) {
608
0
        debug_assert!(self.used > 0);
609
0
        if self.used == 0 {
610
0
            return;
611
0
        }
612
613
0
        self.used -= 1;
614
0
        self.intermediates[self.used] = None;
615
0
    }
616
617
0
    pub(crate) fn node(&self) -> PathNode<'_> {
618
0
        PathNode {
619
0
            path: self,
620
0
            index: self.used,
621
0
            cert: self.head(),
622
0
        }
623
0
    }
624
625
    /// Current head of the path.
626
0
    pub(crate) fn head(&self) -> &Cert<'a> {
627
0
        self.get(self.used)
628
0
    }
629
630
    /// Get the certificate at index `idx` in the path.
631
    ///
632
    // `idx` must be in the range `0..=self.used`; `idx` 0 thus yields the `end_entity`,
633
    // while subsequent indexes yield the intermediate at `self.intermediates[idx - 1]`.
634
0
    fn get(&self, idx: usize) -> &Cert<'a> {
635
0
        match idx {
636
0
            0 => self.end_entity,
637
0
            _ => self.intermediates[idx - 1].as_ref().unwrap(),
638
        }
639
0
    }
640
}
641
642
const MAX_SUB_CA_COUNT: usize = 6;
643
644
pub(crate) struct PathNode<'a> {
645
    /// The path we're iterating.
646
    path: &'a PartialPath<'a>,
647
    /// The index of the current node in the path (input for `path.get()`).
648
    index: usize,
649
    /// The [`Cert`] at `index`.
650
    pub(crate) cert: &'a Cert<'a>,
651
}
652
653
impl<'a> PathNode<'a> {
654
0
    pub(crate) fn iter(&self) -> PathIter<'a> {
655
0
        PathIter {
656
0
            path: self.path,
657
0
            next: Some(self.index),
658
0
        }
659
0
    }
660
661
0
    pub(crate) fn role(&self) -> Role {
662
0
        match self.index {
663
0
            0 => Role::EndEntity,
664
0
            _ => Role::Issuer,
665
        }
666
0
    }
667
}
668
669
pub(crate) struct PathIter<'a> {
670
    path: &'a PartialPath<'a>,
671
    next: Option<usize>,
672
}
673
674
impl<'a> Iterator for PathIter<'a> {
675
    type Item = PathNode<'a>;
676
677
0
    fn next(&mut self) -> Option<Self::Item> {
678
0
        let next = self.next?;
679
0
        self.next = match next {
680
0
            0 => None,
681
0
            _ => Some(next - 1),
682
        };
683
684
0
        Some(PathNode {
685
0
            path: self.path,
686
0
            index: next,
687
0
            cert: self.path.get(next),
688
0
        })
689
0
    }
690
}
691
692
#[derive(Clone, Copy, PartialEq)]
693
pub(crate) enum Role {
694
    Issuer,
695
    EndEntity,
696
}
697
698
#[cfg(all(test, feature = "alloc", any(feature = "ring", feature = "aws_lc_rs")))]
699
mod tests {
700
    use super::*;
701
    use crate::test_utils;
702
    use crate::test_utils::{issuer_params, make_end_entity, make_issuer};
703
    use crate::trust_anchor::anchor_from_trusted_cert;
704
    use rcgen::{CertifiedKey, KeyPair};
705
    use std::dbg;
706
    use std::prelude::v1::*;
707
708
    #[test]
709
    fn eku_key_purpose_id() {
710
        assert!(
711
            ExtendedKeyUsage::RequiredIfPresent(KeyPurposeId::new(EKU_SERVER_AUTH))
712
                .key_purpose_id_equals(KeyPurposeId::new(EKU_SERVER_AUTH).oid_value)
713
        )
714
    }
715
716
    #[test]
717
    fn test_too_many_signatures() {
718
        assert!(matches!(
719
            build_and_verify_degenerate_chain(5, ChainTrustAnchor::NotInChain),
720
            ControlFlow::Break(Error::MaximumSignatureChecksExceeded)
721
        ));
722
    }
723
724
    #[test]
725
    fn test_too_many_path_calls() {
726
        assert!(matches!(
727
            dbg!(build_and_verify_degenerate_chain(
728
                10,
729
                ChainTrustAnchor::InChain
730
            )),
731
            ControlFlow::Break(Error::MaximumPathBuildCallsExceeded)
732
        ));
733
    }
734
735
    #[test]
736
    fn longest_allowed_path() {
737
        assert!(build_and_verify_linear_chain(1).is_ok());
738
        assert!(build_and_verify_linear_chain(2).is_ok());
739
        assert!(build_and_verify_linear_chain(3).is_ok());
740
        assert!(build_and_verify_linear_chain(4).is_ok());
741
        assert!(build_and_verify_linear_chain(5).is_ok());
742
        assert!(build_and_verify_linear_chain(6).is_ok());
743
    }
744
745
    #[test]
746
    fn path_too_long() {
747
        assert!(matches!(
748
            build_and_verify_linear_chain(7),
749
            Err(ControlFlow::Continue(Error::MaximumPathDepthExceeded))
750
        ));
751
    }
752
753
    #[test]
754
    fn name_constraint_budget() {
755
        // Issue a trust anchor that imposes name constraints. The constraint should match
756
        // the end entity certificate SAN.
757
        let mut ca_cert_params = issuer_params("Constrained Root");
758
        ca_cert_params.name_constraints = Some(rcgen::NameConstraints {
759
            permitted_subtrees: vec![rcgen::GeneralSubtree::DnsName(".com".into())],
760
            excluded_subtrees: vec![],
761
        });
762
        let ca_key_pair = KeyPair::generate_for(test_utils::RCGEN_SIGNATURE_ALG).unwrap();
763
        let ca_cert = ca_cert_params.self_signed(&ca_key_pair).unwrap();
764
765
        // Create a series of intermediate issuers. We'll only use one in the actual built path,
766
        // helping demonstrate that the name constraint budget is not expended checking certificates
767
        // that are not part of the path we compute.
768
        let mut intermediates = Vec::with_capacity(5);
769
        for i in 0..5 {
770
            let intermediate = issuer_params(format!("Intermediate {i}"));
771
            let intermediate_key_pair =
772
                KeyPair::generate_for(test_utils::RCGEN_SIGNATURE_ALG).unwrap();
773
            // Each intermediate should be issued by the trust anchor.
774
            let intermediate = intermediate
775
                .signed_by(&intermediate_key_pair, &ca_cert, &ca_key_pair)
776
                .unwrap();
777
            intermediates.push((intermediate, intermediate_key_pair));
778
        }
779
780
        // Create an end-entity cert that is issued by the last of the intermediates.
781
        let last_issuer = intermediates.last().unwrap();
782
        let ee_cert = make_end_entity(&last_issuer.0, &last_issuer.1);
783
        let ee_cert = EndEntityCert::try_from(ee_cert.cert.der()).unwrap();
784
785
        // We use a custom budget to make it easier to write a test, otherwise it is tricky to
786
        // stuff enough names/constraints into the potential chains while staying within the path
787
        // depth limit and the build chain call limit.
788
        let passing_budget = Budget {
789
            // One comparison against the intermediate's distinguished name.
790
            // One comparison against the EE's distinguished name.
791
            // One comparison against the EE's SAN.
792
            //  = 3 total comparisons.
793
            name_constraint_comparisons: 3,
794
            ..Budget::default()
795
        };
796
797
        let ca_cert_der = ca_cert.into();
798
        let anchors = &[anchor_from_trusted_cert(&ca_cert_der).unwrap()];
799
        let intermediates_der = intermediates
800
            .iter()
801
            .map(|(cert, _)| cert.der().clone())
802
            .collect::<Vec<_>>();
803
804
        // Validation should succeed with the name constraint comparison budget allocated above.
805
        // This shows that we're not consuming budget on unused intermediates: we didn't budget
806
        // enough comparisons for that to pass the overall chain building.
807
        let path = verify_chain(
808
            anchors,
809
            &intermediates_der,
810
            &ee_cert,
811
            None,
812
            Some(passing_budget),
813
        )
814
        .unwrap();
815
        assert_eq!(path.anchor().subject, anchors.first().unwrap().subject);
816
817
        let failing_budget = Budget {
818
            // See passing_budget: 2 comparisons is not sufficient.
819
            name_constraint_comparisons: 2,
820
            ..Budget::default()
821
        };
822
        // Validation should fail when the budget is smaller than the number of comparisons performed
823
        // on the validated path. This demonstrates we properly fail path building when too many
824
        // name constraint comparisons occur.
825
        let result = verify_chain(
826
            anchors,
827
            &intermediates_der,
828
            &ee_cert,
829
            None,
830
            Some(failing_budget),
831
        );
832
833
        assert!(matches!(
834
            result,
835
            Err(ControlFlow::Break(
836
                Error::MaximumNameConstraintComparisonsExceeded
837
            ))
838
        ));
839
    }
840
841
    #[test]
842
    fn test_reject_candidate_path() {
843
        /*
844
         This test builds a PKI like the following diagram depicts. We first verify
845
         that we can build a path EE -> B -> A -> TA. Next we supply a custom path verification
846
         function that rejects the B->A path, and verify that we build a path EE -> B -> C -> TA.
847
848
               ┌───────────┐
849
               │           │
850
               │     TA    │
851
               │           │
852
               └───┬───┬───┘
853
                   │   │
854
                   │   │
855
        ┌────────┐◄┘   └──►┌────────┐
856
        │        │         │        │
857
        │   A    │         │   C    │
858
        │        │         │        │
859
        └────┬───┘         └───┬────┘
860
             │                 │
861
             │                 │
862
             │   ┌─────────┐   │
863
             └──►│         │◄──┘
864
                 │    B    │
865
                 │         │
866
                 └────┬────┘
867
868
869
870
                 ┌────▼────┐
871
                 │         │
872
                 │    EE   │
873
                 │         │
874
                 └─────────┘
875
          */
876
877
        // Create a trust anchor, and use it to issue two distinct intermediate certificates, each
878
        // with a unique subject and keypair.
879
        let trust_anchor = make_issuer("Trust Anchor");
880
        let trust_anchor_cert =
881
            Cert::from_der(untrusted::Input::from(trust_anchor.cert.der())).unwrap();
882
        let trust_anchors = &[anchor_from_trusted_cert(trust_anchor.cert.der()).unwrap()];
883
884
        let intermediate_a = issuer_params("Intermediate A");
885
        let intermediate_a_kp = KeyPair::generate_for(test_utils::RCGEN_SIGNATURE_ALG).unwrap();
886
        let intermediate_a = intermediate_a
887
            .signed_by(
888
                &intermediate_a_kp,
889
                &trust_anchor.cert,
890
                &trust_anchor.key_pair,
891
            )
892
            .unwrap();
893
        let intermediate_a_cert =
894
            Cert::from_der(untrusted::Input::from(intermediate_a.der())).unwrap();
895
896
        let intermediate_c = issuer_params("Intermediate C");
897
        let intermediate_c_kp = KeyPair::generate_for(test_utils::RCGEN_SIGNATURE_ALG).unwrap();
898
        let intermediate_c = intermediate_c
899
            .signed_by(
900
                &intermediate_c_kp,
901
                &trust_anchor.cert,
902
                &trust_anchor.key_pair,
903
            )
904
            .unwrap();
905
        let intermediate_c_cert =
906
            Cert::from_der(untrusted::Input::from(intermediate_c.der())).unwrap();
907
908
        // Next, create an intermediate that is issued by both of the intermediates above.
909
        // Both should share the same subject, and key pair, but will differ in the issuer.
910
        let intermediate_b_key = KeyPair::generate_for(test_utils::RCGEN_SIGNATURE_ALG).unwrap();
911
        let intermediate_b_params = issuer_params("Intermediate");
912
        let intermediate_b_a = intermediate_b_params
913
            .clone()
914
            .signed_by(&intermediate_b_key, &intermediate_a, &intermediate_a_kp)
915
            .unwrap();
916
        let intermediate_b_c = intermediate_b_params
917
            .signed_by(&intermediate_b_key, &intermediate_c, &intermediate_c_kp)
918
            .unwrap();
919
920
        let intermediates = &[
921
            intermediate_a.der().clone(),
922
            intermediate_c.der().clone(),
923
            intermediate_b_a.der().clone(),
924
            intermediate_b_c.der().clone(),
925
        ];
926
927
        // Create an end entity certificate signed by the keypair of the intermediates created above.
928
        let ee = make_end_entity(&intermediate_b_a, &intermediate_b_key);
929
        let ee_cert = &EndEntityCert::try_from(ee.cert.der()).unwrap();
930
931
        // We should be able to create a valid path from EE to trust anchor.
932
        let path = verify_chain(trust_anchors, intermediates, ee_cert, None, None).unwrap();
933
        let path_intermediates = path.intermediate_certificates().collect::<Vec<_>>();
934
935
        // We expect that without applying any additional constraints, that the path will be
936
        // EE -> intermediate_b_a -> intermediate_a -> trust_anchor.
937
        assert_eq!(path_intermediates.len(), 2);
938
        assert_eq!(
939
            path_intermediates[0].issuer(),
940
            intermediate_a_cert.subject()
941
        );
942
        assert_eq!(path_intermediates[1].issuer(), trust_anchor_cert.subject());
943
944
        // Now, we'll create a function that will reject the intermediate_b_a path.
945
        let expected_chain = |path: &VerifiedPath<'_>| {
946
            for intermediate in path.intermediate_certificates() {
947
                // Reject any intermediates issued by intermediate A.
948
                if intermediate.issuer() == intermediate_a_cert.subject() {
949
                    return Err(Error::UnknownIssuer);
950
                }
951
            }
952
953
            Ok(())
954
        };
955
956
        // We should still be able to build a valid path.
957
        let path = verify_chain(
958
            trust_anchors,
959
            intermediates,
960
            ee_cert,
961
            Some(&expected_chain),
962
            None,
963
        )
964
        .unwrap();
965
        let path_intermediates = path.intermediate_certificates().collect::<Vec<_>>();
966
967
        // We expect that the path will now be
968
        // EE -> intermediate_b_c -> intermediate_c -> trust_anchor.
969
        assert_eq!(path_intermediates.len(), 2);
970
        assert_eq!(
971
            path_intermediates[0].issuer(),
972
            intermediate_c_cert.subject()
973
        );
974
        assert_eq!(path_intermediates[1].issuer(), trust_anchor_cert.subject());
975
    }
976
977
    fn build_and_verify_degenerate_chain(
978
        intermediate_count: usize,
979
        trust_anchor: ChainTrustAnchor,
980
    ) -> ControlFlow<Error, Error> {
981
        let ca_cert = make_issuer("Bogus Subject");
982
        let mut intermediate_chain = build_linear_chain(&ca_cert, intermediate_count, true);
983
984
        let verify_trust_anchor = match trust_anchor {
985
            ChainTrustAnchor::InChain => make_issuer("Bogus Trust Anchor"),
986
            ChainTrustAnchor::NotInChain => ca_cert,
987
        };
988
989
        let ee_cert = make_end_entity(
990
            &intermediate_chain.last_issuer.cert,
991
            &intermediate_chain.last_issuer.key_pair,
992
        );
993
        let ee_cert = EndEntityCert::try_from(ee_cert.cert.der()).unwrap();
994
        let trust_anchor_der: CertificateDer<'_> = verify_trust_anchor.cert.into();
995
        let webpki_ta = anchor_from_trusted_cert(&trust_anchor_der).unwrap();
996
        if matches!(trust_anchor, ChainTrustAnchor::InChain) {
997
            // Note: we clone the trust anchor DER here because we can't move it into the chain
998
            // as it's loaned to webpki_ta above.
999
            intermediate_chain.chain.insert(0, trust_anchor_der.clone())
1000
        }
1001
1002
        verify_chain(
1003
            &[webpki_ta],
1004
            &intermediate_chain.chain,
1005
            &ee_cert,
1006
            None,
1007
            None,
1008
        )
1009
        .map(|_| ())
1010
        .unwrap_err()
1011
    }
1012
1013
    #[cfg(feature = "alloc")]
1014
    enum ChainTrustAnchor {
1015
        NotInChain,
1016
        InChain,
1017
    }
1018
1019
    fn build_and_verify_linear_chain(chain_length: usize) -> Result<(), ControlFlow<Error, Error>> {
1020
        let ca_cert = make_issuer(format!("Bogus Subject {chain_length}"));
1021
        let intermediate_chain = build_linear_chain(&ca_cert, chain_length, false);
1022
1023
        let ca_cert_der: CertificateDer<'_> = ca_cert.cert.into();
1024
        let anchor = anchor_from_trusted_cert(&ca_cert_der).unwrap();
1025
        let anchors = &[anchor.clone()];
1026
1027
        let ee_cert = make_end_entity(
1028
            &intermediate_chain.last_issuer.cert,
1029
            &intermediate_chain.last_issuer.key_pair,
1030
        );
1031
        let ee_cert = EndEntityCert::try_from(ee_cert.cert.der()).unwrap();
1032
1033
        let expected_chain = |path: &VerifiedPath<'_>| {
1034
            assert_eq!(path.anchor().subject, anchor.subject);
1035
            assert!(public_values_eq(path.end_entity().subject, ee_cert.subject));
1036
            assert_eq!(path.intermediate_certificates().count(), chain_length);
1037
1038
            let intermediate_certs = intermediate_chain
1039
                .chain
1040
                .iter()
1041
                .map(|der| Cert::from_der(untrusted::Input::from(der)).unwrap())
1042
                .collect::<Vec<_>>();
1043
1044
            for (cert, expected) in path
1045
                .intermediate_certificates()
1046
                .rev()
1047
                .zip(intermediate_certs.iter())
1048
            {
1049
                assert!(public_values_eq(cert.subject, expected.subject));
1050
                assert_eq!(cert.der(), expected.der());
1051
            }
1052
1053
            for (cert, expected) in path
1054
                .intermediate_certificates()
1055
                .zip(intermediate_certs.iter().rev())
1056
            {
1057
                assert!(public_values_eq(cert.subject, expected.subject));
1058
                assert_eq!(cert.der(), expected.der());
1059
            }
1060
1061
            Ok(())
1062
        };
1063
1064
        verify_chain(
1065
            anchors,
1066
            &intermediate_chain.chain,
1067
            &ee_cert,
1068
            Some(&expected_chain),
1069
            None,
1070
        )
1071
        .map(|_| ())
1072
    }
1073
1074
    fn build_linear_chain(
1075
        ca_cert: &CertifiedKey,
1076
        chain_length: usize,
1077
        all_same_subject: bool,
1078
    ) -> IntermediateChain {
1079
        let mut chain = Vec::with_capacity(chain_length);
1080
1081
        let mut prev = None;
1082
        for i in 0..chain_length {
1083
            let issuer = match &prev {
1084
                Some(prev) => prev,
1085
                None => ca_cert,
1086
            };
1087
1088
            let intermediate = issuer_params(match all_same_subject {
1089
                true => "Bogus Subject".to_string(),
1090
                false => format!("Bogus Subject {i}"),
1091
            });
1092
1093
            let key_pair = KeyPair::generate_for(test_utils::RCGEN_SIGNATURE_ALG).unwrap();
1094
            let cert = intermediate
1095
                .signed_by(&key_pair, &issuer.cert, &issuer.key_pair)
1096
                .unwrap();
1097
1098
            chain.push(cert.der().clone());
1099
            prev = Some(CertifiedKey { cert, key_pair });
1100
        }
1101
1102
        IntermediateChain {
1103
            last_issuer: prev.unwrap(),
1104
            chain,
1105
        }
1106
    }
1107
1108
    struct IntermediateChain {
1109
        last_issuer: CertifiedKey,
1110
        chain: Vec<CertificateDer<'static>>,
1111
    }
1112
1113
    fn verify_chain<'a>(
1114
        trust_anchors: &'a [TrustAnchor<'a>],
1115
        intermediate_certs: &'a [CertificateDer<'a>],
1116
        ee_cert: &'a EndEntityCert<'a>,
1117
        verify_path: Option<&dyn Fn(&VerifiedPath<'_>) -> Result<(), Error>>,
1118
        budget: Option<Budget>,
1119
    ) -> Result<VerifiedPath<'a>, ControlFlow<Error, Error>> {
1120
        use core::time::Duration;
1121
1122
        let time = UnixTime::since_unix_epoch(Duration::from_secs(0x1fed_f00d));
1123
        let mut path = PartialPath::new(ee_cert);
1124
        let opts = ChainOptions {
1125
            eku: KeyUsage::server_auth(),
1126
            supported_sig_algs: crate::ALL_VERIFICATION_ALGS,
1127
            trust_anchors,
1128
            intermediate_certs,
1129
            revocation: None,
1130
        };
1131
1132
        match opts.build_chain_inner(
1133
            &mut path,
1134
            time,
1135
            verify_path,
1136
            0,
1137
            &mut budget.unwrap_or_default(),
1138
        ) {
1139
            Ok(anchor) => Ok(VerifiedPath::new(ee_cert, anchor, path)),
1140
            Err(err) => Err(err),
1141
        }
1142
    }
1143
}