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}