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