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}