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