1use crate::crypto::aes::Aes;
19#[cfg(feature = "chacha20")]
20use crate::crypto::chacha::chacha20_block;
21use crate::crypto::gcm::AesGcm;
22use crate::crypto::sha2::HashAlg;
23#[cfg(feature = "client")]
24use crate::tls::client::ClientHs;
25#[cfg(feature = "client")]
26use crate::tls::config::ClientConfig;
27use crate::tls::config::ServerConfig;
28use crate::tls::engine::{Engine, Event, HsReader};
29use crate::tls::keyschedule::{expand_label, expand_label_vec};
30use crate::tls::record::{nonce, Aead};
31use crate::tls::server::ServerHs;
32use crate::tls::{alert, AeadAlg, CipherSuite, Error, Result};
33use std::sync::Arc;
34
35pub use crate::tls::Level;
36
37pub const VERSION_1: u32 = 0x0000_0001;
39pub const VERSION_2: u32 = 0x6b33_43cf;
41
42struct Labels {
43 key: &'static [u8],
44 iv: &'static [u8],
45 hp: &'static [u8],
46 ku: &'static [u8],
47}
48
49fn labels(version: u32) -> Labels {
50 if version == VERSION_2 {
51 Labels { key: b"quicv2 key", iv: b"quicv2 iv", hp: b"quicv2 hp", ku: b"quicv2 ku" }
52 } else {
53 Labels { key: b"quic key", iv: b"quic iv", hp: b"quic hp", ku: b"quic ku" }
54 }
55}
56
57#[derive(Clone)]
59pub struct PacketKey {
60 aead: Aead,
61 iv: [u8; 12],
62 alg: AeadAlg,
63}
64
65impl std::fmt::Debug for PacketKey {
66 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
67 write!(f, "PacketKey({:?})", self.alg)
68 }
69}
70
71impl PacketKey {
72 fn new(suite: CipherSuite, version: u32, secret: &[u8]) -> PacketKey {
73 let l = labels(version);
74 let h = suite.hash();
75 let key = expand_label_vec(h, secret, l.key, &[], suite.aead().key_len());
76 let mut iv = [0u8; 12];
77 expand_label(h, secret, l.iv, &[], &mut iv);
78 PacketKey { aead: Aead::new(suite.aead(), &key), iv, alg: suite.aead() }
79 }
80
81 pub fn seal_in_place(&self, pn: u64, header: &[u8], payload: &mut [u8], tag_out: &mut [u8; 16]) {
83 *tag_out = self.aead.seal(&nonce(&self.iv, pn), header, payload);
84 }
85
86 pub fn open_in_place<'a>(&self, pn: u64, header: &[u8], payload_with_tag: &'a mut [u8]) -> Result<&'a mut [u8]> {
88 if payload_with_tag.len() < 16 {
89 return Err(Error::proto(alert::BAD_RECORD_MAC, "packet too short"));
90 }
91 let n = payload_with_tag.len() - 16;
92 let (ct, tag) = payload_with_tag.split_at_mut(n);
93 if !self.aead.open(&nonce(&self.iv, pn), header, ct, tag) {
94 return Err(Error::proto(alert::BAD_RECORD_MAC, "packet authentication failed"));
95 }
96 Ok(ct)
97 }
98
99 pub fn tag_len(&self) -> usize {
100 16
101 }
102
103 pub fn confidentiality_limit(&self) -> u64 {
105 match self.alg {
106 #[cfg(feature = "chacha20")]
107 AeadAlg::Chacha20Poly1305 => 1 << 62,
108 _ => 1 << 23,
109 }
110 }
111
112 pub fn integrity_limit(&self) -> u64 {
114 match self.alg {
115 #[cfg(feature = "chacha20")]
116 AeadAlg::Chacha20Poly1305 => 1 << 36,
117 _ => 1 << 52,
118 }
119 }
120}
121
122#[derive(Clone)]
124#[allow(clippy::large_enum_variant)] pub enum HeaderProtectionKey {
126 Aes(Aes),
127 #[cfg(feature = "chacha20")]
128 ChaCha([u8; 32]),
129}
130
131impl std::fmt::Debug for HeaderProtectionKey {
132 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
133 f.write_str(match self {
134 HeaderProtectionKey::Aes(_) => "HeaderProtectionKey(AES)",
135 #[cfg(feature = "chacha20")]
136 HeaderProtectionKey::ChaCha(_) => "HeaderProtectionKey(ChaCha20)",
137 })
138 }
139}
140
141impl HeaderProtectionKey {
142 fn new(suite: CipherSuite, version: u32, secret: &[u8]) -> HeaderProtectionKey {
143 let key = expand_label_vec(suite.hash(), secret, labels(version).hp, &[], suite.aead().key_len());
144 match suite.aead() {
145 #[cfg(feature = "chacha20")]
146 AeadAlg::Chacha20Poly1305 => HeaderProtectionKey::ChaCha(key.try_into().unwrap()),
147 _ => HeaderProtectionKey::Aes(Aes::new(&key)),
148 }
149 }
150
151 pub fn mask(&self, sample: &[u8]) -> [u8; 5] {
153 assert!(sample.len() >= 16, "header protection sample must be 16 bytes");
154 let mut out = [0u8; 5];
155 match self {
156 HeaderProtectionKey::Aes(a) => {
157 let mut b: [u8; 16] = sample[..16].try_into().unwrap();
158 a.encrypt_block(&mut b);
159 out.copy_from_slice(&b[..5]);
160 }
161 #[cfg(feature = "chacha20")]
162 HeaderProtectionKey::ChaCha(k) => {
163 let counter = u32::from_le_bytes(sample[..4].try_into().unwrap());
164 let block = chacha20_block(k, counter, sample[4..16].try_into().unwrap());
165 out.copy_from_slice(&block[..5]);
166 }
167 }
168 out
169 }
170}
171
172#[derive(Clone, Debug)]
174pub struct DirectionalKeys {
175 pub packet: PacketKey,
176 pub header: HeaderProtectionKey,
177}
178
179impl DirectionalKeys {
180 pub fn new(suite: CipherSuite, version: u32, secret: &[u8]) -> DirectionalKeys {
182 DirectionalKeys { packet: PacketKey::new(suite, version, secret), header: HeaderProtectionKey::new(suite, version, secret) }
183 }
184}
185
186#[derive(Clone, Debug)]
188pub struct Keys {
189 pub local: DirectionalKeys,
190 pub remote: DirectionalKeys,
191}
192
193impl Keys {
194 fn new(suite: CipherSuite, version: u32, is_client: bool, client: &[u8], server: &[u8]) -> Keys {
195 let (l, r) = if is_client { (client, server) } else { (server, client) };
196 Keys { local: DirectionalKeys::new(suite, version, l), remote: DirectionalKeys::new(suite, version, r) }
197 }
198}
199
200fn initial_salt(version: u32) -> &'static [u8; 20] {
201 if version == VERSION_2 {
202 &[0x0d, 0xed, 0xe3, 0xde, 0xf7, 0x00, 0xa6, 0xdb, 0x81, 0x93, 0x81, 0xbe, 0x6e, 0x26, 0x9d, 0xcb, 0xf9, 0xbd, 0x2e, 0xd9]
203 } else {
204 &[0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17, 0x9a, 0xe6, 0xa4, 0xc8, 0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a]
205 }
206}
207
208pub fn initial_secrets(version: u32, dcid: &[u8]) -> (Vec<u8>, Vec<u8>) {
210 let h = HashAlg::Sha256;
211 let initial = h.hkdf_extract(initial_salt(version), dcid);
212 (expand_label_vec(h, &initial, b"client in", &[], 32), expand_label_vec(h, &initial, b"server in", &[], 32))
213}
214
215pub fn initial_keys(version: u32, dcid: &[u8], is_server: bool) -> Keys {
217 let (c, s) = initial_secrets(version, dcid);
218 Keys::new(CipherSuite::Aes128GcmSha256, version, !is_server, &c, &s)
219}
220
221pub fn retry_integrity_tag(version: u32, original_dcid: &[u8], retry_without_tag: &[u8]) -> [u8; 16] {
224 let (key, nonce): ([u8; 16], [u8; 12]) = if version == VERSION_2 {
225 (
226 [0x8f, 0xb4, 0xb0, 0x1b, 0x56, 0xac, 0x48, 0xe2, 0x60, 0xfb, 0xcb, 0xce, 0xad, 0x7c, 0xcc, 0x92],
227 [0xd8, 0x69, 0x69, 0xbc, 0x2d, 0x7c, 0x6d, 0x99, 0x90, 0xef, 0xb0, 0x4a],
228 )
229 } else {
230 (
231 [0xbe, 0x0c, 0x69, 0x0b, 0x9f, 0x66, 0x57, 0x5a, 0x1d, 0x76, 0x6b, 0x54, 0xe3, 0x68, 0xc8, 0x4e],
232 [0x46, 0x15, 0x99, 0xd3, 0x5d, 0x63, 0x2b, 0xf2, 0x23, 0x98, 0x25, 0xbb],
233 )
234 };
235 let mut aad = Vec::with_capacity(1 + original_dcid.len() + retry_without_tag.len());
236 aad.push(original_dcid.len() as u8);
237 aad.extend_from_slice(original_dcid);
238 aad.extend_from_slice(retry_without_tag);
239 AesGcm::new(&key).seal(&nonce, &aad, &mut [])
240}
241
242pub struct Secrets {
244 suite: CipherSuite,
245 version: u32,
246 is_client: bool,
247 client: Vec<u8>,
248 server: Vec<u8>,
249}
250
251impl std::fmt::Debug for Secrets {
252 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
253 write!(f, "Secrets({:?})", self.suite)
254 }
255}
256
257impl Secrets {
258 pub fn new(suite: CipherSuite, version: u32, is_client: bool, client: Vec<u8>, server: Vec<u8>) -> Secrets {
260 Secrets { suite, version, is_client, client, server }
261 }
262
263 pub fn next_packet_keys(&mut self) -> (PacketKey, PacketKey) {
266 let h = self.suite.hash();
267 let ku = labels(self.version).ku;
268 self.client = expand_label_vec(h, &self.client, ku, &[], h.output_len());
269 self.server = expand_label_vec(h, &self.server, ku, &[], h.output_len());
270 let c = PacketKey::new(self.suite, self.version, &self.client);
271 let s = PacketKey::new(self.suite, self.version, &self.server);
272 if self.is_client {
273 (c, s)
274 } else {
275 (s, c)
276 }
277 }
278}
279
280pub enum KeyChange {
282 Handshake { keys: Keys },
284 OneRtt { keys: Keys, next: Secrets },
286}
287
288impl std::fmt::Debug for KeyChange {
289 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
290 f.write_str(match self {
291 KeyChange::Handshake { .. } => "KeyChange::Handshake",
292 KeyChange::OneRtt { .. } => "KeyChange::OneRtt",
293 })
294 }
295}
296
297pub struct QuicConnection {
299 engine: Engine,
300 hs: HsReader,
301 write_level: Level,
302 version: u32,
303 alert: Option<u8>,
304 error: Option<Error>,
305}
306
307impl std::fmt::Debug for QuicConnection {
308 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
309 f.debug_struct("QuicConnection").field("client", &self.engine.is_client()).field("handshaking", &self.is_handshaking()).finish()
310 }
311}
312
313impl QuicConnection {
314 pub fn new_server(cfg: Arc<ServerConfig>, transport_params: Vec<u8>) -> QuicConnection {
316 QuicConnection::from_engine(Engine::Server(Box::new(ServerHs::new(cfg, Some(transport_params)))))
317 }
318
319 #[cfg(feature = "client")]
322 pub fn new_client(cfg: Arc<ClientConfig>, server_name: &str, transport_params: Vec<u8>) -> Result<QuicConnection> {
323 Ok(QuicConnection::from_engine(Engine::Client(Box::new(ClientHs::new(cfg, server_name, Some(transport_params))?))))
324 }
325
326 fn from_engine(engine: Engine) -> QuicConnection {
327 QuicConnection { engine, hs: HsReader::new(), write_level: Level::Initial, version: VERSION_1, alert: None, error: None }
328 }
329
330 pub fn set_version(&mut self, version: u32) {
333 self.version = version;
334 }
335
336 pub fn read_handshake(&mut self, level: Level, data: &[u8]) -> Result<()> {
338 if let Some(e) = &self.error {
339 return Err(e.clone());
340 }
341 let r = self.read_inner(level, data);
342 if let Err(e) = &r {
343 self.alert = e.alert();
344 self.error = Some(e.clone());
345 }
346 r
347 }
348
349 fn read_inner(&mut self, level: Level, data: &[u8]) -> Result<()> {
350 if level != self.engine.shared().expect_level {
351 return Err(Error::unexpected("CRYPTO data at this encryption level"));
352 }
353 self.hs.push(level, data)?;
354 let max = self.engine.shared().max_message;
355 while let Some((lvl, msg)) = self.hs.next(max)? {
356 if msg[0] == crate::tls::hs::KEY_UPDATE {
357 return Err(Error::unexpected("KeyUpdate in QUIC"));
358 }
359 self.engine.handle(lvl, &msg)?;
360 if self.engine.shared().expect_level != lvl && !self.hs.is_empty() {
361 return Err(Error::unexpected("handshake data across a key change"));
362 }
363 }
364 Ok(())
365 }
366
367 pub fn write_level(&self) -> Level {
369 self.write_level
370 }
371
372 pub fn write_handshake(&mut self, out: &mut Vec<u8>) -> Option<KeyChange> {
375 let is_client = self.engine.is_client();
376 let version = self.version;
377 while let Some(ev) = self.engine.shared_mut().events.pop_front() {
378 match ev {
379 Event::Msg(_, m) => out.extend_from_slice(&m),
380 Event::Ccs => {}
381 #[cfg(feature = "tls12")]
383 Event::ChangeCipher12(_) => {}
384 Event::Secrets { level, client, server } => {
385 let suite = self.engine.shared().suite.expect("suite");
386 let keys = Keys::new(suite, version, is_client, &client, &server);
387 self.write_level = level;
388 return Some(match level {
389 Level::OneRtt => KeyChange::OneRtt { keys, next: Secrets { suite, version, is_client, client, server } },
390 _ => KeyChange::Handshake { keys },
391 });
392 }
393 }
394 }
395 None
396 }
397
398 pub fn is_handshaking(&self) -> bool {
399 !self.engine.shared().done
400 }
401
402 pub fn peer_transport_params(&self) -> Option<&[u8]> {
404 self.engine.shared().peer_tp.as_deref()
405 }
406
407 pub fn alpn_protocol(&self) -> Option<&[u8]> {
408 self.engine.shared().alpn.as_deref()
409 }
410
411 pub fn negotiated_cipher_suite(&self) -> Option<CipherSuite> {
412 self.engine.shared().suite
413 }
414
415 pub fn server_name(&self) -> Option<&str> {
416 self.engine.shared().sni.as_deref()
417 }
418
419 pub fn peer_certificates(&self) -> &[Vec<u8>] {
420 &self.engine.shared().peer_certs
421 }
422
423 pub fn is_resumed(&self) -> bool {
424 self.engine.shared().resumed
425 }
426
427 pub fn tls_alert(&self) -> Option<u64> {
429 self.alert.map(|a| 0x100 + a as u64)
430 }
431}