rustls/
error.rs

1use alloc::format;
2use alloc::string::String;
3use alloc::vec::Vec;
4use core::fmt;
5#[cfg(feature = "std")]
6use std::time::SystemTimeError;
7
8use pki_types::{ServerName, UnixTime};
9use webpki::KeyUsage;
10
11use crate::enums::{AlertDescription, ContentType, HandshakeType};
12use crate::msgs::handshake::{EchConfigPayload, KeyExchangeAlgorithm};
13use crate::rand;
14
15/// rustls reports protocol errors using this type.
16#[non_exhaustive]
17#[derive(Debug, PartialEq, Clone)]
18pub enum Error {
19    /// We received a TLS message that isn't valid right now.
20    /// `expect_types` lists the message types we can expect right now.
21    /// `got_type` is the type we found.  This error is typically
22    /// caused by a buggy TLS stack (the peer or this one), a broken
23    /// network, or an attack.
24    InappropriateMessage {
25        /// Which types we expected
26        expect_types: Vec<ContentType>,
27        /// What type we received
28        got_type: ContentType,
29    },
30
31    /// We received a TLS handshake message that isn't valid right now.
32    /// `expect_types` lists the handshake message types we can expect
33    /// right now.  `got_type` is the type we found.
34    InappropriateHandshakeMessage {
35        /// Which handshake type we expected
36        expect_types: Vec<HandshakeType>,
37        /// What handshake type we received
38        got_type: HandshakeType,
39    },
40
41    /// An error occurred while handling Encrypted Client Hello (ECH).
42    InvalidEncryptedClientHello(EncryptedClientHelloError),
43
44    /// The peer sent us a TLS message with invalid contents.
45    InvalidMessage(InvalidMessage),
46
47    /// The peer didn't give us any certificates.
48    NoCertificatesPresented,
49
50    /// The certificate verifier doesn't support the given type of name.
51    UnsupportedNameType,
52
53    /// We couldn't decrypt a message.  This is invariably fatal.
54    DecryptError,
55
56    /// We couldn't encrypt a message because it was larger than the allowed message size.
57    /// This should never happen if the application is using valid record sizes.
58    EncryptError,
59
60    /// The peer doesn't support a protocol version/feature we require.
61    /// The parameter gives a hint as to what version/feature it is.
62    PeerIncompatible(PeerIncompatible),
63
64    /// The peer deviated from the standard TLS protocol.
65    /// The parameter gives a hint where.
66    PeerMisbehaved(PeerMisbehaved),
67
68    /// We received a fatal alert.  This means the peer is unhappy.
69    AlertReceived(AlertDescription),
70
71    /// We saw an invalid certificate.
72    ///
73    /// The contained error is from the certificate validation trait
74    /// implementation.
75    InvalidCertificate(CertificateError),
76
77    /// A provided certificate revocation list (CRL) was invalid.
78    InvalidCertRevocationList(CertRevocationListError),
79
80    /// A catch-all error for unlikely errors.
81    General(String),
82
83    /// We failed to figure out what time it currently is.
84    FailedToGetCurrentTime,
85
86    /// We failed to acquire random bytes from the system.
87    FailedToGetRandomBytes,
88
89    /// This function doesn't work until the TLS handshake
90    /// is complete.
91    HandshakeNotComplete,
92
93    /// The peer sent an oversized record/fragment.
94    PeerSentOversizedRecord,
95
96    /// An incoming connection did not support any known application protocol.
97    NoApplicationProtocol,
98
99    /// The `max_fragment_size` value supplied in configuration was too small,
100    /// or too large.
101    BadMaxFragmentSize,
102
103    /// Specific failure cases from [`keys_match`] or a [`crate::crypto::signer::SigningKey`] that cannot produce a corresponding public key.
104    ///
105    /// [`keys_match`]: crate::crypto::signer::CertifiedKey::keys_match
106    InconsistentKeys(InconsistentKeys),
107
108    /// Any other error.
109    ///
110    /// This variant should only be used when the error is not better described by a more
111    /// specific variant. For example, if a custom crypto provider returns a
112    /// provider specific error.
113    ///
114    /// Enums holding this variant will never compare equal to each other.
115    Other(OtherError),
116}
117
118/// Specific failure cases from [`keys_match`] or a [`crate::crypto::signer::SigningKey`] that cannot produce a corresponding public key.
119///
120/// [`keys_match`]: crate::crypto::signer::CertifiedKey::keys_match
121#[non_exhaustive]
122#[derive(Clone, Copy, Debug, Eq, PartialEq)]
123pub enum InconsistentKeys {
124    /// The public key returned by the [`SigningKey`] does not match the public key information in the certificate.
125    ///
126    /// [`SigningKey`]: crate::crypto::signer::SigningKey
127    KeyMismatch,
128
129    /// The [`SigningKey`] cannot produce its corresponding public key.
130    ///
131    /// [`SigningKey`]: crate::crypto::signer::SigningKey
132    Unknown,
133}
134
135impl From<InconsistentKeys> for Error {
136    #[inline]
137    fn from(e: InconsistentKeys) -> Self {
138        Self::InconsistentKeys(e)
139    }
140}
141
142/// A corrupt TLS message payload that resulted in an error.
143#[non_exhaustive]
144#[derive(Debug, Clone, Copy, PartialEq)]
145
146pub enum InvalidMessage {
147    /// A certificate payload exceeded rustls's 64KB limit
148    CertificatePayloadTooLarge,
149    /// An advertised message was larger then expected.
150    HandshakePayloadTooLarge,
151    /// The peer sent us a syntactically incorrect ChangeCipherSpec payload.
152    InvalidCcs,
153    /// An unknown content type was encountered during message decoding.
154    InvalidContentType,
155    /// A peer sent an invalid certificate status type
156    InvalidCertificateStatusType,
157    /// Context was incorrectly attached to a certificate request during a handshake.
158    InvalidCertRequest,
159    /// A peer's DH params could not be decoded
160    InvalidDhParams,
161    /// A message was zero-length when its record kind forbids it.
162    InvalidEmptyPayload,
163    /// A peer sent an unexpected key update request.
164    InvalidKeyUpdate,
165    /// A peer's server name could not be decoded
166    InvalidServerName,
167    /// A TLS message payload was larger then allowed by the specification.
168    MessageTooLarge,
169    /// Message is shorter than the expected length
170    MessageTooShort,
171    /// Missing data for the named handshake payload value
172    MissingData(&'static str),
173    /// A peer did not advertise its supported key exchange groups.
174    MissingKeyExchange,
175    /// A peer sent an empty list of signature schemes
176    NoSignatureSchemes,
177    /// Trailing data found for the named handshake payload value
178    TrailingData(&'static str),
179    /// A peer sent an unexpected message type.
180    UnexpectedMessage(&'static str),
181    /// An unknown TLS protocol was encountered during message decoding.
182    UnknownProtocolVersion,
183    /// A peer sent a non-null compression method.
184    UnsupportedCompression,
185    /// A peer sent an unknown elliptic curve type.
186    UnsupportedCurveType,
187    /// A peer sent an unsupported key exchange algorithm.
188    UnsupportedKeyExchangeAlgorithm(KeyExchangeAlgorithm),
189    /// A server sent an empty ticket
190    EmptyTicketValue,
191    /// A peer sent an empty list of items, but a non-empty list is required.
192    ///
193    /// The argument names the context.
194    IllegalEmptyList(&'static str),
195    /// A peer sent an empty value, but a non-empty value is required.
196    IllegalEmptyValue,
197}
198
199impl From<InvalidMessage> for Error {
200    #[inline]
201    fn from(e: InvalidMessage) -> Self {
202        Self::InvalidMessage(e)
203    }
204}
205
206#[non_exhaustive]
207#[allow(missing_docs)]
208#[derive(Debug, PartialEq, Clone)]
209/// The set of cases where we failed to make a connection because we thought
210/// the peer was misbehaving.
211///
212/// This is `non_exhaustive`: we might add or stop using items here in minor
213/// versions.  We also don't document what they mean.  Generally a user of
214/// rustls shouldn't vary its behaviour on these error codes, and there is
215/// nothing it can do to improve matters.
216///
217/// Please file a bug against rustls if you see `Error::PeerMisbehaved` in
218/// the wild.
219pub enum PeerMisbehaved {
220    AttemptedDowngradeToTls12WhenTls13IsSupported,
221    BadCertChainExtensions,
222    DisallowedEncryptedExtension,
223    DuplicateClientHelloExtensions,
224    DuplicateEncryptedExtensions,
225    DuplicateHelloRetryRequestExtensions,
226    DuplicateNewSessionTicketExtensions,
227    DuplicateServerHelloExtensions,
228    DuplicateServerNameTypes,
229    EarlyDataAttemptedInSecondClientHello,
230    EarlyDataExtensionWithoutResumption,
231    EarlyDataOfferedWithVariedCipherSuite,
232    HandshakeHashVariedAfterRetry,
233    IllegalHelloRetryRequestWithEmptyCookie,
234    IllegalHelloRetryRequestWithNoChanges,
235    IllegalHelloRetryRequestWithOfferedGroup,
236    IllegalHelloRetryRequestWithUnofferedCipherSuite,
237    IllegalHelloRetryRequestWithUnofferedNamedGroup,
238    IllegalHelloRetryRequestWithUnsupportedVersion,
239    IllegalHelloRetryRequestWithWrongSessionId,
240    IllegalHelloRetryRequestWithInvalidEch,
241    IllegalMiddleboxChangeCipherSpec,
242    IllegalTlsInnerPlaintext,
243    IncorrectBinder,
244    InvalidCertCompression,
245    InvalidMaxEarlyDataSize,
246    InvalidKeyShare,
247    KeyEpochWithPendingFragment,
248    KeyUpdateReceivedInQuicConnection,
249    MessageInterleavedWithHandshakeMessage,
250    MissingBinderInPskExtension,
251    MissingKeyShare,
252    MissingPskModesExtension,
253    MissingQuicTransportParameters,
254    OfferedDuplicateCertificateCompressions,
255    OfferedDuplicateKeyShares,
256    OfferedEarlyDataWithOldProtocolVersion,
257    OfferedEmptyApplicationProtocol,
258    OfferedIncorrectCompressions,
259    PskExtensionMustBeLast,
260    PskExtensionWithMismatchedIdsAndBinders,
261    RefusedToFollowHelloRetryRequest,
262    RejectedEarlyDataInterleavedWithHandshakeMessage,
263    ResumptionAttemptedWithVariedEms,
264    ResumptionOfferedWithVariedCipherSuite,
265    ResumptionOfferedWithVariedEms,
266    ResumptionOfferedWithIncompatibleCipherSuite,
267    SelectedDifferentCipherSuiteAfterRetry,
268    SelectedInvalidPsk,
269    SelectedTls12UsingTls13VersionExtension,
270    SelectedUnofferedApplicationProtocol,
271    SelectedUnofferedCertCompression,
272    SelectedUnofferedCipherSuite,
273    SelectedUnofferedCompression,
274    SelectedUnofferedKxGroup,
275    SelectedUnofferedPsk,
276    SelectedUnusableCipherSuiteForVersion,
277    ServerEchoedCompatibilitySessionId,
278    ServerHelloMustOfferUncompressedEcPoints,
279    ServerNameDifferedOnRetry,
280    ServerNameMustContainOneHostName,
281    SignedKxWithWrongAlgorithm,
282    SignedHandshakeWithUnadvertisedSigScheme,
283    TooManyEmptyFragments,
284    TooManyKeyUpdateRequests,
285    TooManyRenegotiationRequests,
286    TooManyWarningAlertsReceived,
287    TooMuchEarlyDataReceived,
288    UnexpectedCleartextExtension,
289    UnsolicitedCertExtension,
290    UnsolicitedEncryptedExtension,
291    UnsolicitedSctList,
292    UnsolicitedServerHelloExtension,
293    WrongGroupForKeyShare,
294    UnsolicitedEchExtension,
295}
296
297impl From<PeerMisbehaved> for Error {
298    #[inline]
299    fn from(e: PeerMisbehaved) -> Self {
300        Self::PeerMisbehaved(e)
301    }
302}
303
304#[non_exhaustive]
305#[allow(missing_docs)]
306#[derive(Debug, PartialEq, Clone)]
307/// The set of cases where we failed to make a connection because a peer
308/// doesn't support a TLS version/feature we require.
309///
310/// This is `non_exhaustive`: we might add or stop using items here in minor
311/// versions.
312pub enum PeerIncompatible {
313    EcPointsExtensionRequired,
314    ExtendedMasterSecretExtensionRequired,
315    IncorrectCertificateTypeExtension,
316    KeyShareExtensionRequired,
317    NamedGroupsExtensionRequired,
318    NoCertificateRequestSignatureSchemesInCommon,
319    NoCipherSuitesInCommon,
320    NoEcPointFormatsInCommon,
321    NoKxGroupsInCommon,
322    NoSignatureSchemesInCommon,
323    NullCompressionRequired,
324    ServerDoesNotSupportTls12Or13,
325    ServerSentHelloRetryRequestWithUnknownExtension,
326    ServerTlsVersionIsDisabledByOurConfig,
327    SignatureAlgorithmsExtensionRequired,
328    SupportedVersionsExtensionRequired,
329    Tls12NotOffered,
330    Tls12NotOfferedOrEnabled,
331    Tls13RequiredForQuic,
332    UncompressedEcPointsRequired,
333    UnsolicitedCertificateTypeExtension,
334    ServerRejectedEncryptedClientHello(Option<Vec<EchConfigPayload>>),
335}
336
337impl From<PeerIncompatible> for Error {
338    #[inline]
339    fn from(e: PeerIncompatible) -> Self {
340        Self::PeerIncompatible(e)
341    }
342}
343
344#[non_exhaustive]
345#[derive(Debug, Clone)]
346/// The ways in which certificate validators can express errors.
347///
348/// Note that the rustls TLS protocol code interprets specifically these
349/// error codes to send specific TLS alerts.  Therefore, if a
350/// custom certificate validator uses incorrect errors the library as
351/// a whole will send alerts that do not match the standard (this is usually
352/// a minor issue, but could be misleading).
353pub enum CertificateError {
354    /// The certificate is not correctly encoded.
355    BadEncoding,
356
357    /// The current time is after the `notAfter` time in the certificate.
358    Expired,
359
360    /// The current time is after the `notAfter` time in the certificate.
361    ///
362    /// This variant is semantically the same as `Expired`, but includes
363    /// extra data to improve error reports.
364    ExpiredContext {
365        /// The validation time.
366        time: UnixTime,
367        /// The `notAfter` time of the certificate.
368        not_after: UnixTime,
369    },
370
371    /// The current time is before the `notBefore` time in the certificate.
372    NotValidYet,
373
374    /// The current time is before the `notBefore` time in the certificate.
375    ///
376    /// This variant is semantically the same as `NotValidYet`, but includes
377    /// extra data to improve error reports.
378    NotValidYetContext {
379        /// The validation time.
380        time: UnixTime,
381        /// The `notBefore` time of the certificate.
382        not_before: UnixTime,
383    },
384
385    /// The certificate has been revoked.
386    Revoked,
387
388    /// The certificate contains an extension marked critical, but it was
389    /// not processed by the certificate validator.
390    UnhandledCriticalExtension,
391
392    /// The certificate chain is not issued by a known root certificate.
393    UnknownIssuer,
394
395    /// The certificate's revocation status could not be determined.
396    UnknownRevocationStatus,
397
398    /// The certificate's revocation status could not be determined, because the CRL is expired.
399    ExpiredRevocationList,
400
401    /// The certificate's revocation status could not be determined, because the CRL is expired.
402    ///
403    /// This variant is semantically the same as `ExpiredRevocationList`, but includes
404    /// extra data to improve error reports.
405    ExpiredRevocationListContext {
406        /// The validation time.
407        time: UnixTime,
408        /// The nextUpdate time of the CRL.
409        next_update: UnixTime,
410    },
411
412    /// A certificate is not correctly signed by the key of its alleged
413    /// issuer.
414    BadSignature,
415
416    /// The subject names in an end-entity certificate do not include
417    /// the expected name.
418    NotValidForName,
419
420    /// The subject names in an end-entity certificate do not include
421    /// the expected name.
422    ///
423    /// This variant is semantically the same as `NotValidForName`, but includes
424    /// extra data to improve error reports.
425    NotValidForNameContext {
426        /// Expected server name.
427        expected: ServerName<'static>,
428
429        /// The names presented in the end entity certificate.
430        ///
431        /// These are the subject names as present in the leaf certificate and may contain DNS names
432        /// with or without a wildcard label as well as IP address names.
433        presented: Vec<String>,
434    },
435
436    /// The certificate is being used for a different purpose than allowed.
437    InvalidPurpose,
438
439    /// The certificate is being used for a different purpose than allowed.
440    ///
441    /// This variant is semantically the same as `InvalidPurpose`, but includes
442    /// extra data to improve error reports.
443    InvalidPurposeContext {
444        /// Extended key purpose that was required by the application.
445        required: ExtendedKeyPurpose,
446        /// Extended key purposes that were presented in the peer's certificate.
447        presented: Vec<ExtendedKeyPurpose>,
448    },
449
450    /// The certificate is valid, but the handshake is rejected for other
451    /// reasons.
452    ApplicationVerificationFailure,
453
454    /// Any other error.
455    ///
456    /// This can be used by custom verifiers to expose the underlying error
457    /// (where they are not better described by the more specific errors
458    /// above).
459    ///
460    /// It is also used by the default verifier in case its error is
461    /// not covered by the above common cases.
462    ///
463    /// Enums holding this variant will never compare equal to each other.
464    Other(OtherError),
465}
466
467impl PartialEq<Self> for CertificateError {
468    fn eq(&self, other: &Self) -> bool {
469        use CertificateError::*;
470        #[allow(clippy::match_like_matches_macro)]
471        match (self, other) {
472            (BadEncoding, BadEncoding) => true,
473            (Expired, Expired) => true,
474            (
475                ExpiredContext {
476                    time: left_time,
477                    not_after: left_not_after,
478                },
479                ExpiredContext {
480                    time: right_time,
481                    not_after: right_not_after,
482                },
483            ) => (left_time, left_not_after) == (right_time, right_not_after),
484            (NotValidYet, NotValidYet) => true,
485            (
486                NotValidYetContext {
487                    time: left_time,
488                    not_before: left_not_before,
489                },
490                NotValidYetContext {
491                    time: right_time,
492                    not_before: right_not_before,
493                },
494            ) => (left_time, left_not_before) == (right_time, right_not_before),
495            (Revoked, Revoked) => true,
496            (UnhandledCriticalExtension, UnhandledCriticalExtension) => true,
497            (UnknownIssuer, UnknownIssuer) => true,
498            (BadSignature, BadSignature) => true,
499            (NotValidForName, NotValidForName) => true,
500            (
501                NotValidForNameContext {
502                    expected: left_expected,
503                    presented: left_presented,
504                },
505                NotValidForNameContext {
506                    expected: right_expected,
507                    presented: right_presented,
508                },
509            ) => (left_expected, left_presented) == (right_expected, right_presented),
510            (InvalidPurpose, InvalidPurpose) => true,
511            (
512                InvalidPurposeContext {
513                    required: left_required,
514                    presented: left_presented,
515                },
516                InvalidPurposeContext {
517                    required: right_required,
518                    presented: right_presented,
519                },
520            ) => (left_required, left_presented) == (right_required, right_presented),
521            (ApplicationVerificationFailure, ApplicationVerificationFailure) => true,
522            (UnknownRevocationStatus, UnknownRevocationStatus) => true,
523            (ExpiredRevocationList, ExpiredRevocationList) => true,
524            (
525                ExpiredRevocationListContext {
526                    time: left_time,
527                    next_update: left_next_update,
528                },
529                ExpiredRevocationListContext {
530                    time: right_time,
531                    next_update: right_next_update,
532                },
533            ) => (left_time, left_next_update) == (right_time, right_next_update),
534            _ => false,
535        }
536    }
537}
538
539// The following mapping are heavily referenced in:
540// * [OpenSSL Implementation](https://github.com/openssl/openssl/blob/45bb98bfa223efd3258f445ad443f878011450f0/ssl/statem/statem_lib.c#L1434)
541// * [BoringSSL Implementation](https://github.com/google/boringssl/blob/583c60bd4bf76d61b2634a58bcda99a92de106cb/ssl/ssl_x509.cc#L1323)
542impl From<CertificateError> for AlertDescription {
543    fn from(e: CertificateError) -> Self {
544        use CertificateError::*;
545        match e {
546            BadEncoding
547            | UnhandledCriticalExtension
548            | NotValidForName
549            | NotValidForNameContext { .. } => Self::BadCertificate,
550            // RFC 5246/RFC 8446
551            // certificate_expired
552            //  A certificate has expired or **is not currently valid**.
553            Expired | ExpiredContext { .. } | NotValidYet | NotValidYetContext { .. } => {
554                Self::CertificateExpired
555            }
556            Revoked => Self::CertificateRevoked,
557            // OpenSSL, BoringSSL and AWS-LC all generate an Unknown CA alert for
558            // the case where revocation status can not be determined, so we do the same here.
559            UnknownIssuer
560            | UnknownRevocationStatus
561            | ExpiredRevocationList
562            | ExpiredRevocationListContext { .. } => Self::UnknownCA,
563            BadSignature => Self::DecryptError,
564            InvalidPurpose | InvalidPurposeContext { .. } => Self::UnsupportedCertificate,
565            ApplicationVerificationFailure => Self::AccessDenied,
566            // RFC 5246/RFC 8446
567            // certificate_unknown
568            //  Some other (unspecified) issue arose in processing the
569            //  certificate, rendering it unacceptable.
570            Other(..) => Self::CertificateUnknown,
571        }
572    }
573}
574
575impl fmt::Display for CertificateError {
576    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
577        match self {
578            #[cfg(feature = "std")]
579            Self::NotValidForNameContext {
580                expected,
581                presented,
582            } => {
583                write!(
584                    f,
585                    "certificate not valid for name {:?}; certificate ",
586                    expected.to_str()
587                )?;
588
589                match presented.as_slice() {
590                    &[] => write!(
591                        f,
592                        "is not valid for any names (according to its subjectAltName extension)"
593                    ),
594                    [one] => write!(f, "is only valid for {}", one),
595                    many => {
596                        write!(f, "is only valid for ")?;
597
598                        let n = many.len();
599                        let all_but_last = &many[..n - 1];
600                        let last = &many[n - 1];
601
602                        for (i, name) in all_but_last.iter().enumerate() {
603                            write!(f, "{}", name)?;
604                            if i < n - 2 {
605                                write!(f, ", ")?;
606                            }
607                        }
608                        write!(f, " or {}", last)
609                    }
610                }
611            }
612
613            Self::ExpiredContext { time, not_after } => write!(
614                f,
615                "certificate expired: verification time {} (UNIX), \
616                 but certificate is not valid after {} \
617                 ({} seconds ago)",
618                time.as_secs(),
619                not_after.as_secs(),
620                time.as_secs()
621                    .saturating_sub(not_after.as_secs())
622            ),
623
624            Self::NotValidYetContext { time, not_before } => write!(
625                f,
626                "certificate not valid yet: verification time {} (UNIX), \
627                 but certificate is not valid before {} \
628                 ({} seconds in future)",
629                time.as_secs(),
630                not_before.as_secs(),
631                not_before
632                    .as_secs()
633                    .saturating_sub(time.as_secs())
634            ),
635
636            Self::ExpiredRevocationListContext { time, next_update } => write!(
637                f,
638                "certificate revocation list expired: \
639                 verification time {} (UNIX), \
640                 but CRL is not valid after {} \
641                 ({} seconds ago)",
642                time.as_secs(),
643                next_update.as_secs(),
644                time.as_secs()
645                    .saturating_sub(next_update.as_secs())
646            ),
647
648            Self::InvalidPurposeContext {
649                required,
650                presented,
651            } => {
652                write!(
653                    f,
654                    "certificate does not allow extended key usage for {required}, allows "
655                )?;
656                for (i, eku) in presented.iter().enumerate() {
657                    if i > 0 {
658                        write!(f, ", ")?;
659                    }
660                    write!(f, "{eku}")?;
661                }
662                Ok(())
663            }
664
665            other => write!(f, "{:?}", other),
666        }
667    }
668}
669
670impl From<CertificateError> for Error {
671    #[inline]
672    fn from(e: CertificateError) -> Self {
673        Self::InvalidCertificate(e)
674    }
675}
676
677/// Extended Key Usage (EKU) purpose values.
678///
679/// These are usually represented as OID values in the certificate's extension (if present), but
680/// we represent the values that are most relevant to rustls as named enum variants.
681#[derive(Clone, Debug, Eq, PartialEq)]
682pub enum ExtendedKeyPurpose {
683    /// Client authentication
684    ClientAuth,
685    /// Server authentication
686    ServerAuth,
687    /// Other EKU values
688    ///
689    /// Represented here as a `Vec<usize>` for human readability.
690    Other(Vec<usize>),
691}
692
693impl ExtendedKeyPurpose {
694    pub(crate) fn for_values(values: impl Iterator<Item = usize>) -> Self {
695        let values = values.collect::<Vec<_>>();
696        match &*values {
697            KeyUsage::CLIENT_AUTH_REPR => Self::ClientAuth,
698            KeyUsage::SERVER_AUTH_REPR => Self::ServerAuth,
699            _ => Self::Other(values),
700        }
701    }
702}
703
704impl fmt::Display for ExtendedKeyPurpose {
705    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
706        match self {
707            Self::ClientAuth => write!(f, "client authentication"),
708            Self::ServerAuth => write!(f, "server authentication"),
709            Self::Other(values) => {
710                for (i, value) in values.iter().enumerate() {
711                    if i > 0 {
712                        write!(f, ", ")?;
713                    }
714                    write!(f, "{value}")?;
715                }
716                Ok(())
717            }
718        }
719    }
720}
721
722#[non_exhaustive]
723#[derive(Debug, Clone)]
724/// The ways in which a certificate revocation list (CRL) can be invalid.
725pub enum CertRevocationListError {
726    /// The CRL had a bad, or unsupported signature from its issuer.
727    BadSignature,
728
729    /// The CRL contained an invalid CRL number.
730    InvalidCrlNumber,
731
732    /// The CRL contained a revoked certificate with an invalid serial number.
733    InvalidRevokedCertSerialNumber,
734
735    /// The CRL issuer does not specify the cRLSign key usage.
736    IssuerInvalidForCrl,
737
738    /// The CRL is invalid for some other reason.
739    ///
740    /// Enums holding this variant will never compare equal to each other.
741    Other(OtherError),
742
743    /// The CRL is not correctly encoded.
744    ParseError,
745
746    /// The CRL is not a v2 X.509 CRL.
747    UnsupportedCrlVersion,
748
749    /// The CRL, or a revoked certificate in the CRL, contained an unsupported critical extension.
750    UnsupportedCriticalExtension,
751
752    /// The CRL is an unsupported delta CRL, containing only changes relative to another CRL.
753    UnsupportedDeltaCrl,
754
755    /// The CRL is an unsupported indirect CRL, containing revoked certificates issued by a CA
756    /// other than the issuer of the CRL.
757    UnsupportedIndirectCrl,
758
759    /// The CRL contained a revoked certificate with an unsupported revocation reason.
760    /// See RFC 5280 Section 5.3.1[^1] for a list of supported revocation reasons.
761    ///
762    /// [^1]: <https://www.rfc-editor.org/rfc/rfc5280#section-5.3.1>
763    UnsupportedRevocationReason,
764}
765
766impl PartialEq<Self> for CertRevocationListError {
767    fn eq(&self, other: &Self) -> bool {
768        use CertRevocationListError::*;
769        #[allow(clippy::match_like_matches_macro)]
770        match (self, other) {
771            (BadSignature, BadSignature) => true,
772            (InvalidCrlNumber, InvalidCrlNumber) => true,
773            (InvalidRevokedCertSerialNumber, InvalidRevokedCertSerialNumber) => true,
774            (IssuerInvalidForCrl, IssuerInvalidForCrl) => true,
775            (ParseError, ParseError) => true,
776            (UnsupportedCrlVersion, UnsupportedCrlVersion) => true,
777            (UnsupportedCriticalExtension, UnsupportedCriticalExtension) => true,
778            (UnsupportedDeltaCrl, UnsupportedDeltaCrl) => true,
779            (UnsupportedIndirectCrl, UnsupportedIndirectCrl) => true,
780            (UnsupportedRevocationReason, UnsupportedRevocationReason) => true,
781            _ => false,
782        }
783    }
784}
785
786impl From<CertRevocationListError> for Error {
787    #[inline]
788    fn from(e: CertRevocationListError) -> Self {
789        Self::InvalidCertRevocationList(e)
790    }
791}
792
793#[non_exhaustive]
794#[derive(Debug, Clone, Eq, PartialEq)]
795/// An error that occurred while handling Encrypted Client Hello (ECH).
796pub enum EncryptedClientHelloError {
797    /// The provided ECH configuration list was invalid.
798    InvalidConfigList,
799    /// No compatible ECH configuration.
800    NoCompatibleConfig,
801    /// The client configuration has server name indication (SNI) disabled.
802    SniRequired,
803}
804
805impl From<EncryptedClientHelloError> for Error {
806    #[inline]
807    fn from(e: EncryptedClientHelloError) -> Self {
808        Self::InvalidEncryptedClientHello(e)
809    }
810}
811
812fn join<T: fmt::Debug>(items: &[T]) -> String {
813    items
814        .iter()
815        .map(|x| format!("{:?}", x))
816        .collect::<Vec<String>>()
817        .join(" or ")
818}
819
820impl fmt::Display for Error {
821    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
822        match self {
823            Self::InappropriateMessage {
824                expect_types,
825                got_type,
826            } => write!(
827                f,
828                "received unexpected message: got {:?} when expecting {}",
829                got_type,
830                join::<ContentType>(expect_types)
831            ),
832            Self::InappropriateHandshakeMessage {
833                expect_types,
834                got_type,
835            } => write!(
836                f,
837                "received unexpected handshake message: got {:?} when expecting {}",
838                got_type,
839                join::<HandshakeType>(expect_types)
840            ),
841            Self::InvalidMessage(typ) => {
842                write!(f, "received corrupt message of type {:?}", typ)
843            }
844            Self::PeerIncompatible(why) => write!(f, "peer is incompatible: {:?}", why),
845            Self::PeerMisbehaved(why) => write!(f, "peer misbehaved: {:?}", why),
846            Self::AlertReceived(alert) => write!(f, "received fatal alert: {:?}", alert),
847            Self::InvalidCertificate(err) => {
848                write!(f, "invalid peer certificate: {}", err)
849            }
850            Self::InvalidCertRevocationList(err) => {
851                write!(f, "invalid certificate revocation list: {:?}", err)
852            }
853            Self::NoCertificatesPresented => write!(f, "peer sent no certificates"),
854            Self::UnsupportedNameType => write!(f, "presented server name type wasn't supported"),
855            Self::DecryptError => write!(f, "cannot decrypt peer's message"),
856            Self::InvalidEncryptedClientHello(err) => {
857                write!(f, "encrypted client hello failure: {:?}", err)
858            }
859            Self::EncryptError => write!(f, "cannot encrypt message"),
860            Self::PeerSentOversizedRecord => write!(f, "peer sent excess record size"),
861            Self::HandshakeNotComplete => write!(f, "handshake not complete"),
862            Self::NoApplicationProtocol => write!(f, "peer doesn't support any known protocol"),
863            Self::FailedToGetCurrentTime => write!(f, "failed to get current time"),
864            Self::FailedToGetRandomBytes => write!(f, "failed to get random bytes"),
865            Self::BadMaxFragmentSize => {
866                write!(f, "the supplied max_fragment_size was too small or large")
867            }
868            Self::InconsistentKeys(why) => {
869                write!(f, "keys may not be consistent: {:?}", why)
870            }
871            Self::General(err) => write!(f, "unexpected error: {}", err),
872            Self::Other(err) => write!(f, "other error: {}", err),
873        }
874    }
875}
876
877#[cfg(feature = "std")]
878impl From<SystemTimeError> for Error {
879    #[inline]
880    fn from(_: SystemTimeError) -> Self {
881        Self::FailedToGetCurrentTime
882    }
883}
884
885#[cfg(feature = "std")]
886impl std::error::Error for Error {}
887
888impl From<rand::GetRandomFailed> for Error {
889    fn from(_: rand::GetRandomFailed) -> Self {
890        Self::FailedToGetRandomBytes
891    }
892}
893
894mod other_error {
895    use core::fmt;
896    #[cfg(feature = "std")]
897    use std::error::Error as StdError;
898
899    use super::Error;
900    #[cfg(feature = "std")]
901    use crate::sync::Arc;
902
903    /// Any other error that cannot be expressed by a more specific [`Error`] variant.
904    ///
905    /// For example, an `OtherError` could be produced by a custom crypto provider
906    /// exposing a provider specific error.
907    ///
908    /// Enums holding this type will never compare equal to each other.
909    #[derive(Debug, Clone)]
910    pub struct OtherError(#[cfg(feature = "std")] pub Arc<dyn StdError + Send + Sync>);
911
912    impl PartialEq<Self> for OtherError {
913        fn eq(&self, _other: &Self) -> bool {
914            false
915        }
916    }
917
918    impl From<OtherError> for Error {
919        fn from(value: OtherError) -> Self {
920            Self::Other(value)
921        }
922    }
923
924    impl fmt::Display for OtherError {
925        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
926            #[cfg(feature = "std")]
927            {
928                write!(f, "{}", self.0)
929            }
930            #[cfg(not(feature = "std"))]
931            {
932                f.write_str("no further information available")
933            }
934        }
935    }
936
937    #[cfg(feature = "std")]
938    impl StdError for OtherError {
939        fn source(&self) -> Option<&(dyn StdError + 'static)> {
940            Some(self.0.as_ref())
941        }
942    }
943}
944
945pub use other_error::OtherError;
946
947#[cfg(test)]
948mod tests {
949    use core::time::Duration;
950    use std::prelude::v1::*;
951    use std::{println, vec};
952
953    use super::{
954        CertRevocationListError, Error, InconsistentKeys, InvalidMessage, OtherError, UnixTime,
955    };
956    #[cfg(feature = "std")]
957    use crate::sync::Arc;
958    use pki_types::ServerName;
959
960    #[test]
961    fn certificate_error_equality() {
962        use super::CertificateError::*;
963        assert_eq!(BadEncoding, BadEncoding);
964        assert_eq!(Expired, Expired);
965        let context = ExpiredContext {
966            time: UnixTime::since_unix_epoch(Duration::from_secs(1234)),
967            not_after: UnixTime::since_unix_epoch(Duration::from_secs(123)),
968        };
969        assert_eq!(context, context);
970        assert_ne!(
971            context,
972            ExpiredContext {
973                time: UnixTime::since_unix_epoch(Duration::from_secs(12345)),
974                not_after: UnixTime::since_unix_epoch(Duration::from_secs(123)),
975            }
976        );
977        assert_ne!(
978            context,
979            ExpiredContext {
980                time: UnixTime::since_unix_epoch(Duration::from_secs(1234)),
981                not_after: UnixTime::since_unix_epoch(Duration::from_secs(1234)),
982            }
983        );
984        assert_eq!(NotValidYet, NotValidYet);
985        let context = NotValidYetContext {
986            time: UnixTime::since_unix_epoch(Duration::from_secs(123)),
987            not_before: UnixTime::since_unix_epoch(Duration::from_secs(1234)),
988        };
989        assert_eq!(context, context);
990        assert_ne!(
991            context,
992            NotValidYetContext {
993                time: UnixTime::since_unix_epoch(Duration::from_secs(1234)),
994                not_before: UnixTime::since_unix_epoch(Duration::from_secs(1234)),
995            }
996        );
997        assert_ne!(
998            context,
999            NotValidYetContext {
1000                time: UnixTime::since_unix_epoch(Duration::from_secs(123)),
1001                not_before: UnixTime::since_unix_epoch(Duration::from_secs(12345)),
1002            }
1003        );
1004        assert_eq!(Revoked, Revoked);
1005        assert_eq!(UnhandledCriticalExtension, UnhandledCriticalExtension);
1006        assert_eq!(UnknownIssuer, UnknownIssuer);
1007        assert_eq!(ExpiredRevocationList, ExpiredRevocationList);
1008        assert_eq!(UnknownRevocationStatus, UnknownRevocationStatus);
1009        let context = ExpiredRevocationListContext {
1010            time: UnixTime::since_unix_epoch(Duration::from_secs(1234)),
1011            next_update: UnixTime::since_unix_epoch(Duration::from_secs(123)),
1012        };
1013        assert_eq!(context, context);
1014        assert_ne!(
1015            context,
1016            ExpiredRevocationListContext {
1017                time: UnixTime::since_unix_epoch(Duration::from_secs(12345)),
1018                next_update: UnixTime::since_unix_epoch(Duration::from_secs(123)),
1019            }
1020        );
1021        assert_ne!(
1022            context,
1023            ExpiredRevocationListContext {
1024                time: UnixTime::since_unix_epoch(Duration::from_secs(1234)),
1025                next_update: UnixTime::since_unix_epoch(Duration::from_secs(1234)),
1026            }
1027        );
1028        assert_eq!(BadSignature, BadSignature);
1029        assert_eq!(NotValidForName, NotValidForName);
1030        let context = NotValidForNameContext {
1031            expected: ServerName::try_from("example.com")
1032                .unwrap()
1033                .to_owned(),
1034            presented: vec!["other.com".into()],
1035        };
1036        assert_eq!(context, context);
1037        assert_ne!(
1038            context,
1039            NotValidForNameContext {
1040                expected: ServerName::try_from("example.com")
1041                    .unwrap()
1042                    .to_owned(),
1043                presented: vec![]
1044            }
1045        );
1046        assert_ne!(
1047            context,
1048            NotValidForNameContext {
1049                expected: ServerName::try_from("huh.com")
1050                    .unwrap()
1051                    .to_owned(),
1052                presented: vec!["other.com".into()],
1053            }
1054        );
1055        assert_eq!(InvalidPurpose, InvalidPurpose);
1056        assert_eq!(
1057            ApplicationVerificationFailure,
1058            ApplicationVerificationFailure
1059        );
1060        let other = Other(OtherError(
1061            #[cfg(feature = "std")]
1062            Arc::from(Box::from("")),
1063        ));
1064        assert_ne!(other, other);
1065        assert_ne!(BadEncoding, Expired);
1066    }
1067
1068    #[test]
1069    fn crl_error_equality() {
1070        use super::CertRevocationListError::*;
1071        assert_eq!(BadSignature, BadSignature);
1072        assert_eq!(InvalidCrlNumber, InvalidCrlNumber);
1073        assert_eq!(
1074            InvalidRevokedCertSerialNumber,
1075            InvalidRevokedCertSerialNumber
1076        );
1077        assert_eq!(IssuerInvalidForCrl, IssuerInvalidForCrl);
1078        assert_eq!(ParseError, ParseError);
1079        assert_eq!(UnsupportedCriticalExtension, UnsupportedCriticalExtension);
1080        assert_eq!(UnsupportedCrlVersion, UnsupportedCrlVersion);
1081        assert_eq!(UnsupportedDeltaCrl, UnsupportedDeltaCrl);
1082        assert_eq!(UnsupportedIndirectCrl, UnsupportedIndirectCrl);
1083        assert_eq!(UnsupportedRevocationReason, UnsupportedRevocationReason);
1084        let other = Other(OtherError(
1085            #[cfg(feature = "std")]
1086            Arc::from(Box::from("")),
1087        ));
1088        assert_ne!(other, other);
1089        assert_ne!(BadSignature, InvalidCrlNumber);
1090    }
1091
1092    #[test]
1093    #[cfg(feature = "std")]
1094    fn other_error_equality() {
1095        let other_error = OtherError(Arc::from(Box::from("")));
1096        assert_ne!(other_error, other_error);
1097        let other: Error = other_error.into();
1098        assert_ne!(other, other);
1099    }
1100
1101    #[test]
1102    fn smoke() {
1103        use crate::enums::{AlertDescription, ContentType, HandshakeType};
1104
1105        let all = vec![
1106            Error::InappropriateMessage {
1107                expect_types: vec![ContentType::Alert],
1108                got_type: ContentType::Handshake,
1109            },
1110            Error::InappropriateHandshakeMessage {
1111                expect_types: vec![HandshakeType::ClientHello, HandshakeType::Finished],
1112                got_type: HandshakeType::ServerHello,
1113            },
1114            Error::InvalidMessage(InvalidMessage::InvalidCcs),
1115            Error::NoCertificatesPresented,
1116            Error::DecryptError,
1117            super::PeerIncompatible::Tls12NotOffered.into(),
1118            super::PeerMisbehaved::UnsolicitedCertExtension.into(),
1119            Error::AlertReceived(AlertDescription::ExportRestriction),
1120            super::CertificateError::Expired.into(),
1121            super::CertificateError::NotValidForNameContext {
1122                expected: ServerName::try_from("example.com")
1123                    .unwrap()
1124                    .to_owned(),
1125                presented: vec![],
1126            }
1127            .into(),
1128            super::CertificateError::NotValidForNameContext {
1129                expected: ServerName::try_from("example.com")
1130                    .unwrap()
1131                    .to_owned(),
1132                presented: vec!["DnsName(\"hello.com\")".into()],
1133            }
1134            .into(),
1135            super::CertificateError::NotValidForNameContext {
1136                expected: ServerName::try_from("example.com")
1137                    .unwrap()
1138                    .to_owned(),
1139                presented: vec![
1140                    "DnsName(\"hello.com\")".into(),
1141                    "DnsName(\"goodbye.com\")".into(),
1142                ],
1143            }
1144            .into(),
1145            super::CertificateError::NotValidYetContext {
1146                time: UnixTime::since_unix_epoch(Duration::from_secs(300)),
1147                not_before: UnixTime::since_unix_epoch(Duration::from_secs(320)),
1148            }
1149            .into(),
1150            super::CertificateError::ExpiredContext {
1151                time: UnixTime::since_unix_epoch(Duration::from_secs(320)),
1152                not_after: UnixTime::since_unix_epoch(Duration::from_secs(300)),
1153            }
1154            .into(),
1155            super::CertificateError::ExpiredRevocationListContext {
1156                time: UnixTime::since_unix_epoch(Duration::from_secs(320)),
1157                next_update: UnixTime::since_unix_epoch(Duration::from_secs(300)),
1158            }
1159            .into(),
1160            Error::General("undocumented error".to_string()),
1161            Error::FailedToGetCurrentTime,
1162            Error::FailedToGetRandomBytes,
1163            Error::HandshakeNotComplete,
1164            Error::PeerSentOversizedRecord,
1165            Error::NoApplicationProtocol,
1166            Error::BadMaxFragmentSize,
1167            Error::InconsistentKeys(InconsistentKeys::KeyMismatch),
1168            Error::InconsistentKeys(InconsistentKeys::Unknown),
1169            Error::InvalidCertRevocationList(CertRevocationListError::BadSignature),
1170            Error::Other(OtherError(
1171                #[cfg(feature = "std")]
1172                Arc::from(Box::from("")),
1173            )),
1174        ];
1175
1176        for err in all {
1177            println!("{:?}:", err);
1178            println!("  fmt '{}'", err);
1179        }
1180    }
1181
1182    #[test]
1183    fn rand_error_mapping() {
1184        use super::rand;
1185        let err: Error = rand::GetRandomFailed.into();
1186        assert_eq!(err, Error::FailedToGetRandomBytes);
1187    }
1188
1189    #[cfg(feature = "std")]
1190    #[test]
1191    fn time_error_mapping() {
1192        use std::time::SystemTime;
1193
1194        let time_error = SystemTime::UNIX_EPOCH
1195            .duration_since(SystemTime::now())
1196            .unwrap_err();
1197        let err: Error = time_error.into();
1198        assert_eq!(err, Error::FailedToGetCurrentTime);
1199    }
1200}