1use cfg_if::cfg_if;
2use foreign_types::ForeignType;
3use foreign_types::ForeignTypeRef;
4#[cfg(any(ossl111, not(osslconf = "OPENSSL_NO_PSK")))]
5use libc::c_char;
6#[cfg(ossl111)]
7use libc::size_t;
8use libc::{c_int, c_uchar, c_uint, c_void};
9#[cfg(any(ossl111, not(osslconf = "OPENSSL_NO_PSK")))]
10use std::ffi::CStr;
11use std::mem;
12use std::ptr;
13#[cfg(any(ossl111, boringssl, awslc))]
14use std::str;
15use std::sync::Arc;
16
17use crate::dh::Dh;
18#[cfg(all(ossl102, not(ossl110)))]
19use crate::ec::EcKey;
20use crate::error::ErrorStack;
21use crate::pkey::Params;
22use crate::ssl::AlpnError;
23use crate::ssl::{
24 try_get_session_ctx_index, SniError, Ssl, SslAlert, SslContext, SslContextRef, SslRef,
25 SslSession, SslSessionRef,
26};
27#[cfg(ossl111)]
28use crate::ssl::{ClientHelloResponse, ExtensionContext};
29use crate::util;
30#[cfg(any(ossl111, boringssl, awslc))]
31use crate::util::ForeignTypeRefExt;
32#[cfg(ossl111)]
33use crate::x509::X509Ref;
34use crate::x509::{X509StoreContext, X509StoreContextRef};
35
36pub extern "C" fn raw_verify<F>(preverify_ok: c_int, x509_ctx: *mut ffi::X509_STORE_CTX) -> c_int
37where
38 F: Fn(bool, &mut X509StoreContextRef) -> bool + 'static + Sync + Send,
39{
40 unsafe {
41 let ctx = X509StoreContextRef::from_ptr_mut(x509_ctx);
42 let ssl_idx = X509StoreContext::ssl_idx().expect("BUG: store context ssl index missing");
43 let verify_idx = SslContext::cached_ex_index::<F>();
44
45 let verify = ctx
48 .ex_data(ssl_idx)
49 .expect("BUG: store context missing ssl")
50 .ssl_context()
51 .ex_data(verify_idx)
52 .expect("BUG: verify callback missing") as *const F;
53
54 (*verify)(preverify_ok != 0, ctx) as c_int
55 }
56}
57
58#[cfg(not(osslconf = "OPENSSL_NO_PSK"))]
59pub extern "C" fn raw_client_psk<F>(
60 ssl: *mut ffi::SSL,
61 hint: *const c_char,
62 identity: *mut c_char,
63 max_identity_len: c_uint,
64 psk: *mut c_uchar,
65 max_psk_len: c_uint,
66) -> c_uint
67where
68 F: Fn(&mut SslRef, Option<&[u8]>, &mut [u8], &mut [u8]) -> Result<usize, ErrorStack>
69 + 'static
70 + Sync
71 + Send,
72{
73 unsafe {
74 let ssl = SslRef::from_ptr_mut(ssl);
75 let callback_idx = SslContext::cached_ex_index::<F>();
76
77 let callback = ssl
78 .ssl_context()
79 .ex_data(callback_idx)
80 .expect("BUG: psk callback missing") as *const F;
81 let hint = if !hint.is_null() {
82 Some(CStr::from_ptr(hint).to_bytes())
83 } else {
84 None
85 };
86 let identity_sl = util::from_raw_parts_mut(identity as *mut u8, max_identity_len as usize);
88 #[allow(clippy::unnecessary_cast)]
89 let psk_sl = util::from_raw_parts_mut(psk as *mut u8, max_psk_len as usize);
90 match (*callback)(ssl, hint, identity_sl, psk_sl) {
91 Ok(psk_len) => psk_len as u32,
92 Err(e) => {
93 e.put();
94 0
95 }
96 }
97 }
98}
99
100#[cfg(not(osslconf = "OPENSSL_NO_PSK"))]
101pub extern "C" fn raw_server_psk<F>(
102 ssl: *mut ffi::SSL,
103 identity: *const c_char,
104 psk: *mut c_uchar,
105 max_psk_len: c_uint,
106) -> c_uint
107where
108 F: Fn(&mut SslRef, Option<&[u8]>, &mut [u8]) -> Result<usize, ErrorStack>
109 + 'static
110 + Sync
111 + Send,
112{
113 unsafe {
114 let ssl = SslRef::from_ptr_mut(ssl);
115 let callback_idx = SslContext::cached_ex_index::<F>();
116
117 let callback = ssl
118 .ssl_context()
119 .ex_data(callback_idx)
120 .expect("BUG: psk callback missing") as *const F;
121 let identity = if identity.is_null() {
122 None
123 } else {
124 Some(CStr::from_ptr(identity).to_bytes())
125 };
126 #[allow(clippy::unnecessary_cast)]
128 let psk_sl = util::from_raw_parts_mut(psk as *mut u8, max_psk_len as usize);
129 match (*callback)(ssl, identity, psk_sl) {
130 Ok(psk_len) => psk_len as u32,
131 Err(e) => {
132 e.put();
133 0
134 }
135 }
136 }
137}
138
139pub extern "C" fn ssl_raw_verify<F>(
140 preverify_ok: c_int,
141 x509_ctx: *mut ffi::X509_STORE_CTX,
142) -> c_int
143where
144 F: Fn(bool, &mut X509StoreContextRef) -> bool + 'static + Sync + Send,
145{
146 unsafe {
147 let ctx = X509StoreContextRef::from_ptr_mut(x509_ctx);
148 let ssl_idx = X509StoreContext::ssl_idx().expect("BUG: store context ssl index missing");
149 let callback_idx = Ssl::cached_ex_index::<Arc<F>>();
150
151 let callback = ctx
152 .ex_data(ssl_idx)
153 .expect("BUG: store context missing ssl")
154 .ex_data(callback_idx)
155 .expect("BUG: ssl verify callback missing")
156 .clone();
157
158 callback(preverify_ok != 0, ctx) as c_int
159 }
160}
161
162pub extern "C" fn raw_sni<F>(ssl: *mut ffi::SSL, al: *mut c_int, arg: *mut c_void) -> c_int
163where
164 F: Fn(&mut SslRef, &mut SslAlert) -> Result<(), SniError> + 'static + Sync + Send,
165{
166 unsafe {
167 let ssl = SslRef::from_ptr_mut(ssl);
168 let callback = arg as *const F;
169 let mut alert = SslAlert(*al);
170
171 let r = (*callback)(ssl, &mut alert);
172 *al = alert.0;
173 match r {
174 Ok(()) => ffi::SSL_TLSEXT_ERR_OK,
175 Err(e) => e.0,
176 }
177 }
178}
179
180pub extern "C" fn raw_alpn_select<F>(
181 ssl: *mut ffi::SSL,
182 out: *mut *const c_uchar,
183 outlen: *mut c_uchar,
184 inbuf: *const c_uchar,
185 inlen: c_uint,
186 _arg: *mut c_void,
187) -> c_int
188where
189 F: for<'a> Fn(&mut SslRef, &'a [u8]) -> Result<&'a [u8], AlpnError> + 'static + Sync + Send,
190{
191 unsafe {
192 let ssl = SslRef::from_ptr_mut(ssl);
193 let callback = ssl
194 .ssl_context()
195 .ex_data(SslContext::cached_ex_index::<F>())
196 .expect("BUG: alpn callback missing") as *const F;
197 #[allow(clippy::unnecessary_cast)]
198 let protos = util::from_raw_parts(inbuf as *const u8, inlen as usize);
199
200 match (*callback)(ssl, protos) {
201 Ok(proto) => {
202 *out = proto.as_ptr() as *const c_uchar;
203 *outlen = proto.len() as c_uchar;
204 ffi::SSL_TLSEXT_ERR_OK
205 }
206 Err(e) => e.0,
207 }
208 }
209}
210
211pub unsafe extern "C" fn raw_tmp_dh<F>(
212 ssl: *mut ffi::SSL,
213 is_export: c_int,
214 keylength: c_int,
215) -> *mut ffi::DH
216where
217 F: Fn(&mut SslRef, bool, u32) -> Result<Dh<Params>, ErrorStack> + 'static + Sync + Send,
218{
219 let ssl = SslRef::from_ptr_mut(ssl);
220 let callback = ssl
221 .ssl_context()
222 .ex_data(SslContext::cached_ex_index::<F>())
223 .expect("BUG: tmp dh callback missing") as *const F;
224
225 match (*callback)(ssl, is_export != 0, keylength as u32) {
226 Ok(dh) => {
227 let ptr = dh.as_ptr();
228 mem::forget(dh);
229 ptr
230 }
231 Err(e) => {
232 e.put();
233 ptr::null_mut()
234 }
235 }
236}
237
238#[cfg(all(ossl102, not(ossl110)))]
239pub unsafe extern "C" fn raw_tmp_ecdh<F>(
240 ssl: *mut ffi::SSL,
241 is_export: c_int,
242 keylength: c_int,
243) -> *mut ffi::EC_KEY
244where
245 F: Fn(&mut SslRef, bool, u32) -> Result<EcKey<Params>, ErrorStack> + 'static + Sync + Send,
246{
247 let ssl = SslRef::from_ptr_mut(ssl);
248 let callback = ssl
249 .ssl_context()
250 .ex_data(SslContext::cached_ex_index::<F>())
251 .expect("BUG: tmp ecdh callback missing") as *const F;
252
253 match (*callback)(ssl, is_export != 0, keylength as u32) {
254 Ok(ec_key) => {
255 let ptr = ec_key.as_ptr();
256 mem::forget(ec_key);
257 ptr
258 }
259 Err(e) => {
260 e.put();
261 ptr::null_mut()
262 }
263 }
264}
265
266pub unsafe extern "C" fn raw_tmp_dh_ssl<F>(
267 ssl: *mut ffi::SSL,
268 is_export: c_int,
269 keylength: c_int,
270) -> *mut ffi::DH
271where
272 F: Fn(&mut SslRef, bool, u32) -> Result<Dh<Params>, ErrorStack> + 'static + Sync + Send,
273{
274 let ssl = SslRef::from_ptr_mut(ssl);
275 let callback = ssl
276 .ex_data(Ssl::cached_ex_index::<Arc<F>>())
277 .expect("BUG: ssl tmp dh callback missing")
278 .clone();
279
280 match callback(ssl, is_export != 0, keylength as u32) {
281 Ok(dh) => {
282 let ptr = dh.as_ptr();
283 mem::forget(dh);
284 ptr
285 }
286 Err(e) => {
287 e.put();
288 ptr::null_mut()
289 }
290 }
291}
292
293#[cfg(all(ossl102, not(ossl110)))]
294pub unsafe extern "C" fn raw_tmp_ecdh_ssl<F>(
295 ssl: *mut ffi::SSL,
296 is_export: c_int,
297 keylength: c_int,
298) -> *mut ffi::EC_KEY
299where
300 F: Fn(&mut SslRef, bool, u32) -> Result<EcKey<Params>, ErrorStack> + 'static + Sync + Send,
301{
302 let ssl = SslRef::from_ptr_mut(ssl);
303 let callback = ssl
304 .ex_data(Ssl::cached_ex_index::<Arc<F>>())
305 .expect("BUG: ssl tmp ecdh callback missing")
306 .clone();
307
308 match callback(ssl, is_export != 0, keylength as u32) {
309 Ok(ec_key) => {
310 let ptr = ec_key.as_ptr();
311 mem::forget(ec_key);
312 ptr
313 }
314 Err(e) => {
315 e.put();
316 ptr::null_mut()
317 }
318 }
319}
320
321pub unsafe extern "C" fn raw_tlsext_status<F>(ssl: *mut ffi::SSL, _: *mut c_void) -> c_int
322where
323 F: Fn(&mut SslRef) -> Result<bool, ErrorStack> + 'static + Sync + Send,
324{
325 let ssl = SslRef::from_ptr_mut(ssl);
326 let callback = ssl
327 .ssl_context()
328 .ex_data(SslContext::cached_ex_index::<F>())
329 .expect("BUG: ocsp callback missing") as *const F;
330 let ret = (*callback)(ssl);
331
332 if ssl.is_server() {
333 match ret {
334 Ok(true) => ffi::SSL_TLSEXT_ERR_OK,
335 Ok(false) => ffi::SSL_TLSEXT_ERR_NOACK,
336 Err(e) => {
337 e.put();
338 ffi::SSL_TLSEXT_ERR_ALERT_FATAL
339 }
340 }
341 } else {
342 match ret {
343 Ok(true) => 1,
344 Ok(false) => 0,
345 Err(e) => {
346 e.put();
347 -1
348 }
349 }
350 }
351}
352
353pub unsafe extern "C" fn raw_new_session<F>(
354 ssl: *mut ffi::SSL,
355 session: *mut ffi::SSL_SESSION,
356) -> c_int
357where
358 F: Fn(&mut SslRef, SslSession) + 'static + Sync + Send,
359{
360 let session_ctx_index =
361 try_get_session_ctx_index().expect("BUG: session context index initialization failed");
362 let ssl = SslRef::from_ptr_mut(ssl);
363 let callback = ssl
364 .ex_data(*session_ctx_index)
365 .expect("BUG: session context missing")
366 .ex_data(SslContext::cached_ex_index::<F>())
367 .expect("BUG: new session callback missing") as *const F;
368 let session = SslSession::from_ptr(session);
369
370 (*callback)(ssl, session);
371
372 1
374}
375
376pub unsafe extern "C" fn raw_remove_session<F>(
377 ctx: *mut ffi::SSL_CTX,
378 session: *mut ffi::SSL_SESSION,
379) where
380 F: Fn(&SslContextRef, &SslSessionRef) + 'static + Sync + Send,
381{
382 let ctx = SslContextRef::from_ptr(ctx);
383 let callback = ctx
384 .ex_data(SslContext::cached_ex_index::<F>())
385 .expect("BUG: remove session callback missing");
386 let session = SslSessionRef::from_ptr(session);
387
388 callback(ctx, session)
389}
390
391cfg_if! {
392 if #[cfg(any(ossl110, libressl, boringssl, awslc))] {
393 type DataPtr = *const c_uchar;
394 } else {
395 type DataPtr = *mut c_uchar;
396 }
397}
398
399pub unsafe extern "C" fn raw_get_session<F>(
400 ssl: *mut ffi::SSL,
401 data: DataPtr,
402 len: c_int,
403 copy: *mut c_int,
404) -> *mut ffi::SSL_SESSION
405where
406 F: Fn(&mut SslRef, &[u8]) -> Option<SslSession> + 'static + Sync + Send,
407{
408 let session_ctx_index =
409 try_get_session_ctx_index().expect("BUG: session context index initialization failed");
410 let ssl = SslRef::from_ptr_mut(ssl);
411 let callback = ssl
412 .ex_data(*session_ctx_index)
413 .expect("BUG: session context missing")
414 .ex_data(SslContext::cached_ex_index::<F>())
415 .expect("BUG: get session callback missing") as *const F;
416 #[allow(clippy::unnecessary_cast)]
417 let data = util::from_raw_parts(data as *const u8, len as usize);
418
419 match (*callback)(ssl, data) {
420 Some(session) => {
421 let p = session.as_ptr();
422 mem::forget(session);
423 *copy = 0;
424 p
425 }
426 None => ptr::null_mut(),
427 }
428}
429
430#[cfg(any(ossl111, boringssl, awslc))]
431pub unsafe extern "C" fn raw_keylog<F>(ssl: *const ffi::SSL, line: *const c_char)
432where
433 F: Fn(&SslRef, &str) + 'static + Sync + Send,
434{
435 let ssl = SslRef::from_const_ptr(ssl);
436 let callback = ssl
437 .ssl_context()
438 .ex_data(SslContext::cached_ex_index::<F>())
439 .expect("BUG: get session callback missing");
440 let line = CStr::from_ptr(line).to_bytes();
441 let line = str::from_utf8_unchecked(line);
442
443 callback(ssl, line);
444}
445
446#[cfg(ossl111)]
447pub unsafe extern "C" fn raw_stateless_cookie_generate<F>(
448 ssl: *mut ffi::SSL,
449 cookie: *mut c_uchar,
450 cookie_len: *mut size_t,
451) -> c_int
452where
453 F: Fn(&mut SslRef, &mut [u8]) -> Result<usize, ErrorStack> + 'static + Sync + Send,
454{
455 let ssl = SslRef::from_ptr_mut(ssl);
456 let callback = ssl
457 .ssl_context()
458 .ex_data(SslContext::cached_ex_index::<F>())
459 .expect("BUG: stateless cookie generate callback missing") as *const F;
460 #[allow(clippy::unnecessary_cast)]
461 let slice = util::from_raw_parts_mut(cookie as *mut u8, ffi::SSL_COOKIE_LENGTH as usize);
462 match (*callback)(ssl, slice) {
463 Ok(len) => {
464 *cookie_len = len as size_t;
465 1
466 }
467 Err(e) => {
468 e.put();
469 0
470 }
471 }
472}
473
474#[cfg(ossl111)]
475pub unsafe extern "C" fn raw_stateless_cookie_verify<F>(
476 ssl: *mut ffi::SSL,
477 cookie: *const c_uchar,
478 cookie_len: size_t,
479) -> c_int
480where
481 F: Fn(&mut SslRef, &[u8]) -> bool + 'static + Sync + Send,
482{
483 let ssl = SslRef::from_ptr_mut(ssl);
484 let callback = ssl
485 .ssl_context()
486 .ex_data(SslContext::cached_ex_index::<F>())
487 .expect("BUG: stateless cookie verify callback missing") as *const F;
488 #[allow(clippy::unnecessary_cast)]
489 let slice = util::from_raw_parts(cookie as *const c_uchar as *const u8, cookie_len);
490 (*callback)(ssl, slice) as c_int
491}
492
493#[cfg(not(any(boringssl, awslc)))]
494pub extern "C" fn raw_cookie_generate<F>(
495 ssl: *mut ffi::SSL,
496 cookie: *mut c_uchar,
497 cookie_len: *mut c_uint,
498) -> c_int
499where
500 F: Fn(&mut SslRef, &mut [u8]) -> Result<usize, ErrorStack> + 'static + Sync + Send,
501{
502 unsafe {
503 let ssl = SslRef::from_ptr_mut(ssl);
504 let callback = ssl
505 .ssl_context()
506 .ex_data(SslContext::cached_ex_index::<F>())
507 .expect("BUG: cookie generate callback missing") as *const F;
508 #[allow(clippy::unnecessary_cast)]
511 let slice =
512 util::from_raw_parts_mut(cookie as *mut u8, ffi::DTLS1_COOKIE_LENGTH as usize - 1);
513 match (*callback)(ssl, slice) {
514 Ok(len) => {
515 *cookie_len = len as c_uint;
516 1
517 }
518 Err(e) => {
519 e.put();
520 0
521 }
522 }
523 }
524}
525
526#[cfg(not(any(boringssl, awslc)))]
527cfg_if! {
528 if #[cfg(any(ossl110, libressl))] {
529 type CookiePtr = *const c_uchar;
530 } else {
531 type CookiePtr = *mut c_uchar;
532 }
533}
534
535#[cfg(not(any(boringssl, awslc)))]
536pub extern "C" fn raw_cookie_verify<F>(
537 ssl: *mut ffi::SSL,
538 cookie: CookiePtr,
539 cookie_len: c_uint,
540) -> c_int
541where
542 F: Fn(&mut SslRef, &[u8]) -> bool + 'static + Sync + Send,
543{
544 unsafe {
545 let ssl = SslRef::from_ptr_mut(ssl);
546 let callback = ssl
547 .ssl_context()
548 .ex_data(SslContext::cached_ex_index::<F>())
549 .expect("BUG: cookie verify callback missing") as *const F;
550 #[allow(clippy::unnecessary_cast)]
551 let slice =
552 util::from_raw_parts(cookie as *const c_uchar as *const u8, cookie_len as usize);
553 (*callback)(ssl, slice) as c_int
554 }
555}
556
557#[cfg(ossl111)]
558pub struct CustomExtAddState<T>(Option<T>);
559
560#[cfg(ossl111)]
561pub extern "C" fn raw_custom_ext_add<F, T>(
562 ssl: *mut ffi::SSL,
563 _: c_uint,
564 context: c_uint,
565 out: *mut *const c_uchar,
566 outlen: *mut size_t,
567 x: *mut ffi::X509,
568 chainidx: size_t,
569 al: *mut c_int,
570 _: *mut c_void,
571) -> c_int
572where
573 F: Fn(&mut SslRef, ExtensionContext, Option<(usize, &X509Ref)>) -> Result<Option<T>, SslAlert>
574 + 'static
575 + Sync
576 + Send,
577 T: AsRef<[u8]> + 'static + Sync + Send,
578{
579 unsafe {
580 let ssl = SslRef::from_ptr_mut(ssl);
581 let callback = ssl
582 .ssl_context()
583 .ex_data(SslContext::cached_ex_index::<F>())
584 .expect("BUG: custom ext add callback missing") as *const F;
585 let ectx = ExtensionContext::from_bits_truncate(context);
586 let cert = if ectx.contains(ExtensionContext::TLS1_3_CERTIFICATE) {
587 Some((chainidx, X509Ref::from_ptr(x)))
588 } else {
589 None
590 };
591 match (*callback)(ssl, ectx, cert) {
592 Ok(None) => 0,
593 Ok(Some(buf)) => {
594 *outlen = buf.as_ref().len();
595 *out = buf.as_ref().as_ptr();
596
597 let idx = Ssl::cached_ex_index::<CustomExtAddState<T>>();
598 let mut buf = Some(buf);
599 let new = match ssl.ex_data_mut(idx) {
600 Some(state) => {
601 state.0 = buf.take();
602 false
603 }
604 None => true,
605 };
606 if new {
607 ssl.set_ex_data(idx, CustomExtAddState(buf));
608 }
609 1
610 }
611 Err(alert) => {
612 *al = alert.0;
613 -1
614 }
615 }
616 }
617}
618
619#[cfg(ossl111)]
620pub extern "C" fn raw_custom_ext_free<T>(
621 ssl: *mut ffi::SSL,
622 _: c_uint,
623 _: c_uint,
624 _: *const c_uchar,
625 _: *mut c_void,
626) where
627 T: 'static + Sync + Send,
628{
629 unsafe {
630 let ssl = SslRef::from_ptr_mut(ssl);
631 let idx = Ssl::cached_ex_index::<CustomExtAddState<T>>();
632 if let Some(state) = ssl.ex_data_mut(idx) {
633 state.0 = None;
634 }
635 }
636}
637
638#[cfg(ossl111)]
639pub extern "C" fn raw_custom_ext_parse<F>(
640 ssl: *mut ffi::SSL,
641 _: c_uint,
642 context: c_uint,
643 input: *const c_uchar,
644 inlen: size_t,
645 x: *mut ffi::X509,
646 chainidx: size_t,
647 al: *mut c_int,
648 _: *mut c_void,
649) -> c_int
650where
651 F: Fn(&mut SslRef, ExtensionContext, &[u8], Option<(usize, &X509Ref)>) -> Result<(), SslAlert>
652 + 'static
653 + Sync
654 + Send,
655{
656 unsafe {
657 let ssl = SslRef::from_ptr_mut(ssl);
658 let callback = ssl
659 .ssl_context()
660 .ex_data(SslContext::cached_ex_index::<F>())
661 .expect("BUG: custom ext parse callback missing") as *const F;
662 let ectx = ExtensionContext::from_bits_truncate(context);
663 #[allow(clippy::unnecessary_cast)]
664 let slice = util::from_raw_parts(input as *const u8, inlen);
665 let cert = if ectx.contains(ExtensionContext::TLS1_3_CERTIFICATE) {
666 Some((chainidx, X509Ref::from_ptr(x)))
667 } else {
668 None
669 };
670 match (*callback)(ssl, ectx, slice, cert) {
671 Ok(()) => 1,
672 Err(alert) => {
673 *al = alert.0;
674 0
675 }
676 }
677 }
678}
679
680#[cfg(ossl111)]
681pub unsafe extern "C" fn raw_client_hello<F>(
682 ssl: *mut ffi::SSL,
683 al: *mut c_int,
684 arg: *mut c_void,
685) -> c_int
686where
687 F: Fn(&mut SslRef, &mut SslAlert) -> Result<ClientHelloResponse, ErrorStack>
688 + 'static
689 + Sync
690 + Send,
691{
692 let ssl = SslRef::from_ptr_mut(ssl);
693 let callback = arg as *const F;
694 let mut alert = SslAlert(*al);
695
696 let r = (*callback)(ssl, &mut alert);
697 *al = alert.0;
698 match r {
699 Ok(c) => c.0,
700 Err(e) => {
701 e.put();
702 ffi::SSL_CLIENT_HELLO_ERROR
703 }
704 }
705}