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}