s2n_quic_core/crypto/tls/
error.rs1use crate::event::metrics::aggregate;
5use core::fmt;
6use s2n_codec::DecoderError;
7
8#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
10#[cfg_attr(feature = "thiserror", derive(thiserror::Error))]
11pub struct Error {
12 pub reason: &'static str,
13 pub code: u8,
14}
15
16impl Error {
17 pub const fn new(code: u8) -> Self {
19 Self { code, reason: "" }
20 }
21
22 #[must_use]
24 pub const fn with_reason(mut self, reason: &'static str) -> Self {
25 self.reason = reason;
26 self
27 }
28}
29
30impl fmt::Display for Error {
31 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
32 if !self.reason.is_empty() {
33 self.reason.fmt(f)
34 } else if let Some(description) = self.description() {
35 description.fmt(f)
36 } else {
37 write!(f, "tls::Error({})", self.code)
38 }
39 }
40}
41
42impl fmt::Debug for Error {
43 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
44 let mut d = f.debug_struct("tls::Error");
45
46 d.field("code", &self.code);
47
48 if let Some(description) = self.description() {
49 d.field("description", &description);
50 }
51
52 if !self.reason.is_empty() {
53 d.field("reason", &self.reason);
54 }
55
56 d.finish()
57 }
58}
59
60impl From<DecoderError> for Error {
61 fn from(_: DecoderError) -> Self {
62 Self::DECODE_ERROR
63 }
64}
65
66macro_rules! alert_descriptions {
67 ($($name:ident = $value:expr),* $(,)?) => {
68 impl Error {
69 pub fn description(&self) -> Option<&'static str> {
70 match self.code {
71 $(
72 $value => Some(stringify!($name)),
73 )*
74 _ => None,
75 }
76 }
77
78 $(
79 pub const $name: Self = Self::new($value);
80 )*
81 }
82
83 impl aggregate::AsVariant for Error {
84 const VARIANTS: &'static [aggregate::info::Variant] = &{
85 use aggregate::info::{Variant, Str};
86
87 const fn count(_v: u64) -> usize {
88 1
89 }
90
91 const LEN: usize = 1 $(+ count($value))*;
92 let mut array = [Variant { name: Str::new("\0"), id: 0 }; LEN];
93
94 let mut id = 0;
95
96 $(
97 array[id] = Variant {
98 name: Str::new(concat!("TLS_", stringify!($name), "\0")),
99 id,
100 };
101 id += 1;
102 )*
103
104 array[id] = aggregate::info::Variant {
105 name: aggregate::info::Str::new("TLS_UNKNOWN_ERROR\0"),
106 id,
107 };
108
109 array
110 };
111
112 #[inline]
113 fn variant_idx(&self) -> usize {
114 let mut idx = 0;
115
116 $(
117 if self.code == $value {
118 return idx;
119 }
120 idx += 1;
121 )*
122
123 idx
124 }
125 }
126
127 #[test]
128 fn description_test() {
129 $(
130 assert_eq!(&Error::$name.to_string(), stringify!($name));
131 )*
132 }
133
134 #[test]
135 #[cfg_attr(miri, ignore)]
136 fn variants_test() {
137 use aggregate::AsVariant;
138 insta::assert_debug_snapshot!(Error::VARIANTS);
139
140 let mut seen = std::collections::HashSet::new();
141 for variant in Error::VARIANTS {
142 assert!(seen.insert(variant.id));
143 }
144 }
145 };
146}
147
148alert_descriptions!(
195 CLOSE_NOTIFY = 0,
196 UNEXPECTED_MESSAGE = 10,
197 BAD_RECORD_MAC = 20,
198 DECRYPTION_FAILED_RESERVED = 21,
199 RECORD_OVERFLOW = 22,
200 DECOMPRESSION_FAILURE_RESERVED = 30,
201 HANDSHAKE_FAILURE = 40,
202 NO_CERTIFICATE_RESERVED = 41,
203 BAD_CERTIFICATE = 42,
204 UNSUPPORTED_CERTIFICATE = 43,
205 CERTIFICATE_REVOKED = 44,
206 CERTIFICATE_EXPIRED = 45,
207 CERTIFICATE_UNKNOWN = 46,
208 ILLEGAL_PARAMETER = 47,
209 UNKNOWN_CA = 48,
210 ACCESS_DENIED = 49,
211 DECODE_ERROR = 50,
212 DECRYPT_ERROR = 51,
213 EXPORT_RESTRICTION_RESERVED = 60,
214 PROTOCOL_VERSION = 70,
215 INSUFFICIENT_SECURITY = 71,
216 INTERNAL_ERROR = 80,
217 INAPPROPRIATE_FALLBACK = 86,
218 USER_CANCELED = 90,
219 NO_RENEGOTIATION_RESERVED = 100,
220 MISSING_EXTENSION = 109,
221 UNSUPPORTED_EXTENSION = 110,
222 CERTIFICATE_UNOBTAINABLE_RESERVED = 111,
223 UNRECOGNIZED_NAME = 112,
224 BAD_CERTIFICATE_STATUS_RESPONSE = 113,
225 BAD_CERTIFICATE_HASH_VALUE_RESERVED = 114,
226 UNKNOWN_PSK_IDENTITY = 115,
227 CERTIFICATE_REQUIRED = 116,
228 NO_APPLICATION_PROTOCOL = 120,
229);