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}