use std::cmp::Ordering;
use std::fmt;
use std::time::Instant;
use arrayvec::ArrayVec;
use nom::IResult;
use nom::bytes::complete::take;
use nom::number::complete::{be_u8, be_u16};
use crate::SeededRng;
use crate::buffer::Buf;
use crate::time_tricks::InstantExt;
pub type NamedGroupVec = ArrayVec<NamedGroup, { NamedGroup::supported().len() }>;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Random {
pub bytes: [u8; 32],
}
impl Random {
pub fn new(rng: &mut SeededRng) -> Self {
Self {
bytes: rng.random(),
}
}
pub fn new_with_time(now: Instant, rng: &mut SeededRng) -> Self {
let gmt_duration = now.to_unix_duration();
let gmt_unix_time = gmt_duration.as_secs() as u32;
let random_bytes: [u8; 28] = rng.random();
let mut bytes = [0u8; 32];
bytes[..4].copy_from_slice(&gmt_unix_time.to_be_bytes());
bytes[4..].copy_from_slice(&random_bytes);
Self { bytes }
}
pub fn parse(input: &[u8]) -> IResult<&[u8], Random> {
let (input, data) = take(32_usize)(input)?;
let mut bytes = [0u8; 32];
bytes.copy_from_slice(data);
Ok((input, Random { bytes }))
}
pub fn serialize(&self, output: &mut Buf) {
output.extend_from_slice(&self.bytes);
}
}
#[repr(transparent)]
#[derive(Clone, Copy, Default, PartialEq, Eq, Hash)]
pub struct NamedGroup(u16);
#[allow(non_upper_case_globals)]
impl NamedGroup {
pub const Sect163k1: Self = Self(1);
pub const Sect163r1: Self = Self(2);
pub const Sect163r2: Self = Self(3);
pub const Sect193r1: Self = Self(4);
pub const Sect193r2: Self = Self(5);
pub const Sect233k1: Self = Self(6);
pub const Sect233r1: Self = Self(7);
pub const Sect239k1: Self = Self(8);
pub const Sect283k1: Self = Self(9);
pub const Sect283r1: Self = Self(10);
pub const Sect409k1: Self = Self(11);
pub const Sect409r1: Self = Self(12);
pub const Sect571k1: Self = Self(13);
pub const Sect571r1: Self = Self(14);
pub const Secp160k1: Self = Self(15);
pub const Secp160r1: Self = Self(16);
pub const Secp160r2: Self = Self(17);
pub const Secp192k1: Self = Self(18);
pub const Secp192r1: Self = Self(19);
pub const Secp224k1: Self = Self(20);
pub const Secp224r1: Self = Self(21);
pub const Secp256k1: Self = Self(22);
pub const Secp256r1: Self = Self(23);
pub const Secp384r1: Self = Self(24);
pub const Secp521r1: Self = Self(25);
pub const X25519: Self = Self(29);
pub const X448: Self = Self(30);
pub const fn from_u16(value: u16) -> Self {
Self(value)
}
pub const fn as_u16(&self) -> u16 {
self.0
}
pub const fn is_unknown(&self) -> bool {
!matches!(*self, Self(1..=25 | 29..=30))
}
pub fn parse(input: &[u8]) -> IResult<&[u8], NamedGroup> {
let (input, value) = be_u16(input)?;
Ok((input, NamedGroup::from_u16(value)))
}
pub fn is_supported(&self) -> bool {
Self::supported().contains(self)
}
pub const fn all() -> &'static [NamedGroup; 27] {
&[
NamedGroup::Sect163k1,
NamedGroup::Sect163r1,
NamedGroup::Sect163r2,
NamedGroup::Sect193r1,
NamedGroup::Sect193r2,
NamedGroup::Sect233k1,
NamedGroup::Sect233r1,
NamedGroup::Sect239k1,
NamedGroup::Sect283k1,
NamedGroup::Sect283r1,
NamedGroup::Sect409k1,
NamedGroup::Sect409r1,
NamedGroup::Sect571k1,
NamedGroup::Sect571r1,
NamedGroup::Secp160k1,
NamedGroup::Secp160r1,
NamedGroup::Secp160r2,
NamedGroup::Secp192k1,
NamedGroup::Secp192r1,
NamedGroup::Secp224k1,
NamedGroup::Secp224r1,
NamedGroup::Secp256k1,
NamedGroup::Secp256r1,
NamedGroup::Secp384r1,
NamedGroup::Secp521r1,
NamedGroup::X25519,
NamedGroup::X448,
]
}
pub const fn supported() -> &'static [NamedGroup; 4] {
&[
NamedGroup::X25519,
NamedGroup::Secp256r1,
NamedGroup::Secp384r1,
NamedGroup::Secp521r1,
]
}
}
impl fmt::Debug for NamedGroup {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
NamedGroup::Sect163k1 => f.write_str("Sect163k1"),
NamedGroup::Sect163r1 => f.write_str("Sect163r1"),
NamedGroup::Sect163r2 => f.write_str("Sect163r2"),
NamedGroup::Sect193r1 => f.write_str("Sect193r1"),
NamedGroup::Sect193r2 => f.write_str("Sect193r2"),
NamedGroup::Sect233k1 => f.write_str("Sect233k1"),
NamedGroup::Sect233r1 => f.write_str("Sect233r1"),
NamedGroup::Sect239k1 => f.write_str("Sect239k1"),
NamedGroup::Sect283k1 => f.write_str("Sect283k1"),
NamedGroup::Sect283r1 => f.write_str("Sect283r1"),
NamedGroup::Sect409k1 => f.write_str("Sect409k1"),
NamedGroup::Sect409r1 => f.write_str("Sect409r1"),
NamedGroup::Sect571k1 => f.write_str("Sect571k1"),
NamedGroup::Sect571r1 => f.write_str("Sect571r1"),
NamedGroup::Secp160k1 => f.write_str("Secp160k1"),
NamedGroup::Secp160r1 => f.write_str("Secp160r1"),
NamedGroup::Secp160r2 => f.write_str("Secp160r2"),
NamedGroup::Secp192k1 => f.write_str("Secp192k1"),
NamedGroup::Secp192r1 => f.write_str("Secp192r1"),
NamedGroup::Secp224k1 => f.write_str("Secp224k1"),
NamedGroup::Secp224r1 => f.write_str("Secp224r1"),
NamedGroup::Secp256k1 => f.write_str("Secp256k1"),
NamedGroup::Secp256r1 => f.write_str("Secp256r1"),
NamedGroup::Secp384r1 => f.write_str("Secp384r1"),
NamedGroup::Secp521r1 => f.write_str("Secp521r1"),
NamedGroup::X25519 => f.write_str("X25519"),
NamedGroup::X448 => f.write_str("X448"),
_ => f.debug_tuple("Unknown").field(&self.0).finish(),
}
}
}
#[repr(transparent)]
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct HashAlgorithm(u8);
impl Default for HashAlgorithm {
fn default() -> Self {
Self::None
}
}
#[allow(non_upper_case_globals)]
impl HashAlgorithm {
pub const None: Self = Self(0);
pub const MD5: Self = Self(1);
pub const SHA1: Self = Self(2);
pub const SHA224: Self = Self(3);
pub const SHA256: Self = Self(4);
pub const SHA384: Self = Self(5);
pub const SHA512: Self = Self(6);
pub(crate) const UNKNOWN_DERIVED: Self = Self(u8::MAX);
pub const fn from_u8(value: u8) -> Self {
Self(value)
}
pub const fn as_u8(&self) -> u8 {
self.0
}
pub const fn is_unknown(&self) -> bool {
self.0 > Self::SHA512.0
}
pub fn parse(input: &[u8]) -> IResult<&[u8], HashAlgorithm> {
let (input, value) = be_u8(input)?;
Ok((input, HashAlgorithm::from_u8(value)))
}
pub const fn output_len(&self) -> usize {
match *self {
HashAlgorithm::None => 0,
HashAlgorithm::MD5 => 16,
HashAlgorithm::SHA1 => 20,
HashAlgorithm::SHA224 => 28,
HashAlgorithm::SHA256 => 32,
HashAlgorithm::SHA384 => 48,
HashAlgorithm::SHA512 => 64,
_ => 0,
}
}
}
impl fmt::Debug for HashAlgorithm {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
HashAlgorithm::None => f.write_str("None"),
HashAlgorithm::MD5 => f.write_str("MD5"),
HashAlgorithm::SHA1 => f.write_str("SHA1"),
HashAlgorithm::SHA224 => f.write_str("SHA224"),
HashAlgorithm::SHA256 => f.write_str("SHA256"),
HashAlgorithm::SHA384 => f.write_str("SHA384"),
HashAlgorithm::SHA512 => f.write_str("SHA512"),
_ => f.debug_tuple("Unknown").field(&self.0).finish(),
}
}
}
#[repr(transparent)]
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct SignatureAlgorithm(u8);
impl Default for SignatureAlgorithm {
fn default() -> Self {
Self::Anonymous
}
}
#[allow(non_upper_case_globals)]
impl SignatureAlgorithm {
pub const Anonymous: Self = Self(0);
pub const RSA: Self = Self(1);
pub const DSA: Self = Self(2);
pub const ECDSA: Self = Self(3);
pub(crate) const UNKNOWN_DERIVED: Self = Self(u8::MAX);
pub const fn from_u8(value: u8) -> Self {
Self(value)
}
pub const fn as_u8(&self) -> u8 {
self.0
}
pub const fn is_unknown(&self) -> bool {
self.0 > Self::ECDSA.0
}
pub fn parse(input: &[u8]) -> IResult<&[u8], SignatureAlgorithm> {
let (input, value) = be_u8(input)?;
Ok((input, SignatureAlgorithm::from_u8(value)))
}
}
impl fmt::Debug for SignatureAlgorithm {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
SignatureAlgorithm::Anonymous => f.write_str("Anonymous"),
SignatureAlgorithm::RSA => f.write_str("RSA"),
SignatureAlgorithm::DSA => f.write_str("DSA"),
SignatureAlgorithm::ECDSA => f.write_str("ECDSA"),
_ => f.debug_tuple("Unknown").field(&self.0).finish(),
}
}
}
#[repr(transparent)]
#[derive(Clone, Copy, Default, PartialEq, Eq, Hash)]
pub struct ContentType(u8);
#[allow(non_upper_case_globals)]
impl ContentType {
pub const ChangeCipherSpec: Self = Self(20);
pub const Alert: Self = Self(21);
pub const Handshake: Self = Self(22);
pub const ApplicationData: Self = Self(23);
pub const Ack: Self = Self(26);
pub const fn from_u8(value: u8) -> Self {
Self(value)
}
pub const fn as_u8(&self) -> u8 {
self.0
}
pub const fn is_unknown(&self) -> bool {
!matches!(*self, Self(20..=23 | 26))
}
pub fn parse(input: &[u8]) -> IResult<&[u8], ContentType> {
let (input, byte) = be_u8(input)?;
Ok((input, Self::from_u8(byte)))
}
}
impl fmt::Debug for ContentType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
ContentType::ChangeCipherSpec => f.write_str("ChangeCipherSpec"),
ContentType::Alert => f.write_str("Alert"),
ContentType::Handshake => f.write_str("Handshake"),
ContentType::ApplicationData => f.write_str("ApplicationData"),
ContentType::Ack => f.write_str("Ack"),
_ => f.debug_tuple("Unknown").field(&self.0).finish(),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct Sequence {
pub epoch: u16,
pub sequence_number: u64,
}
impl Sequence {
pub fn new(epoch: u16) -> Self {
Self {
epoch,
sequence_number: 0,
}
}
}
impl fmt::Display for Sequence {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"[epoch: {}, sequence_number: {}]",
self.epoch, self.sequence_number,
)
}
}
impl Ord for Sequence {
fn cmp(&self, other: &Self) -> Ordering {
if self.epoch < other.epoch {
Ordering::Less
} else if self.epoch > other.epoch {
Ordering::Greater
} else {
self.sequence_number.cmp(&other.sequence_number)
}
}
}
impl PartialOrd for Sequence {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
#[repr(transparent)]
#[derive(Clone, Copy, Default, PartialEq, Eq, Hash)]
pub struct SignatureScheme(u16);
impl SignatureScheme {
pub const ECDSA_SECP256R1_SHA256: Self = Self(0x0403);
pub const ECDSA_SECP384R1_SHA384: Self = Self(0x0503);
pub const ECDSA_SECP521R1_SHA512: Self = Self(0x0603);
pub const ED25519: Self = Self(0x0807);
pub const ED448: Self = Self(0x0808);
pub const RSA_PSS_RSAE_SHA256: Self = Self(0x0804);
pub const RSA_PSS_RSAE_SHA384: Self = Self(0x0805);
pub const RSA_PSS_RSAE_SHA512: Self = Self(0x0806);
pub const RSA_PSS_PSS_SHA256: Self = Self(0x0809);
pub const RSA_PSS_PSS_SHA384: Self = Self(0x080a);
pub const RSA_PSS_PSS_SHA512: Self = Self(0x080b);
pub const RSA_PKCS1_SHA256: Self = Self(0x0401);
pub const RSA_PKCS1_SHA384: Self = Self(0x0501);
pub const RSA_PKCS1_SHA512: Self = Self(0x0601);
pub const fn from_u16(value: u16) -> Self {
Self(value)
}
pub const fn as_u16(&self) -> u16 {
self.0
}
pub const fn is_unknown(&self) -> bool {
!matches!(
*self,
Self(0x0401 | 0x0403 | 0x0501 | 0x0503 | 0x0601 | 0x0603 | 0x0804..=0x080b)
)
}
pub fn parse(input: &[u8]) -> IResult<&[u8], SignatureScheme> {
let (input, value) = be_u16(input)?;
Ok((input, SignatureScheme::from_u16(value)))
}
pub fn is_supported(&self) -> bool {
Self::SUPPORTED.contains(self)
}
pub const fn all() -> &'static [SignatureScheme] {
&[
SignatureScheme::ECDSA_SECP256R1_SHA256,
SignatureScheme::ECDSA_SECP384R1_SHA384,
SignatureScheme::ECDSA_SECP521R1_SHA512,
SignatureScheme::ED25519,
SignatureScheme::ED448,
SignatureScheme::RSA_PSS_RSAE_SHA256,
SignatureScheme::RSA_PSS_RSAE_SHA384,
SignatureScheme::RSA_PSS_RSAE_SHA512,
SignatureScheme::RSA_PSS_PSS_SHA256,
SignatureScheme::RSA_PSS_PSS_SHA384,
SignatureScheme::RSA_PSS_PSS_SHA512,
SignatureScheme::RSA_PKCS1_SHA256,
SignatureScheme::RSA_PKCS1_SHA384,
SignatureScheme::RSA_PKCS1_SHA512,
]
}
const SUPPORTED: &[SignatureScheme] = &[
SignatureScheme::ECDSA_SECP256R1_SHA256,
SignatureScheme::ECDSA_SECP384R1_SHA384,
];
pub fn supported() -> ArrayVec<SignatureScheme, 2> {
let mut schemes = ArrayVec::new();
schemes.push(SignatureScheme::ECDSA_SECP256R1_SHA256);
schemes.push(SignatureScheme::ECDSA_SECP384R1_SHA384);
schemes
}
pub fn named_group(&self) -> Option<NamedGroup> {
match *self {
SignatureScheme::ECDSA_SECP256R1_SHA256 => Some(NamedGroup::Secp256r1),
SignatureScheme::ECDSA_SECP384R1_SHA384 => Some(NamedGroup::Secp384r1),
_ => None,
}
}
pub fn hash_algorithm(&self) -> HashAlgorithm {
match *self {
SignatureScheme::ECDSA_SECP256R1_SHA256
| SignatureScheme::RSA_PSS_RSAE_SHA256
| SignatureScheme::RSA_PSS_PSS_SHA256
| SignatureScheme::RSA_PKCS1_SHA256 => HashAlgorithm::SHA256,
SignatureScheme::ECDSA_SECP384R1_SHA384
| SignatureScheme::RSA_PSS_RSAE_SHA384
| SignatureScheme::RSA_PSS_PSS_SHA384
| SignatureScheme::RSA_PKCS1_SHA384 => HashAlgorithm::SHA384,
SignatureScheme::ECDSA_SECP521R1_SHA512
| SignatureScheme::RSA_PSS_RSAE_SHA512
| SignatureScheme::RSA_PSS_PSS_SHA512
| SignatureScheme::RSA_PKCS1_SHA512 => HashAlgorithm::SHA512,
SignatureScheme::ED25519 | SignatureScheme::ED448 => HashAlgorithm::None,
_ => HashAlgorithm::UNKNOWN_DERIVED,
}
}
}
impl fmt::Debug for SignatureScheme {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
SignatureScheme::ECDSA_SECP256R1_SHA256 => f.write_str("ECDSA_SECP256R1_SHA256"),
SignatureScheme::ECDSA_SECP384R1_SHA384 => f.write_str("ECDSA_SECP384R1_SHA384"),
SignatureScheme::ECDSA_SECP521R1_SHA512 => f.write_str("ECDSA_SECP521R1_SHA512"),
SignatureScheme::ED25519 => f.write_str("ED25519"),
SignatureScheme::ED448 => f.write_str("ED448"),
SignatureScheme::RSA_PSS_RSAE_SHA256 => f.write_str("RSA_PSS_RSAE_SHA256"),
SignatureScheme::RSA_PSS_RSAE_SHA384 => f.write_str("RSA_PSS_RSAE_SHA384"),
SignatureScheme::RSA_PSS_RSAE_SHA512 => f.write_str("RSA_PSS_RSAE_SHA512"),
SignatureScheme::RSA_PSS_PSS_SHA256 => f.write_str("RSA_PSS_PSS_SHA256"),
SignatureScheme::RSA_PSS_PSS_SHA384 => f.write_str("RSA_PSS_PSS_SHA384"),
SignatureScheme::RSA_PSS_PSS_SHA512 => f.write_str("RSA_PSS_PSS_SHA512"),
SignatureScheme::RSA_PKCS1_SHA256 => f.write_str("RSA_PKCS1_SHA256"),
SignatureScheme::RSA_PKCS1_SHA384 => f.write_str("RSA_PKCS1_SHA384"),
SignatureScheme::RSA_PKCS1_SHA512 => f.write_str("RSA_PKCS1_SHA512"),
_ => f.debug_tuple("Unknown").field(&self.0).finish(),
}
}
}
#[repr(transparent)]
#[derive(Clone, Copy, Default, PartialEq, Eq, Hash)]
pub struct Dtls13CipherSuite(u16);
impl Dtls13CipherSuite {
pub const AES_128_GCM_SHA256: Self = Self(0x1301);
pub const AES_256_GCM_SHA384: Self = Self(0x1302);
pub const CHACHA20_POLY1305_SHA256: Self = Self(0x1303);
pub const AES_128_CCM_SHA256: Self = Self(0x1304);
pub const AES_128_CCM_8_SHA256: Self = Self(0x1305);
pub const fn from_u16(value: u16) -> Self {
Self(value)
}
pub const fn as_u16(&self) -> u16 {
self.0
}
pub const fn is_unknown(&self) -> bool {
!matches!(*self, Self(0x1301..=0x1305))
}
pub fn parse(input: &[u8]) -> IResult<&[u8], Dtls13CipherSuite> {
let (input, value) = be_u16(input)?;
Ok((input, Dtls13CipherSuite::from_u16(value)))
}
pub fn hash_algorithm(&self) -> HashAlgorithm {
match *self {
Dtls13CipherSuite::AES_128_GCM_SHA256
| Dtls13CipherSuite::CHACHA20_POLY1305_SHA256
| Dtls13CipherSuite::AES_128_CCM_SHA256
| Dtls13CipherSuite::AES_128_CCM_8_SHA256 => HashAlgorithm::SHA256,
Dtls13CipherSuite::AES_256_GCM_SHA384 => HashAlgorithm::SHA384,
_ => HashAlgorithm::UNKNOWN_DERIVED,
}
}
pub fn is_supported(&self) -> bool {
Self::supported().contains(self)
}
pub const fn all() -> &'static [Dtls13CipherSuite] {
&[
Dtls13CipherSuite::AES_128_GCM_SHA256,
Dtls13CipherSuite::AES_256_GCM_SHA384,
Dtls13CipherSuite::CHACHA20_POLY1305_SHA256,
Dtls13CipherSuite::AES_128_CCM_SHA256,
Dtls13CipherSuite::AES_128_CCM_8_SHA256,
]
}
pub const fn supported() -> &'static [Dtls13CipherSuite] {
&[
Dtls13CipherSuite::AES_128_GCM_SHA256,
Dtls13CipherSuite::AES_256_GCM_SHA384,
Dtls13CipherSuite::CHACHA20_POLY1305_SHA256,
]
}
pub fn verify_data_length(&self) -> usize {
self.hash_algorithm().output_len()
}
}
impl fmt::Debug for Dtls13CipherSuite {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Dtls13CipherSuite::AES_128_GCM_SHA256 => f.write_str("AES_128_GCM_SHA256"),
Dtls13CipherSuite::AES_256_GCM_SHA384 => f.write_str("AES_256_GCM_SHA384"),
Dtls13CipherSuite::CHACHA20_POLY1305_SHA256 => f.write_str("CHACHA20_POLY1305_SHA256"),
Dtls13CipherSuite::AES_128_CCM_SHA256 => f.write_str("AES_128_CCM_SHA256"),
Dtls13CipherSuite::AES_128_CCM_8_SHA256 => f.write_str("AES_128_CCM_8_SHA256"),
_ => f.debug_tuple("Unknown").field(&self.0).finish(),
}
}
}
#[repr(transparent)]
#[derive(Clone, Copy, Default, PartialEq, Eq, Hash)]
pub struct ProtocolVersion(u16);
impl ProtocolVersion {
pub const DTLS1_0: Self = Self(0xFEFF);
pub const DTLS1_2: Self = Self(0xFEFD);
pub const DTLS1_3: Self = Self(0xFEFC);
pub const fn from_u16(value: u16) -> Self {
Self(value)
}
pub const fn as_u16(&self) -> u16 {
self.0
}
pub const fn is_unknown(&self) -> bool {
!matches!(*self, Self(0xFEFF | 0xFEFD | 0xFEFC))
}
pub fn parse(input: &[u8]) -> IResult<&[u8], ProtocolVersion> {
let (input, version) = be_u16(input)?;
Ok((input, ProtocolVersion::from_u16(version)))
}
pub fn serialize(&self, output: &mut Buf) {
output.extend_from_slice(&self.as_u16().to_be_bytes());
}
}
impl fmt::Debug for ProtocolVersion {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
ProtocolVersion::DTLS1_0 => f.write_str("DTLS1_0"),
ProtocolVersion::DTLS1_2 => f.write_str("DTLS1_2"),
ProtocolVersion::DTLS1_3 => f.write_str("DTLS1_3"),
_ => f.debug_tuple("Unknown").field(&self.0).finish(),
}
}
}
#[repr(transparent)]
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct CompressionMethod(u8);
impl Default for CompressionMethod {
fn default() -> Self {
Self::Null
}
}
#[allow(non_upper_case_globals)]
impl CompressionMethod {
pub const Null: Self = Self(0x00);
pub const Deflate: Self = Self(0x01);
pub const fn from_u8(value: u8) -> Self {
Self(value)
}
pub fn is_supported(&self) -> bool {
Self::supported().contains(self)
}
pub const fn all() -> &'static [CompressionMethod; 2] {
&[CompressionMethod::Null, CompressionMethod::Deflate]
}
pub const fn supported() -> &'static [CompressionMethod; 1] {
&[CompressionMethod::Null]
}
pub const fn as_u8(&self) -> u8 {
self.0
}
pub const fn is_unknown(&self) -> bool {
self.0 > Self::Deflate.0
}
pub fn parse(input: &[u8]) -> IResult<&[u8], CompressionMethod> {
let (input, value) = be_u8(input)?;
Ok((input, CompressionMethod::from_u8(value)))
}
}
impl fmt::Debug for CompressionMethod {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
CompressionMethod::Null => f.write_str("Null"),
CompressionMethod::Deflate => f.write_str("Deflate"),
_ => f.debug_tuple("Unknown").field(&self.0).finish(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn named_group_newtype_shape() {
assert_eq!(std::mem::size_of::<NamedGroup>(), 2);
assert_eq!(NamedGroup::default().as_u16(), 0);
assert!(NamedGroup::default().is_unknown());
}
#[test]
fn named_group_wire_roundtrip() {
for group in NamedGroup::all() {
assert_eq!(NamedGroup::from_u16(group.as_u16()), *group);
assert!(!group.is_unknown());
}
let unknown = NamedGroup::from_u16(0xFFFF);
assert_eq!(unknown.as_u16(), 0xFFFF);
assert!(unknown.is_unknown());
}
#[test]
fn named_group_debug_stays_enum_like() {
assert_eq!(format!("{:?}", NamedGroup::Secp256r1), "Secp256r1");
assert_eq!(format!("{:?}", NamedGroup::X25519), "X25519");
assert_eq!(
format!("{:?}", NamedGroup::from_u16(0xFFFF)),
"Unknown(65535)"
);
}
#[test]
fn hash_algorithm_newtype_shape() {
assert_eq!(std::mem::size_of::<HashAlgorithm>(), 1);
assert_eq!(HashAlgorithm::default().as_u8(), 0);
assert_eq!(HashAlgorithm::default(), HashAlgorithm::None);
}
#[test]
fn hash_algorithm_wire_roundtrip() {
let known = [
(0, HashAlgorithm::None),
(1, HashAlgorithm::MD5),
(2, HashAlgorithm::SHA1),
(3, HashAlgorithm::SHA224),
(4, HashAlgorithm::SHA256),
(5, HashAlgorithm::SHA384),
(6, HashAlgorithm::SHA512),
];
for (wire, algorithm) in known {
assert_eq!(HashAlgorithm::from_u8(wire), algorithm);
assert_eq!(algorithm.as_u8(), wire);
assert!(!algorithm.is_unknown());
}
let unknown = HashAlgorithm::from_u8(7);
assert_eq!(unknown.as_u8(), 7);
assert!(unknown.is_unknown());
}
#[test]
fn hash_algorithm_output_len() {
assert_eq!(HashAlgorithm::None.output_len(), 0);
assert_eq!(HashAlgorithm::MD5.output_len(), 16);
assert_eq!(HashAlgorithm::SHA1.output_len(), 20);
assert_eq!(HashAlgorithm::SHA224.output_len(), 28);
assert_eq!(HashAlgorithm::SHA256.output_len(), 32);
assert_eq!(HashAlgorithm::SHA384.output_len(), 48);
assert_eq!(HashAlgorithm::SHA512.output_len(), 64);
assert_eq!(HashAlgorithm::from_u8(7).output_len(), 0);
}
#[test]
fn hash_algorithm_debug_stays_enum_like() {
assert_eq!(format!("{:?}", HashAlgorithm::None), "None");
assert_eq!(format!("{:?}", HashAlgorithm::SHA256), "SHA256");
assert_eq!(format!("{:?}", HashAlgorithm::from_u8(7)), "Unknown(7)");
}
#[test]
fn signature_algorithm_newtype_shape() {
assert_eq!(std::mem::size_of::<SignatureAlgorithm>(), 1);
assert_eq!(SignatureAlgorithm::default().as_u8(), 0);
assert_eq!(SignatureAlgorithm::default(), SignatureAlgorithm::Anonymous);
}
#[test]
fn signature_algorithm_wire_roundtrip() {
let known = [
(0, SignatureAlgorithm::Anonymous),
(1, SignatureAlgorithm::RSA),
(2, SignatureAlgorithm::DSA),
(3, SignatureAlgorithm::ECDSA),
];
for (wire, algorithm) in known {
assert_eq!(SignatureAlgorithm::from_u8(wire), algorithm);
assert_eq!(algorithm.as_u8(), wire);
assert!(!algorithm.is_unknown());
}
let unknown = SignatureAlgorithm::from_u8(4);
assert_eq!(unknown.as_u8(), 4);
assert!(unknown.is_unknown());
}
#[test]
fn signature_algorithm_debug_stays_enum_like() {
assert_eq!(format!("{:?}", SignatureAlgorithm::Anonymous), "Anonymous");
assert_eq!(format!("{:?}", SignatureAlgorithm::ECDSA), "ECDSA");
assert_eq!(
format!("{:?}", SignatureAlgorithm::from_u8(4)),
"Unknown(4)"
);
}
#[test]
fn compression_method_newtype_shape() {
assert_eq!(std::mem::size_of::<CompressionMethod>(), 1);
assert_eq!(CompressionMethod::default().as_u8(), 0);
assert_eq!(CompressionMethod::default(), CompressionMethod::Null);
}
#[test]
fn compression_method_wire_roundtrip() {
let known = [
(0x00, CompressionMethod::Null),
(0x01, CompressionMethod::Deflate),
];
for (wire, method) in known {
assert_eq!(CompressionMethod::from_u8(wire), method);
assert_eq!(method.as_u8(), wire);
assert!(!method.is_unknown());
}
let unknown = CompressionMethod::from_u8(0x02);
assert_eq!(unknown.as_u8(), 0x02);
assert!(unknown.is_unknown());
}
#[test]
fn compression_method_debug_stays_enum_like() {
assert_eq!(format!("{:?}", CompressionMethod::Null), "Null");
assert_eq!(format!("{:?}", CompressionMethod::Deflate), "Deflate");
assert_eq!(
format!("{:?}", CompressionMethod::from_u8(0x02)),
"Unknown(2)"
);
}
#[test]
fn content_type_newtype_shape() {
assert_eq!(std::mem::size_of::<ContentType>(), 1);
assert_eq!(ContentType::default().as_u8(), 0);
assert!(ContentType::default().is_unknown());
}
#[test]
fn content_type_wire_roundtrip() {
let known = [
(20, ContentType::ChangeCipherSpec),
(21, ContentType::Alert),
(22, ContentType::Handshake),
(23, ContentType::ApplicationData),
(26, ContentType::Ack),
];
for (wire, content_type) in known {
assert_eq!(ContentType::from_u8(wire), content_type);
assert_eq!(content_type.as_u8(), wire);
assert!(!content_type.is_unknown());
}
let unknown = ContentType::from_u8(24);
assert_eq!(unknown.as_u8(), 24);
assert!(unknown.is_unknown());
}
#[test]
fn content_type_debug_stays_enum_like() {
assert_eq!(
format!("{:?}", ContentType::ChangeCipherSpec),
"ChangeCipherSpec"
);
assert_eq!(format!("{:?}", ContentType::Handshake), "Handshake");
assert_eq!(format!("{:?}", ContentType::from_u8(24)), "Unknown(24)");
}
#[test]
fn signature_scheme_newtype_shape() {
assert_eq!(std::mem::size_of::<SignatureScheme>(), 2);
assert_eq!(SignatureScheme::default().as_u16(), 0);
assert!(SignatureScheme::default().is_unknown());
}
#[test]
fn signature_scheme_wire_roundtrip() {
for scheme in SignatureScheme::all() {
assert_eq!(SignatureScheme::from_u16(scheme.as_u16()), *scheme);
assert!(!scheme.is_unknown());
}
let unknown = SignatureScheme::from_u16(0xFFFF);
assert_eq!(unknown.as_u16(), 0xFFFF);
assert!(unknown.is_unknown());
}
#[test]
fn signature_scheme_debug_stays_enum_like() {
assert_eq!(
format!("{:?}", SignatureScheme::ECDSA_SECP256R1_SHA256),
"ECDSA_SECP256R1_SHA256"
);
assert_eq!(
format!("{:?}", SignatureScheme::from_u16(0xFFFF)),
"Unknown(65535)"
);
}
#[test]
fn dtls13_cipher_suite_newtype_shape() {
assert_eq!(std::mem::size_of::<Dtls13CipherSuite>(), 2);
assert_eq!(Dtls13CipherSuite::default().as_u16(), 0);
assert!(Dtls13CipherSuite::default().is_unknown());
}
#[test]
fn dtls13_cipher_suite_wire_roundtrip() {
for suite in Dtls13CipherSuite::all() {
assert_eq!(Dtls13CipherSuite::from_u16(suite.as_u16()), *suite);
assert!(!suite.is_unknown());
}
let unknown = Dtls13CipherSuite::from_u16(0xFFFF);
assert_eq!(unknown.as_u16(), 0xFFFF);
assert!(unknown.is_unknown());
}
#[test]
fn dtls13_cipher_suite_debug_stays_enum_like() {
assert_eq!(
format!("{:?}", Dtls13CipherSuite::AES_128_GCM_SHA256),
"AES_128_GCM_SHA256"
);
assert_eq!(
format!("{:?}", Dtls13CipherSuite::from_u16(0xFFFF)),
"Unknown(65535)"
);
}
#[test]
fn protocol_version_newtype_shape() {
assert_eq!(std::mem::size_of::<ProtocolVersion>(), 2);
assert_eq!(ProtocolVersion::default().as_u16(), 0);
assert!(ProtocolVersion::default().is_unknown());
}
#[test]
fn protocol_version_wire_roundtrip() {
let known = [
(0xFEFF, ProtocolVersion::DTLS1_0),
(0xFEFD, ProtocolVersion::DTLS1_2),
(0xFEFC, ProtocolVersion::DTLS1_3),
];
for (wire, version) in known {
assert_eq!(ProtocolVersion::from_u16(wire), version);
assert_eq!(version.as_u16(), wire);
assert!(!version.is_unknown());
}
let unknown = ProtocolVersion::from_u16(0xFFFF);
assert_eq!(unknown.as_u16(), 0xFFFF);
assert!(unknown.is_unknown());
}
#[test]
fn protocol_version_debug_stays_enum_like() {
assert_eq!(format!("{:?}", ProtocolVersion::DTLS1_2), "DTLS1_2");
assert_eq!(
format!("{:?}", ProtocolVersion::from_u16(0xFFFF)),
"Unknown(65535)"
);
}
#[test]
fn random_parse() {
let data = [
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C,
0x1D, 0x1E, 0x1F, 0x20,
];
let expected = Random { bytes: data };
let (_, parsed) = Random::parse(&data).unwrap();
assert_eq!(parsed, expected);
}
#[test]
fn random_serialize() {
let random = Random {
bytes: [
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C,
0x1D, 0x1E, 0x1F, 0x20,
],
};
let mut serialized = Buf::new();
random.serialize(&mut serialized);
assert_eq!(&*serialized, &random.bytes);
}
#[test]
fn compression_supported_has_only_null() {
let supported = CompressionMethod::supported();
assert_eq!(
supported,
&[CompressionMethod::Null],
"Only Null compression should be supported"
);
}
#[test]
fn signature_scheme_named_group_ecdsa() {
assert_eq!(
SignatureScheme::ECDSA_SECP256R1_SHA256.named_group(),
Some(NamedGroup::Secp256r1)
);
assert_eq!(
SignatureScheme::ECDSA_SECP384R1_SHA384.named_group(),
Some(NamedGroup::Secp384r1)
);
}
#[test]
fn signature_scheme_named_group_non_ecdsa() {
assert_eq!(SignatureScheme::RSA_PSS_RSAE_SHA256.named_group(), None);
assert_eq!(SignatureScheme::ED25519.named_group(), None);
assert_eq!(SignatureScheme::ECDSA_SECP521R1_SHA512.named_group(), None);
assert_eq!(SignatureScheme::from_u16(0xFFFF).named_group(), None);
}
#[test]
fn random_parse_roundtrip() {
let data = [
0x5F, 0x37, 0xA9, 0x4B, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C,
];
let (_, parsed) = Random::parse(&data).unwrap();
let mut serialized = Buf::new();
parsed.serialize(&mut serialized);
assert_eq!(&*serialized, &data[..]);
}
}