1#[cfg(test)]
2mod alert_test;
3
4use std::fmt;
5use std::io::{Read, Write};
6
7use byteorder::{ReadBytesExt, WriteBytesExt};
8
9use super::content::*;
10use crate::error::Result;
11
12#[derive(Copy, Clone, PartialEq, Debug)]
13pub(crate) enum AlertLevel {
14 Warning = 1,
15 Fatal = 2,
16 Invalid,
17}
18
19impl fmt::Display for AlertLevel {
20 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21 match *self {
22 AlertLevel::Warning => write!(f, "LevelWarning"),
23 AlertLevel::Fatal => write!(f, "LevelFatal"),
24 _ => write!(f, "Invalid alert level"),
25 }
26 }
27}
28
29impl From<u8> for AlertLevel {
30 fn from(val: u8) -> Self {
31 match val {
32 1 => AlertLevel::Warning,
33 2 => AlertLevel::Fatal,
34 _ => AlertLevel::Invalid,
35 }
36 }
37}
38
39#[derive(Copy, Clone, PartialEq, Debug)]
40pub(crate) enum AlertDescription {
41 CloseNotify = 0,
42 UnexpectedMessage = 10,
43 BadRecordMac = 20,
44 DecryptionFailed = 21,
45 RecordOverflow = 22,
46 DecompressionFailure = 30,
47 HandshakeFailure = 40,
48 NoCertificate = 41,
49 BadCertificate = 42,
50 UnsupportedCertificate = 43,
51 CertificateRevoked = 44,
52 CertificateExpired = 45,
53 CertificateUnknown = 46,
54 IllegalParameter = 47,
55 UnknownCa = 48,
56 AccessDenied = 49,
57 DecodeError = 50,
58 DecryptError = 51,
59 ExportRestriction = 60,
60 ProtocolVersion = 70,
61 InsufficientSecurity = 71,
62 InternalError = 80,
63 UserCanceled = 90,
64 NoRenegotiation = 100,
65 UnsupportedExtension = 110,
66 UnknownPskIdentity = 115,
67 Invalid,
68}
69
70impl fmt::Display for AlertDescription {
71 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72 match *self {
73 AlertDescription::CloseNotify => write!(f, "CloseNotify"),
74 AlertDescription::UnexpectedMessage => write!(f, "UnexpectedMessage"),
75 AlertDescription::BadRecordMac => write!(f, "BadRecordMac"),
76 AlertDescription::DecryptionFailed => write!(f, "DecryptionFailed"),
77 AlertDescription::RecordOverflow => write!(f, "RecordOverflow"),
78 AlertDescription::DecompressionFailure => write!(f, "DecompressionFailure"),
79 AlertDescription::HandshakeFailure => write!(f, "HandshakeFailure"),
80 AlertDescription::NoCertificate => write!(f, "NoCertificate"),
81 AlertDescription::BadCertificate => write!(f, "BadCertificate"),
82 AlertDescription::UnsupportedCertificate => write!(f, "UnsupportedCertificate"),
83 AlertDescription::CertificateRevoked => write!(f, "CertificateRevoked"),
84 AlertDescription::CertificateExpired => write!(f, "CertificateExpired"),
85 AlertDescription::CertificateUnknown => write!(f, "CertificateUnknown"),
86 AlertDescription::IllegalParameter => write!(f, "IllegalParameter"),
87 AlertDescription::UnknownCa => write!(f, "UnknownCA"),
88 AlertDescription::AccessDenied => write!(f, "AccessDenied"),
89 AlertDescription::DecodeError => write!(f, "DecodeError"),
90 AlertDescription::DecryptError => write!(f, "DecryptError"),
91 AlertDescription::ExportRestriction => write!(f, "ExportRestriction"),
92 AlertDescription::ProtocolVersion => write!(f, "ProtocolVersion"),
93 AlertDescription::InsufficientSecurity => write!(f, "InsufficientSecurity"),
94 AlertDescription::InternalError => write!(f, "InternalError"),
95 AlertDescription::UserCanceled => write!(f, "UserCanceled"),
96 AlertDescription::NoRenegotiation => write!(f, "NoRenegotiation"),
97 AlertDescription::UnsupportedExtension => write!(f, "UnsupportedExtension"),
98 AlertDescription::UnknownPskIdentity => write!(f, "UnknownPskIdentity"),
99 _ => write!(f, "Invalid alert description"),
100 }
101 }
102}
103
104impl From<u8> for AlertDescription {
105 fn from(val: u8) -> Self {
106 match val {
107 0 => AlertDescription::CloseNotify,
108 10 => AlertDescription::UnexpectedMessage,
109 20 => AlertDescription::BadRecordMac,
110 21 => AlertDescription::DecryptionFailed,
111 22 => AlertDescription::RecordOverflow,
112 30 => AlertDescription::DecompressionFailure,
113 40 => AlertDescription::HandshakeFailure,
114 41 => AlertDescription::NoCertificate,
115 42 => AlertDescription::BadCertificate,
116 43 => AlertDescription::UnsupportedCertificate,
117 44 => AlertDescription::CertificateRevoked,
118 45 => AlertDescription::CertificateExpired,
119 46 => AlertDescription::CertificateUnknown,
120 47 => AlertDescription::IllegalParameter,
121 48 => AlertDescription::UnknownCa,
122 49 => AlertDescription::AccessDenied,
123 50 => AlertDescription::DecodeError,
124 51 => AlertDescription::DecryptError,
125 60 => AlertDescription::ExportRestriction,
126 70 => AlertDescription::ProtocolVersion,
127 71 => AlertDescription::InsufficientSecurity,
128 80 => AlertDescription::InternalError,
129 90 => AlertDescription::UserCanceled,
130 100 => AlertDescription::NoRenegotiation,
131 110 => AlertDescription::UnsupportedExtension,
132 115 => AlertDescription::UnknownPskIdentity,
133 _ => AlertDescription::Invalid,
134 }
135 }
136}
137
138#[derive(Copy, Clone, PartialEq, Debug)]
153pub struct Alert {
154 pub(crate) alert_level: AlertLevel,
155 pub(crate) alert_description: AlertDescription,
156}
157
158impl fmt::Display for Alert {
159 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
160 write!(f, "Alert {}: {}", self.alert_level, self.alert_description)
161 }
162}
163
164impl Alert {
165 pub fn content_type(&self) -> ContentType {
166 ContentType::Alert
167 }
168
169 pub fn size(&self) -> usize {
170 2
171 }
172
173 pub fn marshal<W: Write>(&self, writer: &mut W) -> Result<()> {
174 writer.write_u8(self.alert_level as u8)?;
175 writer.write_u8(self.alert_description as u8)?;
176
177 Ok(writer.flush()?)
178 }
179
180 pub fn unmarshal<R: Read>(reader: &mut R) -> Result<Self> {
181 let alert_level = reader.read_u8()?.into();
182 let alert_description = reader.read_u8()?.into();
183
184 Ok(Alert {
185 alert_level,
186 alert_description,
187 })
188 }
189}