#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[non_exhaustive]
pub enum AlertLevel {
Warning = 1,
Fatal = 2,
}
impl From<AlertLevel> for u8 {
#[inline]
fn from(alert_level: AlertLevel) -> Self {
alert_level as u8
}
}
impl TryFrom<u8> for AlertLevel {
type Error = u8;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
x if x == (Self::Warning as u8) => Ok(Self::Warning),
x if x == (Self::Fatal as u8) => Ok(Self::Fatal),
_ => Err(value),
}
}
}
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum AlertDescription {
CloseNotify = 0,
UnexpectedMessage = 10,
BadRecordMac = 20,
RecordOverflow = 22,
HandshakeFailure = 40,
BadCertificate = 42,
UnsupportedCertificate = 43,
CertificateRevoked = 44,
CertificateExpired = 45,
CertificateUnknown = 46,
IllegalParameter = 47,
UnknownCa = 48,
AccessDenied = 49,
DecodeError = 50,
DecryptError = 51,
ProtocolVersion = 70,
InsufficientSecurity = 71,
InternalError = 80,
InappropriateFallback = 86,
UserCanceled = 90,
MissingExtension = 109,
UnsupportedExtension = 110,
UnrecognizedName = 112,
BadCertificateStatusResponse = 113,
UnknownPskIdentity = 115,
CertificateRequired = 116,
NoApplicationProtocol = 120,
}
impl From<AlertDescription> for u8 {
#[inline]
fn from(alert_description: AlertDescription) -> Self {
alert_description as u8
}
}
impl TryFrom<u8> for AlertDescription {
type Error = u8;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
x if x == (Self::CloseNotify as u8) => Ok(Self::CloseNotify),
x if x == (Self::UnexpectedMessage as u8) => Ok(Self::UnexpectedMessage),
x if x == (Self::BadRecordMac as u8) => Ok(Self::BadRecordMac),
x if x == (Self::RecordOverflow as u8) => Ok(Self::RecordOverflow),
x if x == (Self::HandshakeFailure as u8) => Ok(Self::HandshakeFailure),
x if x == (Self::BadCertificate as u8) => Ok(Self::BadCertificate),
x if x == (Self::UnsupportedCertificate as u8) => Ok(Self::UnsupportedCertificate),
x if x == (Self::CertificateRevoked as u8) => Ok(Self::CertificateRevoked),
x if x == (Self::CertificateExpired as u8) => Ok(Self::CertificateExpired),
x if x == (Self::CertificateUnknown as u8) => Ok(Self::CertificateUnknown),
x if x == (Self::IllegalParameter as u8) => Ok(Self::IllegalParameter),
x if x == (Self::UnknownCa as u8) => Ok(Self::UnknownCa),
x if x == (Self::AccessDenied as u8) => Ok(Self::AccessDenied),
x if x == (Self::DecodeError as u8) => Ok(Self::DecodeError),
x if x == (Self::DecryptError as u8) => Ok(Self::DecryptError),
x if x == (Self::ProtocolVersion as u8) => Ok(Self::ProtocolVersion),
x if x == (Self::InsufficientSecurity as u8) => Ok(Self::InsufficientSecurity),
x if x == (Self::InternalError as u8) => Ok(Self::InternalError),
x if x == (Self::InappropriateFallback as u8) => Ok(Self::InappropriateFallback),
x if x == (Self::UserCanceled as u8) => Ok(Self::UserCanceled),
x if x == (Self::MissingExtension as u8) => Ok(Self::MissingExtension),
x if x == (Self::UnsupportedExtension as u8) => Ok(Self::UnsupportedExtension),
x if x == (Self::UnrecognizedName as u8) => Ok(Self::UnrecognizedName),
x if x == (Self::BadCertificateStatusResponse as u8) => {
Ok(Self::BadCertificateStatusResponse)
}
x if x == (Self::UnknownPskIdentity as u8) => Ok(Self::UnknownPskIdentity),
x if x == (Self::CertificateRequired as u8) => Ok(Self::CertificateRequired),
x if x == (Self::NoApplicationProtocol as u8) => Ok(Self::NoApplicationProtocol),
_ => Err(value),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Alert {
pub level: AlertLevel,
pub description: AlertDescription,
}
impl Alert {
pub fn from_be_bytes(bytes: [u8; 2]) -> Result<Self, AlertDescription> {
let level = match AlertLevel::try_from(bytes[0]) {
Ok(level) => level,
Err(val) => {
log::error!("Reserved AlertLevel 0x{val:02x}");
return Err(AlertDescription::DecodeError);
}
};
let description = match AlertDescription::try_from(bytes[1]) {
Ok(description) => description,
Err(val) => {
log::error!("Reserved AlertDescription 0x{val:02x}");
return Err(AlertDescription::DecodeError);
}
};
Ok(Self { level, description })
}
pub fn to_be_bytes(self) -> [u8; 2] {
[self.level.into(), self.description.into()]
}
pub(crate) fn new_fatal(description: AlertDescription) -> Self {
Self {
level: AlertLevel::Warning,
description,
}
}
pub(crate) fn new_warning(description: AlertDescription) -> Self {
Self {
level: AlertLevel::Warning,
description,
}
}
}