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}