ktls_core/
error.rs

1//! Error related types and implementations.
2
3use std::fmt::{self, Debug};
4use std::io;
5
6use crate::tls::{AlertDescription, ProtocolVersion};
7
8/// Specialized `Result` type for this crate.
9pub type Result<T, E = Error> = std::result::Result<T, E>;
10
11#[non_exhaustive]
12#[derive(Debug)]
13/// Unified error type for this crate.
14pub enum Error {
15    /// Errors from outer TLS implementations.
16    Tls(Box<dyn std::error::Error + Send + Sync>),
17
18    /// Setting up TLS ULP failed.
19    Ulp(io::Error),
20
21    /// Unsupported TLS protocol version.
22    UnsupportedProtocolVersion(ProtocolVersion),
23
24    /// Invalid crypto material, this is likely caused by a older kernel
25    /// which doesn't support the requested TLS version or cipher suite.
26    CryptoMaterial(io::Error),
27
28    /// The peer sent us a TLS message with invalid contents.
29    InvalidMessage(InvalidMessage),
30
31    /// The peer deviated from the standard TLS protocol.
32    /// The parameter gives a hint where.
33    PeerMisbehaved(PeerMisbehaved),
34
35    /// The TLS library failed to handle the key update request.
36    KeyUpdateFailed(io::Error),
37
38    /// The TLS library failed to handle the provided session ticket.
39    HandleNewSessionTicketFailed(io::Error),
40
41    /// We received a fatal alert.  This means the peer is unhappy.
42    AlertReceived(AlertDescription),
43
44    /// General error.
45    General(io::Error),
46}
47
48impl Error {
49    /// Returns `true` if the error indicates that kTLS is totally not supported
50    /// by the running kernel (e.g., kernel module `tls` not being enabled or
51    /// the kernel version being too old)
52    #[must_use]
53    pub fn is_ktls_unsupported(&self) -> bool {
54        matches!(self, Self::Ulp(e) if e.raw_os_error() == Some(libc::ENOENT))
55    }
56}
57
58impl fmt::Display for Error {
59    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60        match self {
61            Self::Tls(e) => {
62                write!(f, "TLS error: {e}")
63            }
64            Self::Ulp(e) => {
65                write!(f, "Failed to set TLS ULP: {e}")
66            }
67            Self::UnsupportedProtocolVersion(v) => {
68                write!(f, "The given TLS protocol version is not supported: {v:?}")
69            }
70            Self::CryptoMaterial(e) => {
71                write!(
72                    f,
73                    "The given crypto material is not supported by the running kernel: {e}"
74                )
75            }
76            Self::InvalidMessage(e) => write!(f, "Invalid TLS message: {e:?}"),
77            Self::PeerMisbehaved(e) => write!(f, "The peer misbehaved: {e:?}"),
78            Self::KeyUpdateFailed(e) => write!(f, "Key update failed: {e}"),
79            Self::HandleNewSessionTicketFailed(e) => {
80                write!(f, "Handling NewSessionTicket failed: {e}")
81            }
82            Self::AlertReceived(a) => write!(f, "Received fatal alert from the peer: {a:?}"),
83            Self::General(e) => write!(f, "{e}"),
84        }
85    }
86}
87
88impl std::error::Error for Error {
89    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
90        #[allow(clippy::match_same_arms)]
91        match self {
92            Self::Tls(e) => Some(&**e),
93            Self::Ulp(e) => Some(e),
94            Self::CryptoMaterial(e) => Some(e),
95            Self::KeyUpdateFailed(e) => Some(e),
96            Self::HandleNewSessionTicketFailed(e) => Some(e),
97            Self::General(e) => Some(e),
98            _ => None,
99        }
100    }
101}
102
103impl From<InvalidMessage> for Error {
104    fn from(error: InvalidMessage) -> Self {
105        Self::InvalidMessage(error)
106    }
107}
108
109impl From<PeerMisbehaved> for Error {
110    fn from(error: PeerMisbehaved) -> Self {
111        Self::PeerMisbehaved(error)
112    }
113}
114
115impl From<Error> for io::Error {
116    fn from(error: Error) -> Self {
117        match error {
118            Error::General(error) => error,
119            _ => Self::other(error),
120        }
121    }
122}
123
124#[non_exhaustive]
125#[derive(Debug, Clone, Copy, PartialEq)]
126/// A corrupt TLS message payload that resulted in an error.
127///
128/// (Copied from rustls)
129pub enum InvalidMessage {
130    /// An unknown content type was encountered during message decoding.
131    InvalidContentType,
132
133    /// A peer sent an unexpected key update request.
134    InvalidKeyUpdate,
135
136    /// A TLS message payload was larger then allowed by the specification.
137    MessageTooLarge,
138
139    /// Message is shorter than the expected length
140    MessageTooShort,
141
142    /// A peer sent an unexpected message type.
143    UnexpectedMessage(&'static str),
144}
145
146impl InvalidMessage {
147    pub(crate) const fn description(&self) -> AlertDescription {
148        match self {
149            Self::InvalidContentType | Self::UnexpectedMessage(_) => {
150                AlertDescription::UnexpectedMessage
151            }
152            _ => AlertDescription::DecodeError,
153        }
154    }
155}
156
157#[allow(missing_docs)]
158#[non_exhaustive]
159#[derive(Debug, PartialEq, Clone)]
160/// The set of cases where we failed to make a connection because we thought
161/// the peer was misbehaving.
162///
163/// This is `non_exhaustive`: we might add or stop using items here in minor
164/// versions.  We also don't document what they mean.  Generally a user of
165/// rustls shouldn't vary its behaviour on these error codes, and there is
166/// nothing it can do to improve matters.
167///
168/// (Copied from rustls)
169pub enum PeerMisbehaved {
170    // AttemptedDowngradeToTls12WhenTls13IsSupported,
171    // BadCertChainExtensions,
172    // DisallowedEncryptedExtension,
173    // DuplicateClientHelloExtensions,
174    // DuplicateEncryptedExtensions,
175    // DuplicateHelloRetryRequestExtensions,
176    // DuplicateNewSessionTicketExtensions,
177    // DuplicateServerHelloExtensions,
178    // DuplicateServerNameTypes,
179    // EarlyDataAttemptedInSecondClientHello,
180    // EarlyDataExtensionWithoutResumption,
181    // EarlyDataOfferedWithVariedCipherSuite,
182    // HandshakeHashVariedAfterRetry,
183    // IllegalHelloRetryRequestWithEmptyCookie,
184    // IllegalHelloRetryRequestWithNoChanges,
185    // IllegalHelloRetryRequestWithOfferedGroup,
186    // IllegalHelloRetryRequestWithUnofferedCipherSuite,
187    // IllegalHelloRetryRequestWithUnofferedNamedGroup,
188    // IllegalHelloRetryRequestWithUnsupportedVersion,
189    // IllegalHelloRetryRequestWithWrongSessionId,
190    // IllegalHelloRetryRequestWithInvalidEch,
191    IllegalMiddleboxChangeCipherSpec,
192    // IllegalTlsInnerPlaintext,
193    // IncorrectBinder,
194    // InvalidCertCompression,
195    // InvalidMaxEarlyDataSize,
196    // InvalidKeyShare,
197    KeyEpochWithPendingFragment,
198    // KeyUpdateReceivedInQuicConnection,
199    // MessageInterleavedWithHandshakeMessage,
200    // MissingBinderInPskExtension,
201    // MissingKeyShare,
202    // MissingPskModesExtension,
203    // MissingQuicTransportParameters,
204    // NoCertificatesPresented,
205    // OfferedDuplicateCertificateCompressions,
206    // OfferedDuplicateKeyShares,
207    // OfferedEarlyDataWithOldProtocolVersion,
208    // OfferedEmptyApplicationProtocol,
209    // OfferedIncorrectCompressions,
210    // PskExtensionMustBeLast,
211    // PskExtensionWithMismatchedIdsAndBinders,
212    // RefusedToFollowHelloRetryRequest,
213    // RejectedEarlyDataInterleavedWithHandshakeMessage,
214    // ResumptionAttemptedWithVariedEms,
215    // ResumptionOfferedWithVariedCipherSuite,
216    // ResumptionOfferedWithVariedEms,
217    // ResumptionOfferedWithIncompatibleCipherSuite,
218    // SelectedDifferentCipherSuiteAfterRetry,
219    // SelectedInvalidPsk,
220    // SelectedTls12UsingTls13VersionExtension,
221    // SelectedUnofferedApplicationProtocol,
222    // SelectedUnofferedCertCompression,
223    // SelectedUnofferedCipherSuite,
224    // SelectedUnofferedCompression,
225    // SelectedUnofferedKxGroup,
226    // SelectedUnofferedPsk,
227    // ServerEchoedCompatibilitySessionId,
228    // ServerHelloMustOfferUncompressedEcPoints,
229    // ServerNameDifferedOnRetry,
230    // ServerNameMustContainOneHostName,
231    // SignedKxWithWrongAlgorithm,
232    // SignedHandshakeWithUnadvertisedSigScheme,
233    // TooManyEmptyFragments,
234    // TooManyKeyUpdateRequests,
235    // TooManyRenegotiationRequests,
236    // TooManyWarningAlertsReceived,
237    // TooMuchEarlyDataReceived,
238    // UnexpectedCleartextExtension,
239    // UnsolicitedCertExtension,
240    // UnsolicitedEncryptedExtension,
241    // UnsolicitedSctList,
242    // UnsolicitedServerHelloExtension,
243    // WrongGroupForKeyShare,
244    // UnsolicitedEchExtension,
245}
246
247impl PeerMisbehaved {
248    pub(crate) const fn description(&self) -> AlertDescription {
249        match self {
250            Self::KeyEpochWithPendingFragment | Self::IllegalMiddleboxChangeCipherSpec => {
251                AlertDescription::UnexpectedMessage
252            }
253            #[allow(unreachable_patterns)]
254            _ => AlertDescription::InternalError,
255        }
256    }
257}