1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
//! TLS errors and alerts.
/// A TLS alert: a severity-less description code plus a `fatal` flag.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct Alert {
/// Whether the alert is fatal (level 2) rather than a warning (level 1).
pub fatal: bool,
/// The alert description.
pub description: AlertDescription,
}
/// TLS alert description codes (RFC 8446 §6).
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum AlertDescription {
/// `close_notify` (0).
CloseNotify,
/// `unexpected_message` (10).
UnexpectedMessage,
/// `bad_record_mac` (20).
BadRecordMac,
/// `record_overflow` (22) — RFC 8446 §6: ciphertext > `2^14 + 256` or
/// post-decrypt plaintext > `2^14` bytes.
RecordOverflow,
/// `handshake_failure` (40).
HandshakeFailure,
/// `bad_certificate` (42).
BadCertificate,
/// `unsupported_certificate` (43).
UnsupportedCertificate,
/// `certificate_expired` (45).
CertificateExpired,
/// `certificate_unknown` (46).
CertificateUnknown,
/// `illegal_parameter` (47).
IllegalParameter,
/// `decode_error` (50).
DecodeError,
/// `decrypt_error` (51).
DecryptError,
/// `protocol_version` (70).
ProtocolVersion,
/// `internal_error` (80).
InternalError,
/// `missing_extension` (109).
MissingExtension,
/// `unsupported_extension` (110).
UnsupportedExtension,
/// `unrecognized_name` (112).
UnrecognizedName,
/// `no_application_protocol` (120).
NoApplicationProtocol,
/// `certificate_required` (116) — RFC 8446 §6: server demanded a client
/// certificate but the client offered none.
CertificateRequired,
/// `user_canceled` (90) — RFC 5246 §7.2.1: a warning-level peer notice
/// indicating no protocol failure, just user-initiated close. In TLS
/// 1.2 this is non-fatal; TLS 1.3 §6 elides the warning/fatal split.
UserCanceled,
/// `no_renegotiation` (100) — RFC 5246 §7.2.1: a warning-level peer
/// notice that a renegotiation request was refused. Non-fatal.
NoRenegotiation,
/// An unrecognized alert code.
Unknown(u8),
}
impl AlertDescription {
/// The 8-bit wire encoding.
pub fn as_u8(self) -> u8 {
match self {
AlertDescription::CloseNotify => 0,
AlertDescription::UnexpectedMessage => 10,
AlertDescription::BadRecordMac => 20,
AlertDescription::RecordOverflow => 22,
AlertDescription::HandshakeFailure => 40,
AlertDescription::BadCertificate => 42,
AlertDescription::UnsupportedCertificate => 43,
AlertDescription::CertificateExpired => 45,
AlertDescription::CertificateUnknown => 46,
AlertDescription::IllegalParameter => 47,
AlertDescription::DecodeError => 50,
AlertDescription::DecryptError => 51,
AlertDescription::ProtocolVersion => 70,
AlertDescription::InternalError => 80,
AlertDescription::MissingExtension => 109,
AlertDescription::UnsupportedExtension => 110,
AlertDescription::UnrecognizedName => 112,
AlertDescription::NoApplicationProtocol => 120,
AlertDescription::CertificateRequired => 116,
AlertDescription::UserCanceled => 90,
AlertDescription::NoRenegotiation => 100,
AlertDescription::Unknown(v) => v,
}
}
/// Decodes an 8-bit alert code.
pub fn from_u8(v: u8) -> Self {
match v {
0 => AlertDescription::CloseNotify,
10 => AlertDescription::UnexpectedMessage,
20 => AlertDescription::BadRecordMac,
22 => AlertDescription::RecordOverflow,
40 => AlertDescription::HandshakeFailure,
42 => AlertDescription::BadCertificate,
43 => AlertDescription::UnsupportedCertificate,
45 => AlertDescription::CertificateExpired,
46 => AlertDescription::CertificateUnknown,
47 => AlertDescription::IllegalParameter,
50 => AlertDescription::DecodeError,
51 => AlertDescription::DecryptError,
70 => AlertDescription::ProtocolVersion,
80 => AlertDescription::InternalError,
109 => AlertDescription::MissingExtension,
110 => AlertDescription::UnsupportedExtension,
112 => AlertDescription::UnrecognizedName,
120 => AlertDescription::NoApplicationProtocol,
116 => AlertDescription::CertificateRequired,
90 => AlertDescription::UserCanceled,
100 => AlertDescription::NoRenegotiation,
other => AlertDescription::Unknown(other),
}
}
}
/// Errors produced by the TLS state machine.
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum Error {
/// A message could not be decoded (maps to `decode_error`).
Decode,
/// A message arrived out of sequence (maps to `unexpected_message`).
UnexpectedMessage,
/// Record decryption / AEAD authentication failed (`bad_record_mac`).
BadRecordMac,
/// The peer offered no acceptable parameters (`handshake_failure`).
HandshakeFailure,
/// The negotiated/offered version is unsupported.
UnsupportedVersion,
/// The peer's certificate could not be validated.
BadCertificate,
/// A signature (CertificateVerify or chain) failed to verify.
PeerMisbehaved,
/// A fatal alert was received from the peer.
AlertReceived(AlertDescription),
/// Misuse of the API (e.g. writing before the handshake completes).
InappropriateState,
/// The peer supplied a syntactically valid value that is forbidden by the
/// spec (e.g. an unknown `KeyUpdate` request byte). Maps to
/// `illegal_parameter`.
IllegalParameter,
/// A record's plaintext exceeded `2^14` bytes (RFC 8446 §5.1) or its
/// ciphertext exceeded `2^14 + 256` bytes (RFC 8446 §5.2). Maps to
/// `record_overflow`.
RecordOverflow,
/// The per-key record-sequence cap has been reached without a `KeyUpdate`.
/// Maps to `internal_error`; the connection should rekey before continuing.
TooManyRecords,
/// The peer's ALPN list contains nothing acceptable. Maps to
/// `no_application_protocol` (RFC 7301).
NoApplicationProtocol,
/// A PSK binder failed to verify, or another signed handshake-context
/// authenticator was invalid. Maps to `decrypt_error` (RFC 8446 §6).
DecryptError,
/// Server required a client certificate but the client did not present
/// one. Maps to `certificate_required`.
CertificateRequired,
}
impl core::fmt::Display for Error {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Error::Decode => f.write_str("TLS decode error"),
Error::UnexpectedMessage => f.write_str("unexpected TLS message"),
Error::BadRecordMac => f.write_str("TLS record authentication failed"),
Error::HandshakeFailure => f.write_str("TLS handshake failure"),
Error::UnsupportedVersion => f.write_str("unsupported TLS version"),
Error::BadCertificate => f.write_str("invalid certificate"),
Error::PeerMisbehaved => f.write_str("peer misbehaved (bad signature)"),
Error::AlertReceived(a) => write!(f, "received fatal alert: {a:?}"),
Error::InappropriateState => f.write_str("operation not valid in this state"),
Error::IllegalParameter => f.write_str("TLS illegal parameter"),
Error::RecordOverflow => f.write_str("TLS record-size limit exceeded"),
Error::TooManyRecords => f.write_str("per-key record-sequence cap reached"),
Error::NoApplicationProtocol => f.write_str("no ALPN overlap with peer"),
Error::DecryptError => f.write_str("TLS handshake decrypt error (binder/MAC)"),
Error::CertificateRequired => f.write_str("server required a client certificate"),
}
}
}
impl core::error::Error for Error {}