rustls/msgs/
enums.rs

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