1use crate::TlsError;
2use crate::buffer::CryptoBuffer;
3use crate::parse_buffer::ParseBuffer;
4
5#[derive(Debug, Clone, Copy)]
6#[cfg_attr(feature = "defmt", derive(defmt::Format))]
7pub enum AlertLevel {
8 Warning = 1,
9 Fatal = 2,
10}
11
12impl AlertLevel {
13 #[must_use]
14 pub fn of(num: u8) -> Option<Self> {
15 match num {
16 1 => Some(AlertLevel::Warning),
17 2 => Some(AlertLevel::Fatal),
18 _ => None,
19 }
20 }
21}
22
23#[derive(Debug, Clone, Copy)]
24#[cfg_attr(feature = "defmt", derive(defmt::Format))]
25pub enum AlertDescription {
26 CloseNotify = 0,
27 UnexpectedMessage = 10,
28 BadRecordMac = 20,
29 RecordOverflow = 22,
30 HandshakeFailure = 40,
31 BadCertificate = 42,
32 UnsupportedCertificate = 43,
33 CertificateRevoked = 44,
34 CertificateExpired = 45,
35 CertificateUnknown = 46,
36 IllegalParameter = 47,
37 UnknownCa = 48,
38 AccessDenied = 49,
39 DecodeError = 50,
40 DecryptError = 51,
41 ProtocolVersion = 70,
42 InsufficientSecurity = 71,
43 InternalError = 80,
44 InappropriateFallback = 86,
45 UserCanceled = 90,
46 MissingExtension = 109,
47 UnsupportedExtension = 110,
48 UnrecognizedName = 112,
49 BadCertificateStatusResponse = 113,
50 UnknownPskIdentity = 115,
51 CertificateRequired = 116,
52 NoApplicationProtocol = 120,
53}
54
55impl AlertDescription {
56 #[must_use]
57 pub fn of(num: u8) -> Option<Self> {
58 match num {
59 0 => Some(AlertDescription::CloseNotify),
60 10 => Some(AlertDescription::UnexpectedMessage),
61 20 => Some(AlertDescription::BadRecordMac),
62 22 => Some(AlertDescription::RecordOverflow),
63 40 => Some(AlertDescription::HandshakeFailure),
64 42 => Some(AlertDescription::BadCertificate),
65 43 => Some(AlertDescription::UnsupportedCertificate),
66 44 => Some(AlertDescription::CertificateRevoked),
67 45 => Some(AlertDescription::CertificateExpired),
68 46 => Some(AlertDescription::CertificateUnknown),
69 47 => Some(AlertDescription::IllegalParameter),
70 48 => Some(AlertDescription::UnknownCa),
71 49 => Some(AlertDescription::AccessDenied),
72 50 => Some(AlertDescription::DecodeError),
73 51 => Some(AlertDescription::DecryptError),
74 70 => Some(AlertDescription::ProtocolVersion),
75 71 => Some(AlertDescription::InsufficientSecurity),
76 80 => Some(AlertDescription::InternalError),
77 86 => Some(AlertDescription::InappropriateFallback),
78 90 => Some(AlertDescription::UserCanceled),
79 109 => Some(AlertDescription::MissingExtension),
80 110 => Some(AlertDescription::UnsupportedExtension),
81 112 => Some(AlertDescription::UnrecognizedName),
82 113 => Some(AlertDescription::BadCertificateStatusResponse),
83 115 => Some(AlertDescription::UnknownPskIdentity),
84 116 => Some(AlertDescription::CertificateRequired),
85 120 => Some(AlertDescription::NoApplicationProtocol),
86 _ => None,
87 }
88 }
89}
90
91#[derive(Debug)]
92#[cfg_attr(feature = "defmt", derive(defmt::Format))]
93pub struct Alert {
94 pub(crate) level: AlertLevel,
95 pub(crate) description: AlertDescription,
96}
97
98impl Alert {
99 #[must_use]
100 pub fn new(level: AlertLevel, description: AlertDescription) -> Self {
101 Self { level, description }
102 }
103
104 pub fn parse(buf: &mut ParseBuffer<'_>) -> Result<Alert, TlsError> {
105 let level = buf.read_u8()?;
106 let desc = buf.read_u8()?;
107
108 Ok(Self {
109 level: AlertLevel::of(level).ok_or(TlsError::DecodeError)?,
110 description: AlertDescription::of(desc).ok_or(TlsError::DecodeError)?,
111 })
112 }
113
114 pub fn encode(&self, buf: &mut CryptoBuffer<'_>) -> Result<(), TlsError> {
115 buf.push(self.level as u8)
116 .map_err(|_| TlsError::EncodeError)?;
117 buf.push(self.description as u8)
118 .map_err(|_| TlsError::EncodeError)?;
119 Ok(())
120 }
121}