Skip to main content

quiche/tls/
boringssl.rs

1use super::*;
2
3use libc::c_long;
4
5#[allow(non_camel_case_types)]
6#[repr(transparent)]
7struct CRYPTO_BUFFER {
8    _unused: c_void,
9}
10
11#[repr(C)]
12#[allow(non_camel_case_types)]
13pub(super) struct SSL_QUIC_METHOD {
14    set_read_secret: Option<
15        unsafe extern "C" fn(
16            ssl: *mut SSL,
17            level: crypto::Level,
18            cipher: *const SSL_CIPHER,
19            secret: *const u8,
20            secret_len: usize,
21        ) -> c_int,
22    >,
23
24    set_write_secret: Option<
25        unsafe extern "C" fn(
26            ssl: *mut SSL,
27            level: crypto::Level,
28            cipher: *const SSL_CIPHER,
29            secret: *const u8,
30            secret_len: usize,
31        ) -> c_int,
32    >,
33
34    add_handshake_data: Option<
35        unsafe extern "C" fn(
36            ssl: *mut SSL,
37            level: crypto::Level,
38            data: *const u8,
39            len: usize,
40        ) -> c_int,
41    >,
42
43    flush_flight: Option<extern "C" fn(ssl: *mut SSL) -> c_int>,
44
45    send_alert: Option<
46        extern "C" fn(ssl: *mut SSL, level: crypto::Level, alert: u8) -> c_int,
47    >,
48}
49
50#[cfg(test)]
51#[repr(C)]
52#[allow(non_camel_case_types)]
53struct SSL_PRIVATE_KEY_METHOD {
54    sign: Option<
55        unsafe extern "C" fn(
56            ssl: *mut SSL,
57            out: *mut u8,
58            out_len: *mut usize,
59            max_out: usize,
60            signature_algorithm: u16,
61            r#in: *const u8,
62            in_len: usize,
63        ) -> ssl_private_key_result_t,
64    >,
65
66    decrypt: Option<
67        unsafe extern "C" fn(
68            ssl: *mut SSL,
69            out: *mut u8,
70            out_len: *mut usize,
71            max_out: usize,
72            r#in: *const u8,
73            in_len: usize,
74        ) -> ssl_private_key_result_t,
75    >,
76
77    complete: Option<
78        unsafe extern "C" fn(
79            ssl: *mut SSL,
80            out: *mut u8,
81            out_len: *mut usize,
82            max_out: usize,
83        ) -> ssl_private_key_result_t,
84    >,
85}
86
87pub(super) static QUICHE_STREAM_METHOD: SSL_QUIC_METHOD = SSL_QUIC_METHOD {
88    set_read_secret: Some(set_read_secret),
89    set_write_secret: Some(set_write_secret),
90    add_handshake_data: Some(add_handshake_data),
91    flush_flight: Some(flush_flight),
92    send_alert: Some(send_alert),
93};
94
95impl Context {
96    pub fn set_early_data_enabled(&mut self, _enabled: bool) {
97        unsafe {
98            SSL_CTX_set_early_data_enabled(
99                self.as_mut_ptr(),
100                i32::from(_enabled),
101            );
102        }
103    }
104}
105
106impl Handshake {
107    pub fn set_quic_early_data_context(&mut self, context: &[u8]) -> Result<()> {
108        map_result(unsafe {
109            SSL_set_quic_early_data_context(
110                self.as_mut_ptr(),
111                context.as_ptr(),
112                context.len(),
113            )
114        })
115    }
116
117    pub fn set_session(&mut self, session: &[u8]) -> Result<()> {
118        unsafe {
119            let ctx = SSL_get_SSL_CTX(self.as_ptr());
120
121            if ctx.is_null() {
122                return Err(Error::TlsFail);
123            }
124
125            let session =
126                SSL_SESSION_from_bytes(session.as_ptr(), session.len(), ctx);
127
128            if session.is_null() {
129                return Err(Error::TlsFail);
130            }
131
132            let rc = SSL_set_session(self.as_mut_ptr(), session);
133            SSL_SESSION_free(session);
134
135            map_result(rc)
136        }
137    }
138
139    pub fn reset_early_data_reject(&mut self) {
140        unsafe { SSL_reset_early_data_reject(self.as_mut_ptr()) };
141    }
142
143    pub fn curve(&self) -> Option<String> {
144        let curve = unsafe {
145            let curve_id = SSL_get_curve_id(self.as_ptr());
146            if curve_id == 0 {
147                return None;
148            }
149
150            let curve_name = SSL_get_curve_name(curve_id);
151            match ffi::CStr::from_ptr(curve_name).to_str() {
152                Ok(v) => v,
153
154                Err(_) => return None,
155            }
156        };
157
158        Some(curve.to_string())
159    }
160
161    pub fn sigalg(&self) -> Option<String> {
162        let sigalg = unsafe {
163            let sigalg_id = SSL_get_peer_signature_algorithm(self.as_ptr());
164            if sigalg_id == 0 {
165                return None;
166            }
167
168            let sigalg_name = SSL_get_signature_algorithm_name(sigalg_id, 1);
169            match ffi::CStr::from_ptr(sigalg_name).to_str() {
170                Ok(v) => v,
171
172                Err(_) => return None,
173            }
174        };
175
176        Some(sigalg.to_string())
177    }
178
179    pub fn peer_cert_chain(&self) -> Option<Vec<&[u8]>> {
180        let cert_chain = unsafe {
181            let chain =
182                map_result_ptr(SSL_get0_peer_certificates(self.as_ptr())).ok()?;
183
184            let num = sk_num(chain);
185            if num == 0 {
186                return None;
187            }
188
189            let mut cert_chain = vec![];
190            for i in 0..num {
191                let buffer =
192                    map_result_ptr(sk_value(chain, i) as *const CRYPTO_BUFFER)
193                        .ok()?;
194
195                let out_len = CRYPTO_BUFFER_len(buffer);
196                if out_len == 0 {
197                    return None;
198                }
199
200                let out = CRYPTO_BUFFER_data(buffer);
201                let slice = slice::from_raw_parts(out, out_len);
202
203                cert_chain.push(slice);
204            }
205
206            cert_chain
207        };
208
209        Some(cert_chain)
210    }
211
212    pub fn peer_cert(&self) -> Option<&[u8]> {
213        let peer_cert = unsafe {
214            let chain =
215                map_result_ptr(SSL_get0_peer_certificates(self.as_ptr())).ok()?;
216            if sk_num(chain) == 0 {
217                return None;
218            }
219
220            let buffer =
221                map_result_ptr(sk_value(chain, 0) as *const CRYPTO_BUFFER)
222                    .ok()?;
223
224            let out_len = CRYPTO_BUFFER_len(buffer);
225            if out_len == 0 {
226                return None;
227            }
228
229            let out = CRYPTO_BUFFER_data(buffer);
230            slice::from_raw_parts(out, out_len)
231        };
232
233        Some(peer_cert)
234    }
235
236    // Only used for testing handling of failure during key signing.
237    #[cfg(test)]
238    pub fn set_failing_private_key_method(&mut self) {
239        extern "C" fn failing_sign(
240            _ssl: *mut SSL, _out: *mut u8, _out_len: *mut usize, _max_out: usize,
241            _signature_algorithm: u16, _in: *const u8, _in_len: usize,
242        ) -> ssl_private_key_result_t {
243            ssl_private_key_result_t::ssl_private_key_failure
244        }
245
246        extern "C" fn failing_decrypt(
247            _ssl: *mut SSL, _out: *mut u8, _out_len: *mut usize, _max_out: usize,
248            _in: *const u8, _in_len: usize,
249        ) -> ssl_private_key_result_t {
250            ssl_private_key_result_t::ssl_private_key_failure
251        }
252
253        extern "C" fn failing_complete(
254            _ssl: *mut SSL, _out: *mut u8, _out_len: *mut usize, _max_out: usize,
255        ) -> ssl_private_key_result_t {
256            ssl_private_key_result_t::ssl_private_key_failure
257        }
258
259        static QUICHE_PRIVATE_KEY_METHOD: SSL_PRIVATE_KEY_METHOD =
260            SSL_PRIVATE_KEY_METHOD {
261                decrypt: Some(failing_decrypt),
262                sign: Some(failing_sign),
263                complete: Some(failing_complete),
264            };
265
266        unsafe {
267            SSL_set_private_key_method(
268                self.as_mut_ptr(),
269                &QUICHE_PRIVATE_KEY_METHOD,
270            );
271        }
272    }
273
274    pub fn is_in_early_data(&self) -> bool {
275        unsafe { SSL_in_early_data(self.as_ptr()) == 1 }
276    }
277
278    pub fn early_data_reason(&self) -> u32 {
279        let reuse_reason_status =
280            unsafe { SSL_get_early_data_reason(self.as_ptr()) };
281        reuse_reason_status.0
282    }
283}
284
285pub(super) fn get_session_bytes(session: *mut SSL_SESSION) -> Result<Vec<u8>> {
286    let session_bytes = unsafe {
287        let mut out: *mut u8 = ptr::null_mut();
288        let mut out_len: usize = 0;
289
290        if SSL_SESSION_to_bytes(session, &mut out, &mut out_len) == 0 {
291            return Err(Error::TlsFail);
292        }
293        let session_bytes = slice::from_raw_parts(out, out_len).to_vec();
294        OPENSSL_free(out as *mut c_void);
295        session_bytes
296    };
297
298    Ok(session_bytes)
299}
300pub(super) const TLS_ERROR: c_int = 3;
301
302#[allow(non_camel_case_types)]
303#[repr(transparent)]
304#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
305pub struct ssl_early_data_reason_t(pub ::std::os::raw::c_uint);
306extern "C" {
307    // SSL_METHOD specific for boringssl.
308    pub(super) fn SSL_CTX_set_tlsext_ticket_keys(
309        ctx: *mut SSL_CTX, key: *const u8, key_len: usize,
310    ) -> c_int;
311    fn SSL_CTX_set_early_data_enabled(ctx: *mut SSL_CTX, enabled: i32);
312
313    // BoringSSL exports `SSL_CTX_set1_groups_list` as a real symbol; on
314    // OpenSSL it is a header macro. See `openssl_quictls.rs` for the
315    // OpenSSL shim.
316    pub(super) fn SSL_CTX_set1_groups_list(
317        ctx: *mut SSL_CTX, groups: *const c_char,
318    ) -> c_int;
319
320    pub(super) fn SSL_CTX_set_session_cache_mode(
321        ctx: *mut SSL_CTX, mode: c_int,
322    ) -> c_int;
323    pub(super) fn SSL_get_ex_new_index(
324        argl: c_long, argp: *const c_void, unused: *const c_void,
325        dup_unused: *const c_void, free_func: *const c_void,
326    ) -> c_int;
327
328    fn SSL_get_curve_id(ssl: *const SSL) -> u16;
329    fn SSL_get_curve_name(curve: u16) -> *const c_char;
330
331    fn SSL_get_peer_signature_algorithm(ssl: *const SSL) -> u16;
332    fn SSL_get_signature_algorithm_name(
333        sigalg: u16, include_curve: i32,
334    ) -> *const c_char;
335
336    fn SSL_get0_peer_certificates(ssl: *const SSL) -> *const STACK_OF;
337
338    pub(super) fn SSL_set_min_proto_version(ssl: *mut SSL, version: u16)
339        -> c_int;
340
341    pub(super) fn SSL_set_max_proto_version(ssl: *mut SSL, version: u16)
342        -> c_int;
343
344    pub(super) fn SSL_set_tlsext_host_name(
345        ssl: *mut SSL, name: *const c_char,
346    ) -> c_int;
347
348    fn SSL_set_quic_early_data_context(
349        ssl: *mut SSL, context: *const u8, context_len: usize,
350    ) -> c_int;
351
352    #[cfg(test)]
353    fn SSL_set_private_key_method(
354        ssl: *mut SSL, key_method: *const SSL_PRIVATE_KEY_METHOD,
355    );
356
357    fn SSL_reset_early_data_reject(ssl: *mut SSL);
358
359    fn SSL_in_early_data(ssl: *const SSL) -> c_int;
360
361    fn SSL_get_early_data_reason(ssl: *const SSL) -> ssl_early_data_reason_t;
362
363    fn SSL_SESSION_to_bytes(
364        session: *const SSL_SESSION, out: *mut *mut u8, out_len: *mut usize,
365    ) -> c_int;
366
367    fn SSL_SESSION_from_bytes(
368        input: *const u8, input_len: usize, ctx: *const SSL_CTX,
369    ) -> *mut SSL_SESSION;
370
371    // STACK_OF
372
373    fn sk_num(stack: *const STACK_OF) -> usize;
374
375    fn sk_value(stack: *const STACK_OF, idx: usize) -> *mut c_void;
376
377    // CRYPTO_BUFFER
378
379    fn CRYPTO_BUFFER_len(buffer: *const CRYPTO_BUFFER) -> usize;
380
381    fn CRYPTO_BUFFER_data(buffer: *const CRYPTO_BUFFER) -> *const u8;
382}