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);
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum NamedGroup {
Sect163k1,
Sect163r1,
Sect163r2,
Sect193r1,
Sect193r2,
Sect233k1,
Sect233r1,
Sect239k1,
Sect283k1,
Sect283r1,
Sect409k1,
Sect409r1,
Sect571k1,
Sect571r1,
Secp160k1,
Secp160r1,
Secp160r2,
Secp192k1,
Secp192r1,
Secp224k1,
Secp224r1,
Secp256k1,
Secp256r1,
Secp384r1,
Secp521r1,
X25519,
X448,
Unknown(u16),
}
impl NamedGroup {
pub fn from_u16(value: u16) -> Self {
match value {
1 => NamedGroup::Sect163k1,
2 => NamedGroup::Sect163r1,
3 => NamedGroup::Sect163r2,
4 => NamedGroup::Sect193r1,
5 => NamedGroup::Sect193r2,
6 => NamedGroup::Sect233k1,
7 => NamedGroup::Sect233r1,
8 => NamedGroup::Sect239k1,
9 => NamedGroup::Sect283k1,
10 => NamedGroup::Sect283r1,
11 => NamedGroup::Sect409k1,
12 => NamedGroup::Sect409r1,
13 => NamedGroup::Sect571k1,
14 => NamedGroup::Sect571r1,
15 => NamedGroup::Secp160k1,
16 => NamedGroup::Secp160r1,
17 => NamedGroup::Secp160r2,
18 => NamedGroup::Secp192k1,
19 => NamedGroup::Secp192r1,
20 => NamedGroup::Secp224k1,
21 => NamedGroup::Secp224r1,
22 => NamedGroup::Secp256k1,
23 => NamedGroup::Secp256r1,
24 => NamedGroup::Secp384r1,
25 => NamedGroup::Secp521r1,
29 => NamedGroup::X25519,
30 => NamedGroup::X448,
_ => NamedGroup::Unknown(value),
}
}
pub fn as_u16(&self) -> u16 {
match self {
NamedGroup::Sect163k1 => 1,
NamedGroup::Sect163r1 => 2,
NamedGroup::Sect163r2 => 3,
NamedGroup::Sect193r1 => 4,
NamedGroup::Sect193r2 => 5,
NamedGroup::Sect233k1 => 6,
NamedGroup::Sect233r1 => 7,
NamedGroup::Sect239k1 => 8,
NamedGroup::Sect283k1 => 9,
NamedGroup::Sect283r1 => 10,
NamedGroup::Sect409k1 => 11,
NamedGroup::Sect409r1 => 12,
NamedGroup::Sect571k1 => 13,
NamedGroup::Sect571r1 => 14,
NamedGroup::Secp160k1 => 15,
NamedGroup::Secp160r1 => 16,
NamedGroup::Secp160r2 => 17,
NamedGroup::Secp192k1 => 18,
NamedGroup::Secp192r1 => 19,
NamedGroup::Secp224k1 => 20,
NamedGroup::Secp224r1 => 21,
NamedGroup::Secp256k1 => 22,
NamedGroup::Secp256r1 => 23,
NamedGroup::Secp384r1 => 24,
NamedGroup::Secp521r1 => 25,
NamedGroup::X25519 => 29,
NamedGroup::X448 => 30,
NamedGroup::Unknown(value) => *value,
}
}
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,
]
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[allow(non_camel_case_types)]
pub enum HashAlgorithm {
None,
MD5,
SHA1,
SHA224,
SHA256,
SHA384,
SHA512,
Unknown(u8),
}
impl Default for HashAlgorithm {
fn default() -> Self {
Self::Unknown(0)
}
}
impl HashAlgorithm {
pub fn from_u8(value: u8) -> Self {
match value {
0 => HashAlgorithm::None,
1 => HashAlgorithm::MD5,
2 => HashAlgorithm::SHA1,
3 => HashAlgorithm::SHA224,
4 => HashAlgorithm::SHA256,
5 => HashAlgorithm::SHA384,
6 => HashAlgorithm::SHA512,
_ => HashAlgorithm::Unknown(value),
}
}
pub fn as_u8(&self) -> u8 {
match self {
HashAlgorithm::None => 0,
HashAlgorithm::MD5 => 1,
HashAlgorithm::SHA1 => 2,
HashAlgorithm::SHA224 => 3,
HashAlgorithm::SHA256 => 4,
HashAlgorithm::SHA384 => 5,
HashAlgorithm::SHA512 => 6,
HashAlgorithm::Unknown(value) => *value,
}
}
pub fn parse(input: &[u8]) -> IResult<&[u8], HashAlgorithm> {
let (input, value) = be_u8(input)?;
Ok((input, HashAlgorithm::from_u8(value)))
}
pub 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,
HashAlgorithm::Unknown(_) => 0,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[allow(non_camel_case_types)]
pub enum SignatureAlgorithm {
Anonymous,
RSA,
DSA,
ECDSA,
Unknown(u8),
}
impl Default for SignatureAlgorithm {
fn default() -> Self {
Self::Unknown(0)
}
}
impl SignatureAlgorithm {
pub fn from_u8(value: u8) -> Self {
match value {
0 => SignatureAlgorithm::Anonymous,
1 => SignatureAlgorithm::RSA,
2 => SignatureAlgorithm::DSA,
3 => SignatureAlgorithm::ECDSA,
_ => SignatureAlgorithm::Unknown(value),
}
}
pub fn as_u8(&self) -> u8 {
match self {
SignatureAlgorithm::Anonymous => 0,
SignatureAlgorithm::RSA => 1,
SignatureAlgorithm::DSA => 2,
SignatureAlgorithm::ECDSA => 3,
SignatureAlgorithm::Unknown(value) => *value,
}
}
pub fn parse(input: &[u8]) -> IResult<&[u8], SignatureAlgorithm> {
let (input, value) = be_u8(input)?;
Ok((input, SignatureAlgorithm::from_u8(value)))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ContentType {
ChangeCipherSpec,
Alert,
Handshake,
ApplicationData,
Ack,
Unknown(u8),
}
impl Default for ContentType {
fn default() -> Self {
Self::Unknown(0)
}
}
impl ContentType {
pub fn from_u8(value: u8) -> Self {
match value {
20 => ContentType::ChangeCipherSpec,
21 => ContentType::Alert,
22 => ContentType::Handshake,
23 => ContentType::ApplicationData,
26 => ContentType::Ack,
_ => ContentType::Unknown(value),
}
}
pub fn as_u8(&self) -> u8 {
match self {
ContentType::ChangeCipherSpec => 20,
ContentType::Alert => 21,
ContentType::Handshake => 22,
ContentType::ApplicationData => 23,
ContentType::Ack => 26,
ContentType::Unknown(value) => *value,
}
}
pub fn parse(input: &[u8]) -> IResult<&[u8], ContentType> {
let (input, byte) = be_u8(input)?;
Ok((input, Self::from_u8(byte)))
}
}
#[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))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[allow(non_camel_case_types)]
#[non_exhaustive]
pub enum SignatureScheme {
ECDSA_SECP256R1_SHA256,
ECDSA_SECP384R1_SHA384,
ECDSA_SECP521R1_SHA512,
ED25519,
ED448,
RSA_PSS_RSAE_SHA256,
RSA_PSS_RSAE_SHA384,
RSA_PSS_RSAE_SHA512,
RSA_PSS_PSS_SHA256,
RSA_PSS_PSS_SHA384,
RSA_PSS_PSS_SHA512,
RSA_PKCS1_SHA256,
RSA_PKCS1_SHA384,
RSA_PKCS1_SHA512,
Unknown(u16),
}
impl SignatureScheme {
pub fn from_u16(value: u16) -> Self {
match value {
0x0403 => SignatureScheme::ECDSA_SECP256R1_SHA256,
0x0503 => SignatureScheme::ECDSA_SECP384R1_SHA384,
0x0603 => SignatureScheme::ECDSA_SECP521R1_SHA512,
0x0807 => SignatureScheme::ED25519,
0x0808 => SignatureScheme::ED448,
0x0804 => SignatureScheme::RSA_PSS_RSAE_SHA256,
0x0805 => SignatureScheme::RSA_PSS_RSAE_SHA384,
0x0806 => SignatureScheme::RSA_PSS_RSAE_SHA512,
0x0809 => SignatureScheme::RSA_PSS_PSS_SHA256,
0x080a => SignatureScheme::RSA_PSS_PSS_SHA384,
0x080b => SignatureScheme::RSA_PSS_PSS_SHA512,
0x0401 => SignatureScheme::RSA_PKCS1_SHA256,
0x0501 => SignatureScheme::RSA_PKCS1_SHA384,
0x0601 => SignatureScheme::RSA_PKCS1_SHA512,
_ => SignatureScheme::Unknown(value),
}
}
pub fn as_u16(&self) -> u16 {
match self {
SignatureScheme::ECDSA_SECP256R1_SHA256 => 0x0403,
SignatureScheme::ECDSA_SECP384R1_SHA384 => 0x0503,
SignatureScheme::ECDSA_SECP521R1_SHA512 => 0x0603,
SignatureScheme::ED25519 => 0x0807,
SignatureScheme::ED448 => 0x0808,
SignatureScheme::RSA_PSS_RSAE_SHA256 => 0x0804,
SignatureScheme::RSA_PSS_RSAE_SHA384 => 0x0805,
SignatureScheme::RSA_PSS_RSAE_SHA512 => 0x0806,
SignatureScheme::RSA_PSS_PSS_SHA256 => 0x0809,
SignatureScheme::RSA_PSS_PSS_SHA384 => 0x080a,
SignatureScheme::RSA_PSS_PSS_SHA512 => 0x080b,
SignatureScheme::RSA_PKCS1_SHA256 => 0x0401,
SignatureScheme::RSA_PKCS1_SHA384 => 0x0501,
SignatureScheme::RSA_PKCS1_SHA512 => 0x0601,
SignatureScheme::Unknown(value) => *value,
}
}
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 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,
SignatureScheme::Unknown(_) => HashAlgorithm::Unknown(0),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[allow(non_camel_case_types)]
#[non_exhaustive]
pub enum Dtls13CipherSuite {
AES_128_GCM_SHA256,
AES_256_GCM_SHA384,
CHACHA20_POLY1305_SHA256,
AES_128_CCM_SHA256,
AES_128_CCM_8_SHA256,
Unknown(u16),
}
impl Dtls13CipherSuite {
pub fn from_u16(value: u16) -> Self {
match value {
0x1301 => Dtls13CipherSuite::AES_128_GCM_SHA256,
0x1302 => Dtls13CipherSuite::AES_256_GCM_SHA384,
0x1303 => Dtls13CipherSuite::CHACHA20_POLY1305_SHA256,
0x1304 => Dtls13CipherSuite::AES_128_CCM_SHA256,
0x1305 => Dtls13CipherSuite::AES_128_CCM_8_SHA256,
_ => Dtls13CipherSuite::Unknown(value),
}
}
pub fn as_u16(&self) -> u16 {
match self {
Dtls13CipherSuite::AES_128_GCM_SHA256 => 0x1301,
Dtls13CipherSuite::AES_256_GCM_SHA384 => 0x1302,
Dtls13CipherSuite::CHACHA20_POLY1305_SHA256 => 0x1303,
Dtls13CipherSuite::AES_128_CCM_SHA256 => 0x1304,
Dtls13CipherSuite::AES_128_CCM_8_SHA256 => 0x1305,
Dtls13CipherSuite::Unknown(value) => *value,
}
}
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,
Dtls13CipherSuite::Unknown(_) => HashAlgorithm::Unknown(0),
}
}
pub fn is_supported(&self) -> bool {
Self::supported().contains(self)
}
pub 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 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()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ProtocolVersion {
DTLS1_0,
DTLS1_2,
DTLS1_3,
Unknown(u16),
}
impl Default for ProtocolVersion {
fn default() -> Self {
Self::Unknown(0)
}
}
impl ProtocolVersion {
pub fn as_u16(&self) -> u16 {
match self {
ProtocolVersion::DTLS1_0 => 0xFEFF,
ProtocolVersion::DTLS1_2 => 0xFEFD,
ProtocolVersion::DTLS1_3 => 0xFEFC,
ProtocolVersion::Unknown(value) => *value,
}
}
pub fn parse(input: &[u8]) -> IResult<&[u8], ProtocolVersion> {
let (input, version) = be_u16(input)?;
let protocol_version = match version {
0xFEFF => ProtocolVersion::DTLS1_0,
0xFEFD => ProtocolVersion::DTLS1_2,
0xFEFC => ProtocolVersion::DTLS1_3,
_ => ProtocolVersion::Unknown(version),
};
Ok((input, protocol_version))
}
pub fn serialize(&self, output: &mut Buf) {
output.extend_from_slice(&self.as_u16().to_be_bytes());
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CompressionMethod {
Null,
Deflate,
Unknown(u8),
}
impl Default for CompressionMethod {
fn default() -> Self {
Self::Unknown(0)
}
}
impl CompressionMethod {
pub fn from_u8(value: u8) -> Self {
match value {
0x00 => CompressionMethod::Null,
0x01 => CompressionMethod::Deflate,
_ => CompressionMethod::Unknown(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 fn as_u8(&self) -> u8 {
match self {
CompressionMethod::Null => 0x00,
CompressionMethod::Deflate => 0x01,
CompressionMethod::Unknown(value) => *value,
}
}
pub fn parse(input: &[u8]) -> IResult<&[u8], CompressionMethod> {
let (input, value) = be_u8(input)?;
Ok((input, CompressionMethod::from_u8(value)))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[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::Unknown(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[..]);
}
}