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