use crate::BufError;
use crate::Codec;
use crate::Cursor;
use crate::{Buf, BufMut, BufResult};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(u8)]
pub enum AlertLevel {
Warning = 1,
Fatal = 2,
}
impl Codec for AlertLevel {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
(*self as u8).encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
match u8::decode(reader, ())? {
x if x == (Self::Warning as u8) => Ok(Self::Warning),
x if x == (Self::Fatal as u8) => Ok(Self::Fatal),
_ => Err(BufError::UnexpectedValue),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(u8)]
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,
ExportRestriction = 60,
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 Codec for AlertDescription {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
(*self as u8).encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
match u8::decode(reader, ())? {
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::ExportRestriction as u8) => Ok(Self::ExportRestriction),
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::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(BufError::UnexpectedValue),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Alert {
pub level: AlertLevel,
pub description: AlertDescription,
}
impl Codec for Alert {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
self.level.encode(writer, ())?;
self.description.encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
let level = AlertLevel::decode(reader, ())?;
let description = AlertDescription::decode(reader, ())?;
Ok(Self { level, description })
}
}
#[cfg(test)]
mod tests {
use core::fmt::Debug;
use super::{Alert, AlertDescription, AlertLevel};
use crate::{Codec, Cursor};
fn codec_roundtrip<T: Codec<C> + Debug + Eq, C: Copy>(
etalon_struct: T,
etalon_bytes: &[u8],
context: C,
) {
let mut encoded_bytes = vec![];
{
let writer = &mut Cursor::new(&mut encoded_bytes);
etalon_struct.encode(writer, context).unwrap();
}
assert_eq!(etalon_bytes, &encoded_bytes);
let decoded_struct = {
let reader = &mut Cursor::new(&mut encoded_bytes);
T::decode(reader, context).unwrap()
};
assert_eq!(etalon_struct, decoded_struct);
encoded_bytes.fill(0x00);
{
let writer = &mut Cursor::new(&mut encoded_bytes);
decoded_struct.encode(writer, context).unwrap();
}
assert_eq!(etalon_bytes, &encoded_bytes);
}
#[test]
fn alert() {
let etalon_bytes = &[0x02, 0x14]; let etalon_struct = Alert {
level: AlertLevel::Fatal,
description: AlertDescription::BadRecordMac,
};
codec_roundtrip(etalon_struct, etalon_bytes, ());
}
}