webpki/
error.rs

1// Copyright 2015 Brian Smith.
2//
3// Permission to use, copy, modify, and/or distribute this software for any
4// purpose with or without fee is hereby granted, provided that the above
5// copyright notice and this permission notice appear in all copies.
6//
7// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
8// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
10// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
13// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14
15#[cfg(feature = "alloc")]
16use alloc::string::String;
17#[cfg(feature = "alloc")]
18use alloc::vec::Vec;
19use core::fmt;
20use core::ops::ControlFlow;
21
22use pki_types::UnixTime;
23#[cfg(feature = "alloc")]
24use pki_types::{AlgorithmIdentifier, ServerName};
25
26use crate::verify_cert::RequiredEkuNotFoundContext;
27
28/// An error that occurs during certificate validation or name validation.
29#[derive(Clone, Debug, PartialEq, Eq)]
30#[non_exhaustive]
31pub enum Error {
32    /// The encoding of some ASN.1 DER-encoded item is invalid.
33    BadDer,
34
35    /// The encoding of an ASN.1 DER-encoded time is invalid.
36    BadDerTime,
37
38    /// A CA certificate is being used as an end-entity certificate.
39    CaUsedAsEndEntity,
40
41    /// The certificate is expired; i.e. the time it is being validated for is
42    /// later than the certificate's notAfter time.
43    CertExpired {
44        /// The validation time.
45        time: UnixTime,
46        /// The notAfter time of the certificate.
47        not_after: UnixTime,
48    },
49
50    /// The certificate is not valid for the name it is being validated for.
51    CertNotValidForName(InvalidNameContext),
52
53    /// The certificate is not valid yet; i.e. the time it is being validated
54    /// for is earlier than the certificate's notBefore time.
55    CertNotValidYet {
56        /// The validation time.
57        time: UnixTime,
58        /// The notBefore time of the certificate.
59        not_before: UnixTime,
60    },
61
62    /// The certificate, or one of its issuers, has been revoked.
63    CertRevoked,
64
65    /// The CRL is expired; i.e. the verification time is not before the time
66    /// in the CRL nextUpdate field.
67    CrlExpired {
68        /// The validation time.
69        time: UnixTime,
70        /// The nextUpdate time of the CRL.
71        next_update: UnixTime,
72    },
73
74    /// An end-entity certificate is being used as a CA certificate.
75    EndEntityUsedAsCa,
76
77    /// An X.509 extension is invalid.
78    ExtensionValueInvalid,
79
80    /// The certificate validity period (notBefore, notAfter) is invalid; e.g.
81    /// the notAfter time is earlier than the notBefore time.
82    InvalidCertValidity,
83
84    /// A CRL number extension was invalid:
85    ///  - it was mis-encoded
86    ///  - it was negative
87    ///  - it was too long
88    InvalidCrlNumber,
89
90    /// A iPAddress name constraint was invalid:
91    /// - it had a sparse network mask (ie, cannot be written in CIDR form).
92    /// - it was too long or short
93    InvalidNetworkMaskConstraint,
94
95    /// A serial number was invalid:
96    ///  - it was misencoded
97    ///  - it was negative
98    ///  - it was too long
99    InvalidSerialNumber,
100
101    /// The CRL signature is invalid for the issuer's public key.
102    InvalidCrlSignatureForPublicKey,
103
104    /// The signature is invalid for the given public key.
105    InvalidSignatureForPublicKey,
106
107    /// A CRL was signed by an issuer that has a KeyUsage bitstring that does not include
108    /// the cRLSign key usage bit.
109    IssuerNotCrlSigner,
110
111    /// A presented or reference DNS identifier was malformed, potentially
112    /// containing invalid characters or invalid labels.
113    MalformedDnsIdentifier,
114
115    /// The certificate extensions are malformed.
116    ///
117    /// In particular, webpki requires the DNS name(s) be in the subjectAltName
118    /// extension as required by the CA/Browser Forum Baseline Requirements
119    /// and as recommended by RFC6125.
120    MalformedExtensions,
121
122    /// A name constraint was malformed, potentially containing invalid characters or
123    /// invalid labels.
124    MalformedNameConstraint,
125
126    /// The maximum number of name constraint comparisons has been reached.
127    MaximumNameConstraintComparisonsExceeded,
128
129    /// The maximum number of internal path building calls has been reached. Path complexity is too great.
130    MaximumPathBuildCallsExceeded,
131
132    /// The path search was terminated because it became too deep.
133    MaximumPathDepthExceeded,
134
135    /// The maximum number of signature checks has been reached. Path complexity is too great.
136    MaximumSignatureChecksExceeded,
137
138    /// The certificate violates one or more name constraints.
139    NameConstraintViolation,
140
141    /// The certificate violates one or more path length constraints.
142    PathLenConstraintViolated,
143
144    /// The certificate is not valid for the Extended Key Usage for which it is
145    /// being validated.
146    #[deprecated(since = "0.103.2", note = "use RequiredEkuNotFoundContext instead")]
147    RequiredEkuNotFound,
148
149    /// The certificate is not valid for the Extended Key Usage for which it is
150    /// being validated.
151    RequiredEkuNotFoundContext(RequiredEkuNotFoundContext),
152
153    /// The algorithm in the TBSCertificate "signature" field of a certificate
154    /// does not match the algorithm in the signature of the certificate.
155    SignatureAlgorithmMismatch,
156
157    /// Trailing data was found while parsing DER-encoded input for the named type.
158    TrailingData(DerTypeId),
159
160    /// A valid issuer for the certificate could not be found.
161    UnknownIssuer,
162
163    /// The certificate's revocation status could not be determined.
164    UnknownRevocationStatus,
165
166    /// The certificate is not a v3 X.509 certificate.
167    ///
168    /// This error may be also reported if the certificate version field
169    /// is malformed.
170    UnsupportedCertVersion,
171
172    /// The certificate contains an unsupported critical extension.
173    UnsupportedCriticalExtension,
174
175    /// The CRL contains an issuing distribution point with no distribution point name,
176    /// or a distribution point name relative to an issuer.
177    UnsupportedCrlIssuingDistributionPoint,
178
179    /// The CRL is not a v2 X.509 CRL.
180    ///
181    /// The RFC 5280 web PKI profile mandates only version 2 be used. See section
182    /// 5.1.2.1 for more information.
183    ///
184    /// This error may also be reported if the CRL version field is malformed.
185    UnsupportedCrlVersion,
186
187    /// The CRL is an unsupported "delta" CRL.
188    UnsupportedDeltaCrl,
189
190    /// The CRL contains unsupported "indirect" entries.
191    UnsupportedIndirectCrl,
192
193    /// The `ServerName` contained an unsupported type of value.
194    UnsupportedNameType,
195
196    /// The revocation reason is not in the set of supported revocation reasons.
197    UnsupportedRevocationReason,
198
199    /// The CRL is partitioned by revocation reasons.
200    UnsupportedRevocationReasonsPartitioning,
201
202    /// The signature algorithm for a signature over a CRL is not in the set of supported
203    /// signature algorithms given.
204    #[deprecated(
205        since = "0.103.4",
206        note = "use UnsupportedCrlSignatureAlgorithmContext instead"
207    )]
208    UnsupportedCrlSignatureAlgorithm,
209
210    /// The signature algorithm for a signature is not in the set of supported
211    /// signature algorithms given.
212    UnsupportedCrlSignatureAlgorithmContext(UnsupportedSignatureAlgorithmContext),
213
214    /// The signature algorithm for a signature is not in the set of supported
215    /// signature algorithms given.
216    #[deprecated(
217        since = "0.103.4",
218        note = "use UnsupportedSignatureAlgorithmContext instead"
219    )]
220    UnsupportedSignatureAlgorithm,
221
222    /// The signature algorithm for a signature is not in the set of supported
223    /// signature algorithms given.
224    UnsupportedSignatureAlgorithmContext(UnsupportedSignatureAlgorithmContext),
225
226    /// The CRL signature's algorithm does not match the algorithm of the issuer
227    /// public key it is being validated for. This may be because the public key
228    /// algorithm's OID isn't recognized (e.g. DSA), or the public key
229    /// algorithm's parameters don't match the supported parameters for that
230    /// algorithm (e.g. ECC keys for unsupported curves), or the public key
231    /// algorithm and the signature algorithm simply don't match (e.g.
232    /// verifying an RSA signature with an ECC public key).
233    #[deprecated(
234        since = "0.103.4",
235        note = "use UnsupportedCrlSignatureAlgorithmForPublicKeyContext instead"
236    )]
237    UnsupportedCrlSignatureAlgorithmForPublicKey,
238
239    /// The signature's algorithm does not match the algorithm of the public
240    /// key it is being validated for. This may be because the public key
241    /// algorithm's OID isn't recognized (e.g. DSA), or the public key
242    /// algorithm's parameters don't match the supported parameters for that
243    /// algorithm (e.g. ECC keys for unsupported curves), or the public key
244    /// algorithm and the signature algorithm simply don't match (e.g.
245    /// verifying an RSA signature with an ECC public key).
246    UnsupportedCrlSignatureAlgorithmForPublicKeyContext(
247        UnsupportedSignatureAlgorithmForPublicKeyContext,
248    ),
249
250    /// The signature's algorithm does not match the algorithm of the public
251    /// key it is being validated for. This may be because the public key
252    /// algorithm's OID isn't recognized (e.g. DSA), or the public key
253    /// algorithm's parameters don't match the supported parameters for that
254    /// algorithm (e.g. ECC keys for unsupported curves), or the public key
255    /// algorithm and the signature algorithm simply don't match (e.g.
256    /// verifying an RSA signature with an ECC public key).
257    #[deprecated(
258        since = "0.103.4",
259        note = "use UnsupportedSignatureAlgorithmForPublicKeyContext instead"
260    )]
261    UnsupportedSignatureAlgorithmForPublicKey,
262
263    /// The signature's algorithm does not match the algorithm of the public
264    /// key it is being validated for. This may be because the public key
265    /// algorithm's OID isn't recognized (e.g. DSA), or the public key
266    /// algorithm's parameters don't match the supported parameters for that
267    /// algorithm (e.g. ECC keys for unsupported curves), or the public key
268    /// algorithm and the signature algorithm simply don't match (e.g.
269    /// verifying an RSA signature with an ECC public key).
270    UnsupportedSignatureAlgorithmForPublicKeyContext(
271        UnsupportedSignatureAlgorithmForPublicKeyContext,
272    ),
273}
274
275impl Error {
276    // Compare the Error with the new error by rank, returning the higher rank of the two as
277    // the most specific error.
278    pub(crate) fn most_specific(self, new: Self) -> Self {
279        // Assign an error a numeric value ranking it by specificity.
280        if self.rank() >= new.rank() { self } else { new }
281    }
282
283    // Return a numeric indication of how specific the error is, where an error with a higher rank
284    // is considered more useful to an end user than an error with a lower rank. This is used by
285    // Error::most_specific to compare two errors in order to return which is more specific.
286    #[allow(clippy::as_conversions)] // We won't exceed u32 errors.
287    pub(crate) fn rank(&self) -> u32 {
288        match &self {
289            // Errors related to certificate validity
290            Self::CertNotValidYet { .. } | Self::CertExpired { .. } => 290,
291            Self::CertNotValidForName(_) => 280,
292            Self::CertRevoked | Self::UnknownRevocationStatus | Self::CrlExpired { .. } => 270,
293            Self::InvalidCrlSignatureForPublicKey | Self::InvalidSignatureForPublicKey => 260,
294            Self::SignatureAlgorithmMismatch => 250,
295            #[allow(deprecated)]
296            Self::RequiredEkuNotFound | Self::RequiredEkuNotFoundContext(_) => 240,
297            Self::NameConstraintViolation => 230,
298            Self::PathLenConstraintViolated => 220,
299            Self::CaUsedAsEndEntity | Self::EndEntityUsedAsCa => 210,
300            Self::IssuerNotCrlSigner => 200,
301
302            // Errors related to supported features used in an invalid way.
303            Self::InvalidCertValidity => 190,
304            Self::InvalidNetworkMaskConstraint => 180,
305            Self::InvalidSerialNumber => 170,
306            Self::InvalidCrlNumber => 160,
307
308            // Errors related to unsupported features.
309            #[allow(deprecated)]
310            Self::UnsupportedCrlSignatureAlgorithmForPublicKey
311            | Self::UnsupportedCrlSignatureAlgorithmForPublicKeyContext(_)
312            | Self::UnsupportedSignatureAlgorithmForPublicKey
313            | Self::UnsupportedSignatureAlgorithmForPublicKeyContext(_) => 150,
314            #[allow(deprecated)]
315            Self::UnsupportedCrlSignatureAlgorithm
316            | Self::UnsupportedCrlSignatureAlgorithmContext(_)
317            | Self::UnsupportedSignatureAlgorithm
318            | Self::UnsupportedSignatureAlgorithmContext(_) => 140,
319            Self::UnsupportedCriticalExtension => 130,
320            Self::UnsupportedCertVersion => 130,
321            Self::UnsupportedCrlVersion => 120,
322            Self::UnsupportedDeltaCrl => 110,
323            Self::UnsupportedIndirectCrl => 100,
324            Self::UnsupportedNameType => 95,
325            Self::UnsupportedRevocationReason => 90,
326            Self::UnsupportedRevocationReasonsPartitioning => 80,
327            Self::UnsupportedCrlIssuingDistributionPoint => 70,
328            Self::MaximumPathDepthExceeded => 61,
329
330            // Errors related to malformed data.
331            Self::MalformedDnsIdentifier => 60,
332            Self::MalformedNameConstraint => 50,
333            Self::MalformedExtensions | Self::TrailingData(_) => 40,
334            Self::ExtensionValueInvalid => 30,
335
336            // Generic DER errors.
337            Self::BadDerTime => 20,
338            Self::BadDer => 10,
339
340            // Special case errors - not subject to ranking.
341            Self::MaximumSignatureChecksExceeded => 0,
342            Self::MaximumPathBuildCallsExceeded => 0,
343            Self::MaximumNameConstraintComparisonsExceeded => 0,
344
345            // Default catch all error - should be renamed in the future.
346            Self::UnknownIssuer => 0,
347        }
348    }
349
350    /// Returns true for errors that should be considered fatal during path building. Errors of
351    /// this class should halt any further path building and be returned immediately.
352    #[inline]
353    pub(crate) fn is_fatal(&self) -> bool {
354        matches!(
355            self,
356            Self::MaximumSignatureChecksExceeded
357                | Self::MaximumPathBuildCallsExceeded
358                | Self::MaximumNameConstraintComparisonsExceeded
359        )
360    }
361}
362
363impl From<Error> for ControlFlow<Error, Error> {
364    fn from(value: Error) -> Self {
365        match value {
366            // If an error is fatal, we've exhausted the potential for continued search.
367            err if err.is_fatal() => Self::Break(err),
368            // Otherwise we've rejected one candidate chain, but may continue to search for others.
369            err => Self::Continue(err),
370        }
371    }
372}
373
374impl fmt::Display for Error {
375    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
376        write!(f, "{self:?}")
377    }
378}
379
380#[cfg(feature = "std")]
381impl ::std::error::Error for Error {}
382
383/// Additional context for the `CertNotValidForName` error variant.
384///
385/// The contents of this type depend on whether the `alloc` feature is enabled.
386#[derive(Clone, Debug, PartialEq, Eq)]
387pub struct InvalidNameContext {
388    /// Expected server name.
389    #[cfg(feature = "alloc")]
390    pub expected: ServerName<'static>,
391    /// The names presented in the end entity certificate.
392    ///
393    /// These are the subject names as present in the leaf certificate and may contain DNS names
394    /// with or without a wildcard label as well as IP address names.
395    #[cfg(feature = "alloc")]
396    pub presented: Vec<String>,
397}
398
399/// Additional context for the `UnsupportedSignatureAlgorithmForPublicKey` error variant.
400///
401/// The contents of this type depend on whether the `alloc` feature is enabled.
402#[derive(Clone, Debug, PartialEq, Eq)]
403pub struct UnsupportedSignatureAlgorithmForPublicKeyContext {
404    /// The signature algorithm OID.
405    #[cfg(feature = "alloc")]
406    pub signature_algorithm_id: Vec<u8>,
407    /// The public key algorithm OID.
408    #[cfg(feature = "alloc")]
409    pub public_key_algorithm_id: Vec<u8>,
410}
411
412/// Additional context for the `UnsupportedSignatureAlgorithm` error variant.
413///
414/// The contents of this type depend on whether the `alloc` feature is enabled.
415#[derive(Clone, Debug, PartialEq, Eq)]
416pub struct UnsupportedSignatureAlgorithmContext {
417    /// The signature algorithm OID that was unsupported.
418    #[cfg(feature = "alloc")]
419    pub signature_algorithm_id: Vec<u8>,
420    /// Supported algorithms that were available for signature verification.
421    #[cfg(feature = "alloc")]
422    pub supported_algorithms: Vec<AlgorithmIdentifier>,
423}
424
425/// Trailing data was found while parsing DER-encoded input for the named type.
426#[allow(missing_docs)]
427#[non_exhaustive]
428#[derive(Clone, Copy, Debug, Eq, PartialEq)]
429pub enum DerTypeId {
430    BitString,
431    Bool,
432    Certificate,
433    CertificateExtensions,
434    CertificateTbsCertificate,
435    CertRevocationList,
436    CertRevocationListExtension,
437    CrlDistributionPoint,
438    CommonNameInner,
439    CommonNameOuter,
440    DistributionPointName,
441    Extension,
442    GeneralName,
443    RevocationReason,
444    Signature,
445    SignatureAlgorithm,
446    SignedData,
447    SubjectPublicKeyInfo,
448    Time,
449    TrustAnchorV1,
450    TrustAnchorV1TbsCertificate,
451    U8,
452    RevokedCertificate,
453    RevokedCertificateExtension,
454    RevokedCertEntry,
455    IssuingDistributionPoint,
456}