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,
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    // Client.
328    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    // Server.
339    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    // XOR the last bytes of the IV with the counter. This is equivalent to
464    // left-padding the counter with zero bytes.
465    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    // CRYPTO
492    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        // Client.
520        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        // Server.
553        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::*;