1 | /// This module contains optional APIs for implementing QUIC TLS. |
2 | use crate::client::{ClientConfig, ClientConnectionData}; |
3 | use crate::common_state::{CommonState, Protocol, Side}; |
4 | use crate::conn::{ConnectionCore, SideData}; |
5 | use crate::crypto::cipher::{AeadKey, Iv}; |
6 | use crate::crypto::tls13::{Hkdf, HkdfExpander, OkmBlock}; |
7 | use crate::enums::{AlertDescription, ProtocolVersion}; |
8 | use crate::error::Error; |
9 | use crate::msgs::deframer::DeframerVecBuffer; |
10 | use crate::msgs::handshake::{ClientExtension, ServerExtension}; |
11 | use crate::server::{ServerConfig, ServerConnectionData}; |
12 | use crate::tls13::key_schedule::{ |
13 | hkdf_expand_label, hkdf_expand_label_aead_key, hkdf_expand_label_block, |
14 | }; |
15 | use crate::tls13::Tls13CipherSuite; |
16 | |
17 | use pki_types::ServerName; |
18 | |
19 | use alloc::boxed::Box; |
20 | use alloc::collections::VecDeque; |
21 | use alloc::sync::Arc; |
22 | use alloc::vec; |
23 | use alloc::vec::Vec; |
24 | use core::fmt::{self, Debug}; |
25 | use core::ops::{Deref, DerefMut}; |
26 | |
27 | /// A QUIC client or server connection. |
28 | #[derive (Debug)] |
29 | pub enum Connection { |
30 | /// A client connection |
31 | Client(ClientConnection), |
32 | /// A server connection |
33 | Server(ServerConnection), |
34 | } |
35 | |
36 | impl Connection { |
37 | /// Return the TLS-encoded transport parameters for the session's peer. |
38 | /// |
39 | /// See [`ConnectionCommon::quic_transport_parameters()`] for more details. |
40 | pub fn quic_transport_parameters(&self) -> Option<&[u8]> { |
41 | match self { |
42 | Self::Client(conn) => conn.quic_transport_parameters(), |
43 | Self::Server(conn) => conn.quic_transport_parameters(), |
44 | } |
45 | } |
46 | |
47 | /// Compute the keys for encrypting/decrypting 0-RTT packets, if available |
48 | pub fn zero_rtt_keys(&self) -> Option<DirectionalKeys> { |
49 | match self { |
50 | Self::Client(conn) => conn.zero_rtt_keys(), |
51 | Self::Server(conn) => conn.zero_rtt_keys(), |
52 | } |
53 | } |
54 | |
55 | /// Consume unencrypted TLS handshake data. |
56 | /// |
57 | /// Handshake data obtained from separate encryption levels should be supplied in separate calls. |
58 | pub fn read_hs(&mut self, plaintext: &[u8]) -> Result<(), Error> { |
59 | match self { |
60 | Self::Client(conn) => conn.read_hs(plaintext), |
61 | Self::Server(conn) => conn.read_hs(plaintext), |
62 | } |
63 | } |
64 | |
65 | /// Emit unencrypted TLS handshake data. |
66 | /// |
67 | /// When this returns `Some(_)`, the new keys must be used for future handshake data. |
68 | pub fn write_hs(&mut self, buf: &mut Vec<u8>) -> Option<KeyChange> { |
69 | match self { |
70 | Self::Client(conn) => conn.write_hs(buf), |
71 | Self::Server(conn) => conn.write_hs(buf), |
72 | } |
73 | } |
74 | |
75 | /// Emit the TLS description code of a fatal alert, if one has arisen. |
76 | /// |
77 | /// Check after `read_hs` returns `Err(_)`. |
78 | pub fn alert(&self) -> Option<AlertDescription> { |
79 | match self { |
80 | Self::Client(conn) => conn.alert(), |
81 | Self::Server(conn) => conn.alert(), |
82 | } |
83 | } |
84 | |
85 | /// Derives key material from the agreed connection secrets. |
86 | /// |
87 | /// This function fills in `output` with `output.len()` bytes of key |
88 | /// material derived from the master session secret using `label` |
89 | /// and `context` for diversification. Ownership of the buffer is taken |
90 | /// by the function and returned via the Ok result to ensure no key |
91 | /// material leaks if the function fails. |
92 | /// |
93 | /// See RFC5705 for more details on what this does and is for. |
94 | /// |
95 | /// For TLS1.3 connections, this function does not use the |
96 | /// "early" exporter at any point. |
97 | /// |
98 | /// This function fails if called prior to the handshake completing; |
99 | /// check with [`CommonState::is_handshaking`] first. |
100 | #[inline ] |
101 | pub fn export_keying_material<T: AsMut<[u8]>>( |
102 | &self, |
103 | output: T, |
104 | label: &[u8], |
105 | context: Option<&[u8]>, |
106 | ) -> Result<T, Error> { |
107 | match self { |
108 | Self::Client(conn) => conn |
109 | .core |
110 | .export_keying_material(output, label, context), |
111 | Self::Server(conn) => conn |
112 | .core |
113 | .export_keying_material(output, label, context), |
114 | } |
115 | } |
116 | } |
117 | |
118 | impl Deref for Connection { |
119 | type Target = CommonState; |
120 | |
121 | fn deref(&self) -> &Self::Target { |
122 | match self { |
123 | Self::Client(conn: &ClientConnection) => &conn.core.common_state, |
124 | Self::Server(conn: &ServerConnection) => &conn.core.common_state, |
125 | } |
126 | } |
127 | } |
128 | |
129 | impl DerefMut for Connection { |
130 | fn deref_mut(&mut self) -> &mut Self::Target { |
131 | match self { |
132 | Self::Client(conn: &mut ClientConnection) => &mut conn.core.common_state, |
133 | Self::Server(conn: &mut ServerConnection) => &mut conn.core.common_state, |
134 | } |
135 | } |
136 | } |
137 | |
138 | /// A QUIC client connection. |
139 | pub struct ClientConnection { |
140 | inner: ConnectionCommon<ClientConnectionData>, |
141 | } |
142 | |
143 | impl ClientConnection { |
144 | /// Make a new QUIC ClientConnection. |
145 | /// |
146 | /// This differs from `ClientConnection::new()` in that it takes an extra `params` argument, |
147 | /// which contains the TLS-encoded transport parameters to send. |
148 | pub fn new( |
149 | config: Arc<ClientConfig>, |
150 | quic_version: Version, |
151 | name: ServerName<'static>, |
152 | params: Vec<u8>, |
153 | ) -> Result<Self, Error> { |
154 | if !config.supports_version(ProtocolVersion::TLSv1_3) { |
155 | return Err(Error::General( |
156 | "TLS 1.3 support is required for QUIC" .into(), |
157 | )); |
158 | } |
159 | |
160 | if !config.supports_protocol(Protocol::Quic) { |
161 | return Err(Error::General( |
162 | "at least one ciphersuite must support QUIC" .into(), |
163 | )); |
164 | } |
165 | |
166 | let ext = match quic_version { |
167 | Version::V1Draft => ClientExtension::TransportParametersDraft(params), |
168 | Version::V1 | Version::V2 => ClientExtension::TransportParameters(params), |
169 | }; |
170 | |
171 | let mut inner = ConnectionCore::for_client(config, name, vec![ext], Protocol::Quic)?; |
172 | inner.common_state.quic.version = quic_version; |
173 | Ok(Self { |
174 | inner: inner.into(), |
175 | }) |
176 | } |
177 | |
178 | /// Returns True if the server signalled it will process early data. |
179 | /// |
180 | /// If you sent early data and this returns false at the end of the |
181 | /// handshake then the server will not process the data. This |
182 | /// is not an error, but you may wish to resend the data. |
183 | pub fn is_early_data_accepted(&self) -> bool { |
184 | self.inner.core.is_early_data_accepted() |
185 | } |
186 | } |
187 | |
188 | impl Deref for ClientConnection { |
189 | type Target = ConnectionCommon<ClientConnectionData>; |
190 | |
191 | fn deref(&self) -> &Self::Target { |
192 | &self.inner |
193 | } |
194 | } |
195 | |
196 | impl DerefMut for ClientConnection { |
197 | fn deref_mut(&mut self) -> &mut Self::Target { |
198 | &mut self.inner |
199 | } |
200 | } |
201 | |
202 | impl Debug for ClientConnection { |
203 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
204 | fDebugStruct<'_, '_>.debug_struct(name:"quic::ClientConnection" ) |
205 | .finish() |
206 | } |
207 | } |
208 | |
209 | impl From<ClientConnection> for Connection { |
210 | fn from(c: ClientConnection) -> Self { |
211 | Self::Client(c) |
212 | } |
213 | } |
214 | |
215 | /// A QUIC server connection. |
216 | pub struct ServerConnection { |
217 | inner: ConnectionCommon<ServerConnectionData>, |
218 | } |
219 | |
220 | impl ServerConnection { |
221 | /// Make a new QUIC ServerConnection. |
222 | /// |
223 | /// This differs from `ServerConnection::new()` in that it takes an extra `params` argument, |
224 | /// which contains the TLS-encoded transport parameters to send. |
225 | pub fn new( |
226 | config: Arc<ServerConfig>, |
227 | quic_version: Version, |
228 | params: Vec<u8>, |
229 | ) -> Result<Self, Error> { |
230 | if !config.supports_version(ProtocolVersion::TLSv1_3) { |
231 | return Err(Error::General( |
232 | "TLS 1.3 support is required for QUIC" .into(), |
233 | )); |
234 | } |
235 | |
236 | if !config.supports_protocol(Protocol::Quic) { |
237 | return Err(Error::General( |
238 | "at least one ciphersuite must support QUIC" .into(), |
239 | )); |
240 | } |
241 | |
242 | if config.max_early_data_size != 0 && config.max_early_data_size != 0xffff_ffff { |
243 | return Err(Error::General( |
244 | "QUIC sessions must set a max early data of 0 or 2^32-1" .into(), |
245 | )); |
246 | } |
247 | |
248 | let ext = match quic_version { |
249 | Version::V1Draft => ServerExtension::TransportParametersDraft(params), |
250 | Version::V1 | Version::V2 => ServerExtension::TransportParameters(params), |
251 | }; |
252 | |
253 | let mut core = ConnectionCore::for_server(config, vec![ext])?; |
254 | core.common_state.protocol = Protocol::Quic; |
255 | core.common_state.quic.version = quic_version; |
256 | Ok(Self { inner: core.into() }) |
257 | } |
258 | |
259 | /// Explicitly discard early data, notifying the client |
260 | /// |
261 | /// Useful if invariants encoded in `received_resumption_data()` cannot be respected. |
262 | /// |
263 | /// Must be called while `is_handshaking` is true. |
264 | pub fn reject_early_data(&mut self) { |
265 | self.inner.core.reject_early_data() |
266 | } |
267 | |
268 | /// Retrieves the server name, if any, used to select the certificate and |
269 | /// private key. |
270 | /// |
271 | /// This returns `None` until some time after the client's server name indication |
272 | /// (SNI) extension value is processed during the handshake. It will never be |
273 | /// `None` when the connection is ready to send or process application data, |
274 | /// unless the client does not support SNI. |
275 | /// |
276 | /// This is useful for application protocols that need to enforce that the |
277 | /// server name matches an application layer protocol hostname. For |
278 | /// example, HTTP/1.1 servers commonly expect the `Host:` header field of |
279 | /// every request on a connection to match the hostname in the SNI extension |
280 | /// when the client provides the SNI extension. |
281 | /// |
282 | /// The server name is also used to match sessions during session resumption. |
283 | pub fn server_name(&self) -> Option<&str> { |
284 | self.inner.core.get_sni_str() |
285 | } |
286 | } |
287 | |
288 | impl Deref for ServerConnection { |
289 | type Target = ConnectionCommon<ServerConnectionData>; |
290 | |
291 | fn deref(&self) -> &Self::Target { |
292 | &self.inner |
293 | } |
294 | } |
295 | |
296 | impl DerefMut for ServerConnection { |
297 | fn deref_mut(&mut self) -> &mut Self::Target { |
298 | &mut self.inner |
299 | } |
300 | } |
301 | |
302 | impl Debug for ServerConnection { |
303 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
304 | fDebugStruct<'_, '_>.debug_struct(name:"quic::ServerConnection" ) |
305 | .finish() |
306 | } |
307 | } |
308 | |
309 | impl From<ServerConnection> for Connection { |
310 | fn from(c: ServerConnection) -> Self { |
311 | Self::Server(c) |
312 | } |
313 | } |
314 | |
315 | /// A shared interface for QUIC connections. |
316 | pub struct ConnectionCommon<Data> { |
317 | core: ConnectionCore<Data>, |
318 | deframer_buffer: DeframerVecBuffer, |
319 | } |
320 | |
321 | impl<Data: SideData> ConnectionCommon<Data> { |
322 | /// Return the TLS-encoded transport parameters for the session's peer. |
323 | /// |
324 | /// While the transport parameters are technically available prior to the |
325 | /// completion of the handshake, they cannot be fully trusted until the |
326 | /// handshake completes, and reliance on them should be minimized. |
327 | /// However, any tampering with the parameters will cause the handshake |
328 | /// to fail. |
329 | pub fn quic_transport_parameters(&self) -> Option<&[u8]> { |
330 | self.core |
331 | .common_state |
332 | .quic |
333 | .params |
334 | .as_ref() |
335 | .map(|v| v.as_ref()) |
336 | } |
337 | |
338 | /// Compute the keys for encrypting/decrypting 0-RTT packets, if available |
339 | pub fn zero_rtt_keys(&self) -> Option<DirectionalKeys> { |
340 | let suite = self |
341 | .core |
342 | .common_state |
343 | .suite |
344 | .and_then(|suite| suite.tls13())?; |
345 | Some(DirectionalKeys::new( |
346 | suite, |
347 | suite.quic?, |
348 | self.core |
349 | .common_state |
350 | .quic |
351 | .early_secret |
352 | .as_ref()?, |
353 | self.core.common_state.quic.version, |
354 | )) |
355 | } |
356 | |
357 | /// Consume unencrypted TLS handshake data. |
358 | /// |
359 | /// Handshake data obtained from separate encryption levels should be supplied in separate calls. |
360 | pub fn read_hs(&mut self, plaintext: &[u8]) -> Result<(), Error> { |
361 | self.core.message_deframer.push( |
362 | ProtocolVersion::TLSv1_3, |
363 | plaintext, |
364 | &mut self.deframer_buffer, |
365 | )?; |
366 | self.core |
367 | .process_new_packets(&mut self.deframer_buffer)?; |
368 | Ok(()) |
369 | } |
370 | |
371 | /// Emit unencrypted TLS handshake data. |
372 | /// |
373 | /// When this returns `Some(_)`, the new keys must be used for future handshake data. |
374 | pub fn write_hs(&mut self, buf: &mut Vec<u8>) -> Option<KeyChange> { |
375 | self.core |
376 | .common_state |
377 | .quic |
378 | .write_hs(buf) |
379 | } |
380 | |
381 | /// Emit the TLS description code of a fatal alert, if one has arisen. |
382 | /// |
383 | /// Check after `read_hs` returns `Err(_)`. |
384 | pub fn alert(&self) -> Option<AlertDescription> { |
385 | self.core.common_state.quic.alert |
386 | } |
387 | } |
388 | |
389 | impl<Data> Deref for ConnectionCommon<Data> { |
390 | type Target = CommonState; |
391 | |
392 | fn deref(&self) -> &Self::Target { |
393 | &self.core.common_state |
394 | } |
395 | } |
396 | |
397 | impl<Data> DerefMut for ConnectionCommon<Data> { |
398 | fn deref_mut(&mut self) -> &mut Self::Target { |
399 | &mut self.core.common_state |
400 | } |
401 | } |
402 | |
403 | impl<Data> From<ConnectionCore<Data>> for ConnectionCommon<Data> { |
404 | fn from(core: ConnectionCore<Data>) -> Self { |
405 | Self { |
406 | core, |
407 | deframer_buffer: DeframerVecBuffer::default(), |
408 | } |
409 | } |
410 | } |
411 | |
412 | #[derive (Default)] |
413 | pub(crate) struct Quic { |
414 | /// QUIC transport parameters received from the peer during the handshake |
415 | pub(crate) params: Option<Vec<u8>>, |
416 | pub(crate) alert: Option<AlertDescription>, |
417 | pub(crate) hs_queue: VecDeque<(bool, Vec<u8>)>, |
418 | pub(crate) early_secret: Option<OkmBlock>, |
419 | pub(crate) hs_secrets: Option<Secrets>, |
420 | pub(crate) traffic_secrets: Option<Secrets>, |
421 | /// Whether keys derived from traffic_secrets have been passed to the QUIC implementation |
422 | pub(crate) returned_traffic_keys: bool, |
423 | pub(crate) version: Version, |
424 | } |
425 | |
426 | impl Quic { |
427 | pub(crate) fn write_hs(&mut self, buf: &mut Vec<u8>) -> Option<KeyChange> { |
428 | while let Some((_, msg)) = self.hs_queue.pop_front() { |
429 | buf.extend_from_slice(&msg); |
430 | if let Some(&(true, _)) = self.hs_queue.front() { |
431 | if self.hs_secrets.is_some() { |
432 | // Allow the caller to switch keys before proceeding. |
433 | break; |
434 | } |
435 | } |
436 | } |
437 | |
438 | if let Some(secrets) = self.hs_secrets.take() { |
439 | return Some(KeyChange::Handshake { |
440 | keys: Keys::new(&secrets), |
441 | }); |
442 | } |
443 | |
444 | if let Some(mut secrets) = self.traffic_secrets.take() { |
445 | if !self.returned_traffic_keys { |
446 | self.returned_traffic_keys = true; |
447 | let keys = Keys::new(&secrets); |
448 | secrets.update(); |
449 | return Some(KeyChange::OneRtt { |
450 | keys, |
451 | next: secrets, |
452 | }); |
453 | } |
454 | } |
455 | |
456 | None |
457 | } |
458 | } |
459 | |
460 | /// Secrets used to encrypt/decrypt traffic |
461 | #[derive (Clone)] |
462 | pub struct Secrets { |
463 | /// Secret used to encrypt packets transmitted by the client |
464 | pub(crate) client: OkmBlock, |
465 | /// Secret used to encrypt packets transmitted by the server |
466 | pub(crate) server: OkmBlock, |
467 | /// Cipher suite used with these secrets |
468 | suite: &'static Tls13CipherSuite, |
469 | quic: &'static dyn Algorithm, |
470 | side: Side, |
471 | version: Version, |
472 | } |
473 | |
474 | impl Secrets { |
475 | pub(crate) fn new( |
476 | client: OkmBlock, |
477 | server: OkmBlock, |
478 | suite: &'static Tls13CipherSuite, |
479 | quic: &'static dyn Algorithm, |
480 | side: Side, |
481 | version: Version, |
482 | ) -> Self { |
483 | Self { |
484 | client, |
485 | server, |
486 | suite, |
487 | quic, |
488 | side, |
489 | version, |
490 | } |
491 | } |
492 | |
493 | /// Derive the next set of packet keys |
494 | pub fn next_packet_keys(&mut self) -> PacketKeySet { |
495 | let keys = PacketKeySet::new(self); |
496 | self.update(); |
497 | keys |
498 | } |
499 | |
500 | pub(crate) fn update(&mut self) { |
501 | self.client = hkdf_expand_label_block( |
502 | self.suite |
503 | .hkdf_provider |
504 | .expander_for_okm(&self.client) |
505 | .as_ref(), |
506 | self.version.key_update_label(), |
507 | &[], |
508 | ); |
509 | self.server = hkdf_expand_label_block( |
510 | self.suite |
511 | .hkdf_provider |
512 | .expander_for_okm(&self.server) |
513 | .as_ref(), |
514 | self.version.key_update_label(), |
515 | &[], |
516 | ); |
517 | } |
518 | |
519 | fn local_remote(&self) -> (&OkmBlock, &OkmBlock) { |
520 | match self.side { |
521 | Side::Client => (&self.client, &self.server), |
522 | Side::Server => (&self.server, &self.client), |
523 | } |
524 | } |
525 | } |
526 | |
527 | /// Keys used to communicate in a single direction |
528 | pub struct DirectionalKeys { |
529 | /// Encrypts or decrypts a packet's headers |
530 | pub header: Box<dyn HeaderProtectionKey>, |
531 | /// Encrypts or decrypts the payload of a packet |
532 | pub packet: Box<dyn PacketKey>, |
533 | } |
534 | |
535 | impl DirectionalKeys { |
536 | pub(crate) fn new( |
537 | suite: &'static Tls13CipherSuite, |
538 | quic: &'static dyn Algorithm, |
539 | secret: &OkmBlock, |
540 | version: Version, |
541 | ) -> Self { |
542 | let builder: KeyBuilder<'_> = KeyBuilder::new(secret, version, alg:quic, suite.hkdf_provider); |
543 | Self { |
544 | header: builder.header_protection_key(), |
545 | packet: builder.packet_key(), |
546 | } |
547 | } |
548 | } |
549 | |
550 | /// All AEADs we support have 16-byte tags. |
551 | const TAG_LEN: usize = 16; |
552 | |
553 | /// Authentication tag from an AEAD seal operation. |
554 | pub struct Tag([u8; TAG_LEN]); |
555 | |
556 | impl From<&[u8]> for Tag { |
557 | fn from(value: &[u8]) -> Self { |
558 | let mut array: [u8; 16] = [0u8; TAG_LEN]; |
559 | array.copy_from_slice(src:value); |
560 | Self(array) |
561 | } |
562 | } |
563 | |
564 | impl AsRef<[u8]> for Tag { |
565 | fn as_ref(&self) -> &[u8] { |
566 | &self.0 |
567 | } |
568 | } |
569 | |
570 | /// How a `Tls13CipherSuite` generates `PacketKey`s and `HeaderProtectionKey`s. |
571 | pub trait Algorithm: Send + Sync { |
572 | /// Produce a `PacketKey` encrypter/decrypter for this suite. |
573 | /// |
574 | /// `suite` is the entire suite this `Algorithm` appeared in. |
575 | /// `key` and `iv` is the key material to use. |
576 | fn packet_key(&self, key: AeadKey, iv: Iv) -> Box<dyn PacketKey>; |
577 | |
578 | /// Produce a `HeaderProtectionKey` encrypter/decrypter for this suite. |
579 | /// |
580 | /// `key` is the key material, which is `aead_key_len()` bytes in length. |
581 | fn header_protection_key(&self, key: AeadKey) -> Box<dyn HeaderProtectionKey>; |
582 | |
583 | /// The length in bytes of keys for this Algorithm. |
584 | /// |
585 | /// This controls the size of `AeadKey`s presented to `packet_key()` and `header_protection_key()`. |
586 | fn aead_key_len(&self) -> usize; |
587 | } |
588 | |
589 | /// A QUIC header protection key |
590 | pub trait HeaderProtectionKey: Send + Sync { |
591 | /// Adds QUIC Header Protection. |
592 | /// |
593 | /// `sample` must contain the sample of encrypted payload; see |
594 | /// [Header Protection Sample]. |
595 | /// |
596 | /// `first` must reference the first byte of the header, referred to as |
597 | /// `packet[0]` in [Header Protection Application]. |
598 | /// |
599 | /// `packet_number` must reference the Packet Number field; this is |
600 | /// `packet[pn_offset:pn_offset+pn_length]` in [Header Protection Application]. |
601 | /// |
602 | /// Returns an error without modifying anything if `sample` is not |
603 | /// the correct length (see [Header Protection Sample] and [`Self::sample_len()`]), |
604 | /// or `packet_number` is longer than allowed (see [Packet Number Encoding and Decoding]). |
605 | /// |
606 | /// Otherwise, `first` and `packet_number` will have the header protection added. |
607 | /// |
608 | /// [Header Protection Application]: https://datatracker.ietf.org/doc/html/rfc9001#section-5.4.1 |
609 | /// [Header Protection Sample]: https://datatracker.ietf.org/doc/html/rfc9001#section-5.4.2 |
610 | /// [Packet Number Encoding and Decoding]: https://datatracker.ietf.org/doc/html/rfc9000#section-17.1 |
611 | fn encrypt_in_place( |
612 | &self, |
613 | sample: &[u8], |
614 | first: &mut u8, |
615 | packet_number: &mut [u8], |
616 | ) -> Result<(), Error>; |
617 | |
618 | /// Removes QUIC Header Protection. |
619 | /// |
620 | /// `sample` must contain the sample of encrypted payload; see |
621 | /// [Header Protection Sample]. |
622 | /// |
623 | /// `first` must reference the first byte of the header, referred to as |
624 | /// `packet[0]` in [Header Protection Application]. |
625 | /// |
626 | /// `packet_number` must reference the Packet Number field; this is |
627 | /// `packet[pn_offset:pn_offset+pn_length]` in [Header Protection Application]. |
628 | /// |
629 | /// Returns an error without modifying anything if `sample` is not |
630 | /// the correct length (see [Header Protection Sample] and [`Self::sample_len()`]), |
631 | /// or `packet_number` is longer than allowed (see |
632 | /// [Packet Number Encoding and Decoding]). |
633 | /// |
634 | /// Otherwise, `first` and `packet_number` will have the header protection removed. |
635 | /// |
636 | /// [Header Protection Application]: https://datatracker.ietf.org/doc/html/rfc9001#section-5.4.1 |
637 | /// [Header Protection Sample]: https://datatracker.ietf.org/doc/html/rfc9001#section-5.4.2 |
638 | /// [Packet Number Encoding and Decoding]: https://datatracker.ietf.org/doc/html/rfc9000#section-17.1 |
639 | fn decrypt_in_place( |
640 | &self, |
641 | sample: &[u8], |
642 | first: &mut u8, |
643 | packet_number: &mut [u8], |
644 | ) -> Result<(), Error>; |
645 | |
646 | /// Expected sample length for the key's algorithm |
647 | fn sample_len(&self) -> usize; |
648 | } |
649 | |
650 | /// Keys to encrypt or decrypt the payload of a packet |
651 | pub trait PacketKey: Send + Sync { |
652 | /// Encrypt a QUIC packet |
653 | /// |
654 | /// Takes a `packet_number`, used to derive the nonce; the packet `header`, which is used as |
655 | /// the additional authenticated data; and the `payload`. The authentication tag is returned if |
656 | /// encryption succeeds. |
657 | /// |
658 | /// Fails iff the payload is longer than allowed by the cipher suite's AEAD algorithm. |
659 | fn encrypt_in_place( |
660 | &self, |
661 | packet_number: u64, |
662 | header: &[u8], |
663 | payload: &mut [u8], |
664 | ) -> Result<Tag, Error>; |
665 | |
666 | /// Decrypt a QUIC packet |
667 | /// |
668 | /// Takes the packet `header`, which is used as the additional authenticated data, and the |
669 | /// `payload`, which includes the authentication tag. |
670 | /// |
671 | /// If the return value is `Ok`, the decrypted payload can be found in `payload`, up to the |
672 | /// length found in the return value. |
673 | fn decrypt_in_place<'a>( |
674 | &self, |
675 | packet_number: u64, |
676 | header: &[u8], |
677 | payload: &'a mut [u8], |
678 | ) -> Result<&'a [u8], Error>; |
679 | |
680 | /// Tag length for the underlying AEAD algorithm |
681 | fn tag_len(&self) -> usize; |
682 | } |
683 | |
684 | /// Packet protection keys for bidirectional 1-RTT communication |
685 | pub struct PacketKeySet { |
686 | /// Encrypts outgoing packets |
687 | pub local: Box<dyn PacketKey>, |
688 | /// Decrypts incoming packets |
689 | pub remote: Box<dyn PacketKey>, |
690 | } |
691 | |
692 | impl PacketKeySet { |
693 | fn new(secrets: &Secrets) -> Self { |
694 | let (local: &OkmBlock, remote: &OkmBlock) = secrets.local_remote(); |
695 | let (version: Version, alg: &dyn Algorithm, hkdf: &dyn Hkdf) = (secrets.version, secrets.quic, secrets.suite.hkdf_provider); |
696 | Self { |
697 | local: KeyBuilder::new(secret:local, version, alg, hkdf).packet_key(), |
698 | remote: KeyBuilder::new(secret:remote, version, alg, hkdf).packet_key(), |
699 | } |
700 | } |
701 | } |
702 | |
703 | pub(crate) struct KeyBuilder<'a> { |
704 | expander: Box<dyn HkdfExpander>, |
705 | version: Version, |
706 | alg: &'a dyn Algorithm, |
707 | } |
708 | |
709 | impl<'a> KeyBuilder<'a> { |
710 | pub(crate) fn new( |
711 | secret: &OkmBlock, |
712 | version: Version, |
713 | alg: &'a dyn Algorithm, |
714 | hkdf: &'a dyn Hkdf, |
715 | ) -> Self { |
716 | Self { |
717 | expander: hkdf.expander_for_okm(secret), |
718 | version, |
719 | alg, |
720 | } |
721 | } |
722 | |
723 | /// Derive packet keys |
724 | pub(crate) fn packet_key(&self) -> Box<dyn PacketKey> { |
725 | let aead_key_len = self.alg.aead_key_len(); |
726 | let packet_key = hkdf_expand_label_aead_key( |
727 | self.expander.as_ref(), |
728 | aead_key_len, |
729 | self.version.packet_key_label(), |
730 | &[], |
731 | ); |
732 | |
733 | let packet_iv = |
734 | hkdf_expand_label(self.expander.as_ref(), self.version.packet_iv_label(), &[]); |
735 | self.alg |
736 | .packet_key(packet_key, packet_iv) |
737 | } |
738 | |
739 | /// Derive header protection keys |
740 | pub(crate) fn header_protection_key(&self) -> Box<dyn HeaderProtectionKey> { |
741 | let header_key = hkdf_expand_label_aead_key( |
742 | self.expander.as_ref(), |
743 | self.alg.aead_key_len(), |
744 | self.version.header_key_label(), |
745 | &[], |
746 | ); |
747 | self.alg |
748 | .header_protection_key(header_key) |
749 | } |
750 | } |
751 | |
752 | /// Complete set of keys used to communicate with the peer |
753 | pub struct Keys { |
754 | /// Encrypts outgoing packets |
755 | pub local: DirectionalKeys, |
756 | /// Decrypts incoming packets |
757 | pub remote: DirectionalKeys, |
758 | } |
759 | |
760 | impl Keys { |
761 | /// Construct keys for use with initial packets |
762 | pub fn initial( |
763 | version: Version, |
764 | suite: &'static Tls13CipherSuite, |
765 | quic: &'static dyn Algorithm, |
766 | client_dst_connection_id: &[u8], |
767 | side: Side, |
768 | ) -> Self { |
769 | const CLIENT_LABEL: &[u8] = b"client in" ; |
770 | const SERVER_LABEL: &[u8] = b"server in" ; |
771 | let salt = version.initial_salt(); |
772 | let hs_secret = suite |
773 | .hkdf_provider |
774 | .extract_from_secret(Some(salt), client_dst_connection_id); |
775 | |
776 | let secrets = Secrets { |
777 | version, |
778 | client: hkdf_expand_label_block(hs_secret.as_ref(), CLIENT_LABEL, &[]), |
779 | server: hkdf_expand_label_block(hs_secret.as_ref(), SERVER_LABEL, &[]), |
780 | suite, |
781 | quic, |
782 | side, |
783 | }; |
784 | Self::new(&secrets) |
785 | } |
786 | |
787 | fn new(secrets: &Secrets) -> Self { |
788 | let (local, remote) = secrets.local_remote(); |
789 | Self { |
790 | local: DirectionalKeys::new(secrets.suite, secrets.quic, local, secrets.version), |
791 | remote: DirectionalKeys::new(secrets.suite, secrets.quic, remote, secrets.version), |
792 | } |
793 | } |
794 | } |
795 | |
796 | /// Key material for use in QUIC packet spaces |
797 | /// |
798 | /// QUIC uses 4 different sets of keys (and progressive key updates for long-running connections): |
799 | /// |
800 | /// * Initial: these can be created from [`Keys::initial()`] |
801 | /// * 0-RTT keys: can be retrieved from [`ConnectionCommon::zero_rtt_keys()`] |
802 | /// * Handshake: these are returned from [`ConnectionCommon::write_hs()`] after `ClientHello` and |
803 | /// `ServerHello` messages have been exchanged |
804 | /// * 1-RTT keys: these are returned from [`ConnectionCommon::write_hs()`] after the handshake is done |
805 | /// |
806 | /// Once the 1-RTT keys have been exchanged, either side may initiate a key update. Progressive |
807 | /// update keys can be obtained from the [`Secrets`] returned in [`KeyChange::OneRtt`]. Note that |
808 | /// only packet keys are updated by key updates; header protection keys remain the same. |
809 | #[allow (clippy::large_enum_variant)] |
810 | pub enum KeyChange { |
811 | /// Keys for the handshake space |
812 | Handshake { |
813 | /// Header and packet keys for the handshake space |
814 | keys: Keys, |
815 | }, |
816 | /// Keys for 1-RTT data |
817 | OneRtt { |
818 | /// Header and packet keys for 1-RTT data |
819 | keys: Keys, |
820 | /// Secrets to derive updated keys from |
821 | next: Secrets, |
822 | }, |
823 | } |
824 | |
825 | /// QUIC protocol version |
826 | /// |
827 | /// Governs version-specific behavior in the TLS layer |
828 | #[non_exhaustive ] |
829 | #[derive (Clone, Copy, Debug)] |
830 | pub enum Version { |
831 | /// Draft versions 29, 30, 31 and 32 |
832 | V1Draft, |
833 | /// First stable RFC |
834 | V1, |
835 | /// Anti-ossification variant of V1 |
836 | V2, |
837 | } |
838 | |
839 | impl Version { |
840 | fn initial_salt(self) -> &'static [u8; 20] { |
841 | match self { |
842 | Self::V1Draft => &[ |
843 | // https://datatracker.ietf.org/doc/html/draft-ietf-quic-tls-32#section-5.2 |
844 | 0xaf, 0xbf, 0xec, 0x28, 0x99, 0x93, 0xd2, 0x4c, 0x9e, 0x97, 0x86, 0xf1, 0x9c, 0x61, |
845 | 0x11, 0xe0, 0x43, 0x90, 0xa8, 0x99, |
846 | ], |
847 | Self::V1 => &[ |
848 | // https://www.rfc-editor.org/rfc/rfc9001.html#name-initial-secrets |
849 | 0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17, 0x9a, 0xe6, 0xa4, 0xc8, |
850 | 0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a, |
851 | ], |
852 | Self::V2 => &[ |
853 | // https://www.ietf.org/archive/id/draft-ietf-quic-v2-10.html#name-initial-salt-2 |
854 | 0x0d, 0xed, 0xe3, 0xde, 0xf7, 0x00, 0xa6, 0xdb, 0x81, 0x93, 0x81, 0xbe, 0x6e, 0x26, |
855 | 0x9d, 0xcb, 0xf9, 0xbd, 0x2e, 0xd9, |
856 | ], |
857 | } |
858 | } |
859 | |
860 | /// Key derivation label for packet keys. |
861 | pub(crate) fn packet_key_label(&self) -> &'static [u8] { |
862 | match self { |
863 | Self::V1Draft | Self::V1 => b"quic key" , |
864 | Self::V2 => b"quicv2 key" , |
865 | } |
866 | } |
867 | |
868 | /// Key derivation label for packet "IV"s. |
869 | pub(crate) fn packet_iv_label(&self) -> &'static [u8] { |
870 | match self { |
871 | Self::V1Draft | Self::V1 => b"quic iv" , |
872 | Self::V2 => b"quicv2 iv" , |
873 | } |
874 | } |
875 | |
876 | /// Key derivation for header keys. |
877 | pub(crate) fn header_key_label(&self) -> &'static [u8] { |
878 | match self { |
879 | Self::V1Draft | Self::V1 => b"quic hp" , |
880 | Self::V2 => b"quicv2 hp" , |
881 | } |
882 | } |
883 | |
884 | fn key_update_label(&self) -> &'static [u8] { |
885 | match self { |
886 | Self::V1Draft | Self::V1 => b"quic ku" , |
887 | Self::V2 => b"quicv2 ku" , |
888 | } |
889 | } |
890 | } |
891 | |
892 | impl Default for Version { |
893 | fn default() -> Self { |
894 | Self::V1 |
895 | } |
896 | } |
897 | |
898 | #[cfg (test)] |
899 | mod tests { |
900 | use crate::quic::HeaderProtectionKey; |
901 | |
902 | use super::PacketKey; |
903 | |
904 | #[test ] |
905 | fn auto_traits() { |
906 | fn assert_auto<T: Send + Sync>() {} |
907 | assert_auto::<Box<dyn PacketKey>>(); |
908 | assert_auto::<Box<dyn HeaderProtectionKey>>(); |
909 | } |
910 | } |
911 | |