Skip to main content

quiche/tls/
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 std::ffi;
28use std::mem::ManuallyDrop;
29use std::ptr;
30use std::ptr::NonNull;
31use std::slice;
32
33use std::io::Write;
34
35use std::sync::LazyLock;
36
37use libc::c_char;
38use libc::c_int;
39use libc::c_uint;
40use libc::c_void;
41
42use crate::Error;
43use crate::Result;
44
45use crate::Connection;
46use crate::ConnectionError;
47
48use crate::crypto;
49use crate::packet;
50
51const TLS1_3_VERSION: u16 = 0x0304;
52const TLS_ALERT_ERROR: u64 = 0x100;
53const INTERNAL_ERROR: u64 = 0x01;
54
55#[allow(non_camel_case_types)]
56#[repr(transparent)]
57struct SSL_METHOD {
58    _unused: c_void,
59}
60
61#[allow(non_camel_case_types)]
62#[repr(transparent)]
63struct SSL_CTX {
64    _unused: c_void,
65}
66
67#[allow(non_camel_case_types)]
68#[repr(transparent)]
69struct SSL {
70    _unused: c_void,
71}
72
73#[allow(non_camel_case_types)]
74#[repr(transparent)]
75struct SSL_CIPHER {
76    _unused: c_void,
77}
78
79#[allow(non_camel_case_types)]
80#[repr(transparent)]
81struct SSL_SESSION {
82    _unused: c_void,
83}
84
85#[allow(non_camel_case_types)]
86#[repr(transparent)]
87struct X509_VERIFY_PARAM {
88    _unused: c_void,
89}
90
91#[allow(non_camel_case_types)]
92#[repr(transparent)]
93#[cfg(windows)]
94struct X509_STORE {
95    _unused: c_void,
96}
97
98#[allow(non_camel_case_types)]
99#[repr(transparent)]
100struct X509_STORE_CTX {
101    _unused: c_void,
102}
103
104#[allow(non_camel_case_types)]
105#[repr(transparent)]
106#[cfg(windows)]
107struct X509 {
108    _unused: c_void,
109}
110
111#[allow(non_camel_case_types)]
112#[repr(transparent)]
113struct STACK_OF {
114    _unused: c_void,
115}
116
117#[cfg(test)]
118#[repr(C)]
119#[allow(non_camel_case_types)]
120#[allow(dead_code)]
121enum ssl_private_key_result_t {
122    ssl_private_key_success,
123    ssl_private_key_retry,
124    ssl_private_key_failure,
125}
126
127/// BoringSSL ex_data index for quiche connections.
128pub static QUICHE_EX_DATA_INDEX: LazyLock<c_int> = LazyLock::new(|| unsafe {
129    SSL_get_ex_new_index(0, ptr::null(), ptr::null(), ptr::null(), ptr::null())
130});
131
132pub struct Context(NonNull<SSL_CTX>);
133
134impl Context {
135    // Note: some vendor-specific methods are implemented in the boringssl
136    // submodule.
137    pub fn new() -> Result<Context> {
138        unsafe {
139            let ctx_raw =
140                NonNull::new(SSL_CTX_new(TLS_method())).ok_or(Error::TlsFail)?;
141
142            let mut ctx = Context(ctx_raw);
143
144            ctx.set_session_callback();
145
146            ctx.load_ca_certs()?;
147
148            Ok(ctx)
149        }
150    }
151
152    #[cfg(feature = "boringssl-boring-crate")]
153    pub fn from_boring(
154        ssl_ctx_builder: boring::ssl::SslContextBuilder,
155    ) -> Result<Context> {
156        use foreign_types_shared::ForeignType;
157
158        let ctx_raw = NonNull::new(ssl_ctx_builder.build().into_ptr() as _)
159            .ok_or(Error::TlsFail)?;
160
161        let mut ctx = Context(ctx_raw);
162        ctx.set_session_callback();
163
164        Ok(ctx)
165    }
166
167    pub fn new_handshake(&mut self) -> Result<Handshake> {
168        unsafe {
169            let ssl =
170                NonNull::new(SSL_new(self.as_mut_ptr())).ok_or(Error::TlsFail)?;
171
172            Ok(Handshake::new(ssl))
173        }
174    }
175
176    pub fn load_verify_locations_from_file(&mut self, file: &str) -> Result<()> {
177        let file = ffi::CString::new(file).map_err(|_| Error::TlsFail)?;
178        map_result(unsafe {
179            SSL_CTX_load_verify_locations(
180                self.as_mut_ptr(),
181                file.as_ptr(),
182                ptr::null(),
183            )
184        })
185    }
186
187    pub fn load_verify_locations_from_directory(
188        &mut self, path: &str,
189    ) -> Result<()> {
190        let path = ffi::CString::new(path).map_err(|_| Error::TlsFail)?;
191        map_result(unsafe {
192            SSL_CTX_load_verify_locations(
193                self.as_mut_ptr(),
194                ptr::null(),
195                path.as_ptr(),
196            )
197        })
198    }
199
200    pub fn use_certificate_chain_file(&mut self, file: &str) -> Result<()> {
201        let cstr = ffi::CString::new(file).map_err(|_| Error::TlsFail)?;
202        map_result(unsafe {
203            SSL_CTX_use_certificate_chain_file(self.as_mut_ptr(), cstr.as_ptr())
204        })
205    }
206
207    pub fn use_privkey_file(&mut self, file: &str) -> Result<()> {
208        let cstr = ffi::CString::new(file).map_err(|_| Error::TlsFail)?;
209        map_result(unsafe {
210            SSL_CTX_use_PrivateKey_file(self.as_mut_ptr(), cstr.as_ptr(), 1)
211        })
212    }
213
214    #[cfg(not(windows))]
215    fn load_ca_certs(&mut self) -> Result<()> {
216        unsafe { map_result(SSL_CTX_set_default_verify_paths(self.as_mut_ptr())) }
217    }
218
219    #[cfg(windows)]
220    fn load_ca_certs(&mut self) -> Result<()> {
221        unsafe {
222            let cstr = ffi::CString::new("Root").map_err(|_| Error::TlsFail)?;
223            let sys_store =
224                windows_sys::Win32::Security::Cryptography::CertOpenSystemStoreA(
225                    0,
226                    cstr.as_ptr() as windows_sys::core::PCSTR,
227                );
228            if sys_store.is_null() {
229                return Err(Error::TlsFail);
230            }
231
232            let ctx_store = SSL_CTX_get_cert_store(self.as_mut_ptr());
233            if ctx_store.is_null() {
234                return Err(Error::TlsFail);
235            }
236
237            let mut ctx_p = windows_sys::Win32::Security::Cryptography::CertEnumCertificatesInStore(
238                sys_store,
239                ptr::null(),
240            );
241
242            while !ctx_p.is_null() {
243                let in_p = (*ctx_p).pbCertEncoded as *const u8;
244
245                let cert = d2i_X509(
246                    ptr::null_mut(),
247                    &in_p,
248                    (*ctx_p).cbCertEncoded as i32,
249                );
250                if !cert.is_null() {
251                    X509_STORE_add_cert(ctx_store, cert);
252                }
253
254                X509_free(cert);
255
256                ctx_p = windows_sys::Win32::Security::Cryptography::CertEnumCertificatesInStore(
257                    sys_store, ctx_p,
258                );
259            }
260
261            // tidy up
262            windows_sys::Win32::Security::Cryptography::CertFreeCertificateContext(ctx_p);
263            windows_sys::Win32::Security::Cryptography::CertCloseStore(
264                sys_store, 0,
265            );
266        }
267
268        Ok(())
269    }
270
271    fn set_session_callback(&mut self) {
272        unsafe {
273            // This is needed to enable the session callback on the client. On
274            // the server it doesn't do anything.
275            SSL_CTX_set_session_cache_mode(
276                self.as_mut_ptr(),
277                0x0001, // SSL_SESS_CACHE_CLIENT
278            );
279
280            SSL_CTX_sess_set_new_cb(self.as_mut_ptr(), Some(new_session));
281        };
282    }
283
284    pub fn set_verify(&mut self, verify: bool) {
285        // true  -> 0x01 SSL_VERIFY_PEER
286        // false -> 0x00 SSL_VERIFY_NONE
287        let mode = i32::from(verify);
288
289        // The two modes above work for both BoringSSL and OpenSSL. This may
290        // need adjustment if modes must be combined.
291        unsafe {
292            SSL_CTX_set_verify(self.as_mut_ptr(), mode, None);
293        }
294    }
295
296    pub fn enable_keylog(&mut self) {
297        unsafe {
298            SSL_CTX_set_keylog_callback(self.as_mut_ptr(), Some(keylog));
299        }
300    }
301
302    pub fn set_alpn(&mut self, v: &[&[u8]]) -> Result<()> {
303        let mut protos: Vec<u8> = Vec::new();
304
305        for proto in v {
306            protos.push(proto.len() as u8);
307            protos.extend_from_slice(proto);
308        }
309
310        // Configure ALPN for servers.
311        unsafe {
312            SSL_CTX_set_alpn_select_cb(
313                self.as_mut_ptr(),
314                Some(select_alpn),
315                ptr::null_mut(),
316            );
317        }
318
319        // Configure ALPN for clients.
320        map_result_zero_is_success(unsafe {
321            SSL_CTX_set_alpn_protos(
322                self.as_mut_ptr(),
323                protos.as_ptr(),
324                protos.len(),
325            )
326        })
327    }
328
329    pub fn set_ticket_key(&mut self, key: &[u8]) -> Result<()> {
330        map_result(unsafe {
331            SSL_CTX_set_tlsext_ticket_keys(
332                self.as_mut_ptr(),
333                key.as_ptr(),
334                key.len(),
335            )
336        })
337    }
338
339    pub fn set_curves_list(&mut self, curves: &str) -> Result<()> {
340        // Note: BoringSSL exports `SSL_CTX_set1_groups_list` as a real
341        // function; OpenSSL (and openssl-quictls) defines it as a macro
342        // that expands to `SSL_CTX_ctrl`. Each backend provides a
343        // `SSL_CTX_set1_groups_list` shim in the per-vendor module so this
344        // call site can be backend-agnostic.
345        let cstr = ffi::CString::new(curves).map_err(|_| Error::TlsFail)?;
346        map_result(unsafe {
347            SSL_CTX_set1_groups_list(self.as_mut_ptr(), cstr.as_ptr())
348        })
349    }
350
351    fn as_mut_ptr(&mut self) -> *mut SSL_CTX {
352        self.0.as_ptr()
353    }
354}
355
356// These traits are not automatically implemented because NonNull does not
357// convey ownership. Context uniquely owns the underlying data, and its API
358// preserves Rust's borrowing guarantees.
359unsafe impl Send for Context {}
360unsafe impl Sync for Context {}
361
362impl Drop for Context {
363    fn drop(&mut self) {
364        unsafe { SSL_CTX_free(self.as_mut_ptr()) }
365    }
366}
367
368pub struct Handshake {
369    ptr: NonNull<SSL>,
370    /// SSL_process_quic_post_handshake should be called when whenever
371    /// SSL_provide_quic_data is called to process the provided data.
372    provided_data_outstanding: bool,
373}
374
375impl Handshake {
376    // Note: some vendor-specific methods are implemented in the boringssl
377    // submodule.
378    #[cfg(any(feature = "ffi", feature = "boringssl-boring-crate"))]
379    pub unsafe fn from_ptr(ssl: *mut c_void) -> Result<Handshake> {
380        let ptr = NonNull::new(ssl.cast()).ok_or(Error::TlsFail)?;
381
382        Ok(Handshake::new(ptr))
383    }
384
385    fn new(ptr: NonNull<SSL>) -> Handshake {
386        Handshake {
387            ptr,
388            provided_data_outstanding: false,
389        }
390    }
391
392    pub fn get_error(&self, ret_code: c_int) -> c_int {
393        unsafe { SSL_get_error(self.as_ptr(), ret_code) }
394    }
395
396    pub fn init(&mut self, is_server: bool) -> Result<()> {
397        self.set_state(is_server);
398
399        self.set_min_proto_version(TLS1_3_VERSION)?;
400        self.set_max_proto_version(TLS1_3_VERSION)?;
401
402        self.set_quic_method()?;
403
404        // TODO: the early data context should include transport parameters and
405        // HTTP/3 SETTINGS in wire format.
406        self.set_quic_early_data_context(b"quiche")?;
407
408        self.set_quiet_shutdown(true);
409
410        Ok(())
411    }
412
413    pub fn use_legacy_codepoint(&mut self, use_legacy: bool) {
414        unsafe {
415            SSL_set_quic_use_legacy_codepoint(
416                self.as_mut_ptr(),
417                use_legacy as c_int,
418            );
419        }
420    }
421
422    pub fn set_state(&mut self, is_server: bool) {
423        unsafe {
424            if is_server {
425                SSL_set_accept_state(self.as_mut_ptr());
426            } else {
427                SSL_set_connect_state(self.as_mut_ptr());
428            }
429        }
430    }
431
432    pub fn set_ex_data<T>(&mut self, idx: c_int, data: *const T) -> Result<()> {
433        map_result(unsafe {
434            let ptr = data as *mut c_void;
435            SSL_set_ex_data(self.as_mut_ptr(), idx, ptr)
436        })
437    }
438
439    pub fn set_quic_method(&mut self) -> Result<()> {
440        map_result(unsafe {
441            SSL_set_quic_method(self.as_mut_ptr(), &QUICHE_STREAM_METHOD)
442        })
443    }
444
445    pub fn set_min_proto_version(&mut self, version: u16) -> Result<()> {
446        map_result(unsafe {
447            SSL_set_min_proto_version(self.as_mut_ptr(), version)
448        })
449    }
450
451    pub fn set_max_proto_version(&mut self, version: u16) -> Result<()> {
452        map_result(unsafe {
453            SSL_set_max_proto_version(self.as_mut_ptr(), version)
454        })
455    }
456
457    pub fn set_quiet_shutdown(&mut self, mode: bool) {
458        unsafe { SSL_set_quiet_shutdown(self.as_mut_ptr(), i32::from(mode)) }
459    }
460
461    pub fn set_host_name(&mut self, name: &str) -> Result<()> {
462        let cstr = ffi::CString::new(name).map_err(|_| Error::TlsFail)?;
463        let rc =
464            unsafe { SSL_set_tlsext_host_name(self.as_mut_ptr(), cstr.as_ptr()) };
465        self.map_result_ssl(rc)?;
466
467        let param = unsafe { SSL_get0_param(self.as_mut_ptr()) };
468
469        map_result(unsafe {
470            X509_VERIFY_PARAM_set1_host(param, cstr.as_ptr(), name.len())
471        })
472    }
473
474    pub fn set_quic_transport_params(
475        &mut self, params: &crate::TransportParams, is_server: bool,
476    ) -> Result<()> {
477        let mut raw_params = [0; 128];
478
479        let raw_params =
480            crate::TransportParams::encode(params, is_server, &mut raw_params)?;
481
482        let rc = unsafe {
483            SSL_set_quic_transport_params(
484                self.as_mut_ptr(),
485                raw_params.as_ptr(),
486                raw_params.len(),
487            )
488        };
489        self.map_result_ssl(rc)
490    }
491
492    pub fn quic_transport_params(&self) -> &[u8] {
493        let mut ptr: *const u8 = ptr::null();
494        let mut len: usize = 0;
495
496        unsafe {
497            SSL_get_peer_quic_transport_params(self.as_ptr(), &mut ptr, &mut len);
498        }
499
500        if len == 0 {
501            return &mut [];
502        }
503
504        unsafe { slice::from_raw_parts(ptr, len) }
505    }
506
507    pub fn alpn_protocol(&self) -> &[u8] {
508        let mut ptr: *const u8 = ptr::null();
509        let mut len: u32 = 0;
510
511        unsafe {
512            SSL_get0_alpn_selected(self.as_ptr(), &mut ptr, &mut len);
513        }
514
515        if len == 0 {
516            return &mut [];
517        }
518
519        unsafe { slice::from_raw_parts(ptr, len as usize) }
520    }
521
522    pub fn server_name(&self) -> Option<&str> {
523        let s = unsafe {
524            let ptr = SSL_get_servername(
525                self.as_ptr(),
526                0, // TLSEXT_NAMETYPE_host_name
527            );
528
529            if ptr.is_null() {
530                return None;
531            }
532
533            ffi::CStr::from_ptr(ptr)
534        };
535
536        s.to_str().ok()
537    }
538
539    pub fn provide_data(
540        &mut self, level: crypto::Level, buf: &[u8],
541    ) -> Result<()> {
542        self.provided_data_outstanding = true;
543        let rc = unsafe {
544            SSL_provide_quic_data(
545                self.as_mut_ptr(),
546                level,
547                buf.as_ptr(),
548                buf.len(),
549            )
550        };
551        self.map_result_ssl(rc)
552    }
553
554    pub fn do_handshake(&mut self, ex_data: &mut ExData) -> Result<()> {
555        self.set_ex_data(*QUICHE_EX_DATA_INDEX, ex_data)?;
556        let rc = unsafe { SSL_do_handshake(self.as_mut_ptr()) };
557        self.set_ex_data::<Connection>(*QUICHE_EX_DATA_INDEX, ptr::null())?;
558
559        self.set_transport_error(ex_data, rc);
560        self.map_result_ssl(rc)
561    }
562
563    pub fn process_post_handshake(&mut self, ex_data: &mut ExData) -> Result<()> {
564        // If SSL_provide_quic_data hasn't been called since we last called
565        // SSL_process_quic_post_handshake, then there's nothing to do.
566        if !self.provided_data_outstanding {
567            return Ok(());
568        }
569        self.provided_data_outstanding = false;
570
571        self.set_ex_data(*QUICHE_EX_DATA_INDEX, ex_data)?;
572        let rc = unsafe { SSL_process_quic_post_handshake(self.as_mut_ptr()) };
573        self.set_ex_data::<Connection>(*QUICHE_EX_DATA_INDEX, ptr::null())?;
574
575        self.set_transport_error(ex_data, rc);
576        self.map_result_ssl(rc)
577    }
578
579    pub fn write_level(&self) -> crypto::Level {
580        unsafe { SSL_quic_write_level(self.as_ptr()) }
581    }
582
583    pub fn cipher(&self) -> Option<crypto::Algorithm> {
584        let cipher =
585            map_result_ptr(unsafe { SSL_get_current_cipher(self.as_ptr()) });
586
587        get_cipher_from_ptr(cipher.ok()?).ok()
588    }
589
590    #[cfg(test)]
591    pub fn set_options(&mut self, opts: u32) {
592        unsafe {
593            SSL_set_options(self.as_mut_ptr(), opts);
594        }
595    }
596
597    pub fn is_completed(&self) -> bool {
598        unsafe { SSL_in_init(self.as_ptr()) == 0 }
599    }
600
601    pub fn is_resumed(&self) -> bool {
602        unsafe { SSL_session_reused(self.as_ptr()) == 1 }
603    }
604
605    pub fn clear(&mut self) -> Result<()> {
606        let rc = unsafe { SSL_clear(self.as_mut_ptr()) };
607        self.map_result_ssl(rc)
608    }
609
610    fn as_ptr(&self) -> *const SSL {
611        self.ptr.as_ptr()
612    }
613
614    fn as_mut_ptr(&mut self) -> *mut SSL {
615        self.ptr.as_ptr()
616    }
617
618    fn map_result_ssl(&mut self, bssl_result: c_int) -> Result<()> {
619        match bssl_result {
620            1 => Ok(()),
621
622            _ => {
623                let ssl_err = self.get_error(bssl_result);
624                match ssl_err {
625                    // SSL_ERROR_SSL
626                    1 => {
627                        log_ssl_error();
628
629                        Err(Error::TlsFail)
630                    },
631
632                    // SSL_ERROR_WANT_READ
633                    2 => Err(Error::Done),
634
635                    // SSL_ERROR_WANT_WRITE
636                    3 => Err(Error::Done),
637
638                    // SSL_ERROR_WANT_X509_LOOKUP
639                    4 => Err(Error::Done),
640
641                    // SSL_ERROR_SYSCALL
642                    5 => Err(Error::TlsFail),
643
644                    // SSL_ERROR_PENDING_SESSION
645                    11 => Err(Error::Done),
646
647                    // SSL_ERROR_PENDING_CERTIFICATE
648                    12 => Err(Error::Done),
649
650                    // SSL_ERROR_WANT_PRIVATE_KEY_OPERATION
651                    13 => Err(Error::Done),
652
653                    // SSL_ERROR_PENDING_TICKET
654                    14 => Err(Error::Done),
655
656                    // SSL_ERROR_EARLY_DATA_REJECTED
657                    15 => {
658                        self.reset_early_data_reject();
659                        Err(Error::Done)
660                    },
661
662                    // SSL_ERROR_WANT_CERTIFICATE_VERIFY
663                    16 => Err(Error::Done),
664
665                    _ => Err(Error::TlsFail),
666                }
667            },
668        }
669    }
670
671    fn set_transport_error(&mut self, ex_data: &mut ExData, bssl_result: c_int) {
672        // SSL_ERROR_SSL
673        if self.get_error(bssl_result) == 1 {
674            // SSL_ERROR_SSL can't be recovered so ensure we set a
675            // local_error so the connection is closed.
676            // See https://www.openssl.org/docs/man1.1.1/man3/SSL_get_error.html
677            if ex_data.local_error.is_none() {
678                *ex_data.local_error = Some(ConnectionError {
679                    is_app: false,
680                    error_code: INTERNAL_ERROR,
681                    reason: Vec::new(),
682                })
683            }
684        }
685    }
686
687    #[cfg(feature = "boringssl-boring-crate")]
688    pub(crate) fn ssl_mut(&mut self) -> &mut boring::ssl::SslRef {
689        use foreign_types_shared::ForeignTypeRef;
690
691        unsafe { boring::ssl::SslRef::from_ptr_mut(self.as_mut_ptr() as _) }
692    }
693}
694
695// These traits are not automatically implemented because NonNull does not
696// convey ownership. Handshake uniquely owns the underlying data, and its API
697// preserves Rust's borrowing guarantees.
698unsafe impl Send for Handshake {}
699unsafe impl Sync for Handshake {}
700
701impl Drop for Handshake {
702    fn drop(&mut self) {
703        unsafe { SSL_free(self.as_mut_ptr()) }
704    }
705}
706
707pub struct ExData<'a> {
708    pub application_protos: &'a Vec<Vec<u8>>,
709
710    pub crypto_ctx: &'a mut [packet::CryptoContext; packet::Epoch::count()],
711
712    pub session: &'a mut Option<Vec<u8>>,
713
714    pub local_error: &'a mut Option<ConnectionError>,
715
716    pub keylog: Option<&'a mut Box<dyn Write + Send + Sync>>,
717
718    pub trace_id: &'a str,
719
720    pub local_transport_params: crate::TransportParams,
721
722    pub recovery_config: crate::recovery::RecoveryConfig,
723
724    pub tx_cap_factor: f64,
725
726    /// PMTUD configuration: (enable, max_probes)
727    pub pmtud: Option<(bool, u8)>,
728
729    pub is_server: bool,
730}
731
732impl<'a> ExData<'a> {
733    fn from_ssl_ptr(ptr: *const SSL) -> Option<&'a mut Self> {
734        get_ex_data_from_ptr::<ExData>(ptr, *QUICHE_EX_DATA_INDEX)
735    }
736
737    #[cfg(feature = "boringssl-boring-crate")]
738    pub fn from_ssl_ref(ssl: &mut boring::ssl::SslRef) -> Option<&mut Self> {
739        use boring::ex_data::Index;
740
741        // SAFETY: the QUICHE_EX_DATA_INDEX index is guaranteed to be created,
742        // and the associated data is always `ExData`.
743        let idx: Index<boring::ssl::Ssl, ExData> =
744            unsafe { Index::from_raw(*QUICHE_EX_DATA_INDEX) };
745
746        ssl.ex_data_mut(idx)
747    }
748}
749
750fn get_ex_data_from_ptr<'a, T>(ptr: *const SSL, idx: c_int) -> Option<&'a mut T> {
751    unsafe {
752        let data = SSL_get_ex_data(ptr, idx) as *mut T;
753        data.as_mut()
754    }
755}
756
757fn get_cipher_from_ptr(cipher: *const SSL_CIPHER) -> Result<crypto::Algorithm> {
758    let cipher_id = unsafe { SSL_CIPHER_get_id(cipher) };
759
760    let alg = match cipher_id {
761        0x0300_1301 => crypto::Algorithm::AES128_GCM,
762        0x0300_1302 => crypto::Algorithm::AES256_GCM,
763        0x0300_1303 => crypto::Algorithm::ChaCha20_Poly1305,
764        _ => return Err(Error::TlsFail),
765    };
766
767    Ok(alg)
768}
769
770extern "C" fn set_read_secret(
771    ssl: *mut SSL, level: crypto::Level, cipher: *const SSL_CIPHER,
772    secret: *const u8, secret_len: usize,
773) -> c_int {
774    let ex_data = match ExData::from_ssl_ptr(ssl) {
775        Some(v) => v,
776
777        None => return 0,
778    };
779
780    trace!("{} set read secret lvl={:?}", ex_data.trace_id, level);
781
782    let space = match level {
783        crypto::Level::Initial => &mut ex_data.crypto_ctx[packet::Epoch::Initial],
784        crypto::Level::ZeroRTT =>
785            &mut ex_data.crypto_ctx[packet::Epoch::Application],
786        crypto::Level::Handshake =>
787            &mut ex_data.crypto_ctx[packet::Epoch::Handshake],
788        crypto::Level::OneRTT =>
789            &mut ex_data.crypto_ctx[packet::Epoch::Application],
790    };
791
792    let aead = match get_cipher_from_ptr(cipher) {
793        Ok(v) => v,
794
795        Err(_) => return 0,
796    };
797
798    // 0-RTT read secrets are present only on the server.
799    if level != crypto::Level::ZeroRTT || ex_data.is_server {
800        let secret = unsafe { slice::from_raw_parts(secret, secret_len) };
801
802        let open = match crypto::Open::from_secret(aead, secret) {
803            Ok(v) => v,
804
805            Err(_) => return 0,
806        };
807
808        if level == crypto::Level::ZeroRTT {
809            space.crypto_0rtt_open = Some(open);
810            return 1;
811        }
812
813        space.crypto_open = Some(open);
814    }
815
816    1
817}
818
819extern "C" fn set_write_secret(
820    ssl: *mut SSL, level: crypto::Level, cipher: *const SSL_CIPHER,
821    secret: *const u8, secret_len: usize,
822) -> c_int {
823    let ex_data = match ExData::from_ssl_ptr(ssl) {
824        Some(v) => v,
825
826        None => return 0,
827    };
828
829    trace!("{} set write secret lvl={:?}", ex_data.trace_id, level);
830
831    let space = match level {
832        crypto::Level::Initial => &mut ex_data.crypto_ctx[packet::Epoch::Initial],
833        crypto::Level::ZeroRTT =>
834            &mut ex_data.crypto_ctx[packet::Epoch::Application],
835        crypto::Level::Handshake =>
836            &mut ex_data.crypto_ctx[packet::Epoch::Handshake],
837        crypto::Level::OneRTT =>
838            &mut ex_data.crypto_ctx[packet::Epoch::Application],
839    };
840
841    let aead = match get_cipher_from_ptr(cipher) {
842        Ok(v) => v,
843
844        Err(_) => return 0,
845    };
846
847    // 0-RTT write secrets are present only on the client.
848    if level != crypto::Level::ZeroRTT || !ex_data.is_server {
849        let secret = unsafe { slice::from_raw_parts(secret, secret_len) };
850
851        let seal = match crypto::Seal::from_secret(aead, secret) {
852            Ok(v) => v,
853
854            Err(_) => return 0,
855        };
856
857        space.crypto_seal = Some(seal);
858    }
859
860    1
861}
862
863extern "C" fn add_handshake_data(
864    ssl: *mut SSL, level: crypto::Level, data: *const u8, len: usize,
865) -> c_int {
866    let ex_data = match ExData::from_ssl_ptr(ssl) {
867        Some(v) => v,
868
869        None => return 0,
870    };
871
872    trace!(
873        "{} write message lvl={:?} len={}",
874        ex_data.trace_id,
875        level,
876        len
877    );
878
879    let buf = unsafe { slice::from_raw_parts(data, len) };
880
881    let space = match level {
882        crypto::Level::Initial => &mut ex_data.crypto_ctx[packet::Epoch::Initial],
883        crypto::Level::ZeroRTT => unreachable!(),
884        crypto::Level::Handshake =>
885            &mut ex_data.crypto_ctx[packet::Epoch::Handshake],
886        crypto::Level::OneRTT =>
887            &mut ex_data.crypto_ctx[packet::Epoch::Application],
888    };
889
890    if space.crypto_stream.send.write(buf, false).is_err() {
891        return 0;
892    }
893
894    1
895}
896
897extern "C" fn flush_flight(_ssl: *mut SSL) -> c_int {
898    // We don't really need to anything here since the output packets are
899    // generated separately, when conn.send() is called.
900
901    1
902}
903
904extern "C" fn send_alert(
905    ssl: *mut SSL, level: crypto::Level, alert: u8,
906) -> c_int {
907    let ex_data = match ExData::from_ssl_ptr(ssl) {
908        Some(v) => v,
909
910        None => return 0,
911    };
912
913    trace!(
914        "{} send alert lvl={:?} alert={:x}",
915        ex_data.trace_id,
916        level,
917        alert
918    );
919
920    let error: u64 = TLS_ALERT_ERROR + u64::from(alert);
921    *ex_data.local_error = Some(ConnectionError {
922        is_app: false,
923        error_code: error,
924        reason: Vec::new(),
925    });
926
927    1
928}
929
930extern "C" fn keylog(ssl: *const SSL, line: *const c_char) {
931    let ex_data = match ExData::from_ssl_ptr(ssl) {
932        Some(v) => v,
933
934        None => return,
935    };
936
937    if let Some(keylog) = &mut ex_data.keylog {
938        let data = unsafe { ffi::CStr::from_ptr(line).to_bytes() };
939
940        let mut full_line = Vec::with_capacity(data.len() + 1);
941        full_line.extend_from_slice(data);
942        full_line.push(b'\n');
943
944        keylog.write_all(&full_line[..]).ok();
945        keylog.flush().ok();
946    }
947}
948
949extern "C" fn select_alpn(
950    ssl: *mut SSL, out: *mut *const u8, out_len: *mut u8, inp: *mut u8,
951    in_len: c_uint, _arg: *mut c_void,
952) -> c_int {
953    // SSL_TLSEXT_ERR_OK 0
954    // SSL_TLSEXT_ERR_ALERT_WARNING 1
955    // SSL_TLSEXT_ERR_ALERT_FATAL 2
956    // SSL_TLSEXT_ERR_NOACK 3
957
958    // Boringssl internally overwrite the return value from this callback, if
959    // the returned value is SSL_TLSEXT_ERR_NOACK and is quic, then the value
960    // gets overwritten to SSL_TLSEXT_ERR_ALERT_FATAL.
961    let ex_data = match ExData::from_ssl_ptr(ssl) {
962        Some(v) => v,
963
964        None => return TLS_ERROR,
965    };
966
967    if ex_data.application_protos.is_empty() {
968        return TLS_ERROR;
969    }
970
971    let mut protos = octets::Octets::with_slice(unsafe {
972        slice::from_raw_parts(inp, in_len as usize)
973    });
974
975    while let Ok(proto) = protos.get_bytes_with_u8_length() {
976        let found = ex_data.application_protos.iter().any(|expected| {
977            trace!(
978                "checking peer ALPN {:?} against {:?}",
979                std::str::from_utf8(proto.as_ref()),
980                std::str::from_utf8(expected.as_slice())
981            );
982
983            if expected.len() == proto.len() &&
984                expected.as_slice() == proto.as_ref()
985            {
986                unsafe {
987                    *out = expected.as_slice().as_ptr();
988                    *out_len = expected.len() as u8;
989                }
990
991                return true;
992            }
993
994            false
995        });
996
997        if found {
998            return 0; // SSL_TLSEXT_ERR_OK
999        }
1000    }
1001
1002    TLS_ERROR
1003}
1004
1005extern "C" fn new_session(ssl: *mut SSL, session: *mut SSL_SESSION) -> c_int {
1006    let ssl = match NonNull::new(ssl) {
1007        Some(v) => v,
1008
1009        None => return 0,
1010    };
1011
1012    let ex_data = match ExData::from_ssl_ptr(ssl.as_ptr()) {
1013        Some(v) => v,
1014
1015        None => return 0,
1016    };
1017
1018    // This callback receives a borrowed `SSL*`, so the temporary `Handshake`
1019    // must not free it on any return path.
1020    let handshake = ManuallyDrop::new(Handshake::new(ssl));
1021    let peer_params = handshake.quic_transport_params();
1022
1023    // Serialize session object into buffer.
1024    let session_bytes = match get_session_bytes(session) {
1025        Ok(v) => v,
1026        Err(_) => return 0,
1027    };
1028
1029    let mut buffer =
1030        Vec::with_capacity(8 + peer_params.len() + 8 + session_bytes.len());
1031
1032    let session_bytes_len = session_bytes.len() as u64;
1033
1034    if buffer.write(&session_bytes_len.to_be_bytes()).is_err() {
1035        return 0;
1036    }
1037
1038    if buffer.write(&session_bytes).is_err() {
1039        return 0;
1040    }
1041
1042    let peer_params_len = peer_params.len() as u64;
1043
1044    if buffer.write(&peer_params_len.to_be_bytes()).is_err() {
1045        return 0;
1046    }
1047
1048    if buffer.write(peer_params).is_err() {
1049        return 0;
1050    }
1051
1052    *ex_data.session = Some(buffer);
1053
1054    0
1055}
1056
1057pub fn map_result(bssl_result: c_int) -> Result<()> {
1058    match bssl_result {
1059        1 => Ok(()),
1060        _ => Err(Error::TlsFail),
1061    }
1062}
1063
1064pub fn map_result_zero_is_success(bssl_result: c_int) -> Result<()> {
1065    match bssl_result {
1066        0 => Ok(()),
1067        _ => Err(Error::TlsFail),
1068    }
1069}
1070
1071pub fn map_result_ptr<'a, T>(bssl_result: *const T) -> Result<&'a T> {
1072    match unsafe { bssl_result.as_ref() } {
1073        Some(v) => Ok(v),
1074        None => Err(Error::TlsFail),
1075    }
1076}
1077
1078fn log_ssl_error() {
1079    let mut err = [0u8; 1024];
1080
1081    unsafe {
1082        let e = ERR_peek_error();
1083        ERR_error_string_n(e, err.as_mut_ptr() as *mut c_char, err.len());
1084    }
1085
1086    let cstr = ffi::CStr::from_bytes_until_nul(&err)
1087        .expect("ERR_error_string_n should write a null terminated string");
1088
1089    trace!(
1090        "{}",
1091        cstr.to_str()
1092            .expect("ERR_error_string_n should create a valid UTF-8 message")
1093    );
1094}
1095
1096extern "C" {
1097    // Note: some vendor-specific methods are implemented in the boringssl
1098    // submodule.
1099
1100    // SSL_METHOD
1101    fn TLS_method() -> *const SSL_METHOD;
1102
1103    // SSL_CTX
1104    fn SSL_CTX_new(method: *const SSL_METHOD) -> *mut SSL_CTX;
1105    fn SSL_CTX_free(ctx: *mut SSL_CTX);
1106
1107    fn SSL_CTX_use_certificate_chain_file(
1108        ctx: *mut SSL_CTX, file: *const c_char,
1109    ) -> c_int;
1110
1111    fn SSL_CTX_use_PrivateKey_file(
1112        ctx: *mut SSL_CTX, file: *const c_char, ty: c_int,
1113    ) -> c_int;
1114
1115    fn SSL_CTX_load_verify_locations(
1116        ctx: *mut SSL_CTX, file: *const c_char, path: *const c_char,
1117    ) -> c_int;
1118
1119    #[cfg(not(windows))]
1120    fn SSL_CTX_set_default_verify_paths(ctx: *mut SSL_CTX) -> c_int;
1121
1122    #[cfg(windows)]
1123    fn SSL_CTX_get_cert_store(ctx: *mut SSL_CTX) -> *mut X509_STORE;
1124
1125    fn SSL_CTX_set_verify(
1126        ctx: *mut SSL_CTX, mode: c_int,
1127        cb: Option<
1128            unsafe extern "C" fn(
1129                ok: c_int,
1130                store_ctx: *mut X509_STORE_CTX,
1131            ) -> c_int,
1132        >,
1133    );
1134
1135    fn SSL_CTX_set_keylog_callback(
1136        ctx: *mut SSL_CTX,
1137        cb: Option<unsafe extern "C" fn(ssl: *const SSL, line: *const c_char)>,
1138    );
1139
1140    fn SSL_CTX_set_alpn_protos(
1141        ctx: *mut SSL_CTX, protos: *const u8, protos_len: usize,
1142    ) -> c_int;
1143
1144    fn SSL_CTX_set_alpn_select_cb(
1145        ctx: *mut SSL_CTX,
1146        cb: Option<
1147            unsafe extern "C" fn(
1148                ssl: *mut SSL,
1149                out: *mut *const u8,
1150                out_len: *mut u8,
1151                inp: *mut u8,
1152                in_len: c_uint,
1153                arg: *mut c_void,
1154            ) -> c_int,
1155        >,
1156        arg: *mut c_void,
1157    );
1158
1159    fn SSL_CTX_sess_set_new_cb(
1160        ctx: *mut SSL_CTX,
1161        cb: Option<
1162            unsafe extern "C" fn(
1163                ssl: *mut SSL,
1164                session: *mut SSL_SESSION,
1165            ) -> c_int,
1166        >,
1167    );
1168
1169    fn SSL_new(ctx: *mut SSL_CTX) -> *mut SSL;
1170
1171    fn SSL_get_error(ssl: *const SSL, ret_code: c_int) -> c_int;
1172
1173    fn SSL_set_accept_state(ssl: *mut SSL);
1174    fn SSL_set_connect_state(ssl: *mut SSL);
1175
1176    fn SSL_get0_param(ssl: *mut SSL) -> *mut X509_VERIFY_PARAM;
1177
1178    fn SSL_set_ex_data(ssl: *mut SSL, idx: c_int, ptr: *mut c_void) -> c_int;
1179    fn SSL_get_ex_data(ssl: *const SSL, idx: c_int) -> *mut c_void;
1180
1181    fn SSL_get_current_cipher(ssl: *const SSL) -> *const SSL_CIPHER;
1182
1183    fn SSL_set_session(ssl: *mut SSL, session: *mut SSL_SESSION) -> c_int;
1184
1185    fn SSL_get_SSL_CTX(ssl: *const SSL) -> *mut SSL_CTX;
1186
1187    fn SSL_set_quiet_shutdown(ssl: *mut SSL, mode: c_int);
1188
1189    fn SSL_set_quic_transport_params(
1190        ssl: *mut SSL, params: *const u8, params_len: usize,
1191    ) -> c_int;
1192
1193    fn SSL_set_quic_method(
1194        ssl: *mut SSL, quic_method: *const SSL_QUIC_METHOD,
1195    ) -> c_int;
1196
1197    fn SSL_set_quic_use_legacy_codepoint(ssl: *mut SSL, use_legacy: c_int);
1198
1199    #[cfg(test)]
1200    fn SSL_set_options(ssl: *mut SSL, opts: u32) -> u32;
1201
1202    fn SSL_get_peer_quic_transport_params(
1203        ssl: *const SSL, out_params: *mut *const u8, out_params_len: *mut usize,
1204    );
1205
1206    fn SSL_get0_alpn_selected(
1207        ssl: *const SSL, out: *mut *const u8, out_len: *mut u32,
1208    );
1209
1210    fn SSL_get_servername(ssl: *const SSL, ty: c_int) -> *const c_char;
1211
1212    fn SSL_provide_quic_data(
1213        ssl: *mut SSL, level: crypto::Level, data: *const u8, len: usize,
1214    ) -> c_int;
1215
1216    fn SSL_process_quic_post_handshake(ssl: *mut SSL) -> c_int;
1217
1218    fn SSL_do_handshake(ssl: *mut SSL) -> c_int;
1219
1220    fn SSL_quic_write_level(ssl: *const SSL) -> crypto::Level;
1221
1222    fn SSL_session_reused(ssl: *const SSL) -> c_int;
1223
1224    fn SSL_in_init(ssl: *const SSL) -> c_int;
1225
1226    fn SSL_clear(ssl: *mut SSL) -> c_int;
1227
1228    fn SSL_free(ssl: *mut SSL);
1229
1230    // SSL_CIPHER
1231    fn SSL_CIPHER_get_id(cipher: *const SSL_CIPHER) -> c_uint;
1232
1233    // SSL_SESSION
1234
1235    fn SSL_SESSION_free(session: *mut SSL_SESSION);
1236
1237    // X509_VERIFY_PARAM
1238    fn X509_VERIFY_PARAM_set1_host(
1239        param: *mut X509_VERIFY_PARAM, name: *const c_char, namelen: usize,
1240    ) -> c_int;
1241
1242    // X509_STORE
1243    #[cfg(windows)]
1244    fn X509_STORE_add_cert(ctx: *mut X509_STORE, x: *mut X509) -> c_int;
1245
1246    // X509
1247    #[cfg(windows)]
1248    fn X509_free(x: *mut X509);
1249    #[cfg(windows)]
1250    fn d2i_X509(px: *mut X509, input: *const *const u8, len: c_int) -> *mut X509;
1251
1252    // ERR
1253    fn ERR_peek_error() -> c_uint;
1254
1255    fn ERR_error_string_n(err: c_uint, buf: *mut c_char, len: usize);
1256
1257    // OPENSSL
1258    #[allow(dead_code)]
1259    fn OPENSSL_free(ptr: *mut c_void);
1260
1261}
1262
1263mod boringssl;
1264use boringssl::*;