Skip to main content

rustls/msgs/
enums.rs

1#![allow(clippy::upper_case_acronyms)]
2#![allow(non_camel_case_types)]
3use crate::crypto::{KeyExchangeAlgorithm, hash};
4use crate::msgs::codec::{Codec, Reader};
5
6enum_builder! {
7    /// The `HashAlgorithm` TLS protocol enum.  Values in this enum are taken
8    /// from the various RFCs covering TLS, and are listed by IANA.
9    /// The `Unknown` item is used when processing unrecognised ordinals.
10    #[repr(u8)]
11    pub enum HashAlgorithm {
12        NONE => 0x00,
13        MD5 => 0x01,
14        SHA1 => 0x02,
15        SHA224 => 0x03,
16        SHA256 => 0x04,
17        SHA384 => 0x05,
18        SHA512 => 0x06,
19    }
20}
21
22impl HashAlgorithm {
23    /// Returns the hash of the empty input.
24    ///
25    /// This returns `None` for some hash algorithms, so the caller
26    /// should be prepared to do the computation themselves in this case.
27    pub(crate) fn hash_for_empty_input(&self) -> Option<hash::Output> {
28        match self {
29            Self::SHA256 => Some(hash::Output::new(
30                b"\xe3\xb0\xc4\x42\x98\xfc\x1c\x14\
31                  \x9a\xfb\xf4\xc8\x99\x6f\xb9\x24\
32                  \x27\xae\x41\xe4\x64\x9b\x93\x4c\
33                  \xa4\x95\x99\x1b\x78\x52\xb8\x55",
34            )),
35            Self::SHA384 => Some(hash::Output::new(
36                b"\x38\xb0\x60\xa7\x51\xac\x96\x38\
37                  \x4c\xd9\x32\x7e\xb1\xb1\xe3\x6a\
38                  \x21\xfd\xb7\x11\x14\xbe\x07\x43\
39                  \x4c\x0c\xc7\xbf\x63\xf6\xe1\xda\
40                  \x27\x4e\xde\xbf\xe7\x6f\x65\xfb\
41                  \xd5\x1a\xd2\xf1\x48\x98\xb9\x5b",
42            )),
43            _ => None,
44        }
45    }
46}
47
48enum_builder! {
49    /// The `ClientCertificateType` TLS protocol enum.  Values in this enum are taken
50    /// from the various RFCs covering TLS, and are listed by IANA.
51    /// The `Unknown` item is used when processing unrecognised ordinals.
52    #[repr(u8)]
53    pub(crate) enum ClientCertificateType {
54        RSASign => 0x01,
55        DSSSign => 0x02,
56        RSAFixedDH => 0x03,
57        DSSFixedDH => 0x04,
58        RSAEphemeralDH => 0x05,
59        DSSEphemeralDH => 0x06,
60        FortezzaDMS => 0x14,
61        ECDSASign => 0x40,
62        RSAFixedECDH => 0x41,
63        ECDSAFixedECDH => 0x42,
64    }
65}
66
67enum_builder! {
68    /// The `Compression` TLS protocol enum.  Values in this enum are taken
69    /// from the various RFCs covering TLS, and are listed by IANA.
70    /// The `Unknown` item is used when processing unrecognised ordinals.
71    #[repr(u8)]
72    pub enum Compression {
73        Null => 0x00,
74        Deflate => 0x01,
75        LSZ => 0x40,
76    }
77}
78
79enum_builder! {
80    /// The `AlertLevel` TLS protocol enum.  Values in this enum are taken
81    /// from the various RFCs covering TLS, and are listed by IANA.
82    /// The `Unknown` item is used when processing unrecognised ordinals.
83    #[repr(u8)]
84    pub enum AlertLevel {
85        Warning => 0x01,
86        Fatal => 0x02,
87    }
88}
89
90enum_builder! {
91    /// The `HeartbeatMessageType` TLS protocol enum.  Values in this enum are taken
92    /// from the various RFCs covering TLS, and are listed by IANA.
93    /// The `Unknown` item is used when processing unrecognised ordinals.
94    #[repr(u8)]
95    pub(crate) enum HeartbeatMessageType {
96        Request => 0x01,
97        Response => 0x02,
98    }
99}
100
101enum_builder! {
102    /// The `ExtensionType` TLS protocol enum.  Values in this enum are taken
103    /// from the various RFCs covering TLS, and are listed by IANA.
104    /// The `Unknown` item is used when processing unrecognised ordinals.
105    #[repr(u16)]
106    pub enum ExtensionType {
107        ServerName => 0x0000,
108        MaxFragmentLength => 0x0001,
109        ClientCertificateUrl => 0x0002,
110        TrustedCAKeys => 0x0003,
111        TruncatedHMAC => 0x0004,
112        StatusRequest => 0x0005,
113        UserMapping => 0x0006,
114        ClientAuthz => 0x0007,
115        ServerAuthz => 0x0008,
116        CertificateType => 0x0009,
117        EllipticCurves => 0x000a,
118        ECPointFormats => 0x000b,
119        SRP => 0x000c,
120        SignatureAlgorithms => 0x000d,
121        UseSRTP => 0x000e,
122        Heartbeat => 0x000f,
123        ALProtocolNegotiation => 0x0010,
124        SCT => 0x0012,
125        ClientCertificateType => 0x0013,
126        ServerCertificateType => 0x0014,
127        Padding => 0x0015,
128        ExtendedMasterSecret => 0x0017,
129        CompressCertificate => 0x001b,
130        SessionTicket => 0x0023,
131        PreSharedKey => 0x0029,
132        EarlyData => 0x002a,
133        SupportedVersions => 0x002b,
134        Cookie => 0x002c,
135        PSKKeyExchangeModes => 0x002d,
136        TicketEarlyDataInfo => 0x002e,
137        CertificateAuthorities => 0x002f,
138        OIDFilters => 0x0030,
139        PostHandshakeAuth => 0x0031,
140        SignatureAlgorithmsCert => 0x0032,
141        KeyShare => 0x0033,
142        TransportParameters => 0x0039,
143        TicketRequest => 0x003a,
144        NextProtocolNegotiation => 0x3374,
145        ChannelId => 0x754f,
146        RenegotiationInfo => 0xff01,
147        TransportParametersDraft => 0xffa5,
148        EncryptedClientHello => 0xfe0d, // https://datatracker.ietf.org/doc/html/draft-ietf-tls-esni-18#section-11.1
149        EncryptedClientHelloOuterExtensions => 0xfd00, // https://datatracker.ietf.org/doc/html/draft-ietf-tls-esni-18#section-5.1
150    }
151}
152
153impl ExtensionType {
154    /// Returns true if the extension type can be compressed in an "inner" client hello for ECH.
155    ///
156    /// This function should only return true for extension types where the inner hello and outer
157    /// hello extensions values will always be identical. Extensions that may be identical
158    /// sometimes (e.g. server name, cert compression methods), but not always, SHOULD NOT be
159    /// compressed.
160    ///
161    /// See [draft-ietf-esni-18 §5](https://datatracker.ietf.org/doc/html/draft-ietf-tls-esni-18#section-5)
162    /// and [draft-ietf-esni-18 §10.5](https://datatracker.ietf.org/doc/html/draft-ietf-tls-esni-18#section-10.5)
163    /// for more information.
164    pub(crate) fn ech_compress(&self) -> bool {
165        // We match which extensions we will compress with BoringSSL and Go's stdlib.
166        matches!(
167            self,
168            Self::StatusRequest
169                | Self::EllipticCurves
170                | Self::SignatureAlgorithms
171                | Self::SignatureAlgorithmsCert
172                | Self::ALProtocolNegotiation
173                | Self::SupportedVersions
174                | Self::Cookie
175                | Self::KeyShare
176                | Self::PSKKeyExchangeModes
177        )
178    }
179}
180
181enum_builder! {
182    /// The `ServerNameType` TLS protocol enum.  Values in this enum are taken
183    /// from the various RFCs covering TLS, and are listed by IANA.
184    /// The `Unknown` item is used when processing unrecognised ordinals.
185    #[repr(u8)]
186    pub(crate) enum ServerNameType {
187        HostName => 0x00,
188    }
189}
190
191enum_builder! {
192    /// The `NamedCurve` TLS protocol enum.  Values in this enum are taken
193    /// from the various RFCs covering TLS, and are listed by IANA.
194    /// The `Unknown` item is used when processing unrecognised ordinals.
195    ///
196    /// This enum is used for recognizing elliptic curve parameters advertised
197    /// by a peer during a TLS handshake. It is **not** a list of curves that
198    /// Rustls supports. See [`crate::crypto::ring::kx_group`] for the list of supported
199    /// elliptic curve groups.
200    #[repr(u16)]
201    pub(crate) enum NamedCurve {
202        sect163k1 => 0x0001,
203        sect163r1 => 0x0002,
204        sect163r2 => 0x0003,
205        sect193r1 => 0x0004,
206        sect193r2 => 0x0005,
207        sect233k1 => 0x0006,
208        sect233r1 => 0x0007,
209        sect239k1 => 0x0008,
210        sect283k1 => 0x0009,
211        sect283r1 => 0x000a,
212        sect409k1 => 0x000b,
213        sect409r1 => 0x000c,
214        sect571k1 => 0x000d,
215        sect571r1 => 0x000e,
216        secp160k1 => 0x000f,
217        secp160r1 => 0x0010,
218        secp160r2 => 0x0011,
219        secp192k1 => 0x0012,
220        secp192r1 => 0x0013,
221        secp224k1 => 0x0014,
222        secp224r1 => 0x0015,
223        secp256k1 => 0x0016,
224        secp256r1 => 0x0017,
225        secp384r1 => 0x0018,
226        secp521r1 => 0x0019,
227        brainpoolp256r1 => 0x001a,
228        brainpoolp384r1 => 0x001b,
229        brainpoolp512r1 => 0x001c,
230        X25519 => 0x001d,
231        X448 => 0x001e,
232        arbitrary_explicit_prime_curves => 0xff01,
233        arbitrary_explicit_char2_curves => 0xff02,
234    }
235}
236
237enum_builder! {
238    /// The `NamedGroup` TLS protocol enum.  Values in this enum are taken
239    /// from the various RFCs covering TLS, and are listed by IANA.
240    /// The `Unknown` item is used when processing unrecognised ordinals.
241    #[repr(u16)]
242    pub enum NamedGroup {
243        secp256r1 => 0x0017,
244        secp384r1 => 0x0018,
245        secp521r1 => 0x0019,
246        X25519 => 0x001d,
247        X448 => 0x001e,
248        FFDHE2048 => 0x0100,
249        FFDHE3072 => 0x0101,
250        FFDHE4096 => 0x0102,
251        FFDHE6144 => 0x0103,
252        FFDHE8192 => 0x0104,
253        MLKEM512 => 0x0200,
254        MLKEM768 => 0x0201,
255        MLKEM1024 => 0x0202,
256        secp256r1MLKEM768 => 0x11eb,
257        X25519MLKEM768 => 0x11ec,
258    }
259}
260
261impl NamedGroup {
262    /// Return the key exchange algorithm associated with this `NamedGroup`
263    pub fn key_exchange_algorithm(self) -> KeyExchangeAlgorithm {
264        match u16::from(self) {
265            x if (0x100..0x200).contains(&x) => KeyExchangeAlgorithm::DHE,
266            _ => KeyExchangeAlgorithm::ECDHE,
267        }
268    }
269}
270
271enum_builder! {
272    /// The `ECPointFormat` TLS protocol enum.  Values in this enum are taken
273    /// from the various RFCs covering TLS, and are listed by IANA.
274    /// The `Unknown` item is used when processing unrecognised ordinals.
275    #[repr(u8)]
276    pub enum ECPointFormat {
277        Uncompressed => 0x00,
278        ANSIX962CompressedPrime => 0x01,
279        ANSIX962CompressedChar2 => 0x02,
280    }
281}
282
283enum_builder! {
284    /// The `HeartbeatMode` TLS protocol enum.  Values in this enum are taken
285    /// from the various RFCs covering TLS, and are listed by IANA.
286    /// The `Unknown` item is used when processing unrecognised ordinals.
287    #[repr(u8)]
288    pub(crate) enum HeartbeatMode {
289        PeerAllowedToSend => 0x01,
290        PeerNotAllowedToSend => 0x02,
291    }
292}
293
294enum_builder! {
295    /// The `ECCurveType` TLS protocol enum.  Values in this enum are taken
296    /// from the various RFCs covering TLS, and are listed by IANA.
297    /// The `Unknown` item is used when processing unrecognised ordinals.
298    #[repr(u8)]
299    pub(crate) enum ECCurveType {
300        ExplicitPrime => 0x01,
301        ExplicitChar2 => 0x02,
302        NamedCurve => 0x03,
303    }
304}
305
306enum_builder! {
307    /// The `PskKeyExchangeMode` TLS protocol enum.  Values in this enum are taken
308    /// from the various RFCs covering TLS, and are listed by IANA.
309    /// The `Unknown` item is used when processing unrecognised ordinals.
310    #[repr(u8)]
311    pub enum PskKeyExchangeMode {
312        PSK_KE => 0x00,
313        PSK_DHE_KE => 0x01,
314    }
315}
316
317enum_builder! {
318    /// The `KeyUpdateRequest` TLS protocol enum.  Values in this enum are taken
319    /// from the various RFCs covering TLS, and are listed by IANA.
320    /// The `Unknown` item is used when processing unrecognised ordinals.
321    #[repr(u8)]
322    pub enum KeyUpdateRequest {
323        UpdateNotRequested => 0x00,
324        UpdateRequested => 0x01,
325    }
326}
327
328enum_builder! {
329    /// The `CertificateStatusType` TLS protocol enum.  Values in this enum are taken
330    /// from the various RFCs covering TLS, and are listed by IANA.
331    /// The `Unknown` item is used when processing unrecognised ordinals.
332    #[repr(u8)]
333    pub enum CertificateStatusType {
334        OCSP => 0x01,
335    }
336}
337
338enum_builder! {
339    /// The Key Encapsulation Mechanism (`Kem`) type for HPKE operations.
340    /// Listed by IANA, as specified in [RFC 9180 Section 7.1]
341    ///
342    /// [RFC 9180 Section 7.1]: <https://datatracker.ietf.org/doc/html/rfc9180#kemid-values>
343    #[repr(u16)]
344    pub enum HpkeKem {
345        DHKEM_P256_HKDF_SHA256 => 0x0010,
346        DHKEM_P384_HKDF_SHA384 => 0x0011,
347        DHKEM_P521_HKDF_SHA512 => 0x0012,
348        DHKEM_X25519_HKDF_SHA256 => 0x0020,
349        DHKEM_X448_HKDF_SHA512 => 0x0021,
350    }
351}
352
353enum_builder! {
354    /// The Key Derivation Function (`Kdf`) type for HPKE operations.
355    /// Listed by IANA, as specified in [RFC 9180 Section 7.2]
356    ///
357    /// [RFC 9180 Section 7.2]: <https://datatracker.ietf.org/doc/html/rfc9180#name-key-derivation-functions-kd>
358    #[repr(u16)]
359    #[derive(Default)]
360    pub enum HpkeKdf {
361        // TODO(XXX): revisit the default configuration. This is just what Cloudflare ships right now.
362        #[default]
363        HKDF_SHA256 => 0x0001,
364        HKDF_SHA384 => 0x0002,
365        HKDF_SHA512 => 0x0003,
366    }
367}
368
369enum_builder! {
370    /// The Authenticated Encryption with Associated Data (`Aead`) type for HPKE operations.
371    /// Listed by IANA, as specified in [RFC 9180 Section 7.3]
372    ///
373    /// [RFC 9180 Section 7.3]: <https://datatracker.ietf.org/doc/html/rfc9180#name-authenticated-encryption-wi>
374    #[repr(u16)]
375    #[derive(Default)]
376    pub enum HpkeAead {
377        // TODO(XXX): revisit the default configuration. This is just what Cloudflare ships right now.
378        #[default]
379        AES_128_GCM => 0x0001,
380        AES_256_GCM => 0x0002,
381        CHACHA20_POLY_1305 => 0x0003,
382        EXPORT_ONLY => 0xFFFF,
383    }
384}
385
386impl HpkeAead {
387    /// Returns the length of the tag for the AEAD algorithm, or none if the AEAD is EXPORT_ONLY.
388    pub(crate) fn tag_len(&self) -> Option<usize> {
389        match self {
390            // See RFC 9180 Section 7.3, column `Nt`, the length in bytes of the authentication tag
391            // for the algorithm.
392            // https://www.rfc-editor.org/rfc/rfc9180.html#section-7.3
393            Self::AES_128_GCM | Self::AES_256_GCM | Self::CHACHA20_POLY_1305 => Some(16),
394            _ => None,
395        }
396    }
397}
398
399enum_builder! {
400    /// The Encrypted Client Hello protocol version (`EchVersion`).
401    ///
402    /// Specified in [draft-ietf-tls-esni Section 4].
403    /// TODO(XXX): Update reference once RFC is published.
404    ///
405    /// [draft-ietf-tls-esni Section 4]: <https://www.ietf.org/archive/id/draft-ietf-tls-esni-17.html#section-4>
406    #[repr(u16)]
407    pub enum EchVersion {
408        V18 => 0xfe0d,
409    }
410}
411
412#[cfg(test)]
413pub(crate) mod tests {
414    // These tests are intended to provide coverage and
415    // check panic-safety of relatively unused values.
416
417    use std::prelude::v1::*;
418
419    use super::*;
420
421    #[test]
422    fn test_enums() {
423        test_enum8::<HashAlgorithm>(HashAlgorithm::NONE, HashAlgorithm::SHA512);
424        test_enum8::<ClientCertificateType>(
425            ClientCertificateType::RSASign,
426            ClientCertificateType::ECDSAFixedECDH,
427        );
428        test_enum8::<Compression>(Compression::Null, Compression::LSZ);
429        test_enum8::<AlertLevel>(AlertLevel::Warning, AlertLevel::Fatal);
430        test_enum8::<HeartbeatMessageType>(
431            HeartbeatMessageType::Request,
432            HeartbeatMessageType::Response,
433        );
434        test_enum16::<ExtensionType>(ExtensionType::ServerName, ExtensionType::RenegotiationInfo);
435        test_enum8::<ServerNameType>(ServerNameType::HostName, ServerNameType::HostName);
436        test_enum16::<NamedCurve>(
437            NamedCurve::sect163k1,
438            NamedCurve::arbitrary_explicit_char2_curves,
439        );
440        test_enum16::<NamedGroup>(NamedGroup::secp256r1, NamedGroup::FFDHE8192);
441        test_enum8::<ECPointFormat>(
442            ECPointFormat::Uncompressed,
443            ECPointFormat::ANSIX962CompressedChar2,
444        );
445        test_enum8::<HeartbeatMode>(
446            HeartbeatMode::PeerAllowedToSend,
447            HeartbeatMode::PeerNotAllowedToSend,
448        );
449        test_enum8::<ECCurveType>(ECCurveType::ExplicitPrime, ECCurveType::NamedCurve);
450        test_enum8::<PskKeyExchangeMode>(
451            PskKeyExchangeMode::PSK_KE,
452            PskKeyExchangeMode::PSK_DHE_KE,
453        );
454        test_enum8::<KeyUpdateRequest>(
455            KeyUpdateRequest::UpdateNotRequested,
456            KeyUpdateRequest::UpdateRequested,
457        );
458        test_enum8::<CertificateStatusType>(
459            CertificateStatusType::OCSP,
460            CertificateStatusType::OCSP,
461        );
462    }
463
464    pub(crate) fn test_enum8<T: for<'a> Codec<'a>>(first: T, last: T) {
465        let first_v = get8(&first);
466        let last_v = get8(&last);
467
468        for val in first_v..last_v + 1 {
469            let mut buf = Vec::new();
470            val.encode(&mut buf);
471            assert_eq!(buf.len(), 1);
472
473            let t = T::read_bytes(&buf).unwrap();
474            assert_eq!(val, get8(&t));
475        }
476    }
477
478    pub(crate) fn test_enum16<T: for<'a> Codec<'a>>(first: T, last: T) {
479        let first_v = get16(&first);
480        let last_v = get16(&last);
481
482        for val in first_v..last_v + 1 {
483            let mut buf = Vec::new();
484            val.encode(&mut buf);
485            assert_eq!(buf.len(), 2);
486
487            let t = T::read_bytes(&buf).unwrap();
488            assert_eq!(val, get16(&t));
489        }
490    }
491
492    fn get8<T: for<'a> Codec<'a>>(enum_value: &T) -> u8 {
493        let enc = enum_value.get_encoding();
494        assert_eq!(enc.len(), 1);
495        enc[0]
496    }
497
498    fn get16<T: for<'a> Codec<'a>>(enum_value: &T) -> u16 {
499        let enc = enum_value.get_encoding();
500        assert_eq!(enc.len(), 2);
501        (enc[0] as u16 >> 8) | (enc[1] as u16)
502    }
503}