Skip to main content

oxitls_core/
alert.rs

1//! TLS alert descriptions as defined in RFC 8446 §6.
2
3use std::fmt;
4
5/// A TLS alert description code (RFC 8446 §6).
6///
7/// The `Unknown(u8)` catch-all carries any code not listed in RFC 8446,
8/// allowing the type to remain forwards-compatible without breaking consumers.
9///
10/// # Examples
11/// ```
12/// use oxitls_core::AlertDescription;
13///
14/// let d = AlertDescription::from(40u8);
15/// assert_eq!(d, AlertDescription::HandshakeFailure);
16/// assert_eq!(d.to_u8(), 40);
17/// ```
18#[derive(Debug, Clone, PartialEq, Eq)]
19#[non_exhaustive]
20pub enum AlertDescription {
21    /// `close_notify` (0) — orderly TLS shutdown.
22    CloseNotify,
23    /// `unexpected_message` (10) — inappropriate message received.
24    UnexpectedMessage,
25    /// `bad_record_mac` (20) — record authentication failure.
26    BadRecordMac,
27    /// `record_overflow` (22) — TLSCiphertext record too long.
28    RecordOverflow,
29    /// `handshake_failure` (40) — unable to negotiate acceptable security parameters.
30    HandshakeFailure,
31    /// `bad_certificate` (42) — unacceptable certificate.
32    BadCertificate,
33    /// `unsupported_certificate` (43) — certificate type not supported.
34    UnsupportedCertificate,
35    /// `certificate_revoked` (44) — certificate has been revoked.
36    CertificateRevoked,
37    /// `certificate_expired` (45) — certificate has expired.
38    CertificateExpired,
39    /// `certificate_unknown` (46) — unspecified certificate problem.
40    CertificateUnknown,
41    /// `illegal_parameter` (47) — field in the handshake was out of range or inconsistent.
42    IllegalParameter,
43    /// `unknown_ca` (48) — certificate's CA is not trusted.
44    UnknownCa,
45    /// `access_denied` (49) — valid certificate, but access control denied.
46    AccessDenied,
47    /// `decode_error` (50) — unable to decode a message.
48    DecodeError,
49    /// `decrypt_error` (51) — handshake cryptographic operation failed.
50    DecryptError,
51    /// `protocol_version` (70) — protocol version not supported.
52    ProtocolVersion,
53    /// `insufficient_security` (71) — server requires ciphers more secure than those supported by client.
54    InsufficientSecurity,
55    /// `internal_error` (80) — internal error unrelated to the peer or correctness of the protocol.
56    InternalError,
57    /// `inappropriate_fallback` (86) — TLS_FALLBACK_SCSV in response to version downgrade.
58    InappropriateFallback,
59    /// `user_canceled` (90) — handshake is being canceled for a reason unrelated to a protocol failure.
60    UserCanceled,
61    /// `missing_extension` (109) — negotiated extension was missing from the ClientHello.
62    MissingExtension,
63    /// `unsupported_extension` (110) — extension not permitted for this message.
64    UnsupportedExtension,
65    /// `unrecognized_name` (112) — SNI name not recognized.
66    UnrecognizedName,
67    /// `bad_certificate_status_response` (113) — OCSP response invalid.
68    BadCertificateStatusResponse,
69    /// `unknown_psk_identity` (115) — no acceptable PSK identity was supplied.
70    UnknownPskIdentity,
71    /// `certificate_required` (116) — client certificate required.
72    CertificateRequired,
73    /// `no_application_protocol` (120) — no ALPN protocol overlap.
74    NoApplicationProtocol,
75    /// An alert code not listed in RFC 8446.
76    ///
77    /// The wrapped value is the raw numeric alert code.
78    Unknown(u8),
79}
80
81impl AlertDescription {
82    /// Return the raw RFC 8446 numeric alert code for this description.
83    pub fn to_u8(&self) -> u8 {
84        match self {
85            AlertDescription::CloseNotify => 0,
86            AlertDescription::UnexpectedMessage => 10,
87            AlertDescription::BadRecordMac => 20,
88            AlertDescription::RecordOverflow => 22,
89            AlertDescription::HandshakeFailure => 40,
90            AlertDescription::BadCertificate => 42,
91            AlertDescription::UnsupportedCertificate => 43,
92            AlertDescription::CertificateRevoked => 44,
93            AlertDescription::CertificateExpired => 45,
94            AlertDescription::CertificateUnknown => 46,
95            AlertDescription::IllegalParameter => 47,
96            AlertDescription::UnknownCa => 48,
97            AlertDescription::AccessDenied => 49,
98            AlertDescription::DecodeError => 50,
99            AlertDescription::DecryptError => 51,
100            AlertDescription::ProtocolVersion => 70,
101            AlertDescription::InsufficientSecurity => 71,
102            AlertDescription::InternalError => 80,
103            AlertDescription::InappropriateFallback => 86,
104            AlertDescription::UserCanceled => 90,
105            AlertDescription::MissingExtension => 109,
106            AlertDescription::UnsupportedExtension => 110,
107            AlertDescription::UnrecognizedName => 112,
108            AlertDescription::BadCertificateStatusResponse => 113,
109            AlertDescription::UnknownPskIdentity => 115,
110            AlertDescription::CertificateRequired => 116,
111            AlertDescription::NoApplicationProtocol => 120,
112            AlertDescription::Unknown(code) => *code,
113        }
114    }
115}
116
117impl From<u8> for AlertDescription {
118    fn from(code: u8) -> Self {
119        match code {
120            0 => AlertDescription::CloseNotify,
121            10 => AlertDescription::UnexpectedMessage,
122            20 => AlertDescription::BadRecordMac,
123            22 => AlertDescription::RecordOverflow,
124            40 => AlertDescription::HandshakeFailure,
125            42 => AlertDescription::BadCertificate,
126            43 => AlertDescription::UnsupportedCertificate,
127            44 => AlertDescription::CertificateRevoked,
128            45 => AlertDescription::CertificateExpired,
129            46 => AlertDescription::CertificateUnknown,
130            47 => AlertDescription::IllegalParameter,
131            48 => AlertDescription::UnknownCa,
132            49 => AlertDescription::AccessDenied,
133            50 => AlertDescription::DecodeError,
134            51 => AlertDescription::DecryptError,
135            70 => AlertDescription::ProtocolVersion,
136            71 => AlertDescription::InsufficientSecurity,
137            80 => AlertDescription::InternalError,
138            86 => AlertDescription::InappropriateFallback,
139            90 => AlertDescription::UserCanceled,
140            109 => AlertDescription::MissingExtension,
141            110 => AlertDescription::UnsupportedExtension,
142            112 => AlertDescription::UnrecognizedName,
143            113 => AlertDescription::BadCertificateStatusResponse,
144            115 => AlertDescription::UnknownPskIdentity,
145            116 => AlertDescription::CertificateRequired,
146            120 => AlertDescription::NoApplicationProtocol,
147            other => AlertDescription::Unknown(other),
148        }
149    }
150}
151
152impl fmt::Display for AlertDescription {
153    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
154        match self {
155            AlertDescription::CloseNotify => write!(f, "close_notify"),
156            AlertDescription::UnexpectedMessage => write!(f, "unexpected_message"),
157            AlertDescription::BadRecordMac => write!(f, "bad_record_mac"),
158            AlertDescription::RecordOverflow => write!(f, "record_overflow"),
159            AlertDescription::HandshakeFailure => write!(f, "handshake_failure"),
160            AlertDescription::BadCertificate => write!(f, "bad_certificate"),
161            AlertDescription::UnsupportedCertificate => write!(f, "unsupported_certificate"),
162            AlertDescription::CertificateRevoked => write!(f, "certificate_revoked"),
163            AlertDescription::CertificateExpired => write!(f, "certificate_expired"),
164            AlertDescription::CertificateUnknown => write!(f, "certificate_unknown"),
165            AlertDescription::IllegalParameter => write!(f, "illegal_parameter"),
166            AlertDescription::UnknownCa => write!(f, "unknown_ca"),
167            AlertDescription::AccessDenied => write!(f, "access_denied"),
168            AlertDescription::DecodeError => write!(f, "decode_error"),
169            AlertDescription::DecryptError => write!(f, "decrypt_error"),
170            AlertDescription::ProtocolVersion => write!(f, "protocol_version"),
171            AlertDescription::InsufficientSecurity => write!(f, "insufficient_security"),
172            AlertDescription::InternalError => write!(f, "internal_error"),
173            AlertDescription::InappropriateFallback => write!(f, "inappropriate_fallback"),
174            AlertDescription::UserCanceled => write!(f, "user_canceled"),
175            AlertDescription::MissingExtension => write!(f, "missing_extension"),
176            AlertDescription::UnsupportedExtension => write!(f, "unsupported_extension"),
177            AlertDescription::UnrecognizedName => write!(f, "unrecognized_name"),
178            AlertDescription::BadCertificateStatusResponse => {
179                write!(f, "bad_certificate_status_response")
180            }
181            AlertDescription::UnknownPskIdentity => write!(f, "unknown_psk_identity"),
182            AlertDescription::CertificateRequired => write!(f, "certificate_required"),
183            AlertDescription::NoApplicationProtocol => write!(f, "no_application_protocol"),
184            AlertDescription::Unknown(code) => write!(f, "unknown_alert({code})"),
185        }
186    }
187}