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