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}