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