quiche/crypto/
mod.rs

1// Copyright (C) 2018-2019, Cloudflare, Inc.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8//     * Redistributions of source code must retain the above copyright notice,
9//       this list of conditions and the following disclaimer.
10//
11//     * Redistributions in binary form must reproduce the above copyright
12//       notice, this list of conditions and the following disclaimer in the
13//       documentation and/or other materials provided with the distribution.
14//
15// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
16// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
17// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
19// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27use libc::c_int;
28use libc::c_void;
29
30use crate::Error;
31use crate::Result;
32
33use crate::packet;
34
35// All the AEAD algorithms we support use 96-bit nonces.
36pub const MAX_NONCE_LEN: usize = 12;
37
38// Length of header protection mask.
39pub 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
74// Note: some vendor-specific methods are implemented by each vendor's submodule
75// (openssl-quictls / boringssl).
76impl 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    // Note: some vendor-specific methods are implemented by each vendor's
140    // submodule (openssl-quictls / boringssl).
141
142    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    // Note: some vendor-specific methods are implemented by each vendor's
223    // submodule (openssl-quictls / boringssl).
224
225    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, did_reset: 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    derive_client_initial_secret(aead, &initial_secret, &mut client_secret)?;
328
329    derive_server_initial_secret(aead, &initial_secret, &mut server_secret)?;
330
331    // When the initial key material has been reset (e.g. due to retry or
332    // version negotiation), we need to prime the AEAD context as well, as the
333    // following packet will not start from 0 again. This is done through the
334    // `Open/Seal::from_secret()` path, rather than `Open/Seal::new()`.
335    if did_reset {
336        let (open, seal) = if is_server {
337            (
338                Open::from_secret(aead, &client_secret)?,
339                Seal::from_secret(aead, &server_secret)?,
340            )
341        } else {
342            (
343                Open::from_secret(aead, &server_secret)?,
344                Seal::from_secret(aead, &client_secret)?,
345            )
346        };
347
348        return Ok((open, seal));
349    }
350
351    // Client.
352    let mut client_key = vec![0; key_len];
353    let mut client_iv = vec![0; nonce_len];
354    let mut client_hp_key = vec![0; key_len];
355
356    derive_pkt_key(aead, &client_secret, &mut client_key)?;
357    derive_pkt_iv(aead, &client_secret, &mut client_iv)?;
358    derive_hdr_key(aead, &client_secret, &mut client_hp_key)?;
359
360    // Server.
361    let mut server_key = vec![0; key_len];
362    let mut server_iv = vec![0; nonce_len];
363    let mut server_hp_key = vec![0; key_len];
364
365    derive_pkt_key(aead, &server_secret, &mut server_key)?;
366    derive_pkt_iv(aead, &server_secret, &mut server_iv)?;
367    derive_hdr_key(aead, &server_secret, &mut server_hp_key)?;
368
369    let (open, seal) = if is_server {
370        (
371            Open::new(aead, client_key, client_iv, client_hp_key, client_secret)?,
372            Seal::new(aead, server_key, server_iv, server_hp_key, server_secret)?,
373        )
374    } else {
375        (
376            Open::new(aead, server_key, server_iv, server_hp_key, server_secret)?,
377            Seal::new(aead, client_key, client_iv, client_hp_key, client_secret)?,
378        )
379    };
380
381    Ok((open, seal))
382}
383
384fn derive_initial_secret(
385    secret: &[u8], version: u32, out_prk: &mut [u8],
386) -> Result<()> {
387    const INITIAL_SALT_V1: [u8; 20] = [
388        0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17, 0x9a, 0xe6,
389        0xa4, 0xc8, 0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a,
390    ];
391
392    let salt = match version {
393        crate::PROTOCOL_VERSION_V1 => &INITIAL_SALT_V1,
394
395        _ => &INITIAL_SALT_V1,
396    };
397
398    hkdf_extract(Algorithm::AES128_GCM, out_prk, secret, salt)
399}
400
401fn derive_client_initial_secret(
402    aead: Algorithm, prk: &[u8], out: &mut [u8],
403) -> Result<()> {
404    const LABEL: &[u8] = b"client in";
405    hkdf_expand_label(aead, prk, LABEL, out)
406}
407
408fn derive_server_initial_secret(
409    aead: Algorithm, prk: &[u8], out: &mut [u8],
410) -> Result<()> {
411    const LABEL: &[u8] = b"server in";
412    hkdf_expand_label(aead, prk, LABEL, out)
413}
414
415fn derive_next_secret(aead: Algorithm, secret: &[u8]) -> Result<Vec<u8>> {
416    const LABEL: &[u8] = b"quic ku";
417
418    let mut next_secret = vec![0u8; 32];
419
420    hkdf_expand_label(aead, secret, LABEL, &mut next_secret)?;
421
422    Ok(next_secret)
423}
424
425pub fn derive_hdr_key(
426    aead: Algorithm, secret: &[u8], out: &mut [u8],
427) -> Result<()> {
428    const LABEL: &[u8] = b"quic hp";
429
430    let key_len = aead.key_len();
431
432    if key_len > out.len() {
433        return Err(Error::CryptoFail);
434    }
435
436    hkdf_expand_label(aead, secret, LABEL, &mut out[..key_len])
437}
438
439pub fn derive_pkt_key(aead: Algorithm, prk: &[u8], out: &mut [u8]) -> Result<()> {
440    const LABEL: &[u8] = b"quic key";
441
442    let key_len: usize = aead.key_len();
443
444    if key_len > out.len() {
445        return Err(Error::CryptoFail);
446    }
447
448    hkdf_expand_label(aead, prk, LABEL, &mut out[..key_len])
449}
450
451pub fn derive_pkt_iv(aead: Algorithm, prk: &[u8], out: &mut [u8]) -> Result<()> {
452    const LABEL: &[u8] = b"quic iv";
453
454    let nonce_len = aead.nonce_len();
455
456    if nonce_len > out.len() {
457        return Err(Error::CryptoFail);
458    }
459
460    hkdf_expand_label(aead, prk, LABEL, &mut out[..nonce_len])
461}
462
463fn hkdf_expand_label(
464    alg: Algorithm, prk: &[u8], label: &[u8], out: &mut [u8],
465) -> Result<()> {
466    const LABEL_PREFIX: &[u8] = b"tls13 ";
467
468    let out_len = (out.len() as u16).to_be_bytes();
469    let label_len = (LABEL_PREFIX.len() + label.len()) as u8;
470
471    let info = [&out_len, &[label_len][..], LABEL_PREFIX, label, &[0][..]];
472    let info = info.concat();
473
474    hkdf_expand(alg, out, prk, &info)?;
475
476    Ok(())
477}
478
479fn make_nonce(iv: &[u8], counter: u64) -> [u8; MAX_NONCE_LEN] {
480    let mut nonce = [0; MAX_NONCE_LEN];
481    nonce.copy_from_slice(iv);
482
483    // XOR the last bytes of the IV with the counter. This is equivalent to
484    // left-padding the counter with zero bytes.
485    for (a, b) in nonce[4..].iter_mut().zip(counter.to_be_bytes().iter()) {
486        *a ^= b;
487    }
488
489    nonce
490}
491
492pub fn verify_slices_are_equal(a: &[u8], b: &[u8]) -> Result<()> {
493    if a.len() != b.len() {
494        return Err(Error::CryptoFail);
495    }
496
497    let rc = unsafe { CRYPTO_memcmp(a.as_ptr(), b.as_ptr(), a.len()) };
498
499    if rc == 0 {
500        return Ok(());
501    }
502
503    Err(Error::CryptoFail)
504}
505
506extern "C" {
507    fn EVP_sha256() -> *const EVP_MD;
508
509    fn EVP_sha384() -> *const EVP_MD;
510
511    // CRYPTO
512    fn CRYPTO_memcmp(a: *const u8, b: *const u8, len: usize) -> c_int;
513}
514
515#[cfg(test)]
516mod tests {
517    use super::*;
518
519    #[test]
520    fn derive_initial_secrets_v1() {
521        let dcid = [0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08];
522
523        let mut initial_secret = [0; 32];
524
525        let mut secret = [0; 32];
526        let mut pkt_key = [0; 16];
527        let mut pkt_iv = [0; 12];
528        let mut hdr_key = [0; 16];
529
530        let aead = Algorithm::AES128_GCM;
531
532        assert!(derive_initial_secret(
533            &dcid,
534            crate::PROTOCOL_VERSION_V1,
535            &mut initial_secret,
536        )
537        .is_ok());
538
539        // Client.
540        assert!(
541            derive_client_initial_secret(aead, &initial_secret, &mut secret)
542                .is_ok()
543        );
544        let expected_client_initial_secret = [
545            0xc0, 0x0c, 0xf1, 0x51, 0xca, 0x5b, 0xe0, 0x75, 0xed, 0x0e, 0xbf,
546            0xb5, 0xc8, 0x03, 0x23, 0xc4, 0x2d, 0x6b, 0x7d, 0xb6, 0x78, 0x81,
547            0x28, 0x9a, 0xf4, 0x00, 0x8f, 0x1f, 0x6c, 0x35, 0x7a, 0xea,
548        ];
549        assert_eq!(&secret, &expected_client_initial_secret);
550
551        assert!(derive_pkt_key(aead, &secret, &mut pkt_key).is_ok());
552        let expected_client_pkt_key = [
553            0x1f, 0x36, 0x96, 0x13, 0xdd, 0x76, 0xd5, 0x46, 0x77, 0x30, 0xef,
554            0xcb, 0xe3, 0xb1, 0xa2, 0x2d,
555        ];
556        assert_eq!(&pkt_key, &expected_client_pkt_key);
557
558        assert!(derive_pkt_iv(aead, &secret, &mut pkt_iv).is_ok());
559        let expected_client_pkt_iv = [
560            0xfa, 0x04, 0x4b, 0x2f, 0x42, 0xa3, 0xfd, 0x3b, 0x46, 0xfb, 0x25,
561            0x5c,
562        ];
563        assert_eq!(&pkt_iv, &expected_client_pkt_iv);
564
565        assert!(derive_hdr_key(aead, &secret, &mut hdr_key).is_ok());
566        let expected_client_hdr_key = [
567            0x9f, 0x50, 0x44, 0x9e, 0x04, 0xa0, 0xe8, 0x10, 0x28, 0x3a, 0x1e,
568            0x99, 0x33, 0xad, 0xed, 0xd2,
569        ];
570        assert_eq!(&hdr_key, &expected_client_hdr_key);
571
572        // Server.
573        assert!(
574            derive_server_initial_secret(aead, &initial_secret, &mut secret)
575                .is_ok()
576        );
577
578        let expected_server_initial_secret = [
579            0x3c, 0x19, 0x98, 0x28, 0xfd, 0x13, 0x9e, 0xfd, 0x21, 0x6c, 0x15,
580            0x5a, 0xd8, 0x44, 0xcc, 0x81, 0xfb, 0x82, 0xfa, 0x8d, 0x74, 0x46,
581            0xfa, 0x7d, 0x78, 0xbe, 0x80, 0x3a, 0xcd, 0xda, 0x95, 0x1b,
582        ];
583        assert_eq!(&secret, &expected_server_initial_secret);
584
585        assert!(derive_pkt_key(aead, &secret, &mut pkt_key).is_ok());
586        let expected_server_pkt_key = [
587            0xcf, 0x3a, 0x53, 0x31, 0x65, 0x3c, 0x36, 0x4c, 0x88, 0xf0, 0xf3,
588            0x79, 0xb6, 0x06, 0x7e, 0x37,
589        ];
590        assert_eq!(&pkt_key, &expected_server_pkt_key);
591
592        assert!(derive_pkt_iv(aead, &secret, &mut pkt_iv).is_ok());
593        let expected_server_pkt_iv = [
594            0x0a, 0xc1, 0x49, 0x3c, 0xa1, 0x90, 0x58, 0x53, 0xb0, 0xbb, 0xa0,
595            0x3e,
596        ];
597        assert_eq!(&pkt_iv, &expected_server_pkt_iv);
598
599        assert!(derive_hdr_key(aead, &secret, &mut hdr_key).is_ok());
600        let expected_server_hdr_key = [
601            0xc2, 0x06, 0xb8, 0xd9, 0xb9, 0xf0, 0xf3, 0x76, 0x44, 0x43, 0x0b,
602            0x49, 0x0e, 0xea, 0xa3, 0x14,
603        ];
604        assert_eq!(&hdr_key, &expected_server_hdr_key);
605    }
606
607    #[test]
608    fn derive_chacha20_secrets() {
609        let secret = [
610            0x9a, 0xc3, 0x12, 0xa7, 0xf8, 0x77, 0x46, 0x8e, 0xbe, 0x69, 0x42,
611            0x27, 0x48, 0xad, 0x00, 0xa1, 0x54, 0x43, 0xf1, 0x82, 0x03, 0xa0,
612            0x7d, 0x60, 0x60, 0xf6, 0x88, 0xf3, 0x0f, 0x21, 0x63, 0x2b,
613        ];
614
615        let aead = Algorithm::ChaCha20_Poly1305;
616
617        let mut pkt_key = [0; 32];
618        let mut pkt_iv = [0; 12];
619        let mut hdr_key = [0; 32];
620
621        assert!(derive_pkt_key(aead, &secret, &mut pkt_key).is_ok());
622        let expected_pkt_key = [
623            0xc6, 0xd9, 0x8f, 0xf3, 0x44, 0x1c, 0x3f, 0xe1, 0xb2, 0x18, 0x20,
624            0x94, 0xf6, 0x9c, 0xaa, 0x2e, 0xd4, 0xb7, 0x16, 0xb6, 0x54, 0x88,
625            0x96, 0x0a, 0x7a, 0x98, 0x49, 0x79, 0xfb, 0x23, 0xe1, 0xc8,
626        ];
627        assert_eq!(&pkt_key, &expected_pkt_key);
628
629        assert!(derive_pkt_iv(aead, &secret, &mut pkt_iv).is_ok());
630        let expected_pkt_iv = [
631            0xe0, 0x45, 0x9b, 0x34, 0x74, 0xbd, 0xd0, 0xe4, 0x4a, 0x41, 0xc1,
632            0x44,
633        ];
634        assert_eq!(&pkt_iv, &expected_pkt_iv);
635
636        assert!(derive_hdr_key(aead, &secret, &mut hdr_key).is_ok());
637        let expected_hdr_key = [
638            0x25, 0xa2, 0x82, 0xb9, 0xe8, 0x2f, 0x06, 0xf2, 0x1f, 0x48, 0x89,
639            0x17, 0xa4, 0xfc, 0x8f, 0x1b, 0x73, 0x57, 0x36, 0x85, 0x60, 0x85,
640            0x97, 0xd0, 0xef, 0xcb, 0x07, 0x6b, 0x0a, 0xb7, 0xa7, 0xa4,
641        ];
642        assert_eq!(&hdr_key, &expected_hdr_key);
643    }
644}
645
646#[cfg(not(feature = "openssl"))]
647mod boringssl;
648#[cfg(not(feature = "openssl"))]
649pub(crate) use boringssl::*;
650
651#[cfg(feature = "openssl")]
652mod openssl_quictls;
653#[cfg(feature = "openssl")]
654pub(crate) use openssl_quictls::*;