openmls_traits/
types.rs

1//! # OpenMLS Types
2//!
3//! This module holds a number of types that are needed by the traits.
4
5use std::ops::Deref;
6
7use serde::{Deserialize, Serialize};
8use tls_codec::{
9    SecretVLBytes, TlsDeserialize, TlsDeserializeBytes, TlsSerialize, TlsSize, VLBytes,
10};
11
12#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)]
13#[repr(u16)]
14/// AEAD types
15pub enum AeadType {
16    /// AES GCM 128
17    Aes128Gcm = 0x0001,
18
19    /// AES GCM 256
20    Aes256Gcm = 0x0002,
21
22    /// ChaCha20 Poly1305
23    ChaCha20Poly1305 = 0x0003,
24}
25
26impl AeadType {
27    /// Get the tag size of the [`AeadType`] in bytes.
28    pub const fn tag_size(&self) -> usize {
29        match self {
30            AeadType::Aes128Gcm => 16,
31            AeadType::Aes256Gcm => 16,
32            AeadType::ChaCha20Poly1305 => 16,
33        }
34    }
35
36    /// Get the key size of the [`AeadType`] in bytes.
37    pub const fn key_size(&self) -> usize {
38        match self {
39            AeadType::Aes128Gcm => 16,
40            AeadType::Aes256Gcm => 32,
41            AeadType::ChaCha20Poly1305 => 32,
42        }
43    }
44
45    /// Get the nonce size of the [`AeadType`] in bytes.
46    pub const fn nonce_size(&self) -> usize {
47        match self {
48            AeadType::Aes128Gcm | AeadType::Aes256Gcm | AeadType::ChaCha20Poly1305 => 12,
49        }
50    }
51}
52
53#[derive(Debug, PartialEq, Eq, Clone, Copy)]
54#[repr(u8)]
55#[allow(non_camel_case_types)]
56/// Hash types
57pub enum HashType {
58    Sha2_256 = 0x04,
59    Sha2_384 = 0x05,
60    Sha2_512 = 0x06,
61}
62
63impl HashType {
64    /// Returns the output size of a hash by [`HashType`].
65    #[inline]
66    pub const fn size(&self) -> usize {
67        match self {
68            HashType::Sha2_256 => 32,
69            HashType::Sha2_384 => 48,
70            HashType::Sha2_512 => 64,
71        }
72    }
73}
74
75/// SignatureScheme according to IANA TLS parameters
76#[allow(non_camel_case_types)]
77#[allow(clippy::upper_case_acronyms)]
78#[derive(
79    Copy,
80    Hash,
81    Eq,
82    PartialEq,
83    Clone,
84    Debug,
85    Serialize,
86    Deserialize,
87    TlsSerialize,
88    TlsDeserialize,
89    TlsDeserializeBytes,
90    TlsSize,
91)]
92#[repr(u16)]
93pub enum SignatureScheme {
94    /// ECDSA_SECP256R1_SHA256
95    ECDSA_SECP256R1_SHA256 = 0x0403,
96    /// ECDSA_SECP384R1_SHA384
97    ECDSA_SECP384R1_SHA384 = 0x0503,
98    /// ECDSA_SECP521R1_SHA512
99    ECDSA_SECP521R1_SHA512 = 0x0603,
100    /// ED25519
101    ED25519 = 0x0807,
102    /// ED448
103    ED448 = 0x0808,
104}
105
106impl TryFrom<u16> for SignatureScheme {
107    type Error = String;
108
109    fn try_from(value: u16) -> Result<Self, Self::Error> {
110        match value {
111            0x0403 => Ok(SignatureScheme::ECDSA_SECP256R1_SHA256),
112            0x0503 => Ok(SignatureScheme::ECDSA_SECP384R1_SHA384),
113            0x0603 => Ok(SignatureScheme::ECDSA_SECP521R1_SHA512),
114            0x0807 => Ok(SignatureScheme::ED25519),
115            0x0808 => Ok(SignatureScheme::ED448),
116            _ => Err(format!("Unsupported SignatureScheme: {value}")),
117        }
118    }
119}
120
121/// Crypto errors.
122#[derive(Debug, PartialEq, Eq, Clone, Copy)]
123pub enum CryptoError {
124    CryptoLibraryError,
125    AeadDecryptionError,
126    HpkeDecryptionError,
127    HpkeEncryptionError,
128    UnsupportedSignatureScheme,
129    KdfLabelTooLarge,
130    KdfSerializationError,
131    HkdfOutputLengthInvalid,
132    InsufficientRandomness,
133    InvalidSignature,
134    UnsupportedAeadAlgorithm,
135    UnsupportedKdf,
136    InvalidLength,
137    UnsupportedHashAlgorithm,
138    SignatureEncodingError,
139    SignatureDecodingError,
140    SenderSetupError,
141    ReceiverSetupError,
142    ExporterError,
143    UnsupportedCiphersuite,
144    TlsSerializationError,
145    TooMuchData,
146    SigningError,
147    InvalidPublicKey,
148}
149
150impl std::fmt::Display for CryptoError {
151    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
152        write!(f, "{self:?}")
153    }
154}
155
156impl std::error::Error for CryptoError {}
157
158// === HPKE === //
159
160/// Convenience tuple struct for an HPKE configuration.
161#[derive(Debug)]
162pub struct HpkeConfig(pub HpkeKemType, pub HpkeKdfType, pub HpkeAeadType);
163
164/// KEM Types for HPKE
165#[derive(PartialEq, Eq, Copy, Clone, Debug, Serialize, Deserialize)]
166#[repr(u16)]
167pub enum HpkeKemType {
168    /// DH KEM on P256
169    DhKemP256 = 0x0010,
170
171    /// DH KEM on P384
172    DhKemP384 = 0x0011,
173
174    /// DH KEM on P521
175    DhKemP521 = 0x0012,
176
177    /// DH KEM on x25519
178    DhKem25519 = 0x0020,
179
180    /// DH KEM on x448
181    DhKem448 = 0x0021,
182
183    /// XWing combiner for ML-KEM and X25519
184    XWingKemDraft6 = 0x004D,
185}
186
187/// KDF Types for HPKE
188#[derive(PartialEq, Eq, Copy, Clone, Debug, Serialize, Deserialize)]
189#[repr(u16)]
190pub enum HpkeKdfType {
191    /// HKDF SHA 256
192    HkdfSha256 = 0x0001,
193
194    /// HKDF SHA 384
195    HkdfSha384 = 0x0002,
196
197    /// HKDF SHA 512
198    HkdfSha512 = 0x0003,
199}
200
201/// AEAD Types for HPKE.
202#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
203#[repr(u16)]
204pub enum HpkeAeadType {
205    /// AES GCM 128
206    AesGcm128 = 0x0001,
207
208    /// AES GCM 256
209    AesGcm256 = 0x0002,
210
211    /// ChaCha20 Poly1305
212    ChaCha20Poly1305 = 0x0003,
213
214    /// Export-only
215    Export = 0xFFFF,
216}
217
218/// 7.7. Update Paths
219///
220/// ```text
221/// struct {
222///     opaque kem_output<V>;
223///     opaque ciphertext<V>;
224/// } HPKECiphertext;
225/// ```
226#[derive(
227    Debug,
228    PartialEq,
229    Eq,
230    Clone,
231    Serialize,
232    Deserialize,
233    TlsSerialize,
234    TlsDeserialize,
235    TlsDeserializeBytes,
236    TlsSize,
237)]
238pub struct HpkeCiphertext {
239    pub kem_output: VLBytes,
240    pub ciphertext: VLBytes,
241}
242
243/// A simple type for HPKE private keys.
244#[derive(
245    Debug,
246    Clone,
247    serde::Serialize,
248    serde::Deserialize,
249    TlsSerialize,
250    TlsDeserialize,
251    TlsDeserializeBytes,
252    TlsSize,
253)]
254#[cfg_attr(feature = "test-utils", derive(PartialEq, Eq))]
255#[serde(transparent)]
256pub struct HpkePrivateKey(SecretVLBytes);
257
258impl From<Vec<u8>> for HpkePrivateKey {
259    fn from(bytes: Vec<u8>) -> Self {
260        Self(bytes.into())
261    }
262}
263
264impl From<&[u8]> for HpkePrivateKey {
265    fn from(bytes: &[u8]) -> Self {
266        Self(bytes.into())
267    }
268}
269
270impl std::ops::Deref for HpkePrivateKey {
271    type Target = [u8];
272
273    fn deref(&self) -> &Self::Target {
274        self.0.as_slice()
275    }
276}
277
278/// Helper holding a (private, public) key pair as byte vectors.
279#[derive(Debug, Clone, Serialize, Deserialize)]
280pub struct HpkeKeyPair {
281    pub private: HpkePrivateKey,
282    pub public: Vec<u8>,
283}
284
285pub type KemOutput = Vec<u8>;
286#[derive(Clone, Debug)]
287pub struct ExporterSecret(SecretVLBytes);
288
289impl Deref for ExporterSecret {
290    type Target = [u8];
291
292    fn deref(&self) -> &Self::Target {
293        self.0.as_slice()
294    }
295}
296
297impl From<Vec<u8>> for ExporterSecret {
298    fn from(secret: Vec<u8>) -> Self {
299        Self(secret.into())
300    }
301}
302
303/// A currently unknown ciphersuite.
304///
305/// Used to accept unknown values, e.g., in `Capabilities`.
306#[derive(
307    Clone,
308    Copy,
309    Debug,
310    PartialEq,
311    Eq,
312    Serialize,
313    Deserialize,
314    TlsSerialize,
315    TlsDeserialize,
316    TlsDeserializeBytes,
317    TlsSize,
318)]
319pub struct VerifiableCiphersuite(u16);
320
321impl VerifiableCiphersuite {
322    pub fn new(value: u16) -> Self {
323        Self(value)
324    }
325}
326
327impl From<Ciphersuite> for VerifiableCiphersuite {
328    fn from(value: Ciphersuite) -> Self {
329        Self(value as u16)
330    }
331}
332
333impl TryFrom<VerifiableCiphersuite> for Ciphersuite {
334    type Error = tls_codec::Error;
335
336    fn try_from(value: VerifiableCiphersuite) -> Result<Self, Self::Error> {
337        Ciphersuite::try_from(value.0)
338    }
339}
340
341/// MLS ciphersuites.
342#[allow(non_camel_case_types)]
343#[allow(clippy::upper_case_acronyms)]
344#[derive(
345    Debug,
346    Clone,
347    Copy,
348    PartialEq,
349    Eq,
350    PartialOrd,
351    Ord,
352    Hash,
353    Serialize,
354    Deserialize,
355    TlsDeserialize,
356    TlsDeserializeBytes,
357    TlsSerialize,
358    TlsSize,
359)]
360#[repr(u16)]
361pub enum Ciphersuite {
362    /// DH KEM x25519 | AES-GCM 128 | SHA2-256 | Ed25519
363    MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519 = 0x0001,
364
365    /// DH KEM P256 | AES-GCM 128 | SHA2-256 | EcDSA P256
366    MLS_128_DHKEMP256_AES128GCM_SHA256_P256 = 0x0002,
367
368    /// DH KEM x25519 | Chacha20Poly1305 | SHA2-256 | Ed25519
369    MLS_128_DHKEMX25519_CHACHA20POLY1305_SHA256_Ed25519 = 0x0003,
370
371    /// DH KEM x448 | AES-GCM 256 | SHA2-512 | Ed448
372    MLS_256_DHKEMX448_AES256GCM_SHA512_Ed448 = 0x0004,
373
374    /// DH KEM P521 | AES-GCM 256 | SHA2-512 | EcDSA P521
375    MLS_256_DHKEMP521_AES256GCM_SHA512_P521 = 0x0005,
376
377    /// DH KEM x448 | Chacha20Poly1305 | SHA2-512 | Ed448
378    MLS_256_DHKEMX448_CHACHA20POLY1305_SHA512_Ed448 = 0x0006,
379
380    /// DH KEM P384 | AES-GCM 256 | SHA2-384 | EcDSA P384
381    MLS_256_DHKEMP384_AES256GCM_SHA384_P384 = 0x0007,
382
383    /// X-WING KEM draft-01 | Chacha20Poly1305 | SHA2-256 | Ed25519
384    MLS_256_XWING_CHACHA20POLY1305_SHA256_Ed25519 = 0x004D,
385}
386
387impl core::fmt::Display for Ciphersuite {
388    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
389        write!(f, "{self:?}")
390    }
391}
392
393impl From<Ciphersuite> for u16 {
394    #[inline(always)]
395    fn from(s: Ciphersuite) -> u16 {
396        s as u16
397    }
398}
399
400impl From<&Ciphersuite> for u16 {
401    #[inline(always)]
402    fn from(s: &Ciphersuite) -> u16 {
403        *s as u16
404    }
405}
406
407impl TryFrom<u16> for Ciphersuite {
408    type Error = tls_codec::Error;
409
410    #[inline(always)]
411    fn try_from(v: u16) -> Result<Self, Self::Error> {
412        match v {
413            0x0001 => Ok(Ciphersuite::MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519),
414            0x0002 => Ok(Ciphersuite::MLS_128_DHKEMP256_AES128GCM_SHA256_P256),
415            0x0003 => Ok(Ciphersuite::MLS_128_DHKEMX25519_CHACHA20POLY1305_SHA256_Ed25519),
416            0x0004 => Ok(Ciphersuite::MLS_256_DHKEMX448_AES256GCM_SHA512_Ed448),
417            0x0005 => Ok(Ciphersuite::MLS_256_DHKEMP521_AES256GCM_SHA512_P521),
418            0x0006 => Ok(Ciphersuite::MLS_256_DHKEMX448_CHACHA20POLY1305_SHA512_Ed448),
419            0x0007 => Ok(Ciphersuite::MLS_256_DHKEMP384_AES256GCM_SHA384_P384),
420            0x004D => Ok(Ciphersuite::MLS_256_XWING_CHACHA20POLY1305_SHA256_Ed25519),
421            _ => Err(Self::Error::DecodingError(format!(
422                "{v} is not a valid ciphersuite value"
423            ))),
424        }
425    }
426}
427
428impl From<Ciphersuite> for SignatureScheme {
429    #[inline(always)]
430    fn from(ciphersuite_name: Ciphersuite) -> Self {
431        ciphersuite_name.signature_algorithm()
432    }
433}
434
435impl From<Ciphersuite> for AeadType {
436    #[inline(always)]
437    fn from(ciphersuite_name: Ciphersuite) -> Self {
438        ciphersuite_name.aead_algorithm()
439    }
440}
441
442impl From<Ciphersuite> for HpkeKemType {
443    #[inline(always)]
444    fn from(ciphersuite_name: Ciphersuite) -> Self {
445        ciphersuite_name.hpke_kem_algorithm()
446    }
447}
448
449impl From<Ciphersuite> for HpkeAeadType {
450    #[inline(always)]
451    fn from(ciphersuite_name: Ciphersuite) -> Self {
452        ciphersuite_name.hpke_aead_algorithm()
453    }
454}
455
456impl From<Ciphersuite> for HpkeKdfType {
457    #[inline(always)]
458    fn from(ciphersuite_name: Ciphersuite) -> Self {
459        ciphersuite_name.hpke_kdf_algorithm()
460    }
461}
462
463impl From<Ciphersuite> for HashType {
464    #[inline(always)]
465    fn from(ciphersuite_name: Ciphersuite) -> Self {
466        ciphersuite_name.hash_algorithm()
467    }
468}
469
470impl Ciphersuite {
471    /// Get the [`HashType`] for this [`Ciphersuite`]
472    #[inline]
473    pub const fn hash_algorithm(&self) -> HashType {
474        match self {
475            Ciphersuite::MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519
476            | Ciphersuite::MLS_128_DHKEMP256_AES128GCM_SHA256_P256
477            | Ciphersuite::MLS_128_DHKEMX25519_CHACHA20POLY1305_SHA256_Ed25519
478            | Ciphersuite::MLS_256_XWING_CHACHA20POLY1305_SHA256_Ed25519 => HashType::Sha2_256,
479            Ciphersuite::MLS_256_DHKEMP384_AES256GCM_SHA384_P384 => HashType::Sha2_384,
480            Ciphersuite::MLS_256_DHKEMX448_AES256GCM_SHA512_Ed448
481            | Ciphersuite::MLS_256_DHKEMP521_AES256GCM_SHA512_P521
482            | Ciphersuite::MLS_256_DHKEMX448_CHACHA20POLY1305_SHA512_Ed448 => HashType::Sha2_512,
483        }
484    }
485
486    /// Get the [`SignatureScheme`] for this [`Ciphersuite`].
487    #[inline]
488    pub const fn signature_algorithm(&self) -> SignatureScheme {
489        match self {
490            Ciphersuite::MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519
491            | Ciphersuite::MLS_128_DHKEMX25519_CHACHA20POLY1305_SHA256_Ed25519
492            | Ciphersuite::MLS_256_XWING_CHACHA20POLY1305_SHA256_Ed25519 => {
493                SignatureScheme::ED25519
494            }
495            Ciphersuite::MLS_128_DHKEMP256_AES128GCM_SHA256_P256 => {
496                SignatureScheme::ECDSA_SECP256R1_SHA256
497            }
498            Ciphersuite::MLS_256_DHKEMP521_AES256GCM_SHA512_P521 => {
499                SignatureScheme::ECDSA_SECP521R1_SHA512
500            }
501            Ciphersuite::MLS_256_DHKEMX448_AES256GCM_SHA512_Ed448
502            | Ciphersuite::MLS_256_DHKEMX448_CHACHA20POLY1305_SHA512_Ed448 => {
503                SignatureScheme::ED448
504            }
505            Ciphersuite::MLS_256_DHKEMP384_AES256GCM_SHA384_P384 => {
506                SignatureScheme::ECDSA_SECP384R1_SHA384
507            }
508        }
509    }
510
511    /// Get the [`AeadType`] for this [`Ciphersuite`].
512    #[inline]
513    pub const fn aead_algorithm(&self) -> AeadType {
514        match self {
515            Ciphersuite::MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519
516            | Ciphersuite::MLS_128_DHKEMP256_AES128GCM_SHA256_P256 => AeadType::Aes128Gcm,
517            Ciphersuite::MLS_128_DHKEMX25519_CHACHA20POLY1305_SHA256_Ed25519
518            | Ciphersuite::MLS_256_DHKEMX448_CHACHA20POLY1305_SHA512_Ed448
519            | Ciphersuite::MLS_256_XWING_CHACHA20POLY1305_SHA256_Ed25519 => {
520                AeadType::ChaCha20Poly1305
521            }
522            Ciphersuite::MLS_256_DHKEMX448_AES256GCM_SHA512_Ed448
523            | Ciphersuite::MLS_256_DHKEMP521_AES256GCM_SHA512_P521
524            | Ciphersuite::MLS_256_DHKEMP384_AES256GCM_SHA384_P384 => AeadType::Aes256Gcm,
525        }
526    }
527
528    /// Get the [`HpkeKdfType`] for this [`Ciphersuite`].
529    #[inline]
530    pub const fn hpke_kdf_algorithm(&self) -> HpkeKdfType {
531        match self {
532            Ciphersuite::MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519
533            | Ciphersuite::MLS_128_DHKEMP256_AES128GCM_SHA256_P256
534            | Ciphersuite::MLS_128_DHKEMX25519_CHACHA20POLY1305_SHA256_Ed25519
535            | Self::MLS_256_XWING_CHACHA20POLY1305_SHA256_Ed25519 => HpkeKdfType::HkdfSha256,
536            Ciphersuite::MLS_256_DHKEMP384_AES256GCM_SHA384_P384 => HpkeKdfType::HkdfSha384,
537            Ciphersuite::MLS_256_DHKEMX448_AES256GCM_SHA512_Ed448
538            | Ciphersuite::MLS_256_DHKEMP521_AES256GCM_SHA512_P521
539            | Ciphersuite::MLS_256_DHKEMX448_CHACHA20POLY1305_SHA512_Ed448 => {
540                HpkeKdfType::HkdfSha512
541            }
542        }
543    }
544
545    /// Get the [`HpkeKemType`] for this [`Ciphersuite`].
546    #[inline]
547    pub const fn hpke_kem_algorithm(&self) -> HpkeKemType {
548        match self {
549            Ciphersuite::MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519
550            | Ciphersuite::MLS_128_DHKEMX25519_CHACHA20POLY1305_SHA256_Ed25519 => {
551                HpkeKemType::DhKem25519
552            }
553            Ciphersuite::MLS_128_DHKEMP256_AES128GCM_SHA256_P256 => HpkeKemType::DhKemP256,
554            Ciphersuite::MLS_256_DHKEMX448_AES256GCM_SHA512_Ed448
555            | Ciphersuite::MLS_256_DHKEMX448_CHACHA20POLY1305_SHA512_Ed448 => HpkeKemType::DhKem448,
556            Ciphersuite::MLS_256_DHKEMP384_AES256GCM_SHA384_P384 => HpkeKemType::DhKemP384,
557            Ciphersuite::MLS_256_DHKEMP521_AES256GCM_SHA512_P521 => HpkeKemType::DhKemP521,
558            Ciphersuite::MLS_256_XWING_CHACHA20POLY1305_SHA256_Ed25519 => {
559                HpkeKemType::XWingKemDraft6
560            }
561        }
562    }
563
564    /// Get the [`HpkeAeadType`] for this [`Ciphersuite`].
565    #[inline]
566    pub const fn hpke_aead_algorithm(&self) -> HpkeAeadType {
567        match self {
568            Ciphersuite::MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519
569            | Ciphersuite::MLS_128_DHKEMP256_AES128GCM_SHA256_P256 => HpkeAeadType::AesGcm128,
570            Ciphersuite::MLS_128_DHKEMX25519_CHACHA20POLY1305_SHA256_Ed25519
571            | Ciphersuite::MLS_256_XWING_CHACHA20POLY1305_SHA256_Ed25519 => {
572                HpkeAeadType::ChaCha20Poly1305
573            }
574            Ciphersuite::MLS_256_DHKEMX448_AES256GCM_SHA512_Ed448
575            | Ciphersuite::MLS_256_DHKEMP384_AES256GCM_SHA384_P384
576            | Ciphersuite::MLS_256_DHKEMP521_AES256GCM_SHA512_P521 => HpkeAeadType::AesGcm256,
577            Ciphersuite::MLS_256_DHKEMX448_CHACHA20POLY1305_SHA512_Ed448 => {
578                HpkeAeadType::ChaCha20Poly1305
579            }
580        }
581    }
582
583    /// Get the [`HpkeConfig`] for this [`Ciphersuite`].
584    #[inline]
585    pub const fn hpke_config(&self) -> HpkeConfig {
586        HpkeConfig(
587            self.hpke_kem_algorithm(),
588            self.hpke_kdf_algorithm(),
589            self.hpke_aead_algorithm(),
590        )
591    }
592
593    /// Get the length of the used hash algorithm.
594    #[inline]
595    pub const fn hash_length(&self) -> usize {
596        self.hash_algorithm().size()
597    }
598
599    /// Get the length of the AEAD tag.
600    #[inline]
601    pub const fn mac_length(&self) -> usize {
602        self.aead_algorithm().tag_size()
603    }
604
605    /// Returns the key size of the used AEAD.
606    #[inline]
607    pub const fn aead_key_length(&self) -> usize {
608        self.aead_algorithm().key_size()
609    }
610
611    /// Returns the length of the nonce of the AEAD.
612    #[inline]
613    pub const fn aead_nonce_length(&self) -> usize {
614        self.aead_algorithm().nonce_size()
615    }
616}