1use crate::error::{br, br_zero_is_success, BoringResult};
2use boring::error::ErrorStack;
3use boring::pkey::{HasPrivate, PKey};
4use boring::ssl::{Ssl, SslContext, SslContextRef, SslSession};
5use boring::x509::store::X509StoreBuilderRef;
6use boring::x509::X509;
7use boring_sys as bffi;
8use bytes::{Buf, BufMut};
9use foreign_types_shared::{ForeignType, ForeignTypeRef};
10use std::ffi::{c_char, c_int, c_uint, c_void, CStr};
11use std::fmt::{Display, Formatter};
12use std::result::Result as StdResult;
13use std::{ffi, fmt, mem, ptr, slice};
14
15pub trait QuicSslContext {
17 fn set_options(&mut self, options: u32) -> u32;
18 fn verify_peer(&mut self, verify: bool);
19 fn set_quic_method(&mut self, method: &bffi::SSL_QUIC_METHOD) -> BoringResult;
20 fn set_session_cache_mode(&mut self, mode: c_int) -> c_int;
21 fn set_new_session_callback(
22 &mut self,
23 cb: Option<
24 unsafe extern "C" fn(ssl: *mut bffi::SSL, session: *mut bffi::SSL_SESSION) -> c_int,
25 >,
26 );
27 fn set_info_callback(
28 &mut self,
29 cb: Option<unsafe extern "C" fn(ssl: *const bffi::SSL, type_: c_int, value: c_int)>,
30 );
31 fn set_keylog_callback(
32 &mut self,
33 cb: Option<unsafe extern "C" fn(ssl: *const bffi::SSL, line: *const c_char)>,
34 );
35 fn set_certificate(&mut self, cert: X509) -> BoringResult;
36 fn load_certificate_from_pem_file(&mut self, path: &str) -> BoringResult;
37 fn add_to_cert_chain(&mut self, cert: X509) -> BoringResult;
38 fn load_cert_chain_from_pem_file(&mut self, path: &str) -> BoringResult;
39 fn set_private_key<T: HasPrivate>(&mut self, key: PKey<T>) -> BoringResult;
40 fn load_private_key_from_pem_file(&mut self, path: &str) -> BoringResult;
41 fn check_private_key(&self) -> BoringResult;
42 fn cert_store_mut(&mut self) -> &mut X509StoreBuilderRef;
43
44 fn enable_early_data(&mut self, enable: bool);
45 fn set_alpn_protos(&mut self, protos: &[u8]) -> BoringResult;
46 fn set_alpn_select_cb(
47 &mut self,
48 cb: Option<
49 unsafe extern "C" fn(
50 ssl: *mut bffi::SSL,
51 out: *mut *const u8,
52 out_len: *mut u8,
53 in_: *const u8,
54 in_len: c_uint,
55 arg: *mut c_void,
56 ) -> c_int,
57 >,
58 );
59 fn set_server_name_cb(
60 &mut self,
61 cb: Option<
62 unsafe extern "C" fn(
63 ssl: *mut bffi::SSL,
64 out_alert: *mut c_int,
65 arg: *mut c_void,
66 ) -> c_int,
67 >,
68 );
69 fn set_select_certificate_cb(
70 &mut self,
71 cb: Option<
72 unsafe extern "C" fn(
73 arg1: *const bffi::SSL_CLIENT_HELLO,
74 ) -> bffi::ssl_select_cert_result_t,
75 >,
76 );
77}
78
79impl QuicSslContext for SslContext {
80 fn set_options(&mut self, options: u32) -> u32 {
81 unsafe { bffi::SSL_CTX_set_options(self.as_ptr(), options) }
82 }
83
84 fn verify_peer(&mut self, verify: bool) {
85 let mode = if verify {
86 bffi::SSL_VERIFY_PEER | bffi::SSL_VERIFY_FAIL_IF_NO_PEER_CERT
87 } else {
88 bffi::SSL_VERIFY_NONE
89 };
90
91 unsafe { bffi::SSL_CTX_set_verify(self.as_ptr(), mode, None) }
92 }
93
94 fn set_quic_method(&mut self, method: &bffi::SSL_QUIC_METHOD) -> BoringResult {
95 unsafe { br(bffi::SSL_CTX_set_quic_method(self.as_ptr(), method)) }
96 }
97
98 fn set_session_cache_mode(&mut self, mode: c_int) -> c_int {
99 unsafe { bffi::SSL_CTX_set_session_cache_mode(self.as_ptr(), mode) }
100 }
101
102 fn set_new_session_callback(
103 &mut self,
104 cb: Option<
105 unsafe extern "C" fn(ssl: *mut bffi::SSL, session: *mut bffi::SSL_SESSION) -> c_int,
106 >,
107 ) {
108 unsafe {
109 bffi::SSL_CTX_sess_set_new_cb(self.as_ptr(), cb);
110 }
111 }
112
113 fn set_info_callback(
114 &mut self,
115 cb: Option<unsafe extern "C" fn(ssl: *const bffi::SSL, type_: c_int, value: c_int)>,
116 ) {
117 unsafe { bffi::SSL_CTX_set_info_callback(self.as_ptr(), cb) }
118 }
119
120 fn set_keylog_callback(
121 &mut self,
122 cb: Option<unsafe extern "C" fn(ssl: *const bffi::SSL, line: *const c_char)>,
123 ) {
124 unsafe { bffi::SSL_CTX_set_keylog_callback(self.as_ptr(), cb) }
125 }
126
127 fn set_certificate(&mut self, cert: X509) -> BoringResult {
128 unsafe {
129 br(bffi::SSL_CTX_use_certificate(self.as_ptr(), cert.as_ptr()))?;
130 mem::forget(cert);
131 Ok(())
132 }
133 }
134
135 fn load_certificate_from_pem_file(&mut self, path: &str) -> BoringResult {
136 let path = ffi::CString::new(path).unwrap();
137 unsafe {
138 br(bffi::SSL_CTX_use_certificate_file(
139 self.as_ptr(),
140 path.as_ptr(),
141 bffi::SSL_FILETYPE_PEM,
142 ))
143 }
144 }
145
146 fn add_to_cert_chain(&mut self, cert: X509) -> BoringResult {
147 unsafe {
148 br(bffi::SSL_CTX_add_extra_chain_cert(self.as_ptr(), cert.as_ptr()) as c_int)?;
149 mem::forget(cert);
150 Ok(())
151 }
152 }
153
154 fn load_cert_chain_from_pem_file(&mut self, path: &str) -> BoringResult {
155 let path = ffi::CString::new(path).unwrap();
156 unsafe {
157 br(bffi::SSL_CTX_use_certificate_chain_file(
158 self.as_ptr(),
159 path.as_ptr(),
160 ))
161 }
162 }
163
164 fn set_private_key<T: HasPrivate>(&mut self, key: PKey<T>) -> BoringResult {
165 unsafe {
166 br(bffi::SSL_CTX_use_PrivateKey(self.as_ptr(), key.as_ptr()))?;
167 mem::forget(key);
168 Ok(())
169 }
170 }
171
172 fn load_private_key_from_pem_file(&mut self, path: &str) -> BoringResult {
173 let path = ffi::CString::new(path).unwrap();
174
175 unsafe {
176 br(bffi::SSL_CTX_use_PrivateKey_file(
177 self.as_ptr(),
178 path.as_ptr(),
179 bffi::SSL_FILETYPE_PEM,
180 ))
181 }
182 }
183
184 fn check_private_key(&self) -> BoringResult {
185 unsafe { br(bffi::SSL_CTX_check_private_key(self.as_ptr())) }
186 }
187
188 fn cert_store_mut(&mut self) -> &mut X509StoreBuilderRef {
189 unsafe { X509StoreBuilderRef::from_ptr_mut(bffi::SSL_CTX_get_cert_store(self.as_ptr())) }
190 }
191
192 fn enable_early_data(&mut self, enable: bool) {
193 unsafe { bffi::SSL_CTX_set_early_data_enabled(self.as_ptr(), enable.into()) }
194 }
195
196 fn set_alpn_protos(&mut self, protos: &[u8]) -> BoringResult {
197 unsafe {
198 br_zero_is_success(bffi::SSL_CTX_set_alpn_protos(
199 self.as_ptr(),
200 protos.as_ptr(),
201 protos.len() as _,
202 ))
203 }
204 }
205
206 fn set_alpn_select_cb(
207 &mut self,
208 cb: Option<
209 unsafe extern "C" fn(
210 *mut bffi::SSL,
211 *mut *const u8,
212 *mut u8,
213 *const u8,
214 c_uint,
215 *mut c_void,
216 ) -> c_int,
217 >,
218 ) {
219 unsafe { bffi::SSL_CTX_set_alpn_select_cb(self.as_ptr(), cb, ptr::null_mut()) }
220 }
221
222 fn set_server_name_cb(
223 &mut self,
224 cb: Option<
225 unsafe extern "C" fn(
226 ssl: *mut bffi::SSL,
227 out_alert: *mut c_int,
228 arg: *mut c_void,
229 ) -> c_int,
230 >,
231 ) {
232 unsafe {
234 let _ = bffi::SSL_CTX_set_tlsext_servername_callback(self.as_ptr(), cb);
235 }
236 }
237
238 fn set_select_certificate_cb(
239 &mut self,
240 cb: Option<
241 unsafe extern "C" fn(
242 arg1: *const bffi::SSL_CLIENT_HELLO,
243 ) -> bffi::ssl_select_cert_result_t,
244 >,
245 ) {
246 unsafe { bffi::SSL_CTX_set_select_certificate_cb(self.as_ptr(), cb) }
247 }
248}
249
250pub trait QuicSsl {
252 fn set_connect_state(&mut self);
253 fn set_accept_state(&mut self);
254 fn state_string(&self) -> &'static str;
255 fn set_quic_transport_params(&mut self, params: &[u8]) -> BoringResult;
256 fn get_peer_quic_transport_params(&self) -> Option<&[u8]>;
257 fn get_error(&self, raw: c_int) -> SslError;
258 fn is_handshaking(&self) -> bool;
259 fn do_handshake(&mut self) -> SslError;
260 fn provide_quic_data(&mut self, level: Level, data: &[u8]) -> SslError;
261 fn quic_max_handshake_flight_len(&self, level: Level) -> usize;
262 fn quic_read_level(&self) -> Level;
263 fn quic_write_level(&self) -> Level;
264 fn process_post_handshake(&mut self) -> SslError;
265 fn set_verify_hostname(&mut self, domain: &str) -> BoringResult;
266 fn export_keyring_material(
267 &self,
268 output: &mut [u8],
269 label: &[u8],
270 context: &[u8],
271 ) -> BoringResult;
272
273 fn in_early_data(&self) -> bool;
274 fn early_data_accepted(&self) -> bool;
275 fn set_quic_method(&mut self, method: &bffi::SSL_QUIC_METHOD) -> BoringResult;
276 fn set_quic_early_data_context(&mut self, value: &[u8]) -> BoringResult;
277 fn get_early_data_reason(&self) -> bffi::ssl_early_data_reason_t;
278 fn early_data_reason_string(reason: bffi::ssl_early_data_reason_t) -> &'static str;
279 fn reset_early_rejected_data(&mut self);
280 fn set_quic_use_legacy_codepoint(&mut self, use_legacy: bool);
281}
282
283impl QuicSsl for Ssl {
284 fn set_connect_state(&mut self) {
285 unsafe { bffi::SSL_set_connect_state(self.as_ptr()) }
286 }
287
288 fn set_accept_state(&mut self) {
289 unsafe { bffi::SSL_set_accept_state(self.as_ptr()) }
290 }
291
292 fn state_string(&self) -> &'static str {
293 unsafe {
294 CStr::from_ptr(bffi::SSL_state_string_long(self.as_ptr()))
295 .to_str()
296 .unwrap()
297 }
298 }
299
300 fn set_quic_transport_params(&mut self, params: &[u8]) -> BoringResult {
301 unsafe {
302 br(bffi::SSL_set_quic_transport_params(
303 self.as_ptr(),
304 params.as_ptr(),
305 params.len(),
306 ))
307 }
308 }
309
310 fn get_peer_quic_transport_params(&self) -> Option<&[u8]> {
311 let mut ptr: *const u8 = ptr::null();
312 let mut len: usize = 0;
313
314 unsafe {
315 bffi::SSL_get_peer_quic_transport_params(self.as_ptr(), &mut ptr, &mut len);
316
317 if len == 0 {
318 None
319 } else {
320 Some(slice::from_raw_parts(ptr, len))
321 }
322 }
323 }
324
325 #[inline]
326 fn get_error(&self, raw: c_int) -> SslError {
327 unsafe { SslError(bffi::SSL_get_error(self.as_ptr(), raw)) }
328 }
329
330 #[inline]
331 fn is_handshaking(&self) -> bool {
332 unsafe { bffi::SSL_in_init(self.as_ptr()) == 1 }
333 }
334
335 #[inline]
336 fn do_handshake(&mut self) -> SslError {
337 self.get_error(unsafe { bffi::SSL_do_handshake(self.as_ptr()) })
338 }
339
340 #[inline]
341 fn provide_quic_data(&mut self, level: Level, plaintext: &[u8]) -> SslError {
342 unsafe {
343 self.get_error(bffi::SSL_provide_quic_data(
344 self.as_ptr(),
345 level.into(),
346 plaintext.as_ptr(),
347 plaintext.len(),
348 ))
349 }
350 }
351
352 #[inline]
353 fn quic_max_handshake_flight_len(&self, level: Level) -> usize {
354 unsafe { bffi::SSL_quic_max_handshake_flight_len(self.as_ptr(), level.into()) }
355 }
356
357 #[inline]
358 fn quic_read_level(&self) -> Level {
359 unsafe { bffi::SSL_quic_read_level(self.as_ptr()).into() }
360 }
361
362 #[inline]
363 fn quic_write_level(&self) -> Level {
364 unsafe { bffi::SSL_quic_write_level(self.as_ptr()).into() }
365 }
366
367 #[inline]
368 fn process_post_handshake(&mut self) -> SslError {
369 self.get_error(unsafe { bffi::SSL_process_quic_post_handshake(self.as_ptr()) })
370 }
371
372 fn set_verify_hostname(&mut self, domain: &str) -> BoringResult {
373 let param = self.param_mut();
374 param.set_hostflags(boring::x509::verify::X509CheckFlags::NO_PARTIAL_WILDCARDS);
375 match domain.parse() {
376 Ok(ip) => param.set_ip(ip)?,
377 Err(_) => param.set_host(domain)?,
378 }
379 Ok(())
380 }
381
382 #[inline]
383 fn export_keyring_material(
384 &self,
385 output: &mut [u8],
386 label: &[u8],
387 context: &[u8],
388 ) -> BoringResult {
389 unsafe {
390 br(bffi::SSL_export_keying_material(
391 self.as_ptr(),
392 output.as_mut_ptr(),
393 output.len(),
394 label.as_ptr() as *const c_char,
395 label.len(),
396 context.as_ptr(),
397 context.len(),
398 context.is_empty() as _,
399 ))
400 }
401 }
402
403 #[inline]
404 fn in_early_data(&self) -> bool {
405 unsafe { bffi::SSL_in_early_data(self.as_ptr()) == 1 }
406 }
407
408 #[inline]
409 fn early_data_accepted(&self) -> bool {
410 unsafe { bffi::SSL_early_data_accepted(self.as_ptr()) == 1 }
411 }
412
413 fn set_quic_method(&mut self, method: &bffi::SSL_QUIC_METHOD) -> BoringResult {
414 unsafe { br(bffi::SSL_set_quic_method(self.as_ptr(), method)) }
415 }
416
417 fn set_quic_early_data_context(&mut self, value: &[u8]) -> BoringResult {
418 unsafe {
419 br(bffi::SSL_set_quic_early_data_context(
420 self.as_ptr(),
421 value.as_ptr(),
422 value.len(),
423 ))
424 }
425 }
426
427 fn get_early_data_reason(&self) -> bffi::ssl_early_data_reason_t {
428 unsafe { bffi::SSL_get_early_data_reason(self.as_ptr()) }
429 }
430
431 fn early_data_reason_string(reason: bffi::ssl_early_data_reason_t) -> &'static str {
432 unsafe {
433 bffi::SSL_early_data_reason_string(reason)
434 .as_ref()
435 .map_or("unknown", |reason| CStr::from_ptr(reason).to_str().unwrap())
436 }
437 }
438
439 #[inline]
440 fn reset_early_rejected_data(&mut self) {
441 unsafe { bffi::SSL_reset_early_data_reject(self.as_ptr()) }
442 }
443
444 fn set_quic_use_legacy_codepoint(&mut self, use_legacy: bool) {
445 unsafe { bffi::SSL_set_quic_use_legacy_codepoint(self.as_ptr(), use_legacy as _) }
446 }
447}
448
449pub trait QuicSslSession {
450 fn early_data_capable(&self) -> bool;
451 fn copy_without_early_data(&mut self) -> SslSession;
452 fn encode<W: BufMut>(&self, out: &mut W) -> BoringResult;
453 fn decode<R: Buf>(ctx: &SslContextRef, r: &mut R) -> StdResult<SslSession, ErrorStack>;
454}
455
456impl QuicSslSession for SslSession {
457 fn early_data_capable(&self) -> bool {
458 unsafe { bffi::SSL_SESSION_early_data_capable(self.as_ptr()) == 1 }
459 }
460
461 fn copy_without_early_data(&mut self) -> SslSession {
462 unsafe { SslSession::from_ptr(bffi::SSL_SESSION_copy_without_early_data(self.as_ptr())) }
463 }
464
465 fn encode<W: BufMut>(&self, out: &mut W) -> BoringResult {
466 unsafe {
467 let mut buf: *mut u8 = ptr::null_mut();
468 let mut len = 0usize;
469 br(bffi::SSL_SESSION_to_bytes(
470 self.as_ptr(),
471 &mut buf,
472 &mut len,
473 ))?;
474 out.put_slice(slice::from_raw_parts(buf, len));
475 bffi::OPENSSL_free(buf as _);
476 Ok(())
477 }
478 }
479
480 fn decode<R: Buf>(ctx: &SslContextRef, r: &mut R) -> StdResult<SslSession, ErrorStack> {
481 unsafe {
482 let in_len = r.remaining();
483 let in_ = r.chunk();
484 bffi::SSL_SESSION_from_bytes(in_.as_ptr(), in_len, ctx.as_ptr())
485 .as_mut()
486 .map_or_else(
487 || Err(ErrorStack::get()),
488 |session| Ok(SslSession::from_ptr(session)),
489 )
490 }
491 }
492}
493
494#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
495pub enum Level {
496 Initial = 0,
497 EarlyData = 1,
498 Handshake = 2,
499 Application = 3,
500}
501
502impl Level {
503 pub const NUM_LEVELS: usize = 4;
504
505 pub fn next(&self) -> Self {
506 match self {
507 Level::Initial => Level::Handshake,
508 Level::EarlyData => Level::Handshake,
509 _ => Level::Application,
510 }
511 }
512}
513
514impl From<bffi::ssl_encryption_level_t> for Level {
515 fn from(value: bffi::ssl_encryption_level_t) -> Self {
516 match value {
517 bffi::ssl_encryption_level_t::ssl_encryption_initial => Self::Initial,
518 bffi::ssl_encryption_level_t::ssl_encryption_early_data => Self::EarlyData,
519 bffi::ssl_encryption_level_t::ssl_encryption_handshake => Self::Handshake,
520 bffi::ssl_encryption_level_t::ssl_encryption_application => Self::Application,
521 _ => unreachable!(),
522 }
523 }
524}
525
526impl From<Level> for bffi::ssl_encryption_level_t {
527 fn from(value: Level) -> Self {
528 match value {
529 Level::Initial => bffi::ssl_encryption_level_t::ssl_encryption_initial,
530 Level::EarlyData => bffi::ssl_encryption_level_t::ssl_encryption_early_data,
531 Level::Handshake => bffi::ssl_encryption_level_t::ssl_encryption_handshake,
532 Level::Application => bffi::ssl_encryption_level_t::ssl_encryption_application,
533 }
534 }
535}
536
537#[derive(Copy, Clone)]
538pub struct SslError(c_int);
539
540impl SslError {
541 #[inline]
542 pub fn value(&self) -> c_int {
543 self.0
544 }
545
546 #[inline]
547 pub fn is_none(&self) -> bool {
548 self.0 == bffi::SSL_ERROR_NONE
549 }
550
551 #[inline]
552 pub fn get_description(&self) -> &'static str {
553 unsafe {
554 CStr::from_ptr(bffi::SSL_error_description(self.0))
555 .to_str()
556 .unwrap()
557 }
558 }
559}
560
561impl Display for SslError {
562 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
563 write!(f, "SSL_ERROR[{}]: {}", self.0, self.get_description())
564 }
565}