openssl/ssl/
callbacks.rs

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