aranya_internal_rustls/
error.rs

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