Skip to main content

dimpl/
types.rs

1//! Shared types used by both DTLS 1.2 and DTLS 1.3.
2//!
3//! These types represent cryptographic primitives and protocol elements
4//! that are common across DTLS versions.
5
6use std::cmp::Ordering;
7use std::fmt;
8use std::time::Instant;
9
10use arrayvec::ArrayVec;
11use nom::bytes::complete::take;
12use nom::number::complete::{be_u16, be_u8};
13use nom::IResult;
14
15use crate::buffer::Buf;
16use crate::time_tricks::InstantExt;
17use crate::SeededRng;
18
19pub type NamedGroupVec = ArrayVec<NamedGroup, { NamedGroup::supported().len() }>;
20
21// ============================================================================
22// Random
23// ============================================================================
24
25/// ClientHello / ServerHello random value (32 bytes on the wire).
26///
27/// Used by both DTLS 1.2 and DTLS 1.3. Construction differs:
28/// - DTLS 1.2: first 4 bytes are `gmt_unix_time` ([`Random::new_with_time`]).
29/// - DTLS 1.3: all 32 bytes are random ([`Random::new`]).
30///
31/// After construction neither version accesses sub-fields — all consumers
32/// use [`bytes`](Self::bytes) or [`serialize`](Self::serialize).
33#[derive(Debug, Clone, Copy, PartialEq, Eq)]
34pub struct Random {
35    /// The 32 raw bytes of the random value.
36    pub bytes: [u8; 32],
37}
38
39impl Random {
40    /// All-random (DTLS 1.3 / hybrid style).
41    pub fn new(rng: &mut SeededRng) -> Self {
42        Self {
43            bytes: rng.random(),
44        }
45    }
46
47    /// Timestamp in first 4 bytes (DTLS 1.2 style).
48    pub fn new_with_time(now: Instant, rng: &mut SeededRng) -> Self {
49        let gmt_duration = now.to_unix_duration();
50        // This is valid until year 2106, at which point I will be beyond caring.
51        let gmt_unix_time = gmt_duration.as_secs() as u32;
52
53        let random_bytes: [u8; 28] = rng.random();
54
55        let mut bytes = [0u8; 32];
56        bytes[..4].copy_from_slice(&gmt_unix_time.to_be_bytes());
57        bytes[4..].copy_from_slice(&random_bytes);
58
59        Self { bytes }
60    }
61
62    /// Parse a 32-byte `Random` from wire format.
63    pub fn parse(input: &[u8]) -> IResult<&[u8], Random> {
64        let (input, data) = take(32_usize)(input)?;
65        let mut bytes = [0u8; 32];
66        bytes.copy_from_slice(data);
67        Ok((input, Random { bytes }))
68    }
69
70    /// Serialize this `Random` to wire format.
71    pub fn serialize(&self, output: &mut Buf) {
72        output.extend_from_slice(&self.bytes);
73    }
74}
75
76// ============================================================================
77// Named Groups (Key Exchange)
78// ============================================================================
79
80/// Elliptic curves and key exchange groups (RFC 8422, RFC 8446).
81///
82/// Used for Elliptic Curve Diffie-Hellman Ephemeral (ECDHE) key exchange.
83/// The same named groups are used in both DTLS 1.2 and DTLS 1.3.
84#[derive(Debug, Clone, Copy, PartialEq, Eq)]
85pub enum NamedGroup {
86    /// sect163k1 (deprecated).
87    Sect163k1,
88    /// sect163r1 (deprecated).
89    Sect163r1,
90    /// sect163r2 (deprecated).
91    Sect163r2,
92    /// sect193r1 (deprecated).
93    Sect193r1,
94    /// sect193r2 (deprecated).
95    Sect193r2,
96    /// sect233k1 (deprecated).
97    Sect233k1,
98    /// sect233r1 (deprecated).
99    Sect233r1,
100    /// sect239k1 (deprecated).
101    Sect239k1,
102    /// sect283k1 (deprecated).
103    Sect283k1,
104    /// sect283r1 (deprecated).
105    Sect283r1,
106    /// sect409k1 (deprecated).
107    Sect409k1,
108    /// sect409r1 (deprecated).
109    Sect409r1,
110    /// sect571k1 (deprecated).
111    Sect571k1,
112    /// sect571r1 (deprecated).
113    Sect571r1,
114    /// secp160k1 (deprecated).
115    Secp160k1,
116    /// secp160r1 (deprecated).
117    Secp160r1,
118    /// secp160r2 (deprecated).
119    Secp160r2,
120    /// secp192k1 (deprecated).
121    Secp192k1,
122    /// secp192r1 (deprecated).
123    Secp192r1,
124    /// secp224k1.
125    Secp224k1,
126    /// secp224r1.
127    Secp224r1,
128    /// secp256k1.
129    Secp256k1,
130    /// secp256r1 / P-256 (supported by dimpl).
131    Secp256r1,
132    /// secp384r1 / P-384 (supported by dimpl).
133    Secp384r1,
134    /// secp521r1 / P-521.
135    Secp521r1,
136    /// X25519 (Curve25519 for ECDHE).
137    X25519,
138    /// X448 (Curve448 for ECDHE).
139    X448,
140    /// Unknown or unsupported group.
141    Unknown(u16),
142}
143
144impl NamedGroup {
145    /// Convert a wire format u16 value to a `NamedGroup`.
146    pub fn from_u16(value: u16) -> Self {
147        match value {
148            1 => NamedGroup::Sect163k1,
149            2 => NamedGroup::Sect163r1,
150            3 => NamedGroup::Sect163r2,
151            4 => NamedGroup::Sect193r1,
152            5 => NamedGroup::Sect193r2,
153            6 => NamedGroup::Sect233k1,
154            7 => NamedGroup::Sect233r1,
155            8 => NamedGroup::Sect239k1,
156            9 => NamedGroup::Sect283k1,
157            10 => NamedGroup::Sect283r1,
158            11 => NamedGroup::Sect409k1,
159            12 => NamedGroup::Sect409r1,
160            13 => NamedGroup::Sect571k1,
161            14 => NamedGroup::Sect571r1,
162            15 => NamedGroup::Secp160k1,
163            16 => NamedGroup::Secp160r1,
164            17 => NamedGroup::Secp160r2,
165            18 => NamedGroup::Secp192k1,
166            19 => NamedGroup::Secp192r1,
167            20 => NamedGroup::Secp224k1,
168            21 => NamedGroup::Secp224r1,
169            22 => NamedGroup::Secp256k1,
170            23 => NamedGroup::Secp256r1,
171            24 => NamedGroup::Secp384r1,
172            25 => NamedGroup::Secp521r1,
173            29 => NamedGroup::X25519,
174            30 => NamedGroup::X448,
175            _ => NamedGroup::Unknown(value),
176        }
177    }
178
179    /// Convert this `NamedGroup` to its wire format u16 value.
180    pub fn as_u16(&self) -> u16 {
181        match self {
182            NamedGroup::Sect163k1 => 1,
183            NamedGroup::Sect163r1 => 2,
184            NamedGroup::Sect163r2 => 3,
185            NamedGroup::Sect193r1 => 4,
186            NamedGroup::Sect193r2 => 5,
187            NamedGroup::Sect233k1 => 6,
188            NamedGroup::Sect233r1 => 7,
189            NamedGroup::Sect239k1 => 8,
190            NamedGroup::Sect283k1 => 9,
191            NamedGroup::Sect283r1 => 10,
192            NamedGroup::Sect409k1 => 11,
193            NamedGroup::Sect409r1 => 12,
194            NamedGroup::Sect571k1 => 13,
195            NamedGroup::Sect571r1 => 14,
196            NamedGroup::Secp160k1 => 15,
197            NamedGroup::Secp160r1 => 16,
198            NamedGroup::Secp160r2 => 17,
199            NamedGroup::Secp192k1 => 18,
200            NamedGroup::Secp192r1 => 19,
201            NamedGroup::Secp224k1 => 20,
202            NamedGroup::Secp224r1 => 21,
203            NamedGroup::Secp256k1 => 22,
204            NamedGroup::Secp256r1 => 23,
205            NamedGroup::Secp384r1 => 24,
206            NamedGroup::Secp521r1 => 25,
207            NamedGroup::X25519 => 29,
208            NamedGroup::X448 => 30,
209            NamedGroup::Unknown(value) => *value,
210        }
211    }
212
213    /// Parse a `NamedGroup` from wire format.
214    pub fn parse(input: &[u8]) -> IResult<&[u8], NamedGroup> {
215        let (input, value) = be_u16(input)?;
216        Ok((input, NamedGroup::from_u16(value)))
217    }
218
219    /// Returns true if this named group is supported by this implementation.
220    pub fn is_supported(&self) -> bool {
221        Self::supported().contains(self)
222    }
223
224    /// All recognized named groups (every non-`Unknown` variant).
225    pub const fn all() -> &'static [NamedGroup; 27] {
226        &[
227            NamedGroup::Sect163k1,
228            NamedGroup::Sect163r1,
229            NamedGroup::Sect163r2,
230            NamedGroup::Sect193r1,
231            NamedGroup::Sect193r2,
232            NamedGroup::Sect233k1,
233            NamedGroup::Sect233r1,
234            NamedGroup::Sect239k1,
235            NamedGroup::Sect283k1,
236            NamedGroup::Sect283r1,
237            NamedGroup::Sect409k1,
238            NamedGroup::Sect409r1,
239            NamedGroup::Sect571k1,
240            NamedGroup::Sect571r1,
241            NamedGroup::Secp160k1,
242            NamedGroup::Secp160r1,
243            NamedGroup::Secp160r2,
244            NamedGroup::Secp192k1,
245            NamedGroup::Secp192r1,
246            NamedGroup::Secp224k1,
247            NamedGroup::Secp224r1,
248            NamedGroup::Secp256k1,
249            NamedGroup::Secp256r1,
250            NamedGroup::Secp384r1,
251            NamedGroup::Secp521r1,
252            NamedGroup::X25519,
253            NamedGroup::X448,
254        ]
255    }
256
257    /// Supported named groups in preference order.
258    pub const fn supported() -> &'static [NamedGroup; 4] {
259        &[
260            NamedGroup::X25519,
261            NamedGroup::Secp256r1,
262            NamedGroup::Secp384r1,
263            NamedGroup::Secp521r1,
264        ]
265    }
266}
267
268// ============================================================================
269// Hash Algorithms
270// ============================================================================
271
272/// Hash algorithms used in DTLS (RFC 5246, RFC 8446).
273///
274/// Specifies the hash algorithm to be used in digital signatures,
275/// PRF/HKDF operations, and transcript hashing.
276#[derive(Debug, Clone, Copy, PartialEq, Eq)]
277#[allow(non_camel_case_types)]
278pub enum HashAlgorithm {
279    /// No hash (not typically used).
280    None,
281    /// MD5 hash (deprecated, not supported).
282    MD5,
283    /// SHA-1 hash (deprecated, not supported).
284    SHA1,
285    /// SHA-224 hash.
286    SHA224,
287    /// SHA-256 hash (supported by dimpl).
288    SHA256,
289    /// SHA-384 hash (supported by dimpl).
290    SHA384,
291    /// SHA-512 hash.
292    SHA512,
293    /// Unknown or unsupported hash algorithm.
294    Unknown(u8),
295}
296
297impl Default for HashAlgorithm {
298    fn default() -> Self {
299        Self::Unknown(0)
300    }
301}
302
303impl HashAlgorithm {
304    /// Convert a wire format u8 value to a `HashAlgorithm`.
305    pub fn from_u8(value: u8) -> Self {
306        match value {
307            0 => HashAlgorithm::None,
308            1 => HashAlgorithm::MD5,
309            2 => HashAlgorithm::SHA1,
310            3 => HashAlgorithm::SHA224,
311            4 => HashAlgorithm::SHA256,
312            5 => HashAlgorithm::SHA384,
313            6 => HashAlgorithm::SHA512,
314            _ => HashAlgorithm::Unknown(value),
315        }
316    }
317
318    /// Convert this `HashAlgorithm` to its wire format u8 value.
319    pub fn as_u8(&self) -> u8 {
320        match self {
321            HashAlgorithm::None => 0,
322            HashAlgorithm::MD5 => 1,
323            HashAlgorithm::SHA1 => 2,
324            HashAlgorithm::SHA224 => 3,
325            HashAlgorithm::SHA256 => 4,
326            HashAlgorithm::SHA384 => 5,
327            HashAlgorithm::SHA512 => 6,
328            HashAlgorithm::Unknown(value) => *value,
329        }
330    }
331
332    /// Parse a `HashAlgorithm` from wire format.
333    pub fn parse(input: &[u8]) -> IResult<&[u8], HashAlgorithm> {
334        let (input, value) = be_u8(input)?;
335        Ok((input, HashAlgorithm::from_u8(value)))
336    }
337
338    /// Returns the output length in bytes for this hash algorithm.
339    pub fn output_len(&self) -> usize {
340        match self {
341            HashAlgorithm::None => 0,
342            HashAlgorithm::MD5 => 16,
343            HashAlgorithm::SHA1 => 20,
344            HashAlgorithm::SHA224 => 28,
345            HashAlgorithm::SHA256 => 32,
346            HashAlgorithm::SHA384 => 48,
347            HashAlgorithm::SHA512 => 64,
348            HashAlgorithm::Unknown(_) => 0,
349        }
350    }
351}
352
353// ============================================================================
354// Signature Algorithms
355// ============================================================================
356
357/// Signature algorithms used in DTLS handshakes.
358///
359/// Represents the underlying signature primitive (RSA, ECDSA, etc.).
360/// Used internally for signing operations across both DTLS versions.
361#[derive(Debug, Clone, Copy, PartialEq, Eq)]
362#[allow(non_camel_case_types)]
363pub enum SignatureAlgorithm {
364    /// Anonymous (no certificate).
365    Anonymous,
366    /// RSA signatures.
367    RSA,
368    /// DSA signatures.
369    DSA,
370    /// ECDSA signatures.
371    ECDSA,
372    /// Unknown or unsupported signature algorithm.
373    Unknown(u8),
374}
375
376impl Default for SignatureAlgorithm {
377    fn default() -> Self {
378        Self::Unknown(0)
379    }
380}
381
382impl SignatureAlgorithm {
383    /// Convert an 8-bit value into a `SignatureAlgorithm`.
384    pub fn from_u8(value: u8) -> Self {
385        match value {
386            0 => SignatureAlgorithm::Anonymous,
387            1 => SignatureAlgorithm::RSA,
388            2 => SignatureAlgorithm::DSA,
389            3 => SignatureAlgorithm::ECDSA,
390            _ => SignatureAlgorithm::Unknown(value),
391        }
392    }
393
394    /// Convert this `SignatureAlgorithm` into its 8-bit representation.
395    pub fn as_u8(&self) -> u8 {
396        match self {
397            SignatureAlgorithm::Anonymous => 0,
398            SignatureAlgorithm::RSA => 1,
399            SignatureAlgorithm::DSA => 2,
400            SignatureAlgorithm::ECDSA => 3,
401            SignatureAlgorithm::Unknown(value) => *value,
402        }
403    }
404
405    /// Parse a `SignatureAlgorithm` from network bytes.
406    pub fn parse(input: &[u8]) -> IResult<&[u8], SignatureAlgorithm> {
407        let (input, value) = be_u8(input)?;
408        Ok((input, SignatureAlgorithm::from_u8(value)))
409    }
410}
411
412// ============================================================================
413// Content Type
414// ============================================================================
415
416/// DTLS record content types.
417///
418/// Identifies the type of data in a DTLS record. These values are the same
419/// for both DTLS 1.2 and DTLS 1.3.
420#[derive(Debug, Clone, Copy, PartialEq, Eq)]
421pub enum ContentType {
422    /// Change Cipher Spec (used in DTLS 1.2, compatibility-only in 1.3).
423    ChangeCipherSpec,
424    /// Alert message.
425    Alert,
426    /// Handshake message.
427    Handshake,
428    /// Application data.
429    ApplicationData,
430    /// ACK (DTLS 1.3 only, RFC 9147 Section 7).
431    Ack,
432    /// Unknown content type.
433    Unknown(u8),
434}
435
436impl Default for ContentType {
437    fn default() -> Self {
438        Self::Unknown(0)
439    }
440}
441
442impl ContentType {
443    /// Convert a u8 value to a `ContentType`.
444    pub fn from_u8(value: u8) -> Self {
445        match value {
446            20 => ContentType::ChangeCipherSpec,
447            21 => ContentType::Alert,
448            22 => ContentType::Handshake,
449            23 => ContentType::ApplicationData,
450            26 => ContentType::Ack,
451            _ => ContentType::Unknown(value),
452        }
453    }
454
455    /// Convert this `ContentType` to its u8 value.
456    pub fn as_u8(&self) -> u8 {
457        match self {
458            ContentType::ChangeCipherSpec => 20,
459            ContentType::Alert => 21,
460            ContentType::Handshake => 22,
461            ContentType::ApplicationData => 23,
462            ContentType::Ack => 26,
463            ContentType::Unknown(value) => *value,
464        }
465    }
466
467    /// Parse a `ContentType` from wire format.
468    pub fn parse(input: &[u8]) -> IResult<&[u8], ContentType> {
469        let (input, byte) = be_u8(input)?;
470        Ok((input, Self::from_u8(byte)))
471    }
472}
473
474// ============================================================================
475// Sequence Number
476// ============================================================================
477
478/// DTLS record sequence number (epoch + sequence).
479///
480/// Both DTLS 1.2 and DTLS 1.3 use an epoch and sequence number for
481/// replay protection and AEAD nonce construction.
482#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
483pub struct Sequence {
484    /// The epoch (incremented on key change).
485    pub epoch: u16,
486    /// The sequence number within the epoch (technically u48).
487    pub sequence_number: u64,
488}
489
490impl Sequence {
491    /// Create a new sequence with the given epoch and sequence number 0.
492    pub fn new(epoch: u16) -> Self {
493        Self {
494            epoch,
495            sequence_number: 0,
496        }
497    }
498}
499
500impl fmt::Display for Sequence {
501    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
502        write!(
503            f,
504            "[epoch: {}, sequence_number: {}]",
505            self.epoch, self.sequence_number,
506        )
507    }
508}
509
510impl Ord for Sequence {
511    fn cmp(&self, other: &Self) -> Ordering {
512        if self.epoch < other.epoch {
513            Ordering::Less
514        } else if self.epoch > other.epoch {
515            Ordering::Greater
516        } else {
517            self.sequence_number.cmp(&other.sequence_number)
518        }
519    }
520}
521
522impl PartialOrd for Sequence {
523    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
524        Some(self.cmp(other))
525    }
526}
527
528// ============================================================================
529// Signature Schemes (TLS 1.3)
530// ============================================================================
531
532/// Signature schemes used in TLS 1.3/DTLS 1.3 (RFC 8446).
533///
534/// In TLS 1.3, signature schemes combine the signature algorithm with the
535/// hash algorithm into a single identifier, unlike TLS 1.2 where they were
536/// separate.
537#[derive(Debug, Clone, Copy, PartialEq, Eq)]
538#[allow(non_camel_case_types)]
539pub enum SignatureScheme {
540    /// ECDSA with P-256 and SHA-256.
541    ECDSA_SECP256R1_SHA256,
542    /// ECDSA with P-384 and SHA-384.
543    ECDSA_SECP384R1_SHA384,
544    /// ECDSA with P-521 and SHA-512.
545    ECDSA_SECP521R1_SHA512,
546    /// Ed25519.
547    ED25519,
548    /// Ed448.
549    ED448,
550    /// RSA-PSS with SHA-256 (rsaEncryption OID).
551    RSA_PSS_RSAE_SHA256,
552    /// RSA-PSS with SHA-384 (rsaEncryption OID).
553    RSA_PSS_RSAE_SHA384,
554    /// RSA-PSS with SHA-512 (rsaEncryption OID).
555    RSA_PSS_RSAE_SHA512,
556    /// RSA-PSS with SHA-256 (id-rsassa-pss OID).
557    RSA_PSS_PSS_SHA256,
558    /// RSA-PSS with SHA-384 (id-rsassa-pss OID).
559    RSA_PSS_PSS_SHA384,
560    /// RSA-PSS with SHA-512 (id-rsassa-pss OID).
561    RSA_PSS_PSS_SHA512,
562    /// RSA PKCS#1 v1.5 with SHA-256 (legacy).
563    RSA_PKCS1_SHA256,
564    /// RSA PKCS#1 v1.5 with SHA-384 (legacy).
565    RSA_PKCS1_SHA384,
566    /// RSA PKCS#1 v1.5 with SHA-512 (legacy).
567    RSA_PKCS1_SHA512,
568    /// Unknown or unsupported signature scheme.
569    Unknown(u16),
570}
571
572impl SignatureScheme {
573    /// Convert a wire format u16 value to a `SignatureScheme`.
574    pub fn from_u16(value: u16) -> Self {
575        match value {
576            0x0403 => SignatureScheme::ECDSA_SECP256R1_SHA256,
577            0x0503 => SignatureScheme::ECDSA_SECP384R1_SHA384,
578            0x0603 => SignatureScheme::ECDSA_SECP521R1_SHA512,
579            0x0807 => SignatureScheme::ED25519,
580            0x0808 => SignatureScheme::ED448,
581            0x0804 => SignatureScheme::RSA_PSS_RSAE_SHA256,
582            0x0805 => SignatureScheme::RSA_PSS_RSAE_SHA384,
583            0x0806 => SignatureScheme::RSA_PSS_RSAE_SHA512,
584            0x0809 => SignatureScheme::RSA_PSS_PSS_SHA256,
585            0x080a => SignatureScheme::RSA_PSS_PSS_SHA384,
586            0x080b => SignatureScheme::RSA_PSS_PSS_SHA512,
587            0x0401 => SignatureScheme::RSA_PKCS1_SHA256,
588            0x0501 => SignatureScheme::RSA_PKCS1_SHA384,
589            0x0601 => SignatureScheme::RSA_PKCS1_SHA512,
590            _ => SignatureScheme::Unknown(value),
591        }
592    }
593
594    /// Convert this `SignatureScheme` to its wire format u16 value.
595    pub fn as_u16(&self) -> u16 {
596        match self {
597            SignatureScheme::ECDSA_SECP256R1_SHA256 => 0x0403,
598            SignatureScheme::ECDSA_SECP384R1_SHA384 => 0x0503,
599            SignatureScheme::ECDSA_SECP521R1_SHA512 => 0x0603,
600            SignatureScheme::ED25519 => 0x0807,
601            SignatureScheme::ED448 => 0x0808,
602            SignatureScheme::RSA_PSS_RSAE_SHA256 => 0x0804,
603            SignatureScheme::RSA_PSS_RSAE_SHA384 => 0x0805,
604            SignatureScheme::RSA_PSS_RSAE_SHA512 => 0x0806,
605            SignatureScheme::RSA_PSS_PSS_SHA256 => 0x0809,
606            SignatureScheme::RSA_PSS_PSS_SHA384 => 0x080a,
607            SignatureScheme::RSA_PSS_PSS_SHA512 => 0x080b,
608            SignatureScheme::RSA_PKCS1_SHA256 => 0x0401,
609            SignatureScheme::RSA_PKCS1_SHA384 => 0x0501,
610            SignatureScheme::RSA_PKCS1_SHA512 => 0x0601,
611            SignatureScheme::Unknown(value) => *value,
612        }
613    }
614
615    /// Parse a `SignatureScheme` from wire format.
616    pub fn parse(input: &[u8]) -> IResult<&[u8], SignatureScheme> {
617        let (input, value) = be_u16(input)?;
618        Ok((input, SignatureScheme::from_u16(value)))
619    }
620
621    /// Returns true if this signature scheme is supported by this implementation.
622    pub fn is_supported(&self) -> bool {
623        Self::SUPPORTED.contains(self)
624    }
625
626    /// All recognized signature schemes (every non-`Unknown` variant).
627    pub fn all() -> &'static [SignatureScheme] {
628        &[
629            SignatureScheme::ECDSA_SECP256R1_SHA256,
630            SignatureScheme::ECDSA_SECP384R1_SHA384,
631            SignatureScheme::ECDSA_SECP521R1_SHA512,
632            SignatureScheme::ED25519,
633            SignatureScheme::ED448,
634            SignatureScheme::RSA_PSS_RSAE_SHA256,
635            SignatureScheme::RSA_PSS_RSAE_SHA384,
636            SignatureScheme::RSA_PSS_RSAE_SHA512,
637            SignatureScheme::RSA_PSS_PSS_SHA256,
638            SignatureScheme::RSA_PSS_PSS_SHA384,
639            SignatureScheme::RSA_PSS_PSS_SHA512,
640            SignatureScheme::RSA_PKCS1_SHA256,
641            SignatureScheme::RSA_PKCS1_SHA384,
642            SignatureScheme::RSA_PKCS1_SHA512,
643        ]
644    }
645
646    const SUPPORTED: &[SignatureScheme] = &[
647        SignatureScheme::ECDSA_SECP256R1_SHA256,
648        SignatureScheme::ECDSA_SECP384R1_SHA384,
649    ];
650
651    /// Supported signature schemes in preference order.
652    pub fn supported() -> ArrayVec<SignatureScheme, 2> {
653        let mut schemes = ArrayVec::new();
654        schemes.push(SignatureScheme::ECDSA_SECP256R1_SHA256);
655        schemes.push(SignatureScheme::ECDSA_SECP384R1_SHA384);
656        schemes
657    }
658
659    /// Returns the hash algorithm associated with this signature scheme.
660    pub fn hash_algorithm(&self) -> HashAlgorithm {
661        match self {
662            SignatureScheme::ECDSA_SECP256R1_SHA256
663            | SignatureScheme::RSA_PSS_RSAE_SHA256
664            | SignatureScheme::RSA_PSS_PSS_SHA256
665            | SignatureScheme::RSA_PKCS1_SHA256 => HashAlgorithm::SHA256,
666            SignatureScheme::ECDSA_SECP384R1_SHA384
667            | SignatureScheme::RSA_PSS_RSAE_SHA384
668            | SignatureScheme::RSA_PSS_PSS_SHA384
669            | SignatureScheme::RSA_PKCS1_SHA384 => HashAlgorithm::SHA384,
670            SignatureScheme::ECDSA_SECP521R1_SHA512
671            | SignatureScheme::RSA_PSS_RSAE_SHA512
672            | SignatureScheme::RSA_PSS_PSS_SHA512
673            | SignatureScheme::RSA_PKCS1_SHA512 => HashAlgorithm::SHA512,
674            // Ed25519 and Ed448 have intrinsic hash algorithms
675            SignatureScheme::ED25519 | SignatureScheme::ED448 => HashAlgorithm::None,
676            SignatureScheme::Unknown(_) => HashAlgorithm::Unknown(0),
677        }
678    }
679}
680
681// ============================================================================
682// DTLS 1.3 Cipher Suites
683// ============================================================================
684
685/// Cipher suites for DTLS 1.3 (RFC 9147).
686///
687/// Unlike DTLS 1.2, TLS 1.3 cipher suites only specify the AEAD algorithm
688/// and hash function. Key exchange is negotiated separately via key_share.
689#[derive(Debug, Clone, Copy, PartialEq, Eq)]
690#[allow(non_camel_case_types)]
691pub enum Dtls13CipherSuite {
692    /// TLS_AES_128_GCM_SHA256.
693    AES_128_GCM_SHA256,
694    /// TLS_AES_256_GCM_SHA384.
695    AES_256_GCM_SHA384,
696    /// TLS_CHACHA20_POLY1305_SHA256.
697    CHACHA20_POLY1305_SHA256,
698    /// TLS_AES_128_CCM_SHA256.
699    AES_128_CCM_SHA256,
700    /// TLS_AES_128_CCM_8_SHA256 (shorter tag, for constrained devices).
701    AES_128_CCM_8_SHA256,
702    /// Unknown or unsupported cipher suite.
703    Unknown(u16),
704}
705
706impl Dtls13CipherSuite {
707    /// Convert a wire format u16 value to a `Dtls13CipherSuite`.
708    pub fn from_u16(value: u16) -> Self {
709        match value {
710            0x1301 => Dtls13CipherSuite::AES_128_GCM_SHA256,
711            0x1302 => Dtls13CipherSuite::AES_256_GCM_SHA384,
712            0x1303 => Dtls13CipherSuite::CHACHA20_POLY1305_SHA256,
713            0x1304 => Dtls13CipherSuite::AES_128_CCM_SHA256,
714            0x1305 => Dtls13CipherSuite::AES_128_CCM_8_SHA256,
715            _ => Dtls13CipherSuite::Unknown(value),
716        }
717    }
718
719    /// Convert this `Dtls13CipherSuite` to its wire format u16 value.
720    pub fn as_u16(&self) -> u16 {
721        match self {
722            Dtls13CipherSuite::AES_128_GCM_SHA256 => 0x1301,
723            Dtls13CipherSuite::AES_256_GCM_SHA384 => 0x1302,
724            Dtls13CipherSuite::CHACHA20_POLY1305_SHA256 => 0x1303,
725            Dtls13CipherSuite::AES_128_CCM_SHA256 => 0x1304,
726            Dtls13CipherSuite::AES_128_CCM_8_SHA256 => 0x1305,
727            Dtls13CipherSuite::Unknown(value) => *value,
728        }
729    }
730
731    /// Parse a `Dtls13CipherSuite` from wire format.
732    pub fn parse(input: &[u8]) -> IResult<&[u8], Dtls13CipherSuite> {
733        let (input, value) = be_u16(input)?;
734        Ok((input, Dtls13CipherSuite::from_u16(value)))
735    }
736
737    /// Returns the hash algorithm used by this cipher suite.
738    pub fn hash_algorithm(&self) -> HashAlgorithm {
739        match self {
740            Dtls13CipherSuite::AES_128_GCM_SHA256
741            | Dtls13CipherSuite::CHACHA20_POLY1305_SHA256
742            | Dtls13CipherSuite::AES_128_CCM_SHA256
743            | Dtls13CipherSuite::AES_128_CCM_8_SHA256 => HashAlgorithm::SHA256,
744            Dtls13CipherSuite::AES_256_GCM_SHA384 => HashAlgorithm::SHA384,
745            Dtls13CipherSuite::Unknown(_) => HashAlgorithm::Unknown(0),
746        }
747    }
748
749    /// Returns true if this cipher suite is supported by this implementation.
750    pub fn is_supported(&self) -> bool {
751        Self::supported().contains(self)
752    }
753
754    /// All recognized DTLS 1.3 cipher suites (every non-`Unknown` variant).
755    pub fn all() -> &'static [Dtls13CipherSuite] {
756        &[
757            Dtls13CipherSuite::AES_128_GCM_SHA256,
758            Dtls13CipherSuite::AES_256_GCM_SHA384,
759            Dtls13CipherSuite::CHACHA20_POLY1305_SHA256,
760            Dtls13CipherSuite::AES_128_CCM_SHA256,
761            Dtls13CipherSuite::AES_128_CCM_8_SHA256,
762        ]
763    }
764
765    /// Supported DTLS 1.3 cipher suites in preference order.
766    pub fn supported() -> &'static [Dtls13CipherSuite] {
767        &[
768            Dtls13CipherSuite::AES_128_GCM_SHA256,
769            Dtls13CipherSuite::AES_256_GCM_SHA384,
770        ]
771    }
772
773    /// Length in bytes of verify_data for Finished messages.
774    pub fn verify_data_length(&self) -> usize {
775        self.hash_algorithm().output_len()
776    }
777}
778
779// ============================================================================
780// Protocol Version
781// ============================================================================
782
783/// DTLS protocol version identifiers.
784///
785/// Used in record headers and handshake messages for both DTLS 1.2 and 1.3.
786#[derive(Debug, Clone, Copy, PartialEq, Eq)]
787pub enum ProtocolVersion {
788    /// DTLS 1.0.
789    DTLS1_0,
790    /// DTLS 1.2.
791    DTLS1_2,
792    /// DTLS 1.3.
793    DTLS1_3,
794    /// Unknown protocol version.
795    Unknown(u16),
796}
797
798impl Default for ProtocolVersion {
799    fn default() -> Self {
800        Self::Unknown(0)
801    }
802}
803
804impl ProtocolVersion {
805    /// Convert this `ProtocolVersion` to its wire format u16 value.
806    pub fn as_u16(&self) -> u16 {
807        match self {
808            ProtocolVersion::DTLS1_0 => 0xFEFF,
809            ProtocolVersion::DTLS1_2 => 0xFEFD,
810            ProtocolVersion::DTLS1_3 => 0xFEFC,
811            ProtocolVersion::Unknown(value) => *value,
812        }
813    }
814
815    /// Parse a `ProtocolVersion` from wire format.
816    pub fn parse(input: &[u8]) -> IResult<&[u8], ProtocolVersion> {
817        let (input, version) = be_u16(input)?;
818        let protocol_version = match version {
819            0xFEFF => ProtocolVersion::DTLS1_0,
820            0xFEFD => ProtocolVersion::DTLS1_2,
821            0xFEFC => ProtocolVersion::DTLS1_3,
822            _ => ProtocolVersion::Unknown(version),
823        };
824        Ok((input, protocol_version))
825    }
826
827    /// Serialize this `ProtocolVersion` to wire format.
828    pub fn serialize(&self, output: &mut crate::buffer::Buf) {
829        output.extend_from_slice(&self.as_u16().to_be_bytes());
830    }
831}
832
833// ============================================================================
834// Compression Method
835// ============================================================================
836
837/// TLS compression methods.
838///
839/// Used in ClientHello/ServerHello for both DTLS 1.2 and 1.3.
840/// TLS 1.3 only uses Null compression but includes it for compatibility.
841#[derive(Debug, Clone, Copy, PartialEq, Eq)]
842pub enum CompressionMethod {
843    /// No compression.
844    Null,
845    /// DEFLATE compression.
846    Deflate,
847    /// Unknown compression method.
848    Unknown(u8),
849}
850
851impl Default for CompressionMethod {
852    fn default() -> Self {
853        Self::Unknown(0)
854    }
855}
856
857impl CompressionMethod {
858    /// Convert a u8 value to a `CompressionMethod`.
859    pub fn from_u8(value: u8) -> Self {
860        match value {
861            0x00 => CompressionMethod::Null,
862            0x01 => CompressionMethod::Deflate,
863            _ => CompressionMethod::Unknown(value),
864        }
865    }
866
867    /// Returns true if this compression method is supported by this implementation.
868    pub fn is_supported(&self) -> bool {
869        Self::supported().contains(self)
870    }
871
872    /// All recognized compression methods (every non-`Unknown` variant).
873    pub const fn all() -> &'static [CompressionMethod; 2] {
874        &[CompressionMethod::Null, CompressionMethod::Deflate]
875    }
876
877    /// Supported compression methods.
878    ///
879    /// Only null compression is supported. TLS 1.3 / DTLS 1.3 (RFC 8446
880    /// §4.1.2) mandates exactly one compression method (null). DEFLATE
881    /// is recognized by parsing but not accepted.
882    pub const fn supported() -> &'static [CompressionMethod; 1] {
883        &[CompressionMethod::Null]
884    }
885
886    /// Convert this `CompressionMethod` to its u8 value.
887    pub fn as_u8(&self) -> u8 {
888        match self {
889            CompressionMethod::Null => 0x00,
890            CompressionMethod::Deflate => 0x01,
891            CompressionMethod::Unknown(value) => *value,
892        }
893    }
894
895    /// Parse a `CompressionMethod` from wire format.
896    pub fn parse(input: &[u8]) -> IResult<&[u8], CompressionMethod> {
897        let (input, value) = be_u8(input)?;
898        Ok((input, CompressionMethod::from_u8(value)))
899    }
900}
901
902#[cfg(test)]
903mod tests {
904    use super::*;
905
906    #[test]
907    fn random_parse() {
908        let data = [
909            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
910            0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C,
911            0x1D, 0x1E, 0x1F, 0x20,
912        ];
913
914        let expected = Random { bytes: data };
915
916        let (_, parsed) = Random::parse(&data).unwrap();
917        assert_eq!(parsed, expected);
918    }
919
920    #[test]
921    fn random_serialize() {
922        let random = Random {
923            bytes: [
924                0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
925                0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C,
926                0x1D, 0x1E, 0x1F, 0x20,
927            ],
928        };
929
930        let mut serialized = Buf::new();
931        random.serialize(&mut serialized);
932
933        assert_eq!(&*serialized, &random.bytes);
934    }
935
936    #[test]
937    fn compression_supported_has_only_null() {
938        let supported = CompressionMethod::supported();
939        assert_eq!(
940            supported,
941            &[CompressionMethod::Null],
942            "Only Null compression should be supported"
943        );
944    }
945
946    #[test]
947    fn random_parse_roundtrip() {
948        let data = [
949            0x5F, 0x37, 0xA9, 0x4B, // could be gmt_unix_time in 1.2
950            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
951            0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C,
952        ];
953
954        let (_, parsed) = Random::parse(&data).unwrap();
955        let mut serialized = Buf::new();
956        parsed.serialize(&mut serialized);
957
958        assert_eq!(&*serialized, &data[..]);
959    }
960}