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