1 | #![allow (clippy::upper_case_acronyms)] |
2 | #![allow (non_camel_case_types)] |
3 | use crate::crypto::KeyExchangeAlgorithm; |
4 | use crate::msgs::codec::{Codec, Reader}; |
5 | |
6 | enum_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 | |
22 | enum_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 | |
41 | enum_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 | |
53 | enum_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 | |
64 | enum_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 | |
75 | enum_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 | |
126 | impl 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 | |
154 | enum_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 | |
164 | enum_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 | |
210 | enum_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 | |
234 | impl 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 | |
244 | enum_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 | |
256 | impl ECPointFormat { |
257 | pub(crate) const SUPPORTED: [Self; 1] = [Self::Uncompressed]; |
258 | } |
259 | |
260 | enum_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 | |
271 | enum_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 | |
283 | enum_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 | |
294 | enum_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 | |
305 | enum_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 | |
315 | enum_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 | |
328 | enum_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 | |
343 | enum_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 | |
356 | impl 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 | |
363 | enum_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 | |
377 | impl 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 | |
390 | impl 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 | |
397 | enum_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)] |
411 | pub(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 | |