Skip to main content

rustls_ffi/
acceptor.rs

1use libc::{EINVAL, EIO, c_void, size_t};
2use rustls::server::{Accepted, AcceptedAlert, Acceptor};
3
4use crate::connection::rustls_connection;
5use crate::error::{map_error, rustls_io_result, rustls_result};
6use crate::ffi::{
7    Castable, OwnershipBox, free_box, set_boxed_mut_ptr, to_box, to_boxed_mut_ptr, try_callback,
8    try_clone_arc, try_mut_from_ptr, try_mut_from_ptr_ptr, try_ref_from_ptr, try_take,
9};
10use crate::io::{CallbackReader, CallbackWriter, rustls_read_callback, rustls_write_callback};
11use crate::panic::ffi_panic_boundary;
12use crate::rslice::{rustls_slice_bytes, rustls_str};
13use crate::server::rustls_server_config;
14
15/// A buffer and parser for ClientHello bytes.
16///
17/// This allows reading ClientHello before choosing a rustls_server_config.
18///
19/// It's useful when the server config will be based on parameters in the
20/// ClientHello: server name indication (SNI), ALPN protocols, signature
21/// schemes, and cipher suites.
22///
23/// In particular, if a server wants to do some potentially expensive work
24/// to load a certificate for a given hostname, rustls_acceptor allows doing
25/// that asynchronously, as opposed to rustls_server_config_builder_set_hello_callback(),
26/// which doesn't work well for asynchronous I/O.
27///
28/// The general flow is:
29///  - rustls_acceptor_new()
30///  - Loop:
31///    - Read bytes from the network it with rustls_acceptor_read_tls().
32///    - If successful, parse those bytes with rustls_acceptor_accept().
33///    - If that returns RUSTLS_RESULT_ACCEPTOR_NOT_READY, continue.
34///    - Otherwise, break.
35///  - If rustls_acceptor_accept() returned RUSTLS_RESULT_OK:
36///    - Examine the resulting rustls_accepted.
37///    - Create or select a rustls_server_config.
38///    - Call rustls_accepted_into_connection().
39///  - Otherwise, there was a problem with the ClientHello data and the
40///    connection should be rejected.
41pub struct rustls_acceptor {
42    _private: [u8; 0],
43}
44
45impl Castable for rustls_acceptor {
46    type Ownership = OwnershipBox;
47    type RustType = Acceptor;
48}
49
50/// A parsed ClientHello produced by a rustls_acceptor.
51///
52/// It is used to check server name indication (SNI), ALPN protocols,
53/// signature schemes, and cipher suites. It can be combined with a
54/// `rustls_server_config` to build a `rustls_connection`.
55pub struct rustls_accepted {
56    _private: [u8; 0],
57}
58
59impl Castable for rustls_accepted {
60    type Ownership = OwnershipBox;
61    type RustType = Option<Accepted>;
62}
63
64impl rustls_acceptor {
65    /// Create and return a new rustls_acceptor.
66    ///
67    /// Caller owns the pointed-to memory and must eventually free it with
68    /// `rustls_acceptor_free()`.
69    #[no_mangle]
70    pub extern "C" fn rustls_acceptor_new() -> *mut rustls_acceptor {
71        ffi_panic_boundary! {
72            to_boxed_mut_ptr(Acceptor::default())
73        }
74    }
75
76    /// Free a rustls_acceptor.
77    ///
78    /// Parameters:
79    ///
80    /// acceptor: The rustls_acceptor to free.
81    ///
82    /// Calling with NULL is fine. Must not be called twice with the same value.
83    #[no_mangle]
84    pub extern "C" fn rustls_acceptor_free(acceptor: *mut rustls_acceptor) {
85        ffi_panic_boundary! {
86            to_box(acceptor);
87        }
88    }
89
90    /// Read some TLS bytes from the network into internal buffers.
91    ///
92    /// The actual network I/O is performed by `callback`, which you provide.
93    /// Rustls will invoke your callback with a suitable buffer to store the
94    /// read bytes into. You don't have to fill it up, just fill with as many
95    /// bytes as you get in one syscall.
96    ///
97    /// Parameters:
98    ///
99    /// acceptor: The rustls_acceptor to read bytes into.
100    /// callback: A function that will perform the actual network I/O.
101    ///   Must be valid to call with the given userdata parameter until
102    ///   this function call returns.
103    /// userdata: An opaque parameter to be passed directly to `callback`.
104    ///   Note: this is distinct from the `userdata` parameter set with
105    ///   `rustls_connection_set_userdata`.
106    /// out_n: An output parameter. This will be passed through to `callback`,
107    ///   which should use it to store the number of bytes written.
108    ///
109    /// Returns:
110    ///
111    /// - 0: Success. You should call `rustls_acceptor_accept()` next.
112    /// - Any non-zero value: error.
113    ///
114    /// This function passes through return values from `callback`. Typically
115    /// `callback` should return an errno value. See `rustls_read_callback()` for
116    /// more details.
117    #[no_mangle]
118    pub extern "C" fn rustls_acceptor_read_tls(
119        acceptor: *mut rustls_acceptor,
120        callback: rustls_read_callback,
121        userdata: *mut c_void,
122        out_n: *mut size_t,
123    ) -> rustls_io_result {
124        ffi_panic_boundary! {
125            let acceptor = try_mut_from_ptr!(acceptor);
126            if out_n.is_null() {
127                return rustls_io_result(EINVAL);
128            }
129            let callback = try_callback!(callback);
130
131            let mut reader = CallbackReader { callback, userdata };
132
133            let n_read: usize = match acceptor.read_tls(&mut reader) {
134                Ok(n) => n,
135                Err(e) => return rustls_io_result(e.raw_os_error().unwrap_or(EIO)),
136            };
137            unsafe {
138                *out_n = n_read;
139            }
140
141            rustls_io_result(0)
142        }
143    }
144
145    /// Parse all TLS bytes read so far.
146    ///
147    /// If those bytes make up a ClientHello, create a rustls_accepted from them.
148    ///
149    /// Parameters:
150    ///
151    /// acceptor: The rustls_acceptor to access.
152    /// out_accepted: An output parameter. The pointed-to pointer will be set
153    ///   to a new rustls_accepted only when the function returns
154    ///   RUSTLS_RESULT_OK. The memory is owned by the caller and must eventually
155    ///   be freed
156    /// out_alert: An output parameter. The pointed-to pointer will be set
157    ///   to a new rustls_accepted_alert only when the function returns
158    ///   a non-OK result. The memory is owned by the caller and must eventually
159    ///   be freed with rustls_accepted_alert_free. The caller should call
160    ///   rustls_accepted_alert_write_tls to write the alert bytes to the TLS
161    ///   connection before freeing the rustls_accepted_alert.
162    ///
163    /// At most one of out_accepted or out_alert will be set.
164    ///
165    /// Returns:
166    ///
167    /// - RUSTLS_RESULT_OK: a ClientHello has successfully been parsed.
168    ///   A pointer to a newly allocated rustls_accepted has been written to
169    ///   *out_accepted.
170    /// - RUSTLS_RESULT_ACCEPTOR_NOT_READY: a full ClientHello has not yet been read.
171    ///   Read more TLS bytes to continue.
172    /// - Any other rustls_result: the TLS bytes read so far cannot be parsed
173    ///   as a ClientHello, and reading additional bytes won't help.
174    ///
175    /// Memory and lifetimes:
176    ///
177    /// After this method returns RUSTLS_RESULT_OK, `acceptor` is
178    /// still allocated and valid. It needs to be freed regardless of success
179    /// or failure of this function.
180    ///
181    /// Calling `rustls_acceptor_accept()` multiple times on the same
182    /// `rustls_acceptor` is acceptable from a memory perspective but pointless
183    /// from a protocol perspective.
184    #[no_mangle]
185    pub extern "C" fn rustls_acceptor_accept(
186        acceptor: *mut rustls_acceptor,
187        out_accepted: *mut *mut rustls_accepted,
188        out_alert: *mut *mut rustls_accepted_alert,
189    ) -> rustls_result {
190        ffi_panic_boundary! {
191            let acceptor = try_mut_from_ptr!(acceptor);
192            let out_accepted = try_mut_from_ptr_ptr!(out_accepted);
193            let out_alert = try_mut_from_ptr_ptr!(out_alert);
194            match acceptor.accept() {
195                Ok(None) => rustls_result::AcceptorNotReady,
196                Ok(Some(accepted)) => {
197                    set_boxed_mut_ptr(out_accepted, Some(accepted));
198                    rustls_result::Ok
199                }
200                Err((e, accepted_alert)) => {
201                    set_boxed_mut_ptr(out_alert, accepted_alert);
202                    map_error(e)
203                }
204            }
205        }
206    }
207}
208
209impl rustls_accepted {
210    /// Get the server name indication (SNI) from the ClientHello.
211    ///
212    /// Parameters:
213    ///
214    /// accepted: The rustls_accepted to access.
215    ///
216    /// Returns:
217    ///
218    /// A rustls_str containing the SNI field.
219    ///
220    /// The returned value is valid until rustls_accepted_into_connection or
221    /// rustls_accepted_free is called on the same `accepted`. It is not owned
222    /// by the caller and does not need to be freed.
223    ///
224    /// This will be a zero-length rustls_str in these error cases:
225    ///
226    ///  - The SNI contains a NUL byte.
227    ///  - The `accepted` parameter was NULL.
228    ///  - The `accepted` parameter was already transformed into a connection
229    ///    with rustls_accepted_into_connection.
230    #[no_mangle]
231    pub extern "C" fn rustls_accepted_server_name(
232        accepted: *const rustls_accepted,
233    ) -> rustls_str<'static> {
234        ffi_panic_boundary! {
235            let accepted = try_ref_from_ptr!(accepted);
236            let accepted = match accepted {
237                Some(a) => a,
238                None => return Default::default(),
239            };
240            let hello = accepted.client_hello();
241            let sni = match hello.server_name() {
242                Some(s) => s,
243                None => return Default::default(),
244            };
245            match rustls_str::try_from(sni) {
246                Ok(s) => unsafe { s.into_static() },
247                Err(_) => Default::default(),
248            }
249        }
250    }
251
252    /// Get the i'th in the list of signature schemes offered in the ClientHello.
253    ///
254    /// This is useful in selecting a server certificate when there are multiple
255    /// available for the same server name, for instance when selecting
256    /// between an RSA and an ECDSA certificate.
257    ///
258    /// Parameters:
259    ///
260    /// accepted: The rustls_accepted to access.
261    /// i: Fetch the signature scheme at this offset.
262    ///
263    /// Returns:
264    ///
265    /// A TLS Signature Scheme from <https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-signaturescheme>
266    ///
267    /// This will be 0 in these cases:
268    ///   - i is greater than the number of available cipher suites.
269    ///   - accepted is NULL.
270    ///   - rustls_accepted_into_connection has already been called with `accepted`.
271    #[no_mangle]
272    pub extern "C" fn rustls_accepted_signature_scheme(
273        accepted: *const rustls_accepted,
274        i: usize,
275    ) -> u16 {
276        ffi_panic_boundary! {
277            let accepted = try_ref_from_ptr!(accepted);
278            let accepted = match accepted {
279                Some(a) => a,
280                None => return 0,
281            };
282            let hello = accepted.client_hello();
283            let signature_schemes = hello.signature_schemes();
284            match signature_schemes.get(i) {
285                Some(s) => u16::from(*s),
286                None => 0,
287            }
288        }
289    }
290
291    /// Get the i'th in the list of cipher suites offered in the ClientHello.
292    ///
293    /// Parameters:
294    ///
295    /// accepted: The rustls_accepted to access.
296    /// i: Fetch the cipher suite at this offset.
297    ///
298    /// Returns:
299    ///
300    /// A cipher suite value from <https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-4.>
301    ///
302    /// This will be 0 in these cases:
303    ///   - i is greater than the number of available cipher suites.
304    ///   - accepted is NULL.
305    ///   - rustls_accepted_into_connection has already been called with `accepted`.
306    ///
307    /// Note that 0 is technically a valid cipher suite "TLS_NULL_WITH_NULL_NULL",
308    /// but this library will never support null ciphers.
309    #[no_mangle]
310    pub extern "C" fn rustls_accepted_cipher_suite(
311        accepted: *const rustls_accepted,
312        i: usize,
313    ) -> u16 {
314        ffi_panic_boundary! {
315            let accepted = try_ref_from_ptr!(accepted);
316            let accepted = match accepted {
317                Some(a) => a,
318                None => return 0,
319            };
320            let hello = accepted.client_hello();
321            let cipher_suites = hello.cipher_suites();
322            match cipher_suites.get(i) {
323                Some(cs) => u16::from(*cs),
324                None => 0,
325            }
326        }
327    }
328
329    /// Get the i'th in the list of ALPN protocols requested in the ClientHello.
330    ///
331    /// accepted: The rustls_accepted to access.
332    /// i: Fetch the ALPN value at this offset.
333    ///
334    /// Returns:
335    ///
336    /// A rustls_slice_bytes containing the i'th ALPN protocol. This may
337    /// contain internal NUL bytes and is not guaranteed to contain valid
338    /// UTF-8.
339    ///
340    /// This will be a zero-length rustls_slice bytes in these cases:
341    ///   - i is greater than the number of offered ALPN protocols.
342    ///   - The client did not offer the ALPN extension.
343    ///   - The `accepted` parameter was already transformed into a connection
344    ///     with rustls_accepted_into_connection.
345    ///
346    /// The returned value is valid until rustls_accepted_into_connection or
347    /// rustls_accepted_free is called on the same `accepted`. It is not owned
348    /// by the caller and does not need to be freed.
349    ///
350    /// If you are calling this from Rust, note that the `'static` lifetime
351    /// in the return signature is fake and must not be relied upon.
352    #[no_mangle]
353    pub extern "C" fn rustls_accepted_alpn(
354        accepted: *const rustls_accepted,
355        i: usize,
356    ) -> rustls_slice_bytes<'static> {
357        ffi_panic_boundary! {
358            let accepted = try_ref_from_ptr!(accepted);
359            let accepted = match accepted {
360                Some(a) => a,
361                None => return Default::default(),
362            };
363            let mut alpn_iter = match accepted.client_hello().alpn() {
364                Some(iter) => iter,
365                None => return Default::default(),
366            };
367            match alpn_iter.nth(i) {
368                Some(slice_bytes) => slice_bytes.into(),
369                None => rustls_slice_bytes::default(),
370            }
371        }
372    }
373
374    /// Turn a rustls_accepted into a rustls_connection, given the provided
375    /// rustls_server_config.
376    ///
377    /// Parameters:
378    ///
379    /// accepted: The rustls_accepted to transform.
380    /// config: The configuration with which to create this connection.
381    /// out_conn: An output parameter. The pointed-to pointer will be set
382    ///   to a new rustls_connection only when the function returns
383    ///   RUSTLS_RESULT_OK.
384    /// out_alert: An output parameter. The pointed-to pointer will be set
385    ///   to a new rustls_accepted_alert when, and only when, the function returns
386    ///   a non-OK result. The memory is owned by the caller and must eventually
387    ///   be freed with rustls_accepted_alert_free. The caller should call
388    ///   rustls_accepted_alert_write_tls to write the alert bytes to
389    ///   the TLS connection before freeing the rustls_accepted_alert.
390    ///
391    /// At most one of out_conn or out_alert will be set.
392    ///
393    /// Returns:
394    ///
395    /// - RUSTLS_RESULT_OK: The `accepted` parameter was successfully
396    ///   transformed into a rustls_connection, and *out_conn was written to.
397    /// - RUSTLS_RESULT_ALREADY_USED: This function was called twice on the
398    ///   same rustls_connection.
399    /// - RUSTLS_RESULT_NULL_PARAMETER: One of the input parameters was NULL.
400    ///
401    /// Memory and lifetimes:
402    ///
403    /// In both success and failure cases, this consumes the contents of
404    /// `accepted` but does not free its allocated memory. In either case,
405    /// call rustls_accepted_free to avoid a memory leak.
406    ///
407    /// Calling accessor methods on an `accepted` after consuming it will
408    /// return zero or default values.
409    ///
410    /// The rustls_connection emitted by this function in the success case
411    /// is owned by the caller and must eventually be freed.
412    ///
413    /// This function does not take ownership of `config`. It does increment
414    /// `config`'s internal reference count, indicating that the
415    /// rustls_connection may hold a reference to it until it is done.
416    /// See the documentation for rustls_connection for details.
417    #[no_mangle]
418    pub extern "C" fn rustls_accepted_into_connection(
419        accepted: *mut rustls_accepted,
420        config: *const rustls_server_config,
421        out_conn: *mut *mut rustls_connection,
422        out_alert: *mut *mut rustls_accepted_alert,
423    ) -> rustls_result {
424        ffi_panic_boundary! {
425            let accepted = try_mut_from_ptr!(accepted);
426            let accepted = try_take!(accepted);
427            let config = try_clone_arc!(config);
428            let out_conn = try_mut_from_ptr_ptr!(out_conn);
429            let out_alert = try_mut_from_ptr_ptr!(out_alert);
430            match accepted.into_connection(config) {
431                Ok(built) => {
432                    let wrapped = crate::connection::Connection::from_server(built);
433                    set_boxed_mut_ptr(out_conn, wrapped);
434                    rustls_result::Ok
435                }
436                Err((e, accepted_alert)) => {
437                    set_boxed_mut_ptr(out_alert, accepted_alert);
438                    map_error(e)
439                }
440            }
441        }
442    }
443
444    /// Free a rustls_accepted.
445    ///
446    /// Parameters:
447    ///
448    /// accepted: The rustls_accepted to free.
449    ///
450    /// Calling with NULL is fine. Must not be called twice with the same value.
451    #[no_mangle]
452    pub extern "C" fn rustls_accepted_free(accepted: *mut rustls_accepted) {
453        ffi_panic_boundary! {
454            free_box(accepted);
455        }
456    }
457}
458
459/// Represents a TLS alert resulting from accepting a client.
460pub struct rustls_accepted_alert {
461    _private: [u8; 0],
462}
463
464impl Castable for rustls_accepted_alert {
465    type Ownership = OwnershipBox;
466    type RustType = AcceptedAlert;
467}
468
469impl rustls_accepted_alert {
470    /// Write some TLS bytes (an alert) to the network.
471    ///
472    /// The actual network I/O is performed by `callback`, which you provide.
473    /// Rustls will invoke your callback with a suitable buffer containing TLS
474    /// bytes to send. You don't have to write them all, just as many as you can
475    /// in one syscall.
476    ///
477    /// The `userdata` parameter is passed through directly to `callback`. Note that
478    /// this is distinct from the `userdata` parameter set with
479    /// `rustls_connection_set_userdata`.
480    ///
481    /// Returns 0 for success, or an errno value on error. Passes through return values
482    /// from callback. See [`rustls_write_callback`] or [`AcceptedAlert`] for
483    /// more details.
484    #[no_mangle]
485    pub extern "C" fn rustls_accepted_alert_write_tls(
486        accepted_alert: *mut rustls_accepted_alert,
487        callback: rustls_write_callback,
488        userdata: *mut c_void,
489        out_n: *mut size_t,
490    ) -> rustls_io_result {
491        ffi_panic_boundary! {
492            if out_n.is_null() {
493                return rustls_io_result(EINVAL);
494            }
495            let accepted_alert = try_mut_from_ptr!(accepted_alert);
496            let mut writer = CallbackWriter {
497                callback: try_callback!(callback),
498                userdata,
499            };
500            let n_written = match accepted_alert.write(&mut writer) {
501                Ok(n) => n,
502                Err(e) => return rustls_io_result(e.raw_os_error().unwrap_or(EIO)),
503            };
504            unsafe {
505                *out_n = n_written;
506            }
507            rustls_io_result(0)
508        }
509    }
510
511    /// Free a rustls_accepted_alert.
512    ///
513    /// Parameters:
514    ///
515    /// accepted_alert: The rustls_accepted_alert to free.
516    ///
517    /// Calling with NULL is fine. Must not be called twice with the same value.
518    #[no_mangle]
519    pub extern "C" fn rustls_accepted_alert_free(accepted_alert: *mut rustls_accepted_alert) {
520        ffi_panic_boundary! {
521            free_box(accepted_alert);
522        }
523    }
524}
525
526#[cfg(all(test, any(feature = "ring", feature = "aws-lc-rs")))]
527mod tests {
528    use std::cmp::min;
529    use std::collections::VecDeque;
530    use std::ptr::{null, null_mut};
531    use std::slice;
532
533    use libc::c_char;
534    use rustls::internal::msgs::codec::Codec;
535    use rustls::internal::msgs::enums::AlertLevel;
536    use rustls::{AlertDescription, ContentType, ProtocolVersion, SignatureScheme};
537
538    use crate::certificate::rustls_certified_key;
539    use crate::client::{rustls_client_config, rustls_client_config_builder};
540    use crate::server::rustls_server_config_builder;
541    use crate::verifier::rustls_server_cert_verifier;
542
543    use super::*;
544
545    #[test]
546    fn test_acceptor_new_and_free() {
547        let acceptor = rustls_acceptor::rustls_acceptor_new();
548        rustls_acceptor::rustls_acceptor_free(acceptor);
549    }
550
551    unsafe extern "C" fn vecdeque_read(
552        userdata: *mut c_void,
553        buf: *mut u8,
554        n: usize,
555        out_n: *mut usize,
556    ) -> rustls_io_result {
557        let vecdeq: *mut VecDeque<u8> = userdata as *mut _;
558        (*vecdeq).make_contiguous();
559        let first = (*vecdeq).as_slices().0;
560        let n = min(n, first.len());
561        std::ptr::copy_nonoverlapping(first.as_ptr(), buf, n);
562        (*vecdeq).drain(0..n).count();
563        *out_n = n;
564        rustls_io_result(0)
565    }
566
567    // Write bytes from the provided buffer into userdata (a `*mut VecDeque<u8>`).
568    unsafe extern "C" fn vecdeque_write(
569        userdata: *mut c_void,
570        buf: *const u8,
571        n: size_t,
572        out_n: *mut size_t,
573    ) -> rustls_io_result {
574        let vecdeq: *mut VecDeque<u8> = userdata as *mut _;
575        let buf = slice::from_raw_parts(buf, n);
576        (*vecdeq).extend(buf);
577        *out_n = n;
578        rustls_io_result(0)
579    }
580
581    // Send junk data to a rustls_acceptor, expect MessageInvalidContentType from accept().
582    #[test]
583    fn test_acceptor_corrupt_message() {
584        let acceptor = rustls_acceptor::rustls_acceptor_new();
585
586        let mut accepted = null_mut();
587        let mut accepted_alert = null_mut();
588        let mut n = 0_usize;
589        let mut data = VecDeque::new();
590        for _ in 0..1024 {
591            data.push_back(0u8);
592        }
593        let result = rustls_acceptor::rustls_acceptor_read_tls(
594            acceptor,
595            Some(vecdeque_read),
596            &mut data as *mut _ as *mut _,
597            &mut n,
598        );
599        assert!(matches!(result, rustls_io_result(0)));
600        assert_eq!(data.len(), 0);
601        assert_eq!(n, 1024);
602
603        let result =
604            rustls_acceptor::rustls_acceptor_accept(acceptor, &mut accepted, &mut accepted_alert);
605        assert_eq!(result, rustls_result::MessageInvalidContentType);
606        assert_eq!(accepted, null_mut());
607        assert_ne!(accepted_alert, null_mut());
608
609        unsafe extern "C" fn expected_alert_callback(
610            _userdata: *mut c_void,
611            buf: *const u8,
612            n: size_t,
613            _out_n: *mut size_t,
614        ) -> rustls_io_result {
615            let mut expected = vec![ContentType::Alert.into()];
616            ProtocolVersion::TLSv1_2.encode(&mut expected);
617            (2_u16).encode(&mut expected);
618            AlertLevel::Fatal.encode(&mut expected);
619            AlertDescription::DecodeError.encode(&mut expected);
620
621            let alert_bytes = slice::from_raw_parts(buf, n);
622            assert_eq!(alert_bytes, &expected);
623            rustls_io_result(0)
624        }
625
626        // We expect that an accepted alert was generated, and that its bytes match a fatal level
627        // TLS alert indicating a decode error.
628        let res = rustls_accepted_alert::rustls_accepted_alert_write_tls(
629            accepted_alert,
630            Some(expected_alert_callback),
631            null_mut(),
632            &mut n,
633        );
634        assert_eq!(res, rustls_io_result(0));
635
636        rustls_accepted_alert::rustls_accepted_alert_free(accepted_alert);
637        rustls_acceptor::rustls_acceptor_free(acceptor);
638    }
639
640    // Generate the bytes of a ClientHello for example.com. Helper function.
641    fn client_hello_bytes() -> VecDeque<u8> {
642        type ccb = rustls_client_config_builder;
643        type conn = rustls_connection;
644        let builder = ccb::rustls_client_config_builder_new();
645        let protocols: Vec<Vec<u8>> = vec!["zarp".into(), "yuun".into()];
646        let mut protocols_slices = vec![];
647        for p in &protocols {
648            protocols_slices.push(p.as_slice().into());
649        }
650        ccb::rustls_client_config_builder_set_alpn_protocols(
651            builder,
652            protocols_slices.as_slice().as_ptr(),
653            protocols_slices.len(),
654        );
655
656        let mut verifier = null_mut();
657        let result =
658            rustls_server_cert_verifier::rustls_platform_server_cert_verifier(&mut verifier);
659        assert_eq!(result, rustls_result::Ok);
660        assert!(!verifier.is_null());
661        rustls_client_config_builder::rustls_client_config_builder_set_server_verifier(
662            builder, verifier,
663        );
664
665        let mut config = null();
666        let result = ccb::rustls_client_config_builder_build(builder, &mut config);
667        assert_eq!(result, rustls_result::Ok);
668        assert!(!config.is_null());
669        let mut client_conn = null_mut();
670        let result = rustls_client_config::rustls_client_connection_new(
671            config,
672            c"example.com".as_ptr() as *const c_char,
673            &mut client_conn,
674        );
675        assert_eq!(result, rustls_result::Ok);
676        assert_ne!(client_conn, null_mut());
677
678        let mut buf = VecDeque::<u8>::new();
679        let mut n = 0_usize;
680        conn::rustls_connection_write_tls(
681            client_conn,
682            Some(vecdeque_write),
683            &mut buf as *mut _ as *mut _,
684            &mut n,
685        );
686
687        rustls_connection::rustls_connection_free(client_conn);
688        rustls_client_config::rustls_client_config_free(config);
689        rustls_server_cert_verifier::rustls_server_cert_verifier_free(verifier);
690        buf
691    }
692
693    fn make_server_config() -> *const rustls_server_config {
694        let builder = rustls_server_config_builder::rustls_server_config_builder_new();
695        let cert_pem = include_str!("../testdata/example.com/cert.pem").as_bytes();
696        let key_pem = include_str!("../testdata/example.com/key.pem").as_bytes();
697        let mut certified_key = null();
698        let result = rustls_certified_key::rustls_certified_key_build(
699            cert_pem.as_ptr(),
700            cert_pem.len(),
701            key_pem.as_ptr(),
702            key_pem.len(),
703            &mut certified_key,
704        );
705        assert_eq!(result, rustls_result::Ok);
706        let result = rustls_server_config_builder::rustls_server_config_builder_set_certified_keys(
707            builder,
708            &certified_key,
709            1,
710        );
711        assert_eq!(result, rustls_result::Ok);
712        rustls_certified_key::rustls_certified_key_free(certified_key);
713
714        let mut config = null();
715        let res =
716            rustls_server_config_builder::rustls_server_config_builder_build(builder, &mut config);
717        assert_eq!(res, rustls_result::Ok);
718        assert!(!config.is_null());
719        config
720    }
721
722    // Send a real ClientHello to acceptor, expect success
723    #[cfg_attr(miri, ignore)]
724    #[test]
725    fn test_acceptor_success() {
726        let acceptor = rustls_acceptor::rustls_acceptor_new();
727
728        let mut accepted = null_mut();
729        let mut accepted_alert = null_mut();
730        let mut n = 0;
731        let mut data = client_hello_bytes();
732        let data_len = data.len();
733
734        let result = rustls_acceptor::rustls_acceptor_read_tls(
735            acceptor,
736            Some(vecdeque_read),
737            &mut data as *mut _ as *mut _,
738            &mut n,
739        );
740        assert_eq!(result, rustls_io_result(0));
741        assert_eq!(data.len(), 0);
742        assert_eq!(n, data_len);
743
744        let result =
745            rustls_acceptor::rustls_acceptor_accept(acceptor, &mut accepted, &mut accepted_alert);
746        assert_eq!(result, rustls_result::Ok);
747        assert_ne!(accepted, null_mut());
748        assert_eq!(accepted_alert, null_mut());
749
750        let sni = rustls_accepted::rustls_accepted_server_name(accepted);
751        let sni_as_slice = unsafe { slice::from_raw_parts(sni.data as *const u8, sni.len) };
752        let sni_as_str = std::str::from_utf8(sni_as_slice).unwrap_or("%!(ERROR)");
753        assert_eq!(sni_as_str, "example.com");
754
755        let mut signature_schemes = vec![];
756        for i in 0.. {
757            let s = rustls_accepted::rustls_accepted_signature_scheme(accepted, i);
758            if s == 0 {
759                break;
760            }
761            signature_schemes.push(s);
762        }
763        // Sort to ensure consistent comparison
764        signature_schemes.sort();
765
766        #[cfg_attr(not(feature = "aws-lc-rs"), allow(unused_mut))]
767        let mut expected_schemes = vec![
768            SignatureScheme::RSA_PKCS1_SHA256,
769            SignatureScheme::ECDSA_NISTP256_SHA256,
770            SignatureScheme::RSA_PKCS1_SHA384,
771            SignatureScheme::ECDSA_NISTP384_SHA384,
772            SignatureScheme::RSA_PKCS1_SHA512,
773            SignatureScheme::RSA_PSS_SHA256,
774            SignatureScheme::RSA_PSS_SHA384,
775            SignatureScheme::RSA_PSS_SHA512,
776            SignatureScheme::ED25519,
777        ];
778        #[cfg(feature = "aws-lc-rs")] // aws-lc-rs also includes P-521.
779        expected_schemes.push(SignatureScheme::ECDSA_NISTP521_SHA512);
780
781        let mut expected_schemes = expected_schemes
782            .into_iter()
783            .map(u16::from)
784            .collect::<Vec<_>>();
785        expected_schemes.sort();
786        assert_eq!(signature_schemes, expected_schemes);
787
788        let mut alpn = vec![];
789        for i in 0.. {
790            let a = rustls_accepted::rustls_accepted_alpn(accepted, i);
791            if a.len == 0 {
792                break;
793            }
794            alpn.push(a);
795        }
796
797        assert_eq!(alpn.len(), 2);
798        // No need to sort ALPN because order is determine by what the client sent.
799        let alpn0 = unsafe { slice::from_raw_parts(alpn[0].data, alpn[0].len) };
800        let alpn1 = unsafe { slice::from_raw_parts(alpn[1].data, alpn[1].len) };
801        assert_eq!(alpn0, "zarp".as_bytes());
802        assert_eq!(alpn1, "yuun".as_bytes());
803
804        let server_config = make_server_config();
805        let mut conn = null_mut();
806        let result = rustls_accepted::rustls_accepted_into_connection(
807            accepted,
808            server_config,
809            &mut conn,
810            &mut accepted_alert,
811        );
812        assert_eq!(result, rustls_result::Ok);
813        assert_eq!(accepted_alert, null_mut());
814        assert!(!rustls_connection::rustls_connection_wants_read(conn));
815        assert!(rustls_connection::rustls_connection_wants_write(conn));
816        assert!(rustls_connection::rustls_connection_is_handshaking(conn));
817
818        rustls_accepted_alert::rustls_accepted_alert_free(accepted_alert);
819        rustls_acceptor::rustls_acceptor_free(acceptor);
820        rustls_accepted::rustls_accepted_free(accepted);
821        rustls_connection::rustls_connection_free(conn);
822        rustls_server_config::rustls_server_config_free(server_config);
823    }
824}