1use libc::c_int;
28use libc::c_void;
29
30use crate::Error;
31use crate::Result;
32
33use crate::packet;
34
35pub const MAX_NONCE_LEN: usize = 12;
37
38pub const HP_MASK_LEN: usize = 5;
40
41#[repr(C)]
42#[derive(Clone, Copy, Debug, PartialEq, Eq)]
43pub enum Level {
44 Initial = 0,
45 ZeroRTT = 1,
46 Handshake = 2,
47 OneRTT = 3,
48}
49
50impl Level {
51 pub fn from_epoch(e: packet::Epoch) -> Level {
52 match e {
53 packet::Epoch::Initial => Level::Initial,
54
55 packet::Epoch::Handshake => Level::Handshake,
56
57 packet::Epoch::Application => Level::OneRTT,
58 }
59 }
60}
61
62#[derive(Clone, Copy, Debug, PartialEq, Eq)]
63pub enum Algorithm {
64 #[allow(non_camel_case_types)]
65 AES128_GCM,
66
67 #[allow(non_camel_case_types)]
68 AES256_GCM,
69
70 #[allow(non_camel_case_types)]
71 ChaCha20_Poly1305,
72}
73
74impl Algorithm {
77 fn get_evp_digest(self) -> *const EVP_MD {
78 match self {
79 Algorithm::AES128_GCM => unsafe { EVP_sha256() },
80 Algorithm::AES256_GCM => unsafe { EVP_sha384() },
81 Algorithm::ChaCha20_Poly1305 => unsafe { EVP_sha256() },
82 }
83 }
84
85 pub const fn key_len(self) -> usize {
86 match self {
87 Algorithm::AES128_GCM => 16,
88 Algorithm::AES256_GCM => 32,
89 Algorithm::ChaCha20_Poly1305 => 32,
90 }
91 }
92
93 pub const fn tag_len(self) -> usize {
94 if cfg!(feature = "fuzzing") {
95 return 0;
96 }
97
98 match self {
99 Algorithm::AES128_GCM => 16,
100 Algorithm::AES256_GCM => 16,
101 Algorithm::ChaCha20_Poly1305 => 16,
102 }
103 }
104
105 pub const fn nonce_len(self) -> usize {
106 match self {
107 Algorithm::AES128_GCM => 12,
108 Algorithm::AES256_GCM => 12,
109 Algorithm::ChaCha20_Poly1305 => 12,
110 }
111 }
112}
113
114#[allow(non_camel_case_types)]
115#[repr(transparent)]
116pub struct EVP_AEAD {
117 _unused: c_void,
118}
119
120#[allow(non_camel_case_types)]
121#[repr(transparent)]
122struct EVP_MD {
123 _unused: c_void,
124}
125
126type HeaderProtectionMask = [u8; HP_MASK_LEN];
127
128pub struct Open {
129 alg: Algorithm,
130
131 secret: Vec<u8>,
132
133 header: HeaderProtectionKey,
134
135 packet: PacketKey,
136}
137
138impl Open {
139 pub const DECRYPT: u32 = 0;
143
144 pub fn new(
145 alg: Algorithm, key: Vec<u8>, iv: Vec<u8>, hp_key: Vec<u8>,
146 secret: Vec<u8>,
147 ) -> Result<Open> {
148 Ok(Open {
149 alg,
150
151 secret,
152
153 header: HeaderProtectionKey::new(alg, hp_key)?,
154
155 packet: PacketKey::new(alg, key, iv, Self::DECRYPT)?,
156 })
157 }
158
159 pub fn from_secret(aead: Algorithm, secret: &[u8]) -> Result<Open> {
160 Ok(Open {
161 alg: aead,
162
163 secret: secret.to_vec(),
164
165 header: HeaderProtectionKey::from_secret(aead, secret)?,
166
167 packet: PacketKey::from_secret(aead, secret, Self::DECRYPT)?,
168 })
169 }
170
171 pub fn new_mask(&self, sample: &[u8]) -> Result<[u8; 5]> {
172 if cfg!(feature = "fuzzing") {
173 return Ok(<[u8; 5]>::default());
174 }
175
176 self.header.new_mask(sample)
177 }
178
179 pub fn alg(&self) -> Algorithm {
180 self.alg
181 }
182
183 pub fn derive_next_packet_key(&self) -> Result<Open> {
184 let next_secret = derive_next_secret(self.alg, &self.secret)?;
185
186 let next_packet_key =
187 PacketKey::from_secret(self.alg, &next_secret, Self::DECRYPT)?;
188
189 Ok(Open {
190 alg: self.alg,
191
192 secret: next_secret,
193
194 header: self.header.clone(),
195
196 packet: next_packet_key,
197 })
198 }
199
200 pub fn open_with_u64_counter(
201 &self, counter: u64, ad: &[u8], buf: &mut [u8],
202 ) -> Result<usize> {
203 if cfg!(feature = "fuzzing") {
204 return Ok(buf.len());
205 }
206
207 self.packet.open_with_u64_counter(counter, ad, buf)
208 }
209}
210
211pub struct Seal {
212 alg: Algorithm,
213
214 secret: Vec<u8>,
215
216 header: HeaderProtectionKey,
217
218 packet: PacketKey,
219}
220
221impl Seal {
222 pub const ENCRYPT: u32 = 1;
226
227 pub fn new(
228 alg: Algorithm, key: Vec<u8>, iv: Vec<u8>, hp_key: Vec<u8>,
229 secret: Vec<u8>,
230 ) -> Result<Seal> {
231 Ok(Seal {
232 alg,
233
234 secret,
235
236 header: HeaderProtectionKey::new(alg, hp_key)?,
237
238 packet: PacketKey::new(alg, key, iv, Self::ENCRYPT)?,
239 })
240 }
241
242 pub fn from_secret(aead: Algorithm, secret: &[u8]) -> Result<Seal> {
243 Ok(Seal {
244 alg: aead,
245
246 secret: secret.to_vec(),
247
248 header: HeaderProtectionKey::from_secret(aead, secret)?,
249
250 packet: PacketKey::from_secret(aead, secret, Self::ENCRYPT)?,
251 })
252 }
253
254 pub fn new_mask(&self, sample: &[u8]) -> Result<[u8; 5]> {
255 if cfg!(feature = "fuzzing") {
256 return Ok(<[u8; 5]>::default());
257 }
258
259 self.header.new_mask(sample)
260 }
261
262 pub fn alg(&self) -> Algorithm {
263 self.alg
264 }
265
266 pub fn derive_next_packet_key(&self) -> Result<Seal> {
267 let next_secret = derive_next_secret(self.alg, &self.secret)?;
268
269 let next_packet_key =
270 PacketKey::from_secret(self.alg, &next_secret, Self::ENCRYPT)?;
271
272 Ok(Seal {
273 alg: self.alg,
274
275 secret: next_secret,
276
277 header: self.header.clone(),
278
279 packet: next_packet_key,
280 })
281 }
282
283 pub fn seal_with_u64_counter(
284 &self, counter: u64, ad: &[u8], buf: &mut [u8], in_len: usize,
285 extra_in: Option<&[u8]>,
286 ) -> Result<usize> {
287 if cfg!(feature = "fuzzing") {
288 if let Some(extra) = extra_in {
289 buf[in_len..in_len + extra.len()].copy_from_slice(extra);
290 return Ok(in_len + extra.len());
291 }
292
293 return Ok(in_len);
294 }
295
296 self.packet
297 .seal_with_u64_counter(counter, ad, buf, in_len, extra_in)
298 }
299}
300
301impl HeaderProtectionKey {
302 pub fn from_secret(aead: Algorithm, secret: &[u8]) -> Result<Self> {
303 let key_len = aead.key_len();
304
305 let mut hp_key = vec![0; key_len];
306
307 derive_hdr_key(aead, secret, &mut hp_key)?;
308
309 Self::new(aead, hp_key)
310 }
311}
312
313pub fn derive_initial_key_material(
314 cid: &[u8], version: u32, is_server: bool,
315) -> Result<(Open, Seal)> {
316 let mut initial_secret = [0; 32];
317 let mut client_secret = vec![0; 32];
318 let mut server_secret = vec![0; 32];
319
320 let aead = Algorithm::AES128_GCM;
321
322 let key_len = aead.key_len();
323 let nonce_len = aead.nonce_len();
324
325 derive_initial_secret(cid, version, &mut initial_secret)?;
326
327 let mut client_key = vec![0; key_len];
329 let mut client_iv = vec![0; nonce_len];
330 let mut client_hp_key = vec![0; key_len];
331
332 derive_client_initial_secret(aead, &initial_secret, &mut client_secret)?;
333
334 derive_pkt_key(aead, &client_secret, &mut client_key)?;
335 derive_pkt_iv(aead, &client_secret, &mut client_iv)?;
336 derive_hdr_key(aead, &client_secret, &mut client_hp_key)?;
337
338 let mut server_key = vec![0; key_len];
340 let mut server_iv = vec![0; nonce_len];
341 let mut server_hp_key = vec![0; key_len];
342
343 derive_server_initial_secret(aead, &initial_secret, &mut server_secret)?;
344
345 derive_pkt_key(aead, &server_secret, &mut server_key)?;
346 derive_pkt_iv(aead, &server_secret, &mut server_iv)?;
347 derive_hdr_key(aead, &server_secret, &mut server_hp_key)?;
348
349 let (open, seal) = if is_server {
350 (
351 Open::new(aead, client_key, client_iv, client_hp_key, client_secret)?,
352 Seal::new(aead, server_key, server_iv, server_hp_key, server_secret)?,
353 )
354 } else {
355 (
356 Open::new(aead, server_key, server_iv, server_hp_key, server_secret)?,
357 Seal::new(aead, client_key, client_iv, client_hp_key, client_secret)?,
358 )
359 };
360
361 Ok((open, seal))
362}
363
364fn derive_initial_secret(
365 secret: &[u8], version: u32, out_prk: &mut [u8],
366) -> Result<()> {
367 const INITIAL_SALT_V1: [u8; 20] = [
368 0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17, 0x9a, 0xe6,
369 0xa4, 0xc8, 0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a,
370 ];
371
372 let salt = match version {
373 crate::PROTOCOL_VERSION_V1 => &INITIAL_SALT_V1,
374
375 _ => &INITIAL_SALT_V1,
376 };
377
378 hkdf_extract(Algorithm::AES128_GCM, out_prk, secret, salt)
379}
380
381fn derive_client_initial_secret(
382 aead: Algorithm, prk: &[u8], out: &mut [u8],
383) -> Result<()> {
384 const LABEL: &[u8] = b"client in";
385 hkdf_expand_label(aead, prk, LABEL, out)
386}
387
388fn derive_server_initial_secret(
389 aead: Algorithm, prk: &[u8], out: &mut [u8],
390) -> Result<()> {
391 const LABEL: &[u8] = b"server in";
392 hkdf_expand_label(aead, prk, LABEL, out)
393}
394
395fn derive_next_secret(aead: Algorithm, secret: &[u8]) -> Result<Vec<u8>> {
396 const LABEL: &[u8] = b"quic ku";
397
398 let mut next_secret = vec![0u8; 32];
399
400 hkdf_expand_label(aead, secret, LABEL, &mut next_secret)?;
401
402 Ok(next_secret)
403}
404
405pub fn derive_hdr_key(
406 aead: Algorithm, secret: &[u8], out: &mut [u8],
407) -> Result<()> {
408 const LABEL: &[u8] = b"quic hp";
409
410 let key_len = aead.key_len();
411
412 if key_len > out.len() {
413 return Err(Error::CryptoFail);
414 }
415
416 hkdf_expand_label(aead, secret, LABEL, &mut out[..key_len])
417}
418
419pub fn derive_pkt_key(aead: Algorithm, prk: &[u8], out: &mut [u8]) -> Result<()> {
420 const LABEL: &[u8] = b"quic key";
421
422 let key_len: usize = aead.key_len();
423
424 if key_len > out.len() {
425 return Err(Error::CryptoFail);
426 }
427
428 hkdf_expand_label(aead, prk, LABEL, &mut out[..key_len])
429}
430
431pub fn derive_pkt_iv(aead: Algorithm, prk: &[u8], out: &mut [u8]) -> Result<()> {
432 const LABEL: &[u8] = b"quic iv";
433
434 let nonce_len = aead.nonce_len();
435
436 if nonce_len > out.len() {
437 return Err(Error::CryptoFail);
438 }
439
440 hkdf_expand_label(aead, prk, LABEL, &mut out[..nonce_len])
441}
442
443fn hkdf_expand_label(
444 alg: Algorithm, prk: &[u8], label: &[u8], out: &mut [u8],
445) -> Result<()> {
446 const LABEL_PREFIX: &[u8] = b"tls13 ";
447
448 let out_len = (out.len() as u16).to_be_bytes();
449 let label_len = (LABEL_PREFIX.len() + label.len()) as u8;
450
451 let info = [&out_len, &[label_len][..], LABEL_PREFIX, label, &[0][..]];
452 let info = info.concat();
453
454 hkdf_expand(alg, out, prk, &info)?;
455
456 Ok(())
457}
458
459fn make_nonce(iv: &[u8], counter: u64) -> [u8; MAX_NONCE_LEN] {
460 let mut nonce = [0; MAX_NONCE_LEN];
461 nonce.copy_from_slice(iv);
462
463 for (a, b) in nonce[4..].iter_mut().zip(counter.to_be_bytes().iter()) {
466 *a ^= b;
467 }
468
469 nonce
470}
471
472pub fn verify_slices_are_equal(a: &[u8], b: &[u8]) -> Result<()> {
473 if a.len() != b.len() {
474 return Err(Error::CryptoFail);
475 }
476
477 let rc = unsafe { CRYPTO_memcmp(a.as_ptr(), b.as_ptr(), a.len()) };
478
479 if rc == 0 {
480 return Ok(());
481 }
482
483 Err(Error::CryptoFail)
484}
485
486extern "C" {
487 fn EVP_sha256() -> *const EVP_MD;
488
489 fn EVP_sha384() -> *const EVP_MD;
490
491 fn CRYPTO_memcmp(a: *const u8, b: *const u8, len: usize) -> c_int;
493}
494
495#[cfg(test)]
496mod tests {
497 use super::*;
498
499 #[test]
500 fn derive_initial_secrets_v1() {
501 let dcid = [0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08];
502
503 let mut initial_secret = [0; 32];
504
505 let mut secret = [0; 32];
506 let mut pkt_key = [0; 16];
507 let mut pkt_iv = [0; 12];
508 let mut hdr_key = [0; 16];
509
510 let aead = Algorithm::AES128_GCM;
511
512 assert!(derive_initial_secret(
513 &dcid,
514 crate::PROTOCOL_VERSION_V1,
515 &mut initial_secret,
516 )
517 .is_ok());
518
519 assert!(
521 derive_client_initial_secret(aead, &initial_secret, &mut secret)
522 .is_ok()
523 );
524 let expected_client_initial_secret = [
525 0xc0, 0x0c, 0xf1, 0x51, 0xca, 0x5b, 0xe0, 0x75, 0xed, 0x0e, 0xbf,
526 0xb5, 0xc8, 0x03, 0x23, 0xc4, 0x2d, 0x6b, 0x7d, 0xb6, 0x78, 0x81,
527 0x28, 0x9a, 0xf4, 0x00, 0x8f, 0x1f, 0x6c, 0x35, 0x7a, 0xea,
528 ];
529 assert_eq!(&secret, &expected_client_initial_secret);
530
531 assert!(derive_pkt_key(aead, &secret, &mut pkt_key).is_ok());
532 let expected_client_pkt_key = [
533 0x1f, 0x36, 0x96, 0x13, 0xdd, 0x76, 0xd5, 0x46, 0x77, 0x30, 0xef,
534 0xcb, 0xe3, 0xb1, 0xa2, 0x2d,
535 ];
536 assert_eq!(&pkt_key, &expected_client_pkt_key);
537
538 assert!(derive_pkt_iv(aead, &secret, &mut pkt_iv).is_ok());
539 let expected_client_pkt_iv = [
540 0xfa, 0x04, 0x4b, 0x2f, 0x42, 0xa3, 0xfd, 0x3b, 0x46, 0xfb, 0x25,
541 0x5c,
542 ];
543 assert_eq!(&pkt_iv, &expected_client_pkt_iv);
544
545 assert!(derive_hdr_key(aead, &secret, &mut hdr_key).is_ok());
546 let expected_client_hdr_key = [
547 0x9f, 0x50, 0x44, 0x9e, 0x04, 0xa0, 0xe8, 0x10, 0x28, 0x3a, 0x1e,
548 0x99, 0x33, 0xad, 0xed, 0xd2,
549 ];
550 assert_eq!(&hdr_key, &expected_client_hdr_key);
551
552 assert!(
554 derive_server_initial_secret(aead, &initial_secret, &mut secret)
555 .is_ok()
556 );
557
558 let expected_server_initial_secret = [
559 0x3c, 0x19, 0x98, 0x28, 0xfd, 0x13, 0x9e, 0xfd, 0x21, 0x6c, 0x15,
560 0x5a, 0xd8, 0x44, 0xcc, 0x81, 0xfb, 0x82, 0xfa, 0x8d, 0x74, 0x46,
561 0xfa, 0x7d, 0x78, 0xbe, 0x80, 0x3a, 0xcd, 0xda, 0x95, 0x1b,
562 ];
563 assert_eq!(&secret, &expected_server_initial_secret);
564
565 assert!(derive_pkt_key(aead, &secret, &mut pkt_key).is_ok());
566 let expected_server_pkt_key = [
567 0xcf, 0x3a, 0x53, 0x31, 0x65, 0x3c, 0x36, 0x4c, 0x88, 0xf0, 0xf3,
568 0x79, 0xb6, 0x06, 0x7e, 0x37,
569 ];
570 assert_eq!(&pkt_key, &expected_server_pkt_key);
571
572 assert!(derive_pkt_iv(aead, &secret, &mut pkt_iv).is_ok());
573 let expected_server_pkt_iv = [
574 0x0a, 0xc1, 0x49, 0x3c, 0xa1, 0x90, 0x58, 0x53, 0xb0, 0xbb, 0xa0,
575 0x3e,
576 ];
577 assert_eq!(&pkt_iv, &expected_server_pkt_iv);
578
579 assert!(derive_hdr_key(aead, &secret, &mut hdr_key).is_ok());
580 let expected_server_hdr_key = [
581 0xc2, 0x06, 0xb8, 0xd9, 0xb9, 0xf0, 0xf3, 0x76, 0x44, 0x43, 0x0b,
582 0x49, 0x0e, 0xea, 0xa3, 0x14,
583 ];
584 assert_eq!(&hdr_key, &expected_server_hdr_key);
585 }
586
587 #[test]
588 fn derive_chacha20_secrets() {
589 let secret = [
590 0x9a, 0xc3, 0x12, 0xa7, 0xf8, 0x77, 0x46, 0x8e, 0xbe, 0x69, 0x42,
591 0x27, 0x48, 0xad, 0x00, 0xa1, 0x54, 0x43, 0xf1, 0x82, 0x03, 0xa0,
592 0x7d, 0x60, 0x60, 0xf6, 0x88, 0xf3, 0x0f, 0x21, 0x63, 0x2b,
593 ];
594
595 let aead = Algorithm::ChaCha20_Poly1305;
596
597 let mut pkt_key = [0; 32];
598 let mut pkt_iv = [0; 12];
599 let mut hdr_key = [0; 32];
600
601 assert!(derive_pkt_key(aead, &secret, &mut pkt_key).is_ok());
602 let expected_pkt_key = [
603 0xc6, 0xd9, 0x8f, 0xf3, 0x44, 0x1c, 0x3f, 0xe1, 0xb2, 0x18, 0x20,
604 0x94, 0xf6, 0x9c, 0xaa, 0x2e, 0xd4, 0xb7, 0x16, 0xb6, 0x54, 0x88,
605 0x96, 0x0a, 0x7a, 0x98, 0x49, 0x79, 0xfb, 0x23, 0xe1, 0xc8,
606 ];
607 assert_eq!(&pkt_key, &expected_pkt_key);
608
609 assert!(derive_pkt_iv(aead, &secret, &mut pkt_iv).is_ok());
610 let expected_pkt_iv = [
611 0xe0, 0x45, 0x9b, 0x34, 0x74, 0xbd, 0xd0, 0xe4, 0x4a, 0x41, 0xc1,
612 0x44,
613 ];
614 assert_eq!(&pkt_iv, &expected_pkt_iv);
615
616 assert!(derive_hdr_key(aead, &secret, &mut hdr_key).is_ok());
617 let expected_hdr_key = [
618 0x25, 0xa2, 0x82, 0xb9, 0xe8, 0x2f, 0x06, 0xf2, 0x1f, 0x48, 0x89,
619 0x17, 0xa4, 0xfc, 0x8f, 0x1b, 0x73, 0x57, 0x36, 0x85, 0x60, 0x85,
620 0x97, 0xd0, 0xef, 0xcb, 0x07, 0x6b, 0x0a, 0xb7, 0xa7, 0xa4,
621 ];
622 assert_eq!(&hdr_key, &expected_hdr_key);
623 }
624}
625
626#[cfg(not(feature = "openssl"))]
627mod boringssl;
628#[cfg(not(feature = "openssl"))]
629pub(crate) use boringssl::*;
630
631#[cfg(feature = "openssl")]
632mod openssl_quictls;
633#[cfg(feature = "openssl")]
634pub(crate) use openssl_quictls::*;