quiche/crypto/
openssl_quictls.rs

1use super::*;
2
3use libc::c_int;
4use libc::c_uchar;
5
6#[allow(non_camel_case_types)]
7#[repr(transparent)]
8struct EVP_CIPHER_CTX {
9    _unused: *mut EVP_CIPHER_CTX,
10}
11
12#[allow(non_camel_case_types)]
13#[repr(transparent)]
14struct EVP_PKEY_CTX {
15    _unused: c_void,
16}
17
18#[allow(non_camel_case_types)]
19#[repr(transparent)]
20struct OSSL_PARAM {
21    _unused: c_void,
22}
23
24impl Algorithm {
25    pub fn get_evp(self) -> *const EVP_AEAD {
26        match self {
27            Algorithm::AES128_GCM => unsafe { EVP_aes_128_ctr() },
28            Algorithm::AES256_GCM => unsafe { EVP_aes_256_ctr() },
29            Algorithm::ChaCha20_Poly1305 => unsafe { EVP_chacha20() },
30        }
31    }
32
33    pub fn get_evp_aead(self) -> *const EVP_AEAD {
34        match self {
35            Algorithm::AES128_GCM => unsafe { EVP_aes_128_gcm() },
36            Algorithm::AES256_GCM => unsafe { EVP_aes_256_gcm() },
37            Algorithm::ChaCha20_Poly1305 => unsafe { EVP_chacha20_poly1305() },
38        }
39    }
40}
41
42pub(crate) struct PacketKey {
43    alg: Algorithm,
44
45    ctx: *mut EVP_CIPHER_CTX,
46
47    nonce: Vec<u8>,
48
49    // Note: We'd need the key for later use as it is needed by the openssl API.
50    // TODO: check if we can avoid this and get the key when needed and not
51    // have it stored here.
52    key: Vec<u8>,
53}
54
55impl PacketKey {
56    pub fn new(
57        alg: Algorithm, key: Vec<u8>, iv: Vec<u8>, enc: u32,
58    ) -> Result<Self> {
59        Ok(Self {
60            alg,
61            ctx: make_evp_cipher_ctx_basic(alg, true, enc)?,
62            nonce: iv,
63            key,
64        })
65    }
66
67    pub fn from_secret(aead: Algorithm, secret: &[u8], enc: u32) -> Result<Self> {
68        let key_len = aead.key_len();
69        let nonce_len = aead.nonce_len();
70
71        let mut key = vec![0; key_len];
72        let mut iv = vec![0; nonce_len];
73
74        derive_pkt_key(aead, secret, &mut key)?;
75        derive_pkt_iv(aead, secret, &mut iv)?;
76
77        Self::new(aead, key, iv, enc)
78    }
79
80    pub fn open_with_u64_counter(
81        &self, counter: u64, ad: &[u8], buf: &mut [u8],
82    ) -> Result<usize> {
83        let tag_len = self.alg.tag_len();
84
85        let in_buf = buf.to_owned(); // very inefficient
86
87        let mut cipher_len = buf.len();
88
89        let nonce = make_nonce(&self.nonce, counter);
90
91        // Set the IV len.
92        const EVP_CTRL_AEAD_SET_IVLEN: i32 = 0x9;
93        let mut rc = unsafe {
94            EVP_CIPHER_CTX_ctrl(
95                self.ctx,
96                EVP_CTRL_AEAD_SET_IVLEN,
97                nonce.len() as i32,
98                std::ptr::null_mut(),
99            )
100        };
101        if rc != 1 {
102            return Err(Error::CryptoFail);
103        }
104
105        rc = unsafe {
106            EVP_CipherInit_ex2(
107                self.ctx,
108                std::ptr::null_mut(), // already set
109                self.key.as_ptr(),
110                nonce[..].as_ptr(),
111                Open::DECRYPT as i32,
112                std::ptr::null(),
113            )
114        };
115
116        if rc != 1 {
117            return Err(Error::CryptoFail);
118        }
119
120        let mut olen: i32 = 0;
121
122        if !ad.is_empty() {
123            rc = unsafe {
124                EVP_CipherUpdate(
125                    self.ctx,
126                    std::ptr::null_mut(),
127                    &mut olen,
128                    ad.as_ptr(),
129                    ad.len() as i32,
130                )
131            };
132
133            if rc != 1 {
134                return Err(Error::CryptoFail);
135            }
136        }
137
138        if cipher_len < tag_len {
139            return Err(Error::CryptoFail);
140        }
141
142        cipher_len -= tag_len;
143
144        rc = unsafe {
145            EVP_CipherUpdate(
146                self.ctx,
147                buf.as_mut_ptr(),
148                &mut olen,
149                in_buf.as_ptr(),
150                cipher_len as i32,
151            )
152        };
153
154        if rc != 1 {
155            return Err(Error::CryptoFail);
156        }
157
158        let plaintext_len = olen as usize;
159
160        const EVP_CTRL_AEAD_SET_TAG: i32 = 0x11;
161        rc = unsafe {
162            EVP_CIPHER_CTX_ctrl(
163                self.ctx,
164                EVP_CTRL_AEAD_SET_TAG,
165                tag_len as i32,
166                buf[cipher_len..].as_mut_ptr() as *mut c_void,
167            )
168        };
169
170        if rc != 1 {
171            return Err(Error::CryptoFail);
172        }
173
174        rc = unsafe {
175            EVP_CipherFinal_ex(
176                self.ctx,
177                buf[plaintext_len..].as_mut_ptr(),
178                &mut olen,
179            )
180        };
181
182        if rc != 1 {
183            return Err(Error::CryptoFail);
184        }
185
186        Ok(plaintext_len + olen as usize)
187    }
188
189    pub fn seal_with_u64_counter(
190        &self, counter: u64, ad: &[u8], buf: &mut [u8], in_len: usize,
191        _extra_in: Option<&[u8]>,
192    ) -> Result<usize> {
193        let tag_len = self.alg.tag_len();
194
195        // TODO: replace this with something more efficient.
196        let in_buf = buf.to_owned();
197
198        let nonce = make_nonce(&self.nonce, counter);
199
200        // Set the IV len.
201        const EVP_CTRL_AEAD_SET_IVLEN: i32 = 0x9;
202        let mut rc = unsafe {
203            EVP_CIPHER_CTX_ctrl(
204                self.ctx,
205                EVP_CTRL_AEAD_SET_IVLEN,
206                nonce.len() as i32,
207                std::ptr::null_mut(),
208            )
209        };
210
211        if rc != 1 {
212            return Err(Error::CryptoFail);
213        }
214
215        rc = unsafe {
216            EVP_CipherInit_ex2(
217                self.ctx,
218                std::ptr::null_mut(), // already set
219                self.key.as_ptr(),
220                nonce[..].as_ptr(),
221                Seal::ENCRYPT as i32,
222                std::ptr::null(),
223            )
224        };
225        if rc != 1 {
226            return Err(Error::CryptoFail);
227        }
228
229        let mut olen: i32 = 0;
230        let mut rc;
231
232        if !ad.is_empty() {
233            rc = unsafe {
234                EVP_CipherUpdate(
235                    self.ctx,
236                    std::ptr::null_mut(),
237                    &mut olen,
238                    ad.as_ptr(),
239                    ad.len() as i32,
240                )
241            };
242
243            if rc != 1 {
244                // We had AD but we couldn't set it.
245                return Err(Error::CryptoFail);
246            }
247        }
248
249        let mut ciphertext_len: usize = 0;
250
251        rc = unsafe {
252            EVP_CipherUpdate(
253                self.ctx,
254                buf.as_mut_ptr(),
255                &mut olen,
256                in_buf.as_ptr(),
257                in_len as i32,
258            )
259        };
260
261        if rc != 1 {
262            return Err(Error::CryptoFail);
263        };
264
265        ciphertext_len += olen as usize;
266
267        let len = olen as usize;
268        rc = unsafe {
269            EVP_CipherFinal_ex(self.ctx, buf[len..].as_mut_ptr(), &mut olen)
270        };
271
272        if rc != 1 {
273            return Err(Error::CryptoFail);
274        }
275
276        ciphertext_len += olen as usize;
277
278        const EVP_CTRL_AEAD_GET_TAG: i32 = 0x10;
279        rc = unsafe {
280            EVP_CIPHER_CTX_ctrl(
281                self.ctx,
282                EVP_CTRL_AEAD_GET_TAG,
283                tag_len as i32,
284                buf[ciphertext_len..].as_mut_ptr() as *mut c_void,
285            )
286        };
287
288        if rc != 1 {
289            return Err(Error::CryptoFail);
290        }
291
292        Ok(in_len + tag_len)
293    }
294}
295
296impl Drop for PacketKey {
297    fn drop(&mut self) {
298        unsafe { EVP_CIPHER_CTX_free(self.ctx) }
299    }
300}
301
302unsafe impl std::marker::Send for PacketKey {}
303unsafe impl std::marker::Sync for PacketKey {}
304
305pub(crate) struct HeaderProtectionKey {
306    ctx: *mut EVP_CIPHER_CTX,
307
308    key: Vec<u8>,
309}
310
311impl HeaderProtectionKey {
312    pub fn new(alg: Algorithm, hp_key: Vec<u8>) -> Result<Self> {
313        Ok(Self {
314            ctx: make_evp_cipher_ctx_basic(alg, false, 1)?,
315            key: hp_key,
316        })
317    }
318
319    pub fn new_mask(&self, sample: &[u8]) -> Result<HeaderProtectionMask> {
320        const PLAINTEXT: &[u8; 5] = &[0_u8; 5];
321
322        let mut new_mask = HeaderProtectionMask::default();
323
324        // Set IV (i.e. the sample).
325        let rc = unsafe {
326            EVP_CipherInit_ex2(
327                self.ctx,
328                std::ptr::null_mut(), // already set
329                self.key.as_ptr(),
330                sample.as_ptr(),
331                -1,
332                std::ptr::null(),
333            )
334        };
335
336        if rc != 1 {
337            return Err(Error::CryptoFail);
338        }
339
340        let mut out_len: i32 = 0;
341
342        let rc = unsafe {
343            EVP_CipherUpdate(
344                self.ctx,
345                new_mask.as_mut_ptr(),
346                &mut out_len,
347                PLAINTEXT.as_ptr(),
348                PLAINTEXT.len() as i32,
349            )
350        };
351
352        if rc != 1 {
353            return Err(Error::CryptoFail);
354        };
355
356        let rc = unsafe {
357            EVP_CipherFinal_ex(
358                self.ctx,
359                new_mask[out_len as usize..].as_mut_ptr(),
360                &mut out_len,
361            )
362        };
363
364        if rc != 1 {
365            return Err(Error::CryptoFail);
366        }
367
368        Ok(new_mask)
369    }
370}
371
372impl Clone for HeaderProtectionKey {
373    fn clone(&self) -> Self {
374        let ctx = unsafe { EVP_CIPHER_CTX_dup(self.ctx) };
375
376        Self {
377            ctx,
378            key: self.key.clone(),
379        }
380    }
381}
382
383impl Drop for HeaderProtectionKey {
384    fn drop(&mut self) {
385        unsafe { EVP_CIPHER_CTX_free(self.ctx) }
386    }
387}
388
389unsafe impl std::marker::Send for HeaderProtectionKey {}
390unsafe impl std::marker::Sync for HeaderProtectionKey {}
391
392fn make_evp_cipher_ctx_basic(
393    alg: Algorithm, aead: bool, enc: u32,
394) -> Result<*mut EVP_CIPHER_CTX> {
395    let ctx: *mut EVP_CIPHER_CTX = unsafe {
396        let cipher: *const EVP_AEAD = if aead {
397            alg.get_evp_aead()
398        } else {
399            alg.get_evp()
400        };
401
402        let ctx = EVP_CIPHER_CTX_new();
403
404        if ctx.is_null() {
405            return Err(Error::CryptoFail);
406        }
407
408        let rc = EVP_CipherInit_ex2(
409            ctx,
410            cipher,
411            std::ptr::null_mut(),
412            std::ptr::null_mut(),
413            enc as c_int, // Following calls can use -1 once this is set.
414            std::ptr::null(),
415        );
416
417        if rc != 1 {
418            return Err(Error::CryptoFail);
419        }
420
421        ctx
422    };
423
424    Ok(ctx)
425}
426
427pub(crate) fn hkdf_extract(
428    alg: Algorithm, out: &mut [u8], secret: &[u8], salt: &[u8],
429) -> Result<()> {
430    let mut out_len = out.len();
431
432    unsafe {
433        let prf = alg.get_evp_digest();
434
435        let ctx = EVP_PKEY_CTX_new_id(
436            1036, // EVP_PKEY_HKDF
437            std::ptr::null_mut(),
438        );
439
440        if EVP_PKEY_derive_init(ctx) != 1 ||
441            EVP_PKEY_CTX_set_hkdf_mode(
442                ctx, 1, // EVP_PKEY_HKDF_MODE_EXTRACT_ONLY
443            ) != 1 ||
444            EVP_PKEY_CTX_set_hkdf_md(ctx, prf) != 1 ||
445            EVP_PKEY_CTX_set1_hkdf_salt(ctx, salt.as_ptr(), salt.len()) != 1 ||
446            EVP_PKEY_CTX_set1_hkdf_key(ctx, secret.as_ptr(), secret.len()) != 1 ||
447            EVP_PKEY_derive(ctx, out.as_mut_ptr(), &mut out_len) != 1
448        {
449            EVP_PKEY_CTX_free(ctx);
450            return Err(Error::CryptoFail);
451        }
452
453        EVP_PKEY_CTX_free(ctx);
454    }
455
456    Ok(())
457}
458
459pub(crate) fn hkdf_expand(
460    alg: Algorithm, out: &mut [u8], secret: &[u8], info: &[u8],
461) -> Result<()> {
462    let mut out_len = out.len();
463
464    unsafe {
465        let prf = alg.get_evp_digest();
466
467        let ctx = EVP_PKEY_CTX_new_id(
468            1036, // EVP_PKEY_HKDF
469            std::ptr::null_mut(),
470        );
471
472        if EVP_PKEY_derive_init(ctx) != 1 ||
473            EVP_PKEY_CTX_set_hkdf_mode(
474                ctx, 2, // EVP_PKEY_HKDF_MODE_EXPAND_ONLY
475            ) != 1 ||
476            EVP_PKEY_CTX_set_hkdf_md(ctx, prf) != 1 ||
477            EVP_PKEY_CTX_set1_hkdf_key(ctx, secret.as_ptr(), secret.len()) != 1 ||
478            EVP_PKEY_CTX_add1_hkdf_info(ctx, info.as_ptr(), info.len()) != 1 ||
479            EVP_PKEY_derive(ctx, out.as_mut_ptr(), &mut out_len) != 1
480        {
481            EVP_PKEY_CTX_free(ctx);
482            return Err(Error::CryptoFail);
483        }
484
485        EVP_PKEY_CTX_free(ctx);
486    }
487
488    Ok(())
489}
490
491extern "C" {
492    // EVP
493    fn EVP_aes_128_ctr() -> *const EVP_AEAD;
494    fn EVP_aes_128_gcm() -> *const EVP_AEAD;
495
496    fn EVP_aes_256_ctr() -> *const EVP_AEAD;
497    fn EVP_aes_256_gcm() -> *const EVP_AEAD;
498
499    fn EVP_chacha20() -> *const EVP_AEAD;
500    fn EVP_chacha20_poly1305() -> *const EVP_AEAD;
501
502    // EVP_CIPHER_CTX
503    fn EVP_CIPHER_CTX_new() -> *mut EVP_CIPHER_CTX;
504
505    fn EVP_CIPHER_CTX_dup(ctx: *const EVP_CIPHER_CTX) -> *mut EVP_CIPHER_CTX;
506
507    fn EVP_CIPHER_CTX_free(ctx: *mut EVP_CIPHER_CTX);
508
509    fn EVP_CipherInit_ex2(
510        ctx: *mut EVP_CIPHER_CTX, cipher: *const EVP_AEAD, key: *const c_uchar,
511        iv: *const c_uchar, enc: c_int, params: *const OSSL_PARAM,
512    ) -> c_int;
513
514    fn EVP_CIPHER_CTX_ctrl(
515        ctx: *mut EVP_CIPHER_CTX, type_: i32, arg: i32, ptr: *mut c_void,
516    ) -> c_int;
517
518    fn EVP_CipherUpdate(
519        ctx: *mut EVP_CIPHER_CTX, out: *mut c_uchar, outl: *mut c_int,
520        in_: *const c_uchar, inl: i32,
521    ) -> c_int;
522
523    fn EVP_CipherFinal_ex(
524        ctx: *mut EVP_CIPHER_CTX, out: *mut c_uchar, outl: *mut c_int,
525    ) -> c_int;
526
527    // EVP_PKEY
528    fn EVP_PKEY_CTX_new_id(id: c_int, e: *mut c_void) -> *mut EVP_PKEY_CTX;
529
530    fn EVP_PKEY_CTX_set_hkdf_mode(ctx: *mut EVP_PKEY_CTX, mode: c_int) -> c_int;
531    fn EVP_PKEY_CTX_set_hkdf_md(
532        ctx: *mut EVP_PKEY_CTX, md: *const EVP_MD,
533    ) -> c_int;
534    fn EVP_PKEY_CTX_set1_hkdf_salt(
535        ctx: *mut EVP_PKEY_CTX, salt: *const u8, salt_len: usize,
536    ) -> c_int;
537    fn EVP_PKEY_CTX_set1_hkdf_key(
538        ctx: *mut EVP_PKEY_CTX, key: *const u8, key_len: usize,
539    ) -> c_int;
540    fn EVP_PKEY_CTX_add1_hkdf_info(
541        ctx: *mut EVP_PKEY_CTX, info: *const u8, info_len: usize,
542    ) -> c_int;
543
544    fn EVP_PKEY_derive_init(ctx: *mut EVP_PKEY_CTX) -> c_int;
545
546    fn EVP_PKEY_derive(
547        ctx: *mut EVP_PKEY_CTX, key: *mut u8, key_len: *mut usize,
548    ) -> c_int;
549
550    fn EVP_PKEY_CTX_free(ctx: *mut EVP_PKEY_CTX);
551}