1use std::{any::Any, io, str, sync::Arc};
2
3use aes_gcm::{KeyInit, aead::AeadMutInPlace};
4use bytes::BytesMut;
5pub use rustls::Error;
6use rustls::{
7 self, CipherSuite,
8 pki_types::{CertificateDer, ServerName},
9 quic::{Connection, HeaderProtectionKey, KeyChange, PacketKey, Secrets, Suite, Version},
10};
11#[cfg(any(feature = "aws-lc-rs", feature = "ring"))]
12use rustls::{client::danger::ServerCertVerifier, pki_types::PrivateKeyDer};
13
14use crate::{
15 ConnectError, ConnectionId, PathId, Side, TransportError, TransportErrorCode,
16 crypto::{
17 self, CryptoError, ExportKeyingMaterialError, HeaderKey, KeyPair, Keys, UnsupportedVersion,
18 },
19 transport_parameters::TransportParameters,
20};
21
22impl From<Side> for rustls::Side {
23 fn from(s: Side) -> Self {
24 match s {
25 Side::Client => Self::Client,
26 Side::Server => Self::Server,
27 }
28 }
29}
30
31pub struct TlsSession {
33 version: Version,
34 got_handshake_data: bool,
35 next_secrets: Option<Secrets>,
36 inner: Connection,
37 suite: Suite,
38}
39
40impl TlsSession {
41 fn side(&self) -> Side {
42 match self.inner {
43 Connection::Client(_) => Side::Client,
44 Connection::Server(_) => Side::Server,
45 }
46 }
47}
48
49impl crypto::Session for TlsSession {
50 fn initial_keys(&self, dst_cid: ConnectionId, side: Side) -> Keys {
51 initial_keys(self.version, dst_cid, side, &self.suite)
52 }
53
54 fn handshake_data(&self) -> Option<Box<dyn Any>> {
55 if !self.got_handshake_data {
56 return None;
57 }
58 Some(Box::new(HandshakeData {
59 protocol: self.inner.alpn_protocol().map(|x| x.into()),
60 server_name: match self.inner {
61 Connection::Client(_) => None,
62 Connection::Server(ref session) => session.server_name().map(|x| x.into()),
63 },
64 negotiated_key_exchange_group: self
65 .inner
66 .negotiated_key_exchange_group()
67 .map(|kx| kx.name()),
68 }))
69 }
70
71 fn peer_identity(&self) -> Option<Box<dyn Any>> {
73 self.inner.peer_certificates().map(|v| -> Box<dyn Any> {
74 Box::new(
75 v.iter()
76 .map(|v| v.clone().into_owned())
77 .collect::<Vec<CertificateDer<'static>>>(),
78 )
79 })
80 }
81
82 fn early_crypto(&self) -> Option<(Box<dyn HeaderKey>, Box<dyn crypto::PacketKey>)> {
83 let keys = self.inner.zero_rtt_keys()?;
84 Some((Box::new(keys.header), Box::new(keys.packet)))
85 }
86
87 fn early_data_accepted(&self) -> Option<bool> {
88 match self.inner {
89 Connection::Client(ref session) => Some(session.is_early_data_accepted()),
90 _ => None,
91 }
92 }
93
94 fn is_handshaking(&self) -> bool {
95 self.inner.is_handshaking()
96 }
97
98 fn read_handshake(&mut self, buf: &[u8]) -> Result<bool, TransportError> {
99 self.inner.read_hs(buf).map_err(|e| {
100 if let Some(alert) = self.inner.alert() {
101 TransportError {
102 code: TransportErrorCode::crypto(alert.into()),
103 frame: crate::frame::MaybeFrame::None,
104 reason: e.to_string(),
105 crypto: Some(Arc::new(e)),
106 }
107 } else {
108 TransportError::PROTOCOL_VIOLATION(format!("TLS error: {e}"))
109 }
110 })?;
111 if !self.got_handshake_data {
112 let have_server_name = match self.inner {
116 Connection::Client(_) => false,
117 Connection::Server(ref session) => session.server_name().is_some(),
118 };
119 if self.inner.alpn_protocol().is_some() || have_server_name || !self.is_handshaking() {
120 self.got_handshake_data = true;
121 return Ok(true);
122 }
123 }
124 Ok(false)
125 }
126
127 fn transport_parameters(&self) -> Result<Option<TransportParameters>, TransportError> {
128 match self.inner.quic_transport_parameters() {
129 None => Ok(None),
130 Some(buf) => match TransportParameters::read(self.side(), &mut io::Cursor::new(buf)) {
131 Ok(params) => Ok(Some(params)),
132 Err(e) => Err(e.into()),
133 },
134 }
135 }
136
137 fn write_handshake(&mut self, buf: &mut Vec<u8>) -> Option<Keys> {
138 let keys = match self.inner.write_hs(buf)? {
139 KeyChange::Handshake { keys } => keys,
140 KeyChange::OneRtt { keys, next } => {
141 self.next_secrets = Some(next);
142 keys
143 }
144 };
145
146 Some(Keys {
147 header: KeyPair {
148 local: Box::new(keys.local.header),
149 remote: Box::new(keys.remote.header),
150 },
151 packet: KeyPair {
152 local: Box::new(keys.local.packet),
153 remote: Box::new(keys.remote.packet),
154 },
155 })
156 }
157
158 fn next_1rtt_keys(&mut self) -> Option<KeyPair<Box<dyn crypto::PacketKey>>> {
159 let secrets = self.next_secrets.as_mut()?;
160 let keys = secrets.next_packet_keys();
161 Some(KeyPair {
162 local: Box::new(keys.local),
163 remote: Box::new(keys.remote),
164 })
165 }
166
167 fn is_valid_retry(&self, orig_dst_cid: ConnectionId, header: &[u8], payload: &[u8]) -> bool {
168 if payload.len() < 16 {
169 return false;
170 }
171
172 let mut pseudo_packet =
173 Vec::with_capacity(header.len() + payload.len() + orig_dst_cid.len() + 1);
174 pseudo_packet.push(orig_dst_cid.len() as u8);
175 pseudo_packet.extend_from_slice(&orig_dst_cid);
176 pseudo_packet.extend_from_slice(header);
177 pseudo_packet.extend_from_slice(payload);
178
179 let (nonce, key) = match self.version {
180 Version::V1 => (&RETRY_INTEGRITY_NONCE_V1, &RETRY_INTEGRITY_KEY_V1),
181 Version::V1Draft => (&RETRY_INTEGRITY_NONCE_DRAFT, &RETRY_INTEGRITY_KEY_DRAFT),
182 _ => unreachable!(),
183 };
184
185 let Some((aad, tag)) = pseudo_packet.split_last_chunk::<16>() else {
186 return false; };
188
189 let key = aes_gcm::Key::<aes_gcm::Aes128Gcm>::from_slice(key);
191 let nonce = aes_gcm::Nonce::from_slice(nonce);
192 let tag = aes_gcm::Tag::from_slice(tag);
193 aes_gcm::Aes128Gcm::new(key)
194 .decrypt_in_place_detached(nonce, aad, &mut [], tag)
195 .is_ok()
196 }
197
198 fn export_keying_material(
199 &self,
200 output: &mut [u8],
201 label: &[u8],
202 context: &[u8],
203 ) -> Result<(), ExportKeyingMaterialError> {
204 self.inner
205 .export_keying_material(output, label, Some(context))
206 .map_err(|_| ExportKeyingMaterialError)?;
207 Ok(())
208 }
209}
210
211const RETRY_INTEGRITY_KEY_DRAFT: [u8; 16] = [
212 0xcc, 0xce, 0x18, 0x7e, 0xd0, 0x9a, 0x09, 0xd0, 0x57, 0x28, 0x15, 0x5a, 0x6c, 0xb9, 0x6b, 0xe1,
213];
214const RETRY_INTEGRITY_NONCE_DRAFT: [u8; 12] = [
215 0xe5, 0x49, 0x30, 0xf9, 0x7f, 0x21, 0x36, 0xf0, 0x53, 0x0a, 0x8c, 0x1c,
216];
217
218const RETRY_INTEGRITY_KEY_V1: [u8; 16] = [
219 0xbe, 0x0c, 0x69, 0x0b, 0x9f, 0x66, 0x57, 0x5a, 0x1d, 0x76, 0x6b, 0x54, 0xe3, 0x68, 0xc8, 0x4e,
220];
221const RETRY_INTEGRITY_NONCE_V1: [u8; 12] = [
222 0x46, 0x15, 0x99, 0xd3, 0x5d, 0x63, 0x2b, 0xf2, 0x23, 0x98, 0x25, 0xbb,
223];
224
225impl HeaderKey for Box<dyn HeaderProtectionKey> {
226 fn decrypt(&self, pn_offset: usize, packet: &mut [u8]) {
227 let (header, sample) = packet.split_at_mut(pn_offset + 4);
228 let (first, rest) = header.split_at_mut(1);
229 let pn_end = Ord::min(pn_offset + 3, rest.len());
230 self.decrypt_in_place(
231 &sample[..self.sample_size()],
232 &mut first[0],
233 &mut rest[pn_offset - 1..pn_end],
234 )
235 .unwrap();
236 }
237
238 fn encrypt(&self, pn_offset: usize, packet: &mut [u8]) {
239 let (header, sample) = packet.split_at_mut(pn_offset + 4);
240 let (first, rest) = header.split_at_mut(1);
241 let pn_end = Ord::min(pn_offset + 3, rest.len());
242 self.encrypt_in_place(
243 &sample[..self.sample_size()],
244 &mut first[0],
245 &mut rest[pn_offset - 1..pn_end],
246 )
247 .unwrap();
248 }
249
250 fn sample_size(&self) -> usize {
251 self.sample_len()
252 }
253}
254
255#[non_exhaustive]
257pub struct HandshakeData {
258 pub protocol: Option<Vec<u8>>,
262 pub server_name: Option<String>,
266 pub negotiated_key_exchange_group: Option<rustls::NamedGroup>,
270}
271
272#[derive(Clone)] pub struct QuicClientConfig {
293 pub(crate) inner: Arc<rustls::ClientConfig>,
294 initial: Suite,
295}
296
297impl QuicClientConfig {
298 #[cfg(all(
299 feature = "platform-verifier",
300 any(feature = "aws-lc-rs", feature = "ring")
301 ))]
302 pub(crate) fn with_platform_verifier() -> Result<Self, Error> {
303 use rustls_platform_verifier::BuilderVerifierExt;
304
305 let mut inner = rustls::ClientConfig::builder_with_provider(configured_provider())
307 .with_protocol_versions(&[&rustls::version::TLS13])
308 .unwrap() .with_platform_verifier()?
310 .with_no_client_auth();
311
312 inner.enable_early_data = true;
313 Ok(Self {
314 initial: initial_suite_from_provider(inner.crypto_provider())
316 .expect("no initial cipher suite found"),
317 inner: Arc::new(inner),
318 })
319 }
320
321 #[cfg(any(feature = "aws-lc-rs", feature = "ring"))]
326 pub(crate) fn new(verifier: Arc<dyn ServerCertVerifier>) -> Self {
327 let inner = Self::inner(verifier);
328 Self {
329 initial: initial_suite_from_provider(inner.crypto_provider())
331 .expect("no initial cipher suite found"),
332 inner: Arc::new(inner),
333 }
334 }
335
336 pub fn with_initial(
340 inner: Arc<rustls::ClientConfig>,
341 initial: Suite,
342 ) -> Result<Self, NoInitialCipherSuite> {
343 match initial.suite.common.suite {
344 CipherSuite::TLS13_AES_128_GCM_SHA256 => Ok(Self { inner, initial }),
345 _ => Err(NoInitialCipherSuite { specific: true }),
346 }
347 }
348
349 pub fn set_alpn_protocols(&mut self, alpn_protocols: Vec<Vec<u8>>) {
351 let config = Arc::make_mut(&mut self.inner);
352 config.alpn_protocols = alpn_protocols;
353 }
354
355 #[cfg(any(feature = "aws-lc-rs", feature = "ring"))]
356 pub(crate) fn inner(verifier: Arc<dyn ServerCertVerifier>) -> rustls::ClientConfig {
357 let mut config = rustls::ClientConfig::builder_with_provider(configured_provider())
359 .with_protocol_versions(&[&rustls::version::TLS13])
360 .unwrap() .dangerous()
362 .with_custom_certificate_verifier(verifier)
363 .with_no_client_auth();
364
365 config.enable_early_data = true;
366 config
367 }
368}
369
370impl crypto::ClientConfig for QuicClientConfig {
371 fn start_session(
372 &self,
373 version: u32,
374 server_name: &str,
375 params: &TransportParameters,
376 ) -> Result<Box<dyn crypto::Session>, ConnectError> {
377 let version = interpret_version(version)?;
378 Ok(Box::new(TlsSession {
379 version,
380 got_handshake_data: false,
381 next_secrets: None,
382 inner: Connection::Client(
383 rustls::quic::ClientConnection::new(
384 self.inner.clone(),
385 version,
386 ServerName::try_from(server_name)
387 .map_err(|_| ConnectError::InvalidServerName(server_name.into()))?
388 .to_owned(),
389 to_vec(params),
390 )
391 .unwrap(),
392 ),
393 suite: self.initial,
394 }))
395 }
396}
397
398impl TryFrom<rustls::ClientConfig> for QuicClientConfig {
399 type Error = NoInitialCipherSuite;
400
401 fn try_from(inner: rustls::ClientConfig) -> Result<Self, Self::Error> {
402 Arc::new(inner).try_into()
403 }
404}
405
406impl TryFrom<Arc<rustls::ClientConfig>> for QuicClientConfig {
407 type Error = NoInitialCipherSuite;
408
409 fn try_from(inner: Arc<rustls::ClientConfig>) -> Result<Self, Self::Error> {
410 Ok(Self {
411 initial: initial_suite_from_provider(inner.crypto_provider())
412 .ok_or(NoInitialCipherSuite { specific: false })?,
413 inner,
414 })
415 }
416}
417
418#[derive(Clone, Debug)]
426pub struct NoInitialCipherSuite {
427 specific: bool,
429}
430
431impl std::fmt::Display for NoInitialCipherSuite {
432 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
433 f.write_str(match self.specific {
434 true => "invalid cipher suite specified",
435 false => "no initial cipher suite found",
436 })
437 }
438}
439
440impl std::error::Error for NoInitialCipherSuite {}
441
442#[derive(Clone)] pub struct QuicServerConfig {
456 inner: Arc<rustls::ServerConfig>,
457 initial: Suite,
458}
459
460impl QuicServerConfig {
461 #[cfg(any(feature = "aws-lc-rs", feature = "ring"))]
462 pub(crate) fn new(
463 cert_chain: Vec<CertificateDer<'static>>,
464 key: PrivateKeyDer<'static>,
465 ) -> Result<Self, Error> {
466 let inner = Self::inner(cert_chain, key)?;
467 Ok(Self {
468 initial: initial_suite_from_provider(inner.crypto_provider())
470 .expect("no initial cipher suite found"),
471 inner: Arc::new(inner),
472 })
473 }
474
475 pub fn with_initial(
479 inner: Arc<rustls::ServerConfig>,
480 initial: Suite,
481 ) -> Result<Self, NoInitialCipherSuite> {
482 match initial.suite.common.suite {
483 CipherSuite::TLS13_AES_128_GCM_SHA256 => Ok(Self { inner, initial }),
484 _ => Err(NoInitialCipherSuite { specific: true }),
485 }
486 }
487
488 pub fn set_alpn_protocols(&mut self, alpn_protocols: Vec<Vec<u8>>) {
490 let config = Arc::make_mut(&mut self.inner);
491 config.alpn_protocols = alpn_protocols;
492 }
493
494 #[cfg(any(feature = "aws-lc-rs", feature = "ring"))]
500 pub(crate) fn inner(
501 cert_chain: Vec<CertificateDer<'static>>,
502 key: PrivateKeyDer<'static>,
503 ) -> Result<rustls::ServerConfig, Error> {
504 let mut inner = rustls::ServerConfig::builder_with_provider(configured_provider())
505 .with_protocol_versions(&[&rustls::version::TLS13])
506 .unwrap() .with_no_client_auth()
508 .with_single_cert(cert_chain, key)?;
509
510 inner.max_early_data_size = u32::MAX;
511 Ok(inner)
512 }
513}
514
515impl TryFrom<rustls::ServerConfig> for QuicServerConfig {
516 type Error = NoInitialCipherSuite;
517
518 fn try_from(inner: rustls::ServerConfig) -> Result<Self, Self::Error> {
519 Arc::new(inner).try_into()
520 }
521}
522
523impl TryFrom<Arc<rustls::ServerConfig>> for QuicServerConfig {
524 type Error = NoInitialCipherSuite;
525
526 fn try_from(inner: Arc<rustls::ServerConfig>) -> Result<Self, Self::Error> {
527 Ok(Self {
528 initial: initial_suite_from_provider(inner.crypto_provider())
529 .ok_or(NoInitialCipherSuite { specific: false })?,
530 inner,
531 })
532 }
533}
534
535impl crypto::ServerConfig for QuicServerConfig {
536 fn start_session(
537 &self,
538 version: u32,
539 params: &TransportParameters,
540 ) -> Box<dyn crypto::Session> {
541 let version = interpret_version(version).unwrap();
543 Box::new(TlsSession {
544 version,
545 got_handshake_data: false,
546 next_secrets: None,
547 inner: Connection::Server(
548 rustls::quic::ServerConnection::new(self.inner.clone(), version, to_vec(params))
549 .unwrap(),
550 ),
551 suite: self.initial,
552 })
553 }
554
555 fn initial_keys(
556 &self,
557 version: u32,
558 dst_cid: ConnectionId,
559 ) -> Result<Keys, UnsupportedVersion> {
560 let version = interpret_version(version)?;
561 Ok(initial_keys(version, dst_cid, Side::Server, &self.initial))
562 }
563
564 fn retry_tag(&self, version: u32, orig_dst_cid: ConnectionId, packet: &[u8]) -> [u8; 16] {
565 let version = interpret_version(version).unwrap();
567 let (nonce, key) = match version {
568 Version::V1 => (&RETRY_INTEGRITY_NONCE_V1, &RETRY_INTEGRITY_KEY_V1),
569 Version::V1Draft => (&RETRY_INTEGRITY_NONCE_DRAFT, &RETRY_INTEGRITY_KEY_DRAFT),
570 _ => unreachable!(),
571 };
572
573 let mut pseudo_packet = Vec::with_capacity(packet.len() + orig_dst_cid.len() + 1);
574 pseudo_packet.push(orig_dst_cid.len() as u8);
575 pseudo_packet.extend_from_slice(&orig_dst_cid);
576 pseudo_packet.extend_from_slice(packet);
577
578 let nonce = aes_gcm::Nonce::from_slice(nonce);
579 let key = aes_gcm::Key::<aes_gcm::Aes128Gcm>::from_slice(key);
580 let tag = aes_gcm::Aes128Gcm::new(key)
581 .encrypt_in_place_detached(nonce, &pseudo_packet, &mut [])
582 .unwrap();
583 tag.into()
584 }
585}
586
587pub(crate) fn initial_suite_from_provider(
588 provider: &Arc<rustls::crypto::CryptoProvider>,
589) -> Option<Suite> {
590 provider
591 .cipher_suites
592 .iter()
593 .find_map(|cs| match (cs.suite(), cs.tls13()) {
594 (CipherSuite::TLS13_AES_128_GCM_SHA256, Some(suite)) => Some(suite.quic_suite()),
595 _ => None,
596 })
597 .flatten()
598}
599
600#[cfg(all(feature = "aws-lc-rs", not(feature = "ring")))]
601pub(crate) fn configured_provider() -> Arc<rustls::crypto::CryptoProvider> {
602 Arc::new(rustls::crypto::aws_lc_rs::default_provider())
603}
604
605#[cfg(feature = "ring")]
606pub(crate) fn configured_provider() -> Arc<rustls::crypto::CryptoProvider> {
607 Arc::new(rustls::crypto::ring::default_provider())
608}
609
610fn to_vec(params: &TransportParameters) -> Vec<u8> {
611 let mut bytes = Vec::new();
612 params.write(&mut bytes);
613 bytes
614}
615
616pub(crate) fn initial_keys(
617 version: Version,
618 dst_cid: ConnectionId,
619 side: Side,
620 suite: &Suite,
621) -> Keys {
622 let keys = suite.keys(&dst_cid, side.into(), version);
623 Keys {
624 header: KeyPair {
625 local: Box::new(keys.local.header),
626 remote: Box::new(keys.remote.header),
627 },
628 packet: KeyPair {
629 local: Box::new(keys.local.packet),
630 remote: Box::new(keys.remote.packet),
631 },
632 }
633}
634
635impl crypto::PacketKey for Box<dyn PacketKey> {
636 fn encrypt(&self, path_id: PathId, packet: u64, buf: &mut [u8], header_len: usize) {
637 let (header, payload_tag) = buf.split_at_mut(header_len);
638 let (payload, tag_storage) = payload_tag.split_at_mut(payload_tag.len() - self.tag_len());
639 let tag = self
640 .encrypt_in_place_for_path(path_id.as_u32(), packet, &*header, payload)
641 .unwrap();
642 tag_storage.copy_from_slice(tag.as_ref());
643 }
644
645 fn decrypt(
646 &self,
647 path_id: PathId,
648 packet: u64,
649 header: &[u8],
650 payload: &mut BytesMut,
651 ) -> Result<(), CryptoError> {
652 let plain = self
653 .decrypt_in_place_for_path(path_id.as_u32(), packet, header, payload.as_mut())
654 .map_err(|_| CryptoError)?;
655 let plain_len = plain.len();
656 payload.truncate(plain_len);
657 Ok(())
658 }
659
660 fn tag_len(&self) -> usize {
661 (**self).tag_len()
662 }
663
664 fn confidentiality_limit(&self) -> u64 {
665 (**self).confidentiality_limit()
666 }
667
668 fn integrity_limit(&self) -> u64 {
669 (**self).integrity_limit()
670 }
671}
672
673fn interpret_version(version: u32) -> Result<Version, UnsupportedVersion> {
674 match version {
675 0xff00_001d..=0xff00_0020 => Ok(Version::V1Draft),
676 0x0000_0001 | 0xff00_0021..=0xff00_0022 => Ok(Version::V1),
677 _ => Err(UnsupportedVersion),
678 }
679}