ktls_core/
error.rs

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