1use std::ffi::CStr;
2use std::fmt::{Debug, Formatter};
3use std::slice;
4use std::sync::Arc;
5
6use libc::{c_char, size_t};
7use rustls::client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier};
8use rustls::client::{EchConfig, EchGreaseConfig, EchMode, ResolvesClientCert};
9use rustls::crypto::{CryptoProvider, verify_tls12_signature, verify_tls13_signature};
10use rustls::pki_types::{CertificateDer, EchConfigListBytes, ServerName, UnixTime};
11use rustls::{
12 ClientConfig, ClientConnection, DigitallySignedStruct, Error, KeyLog, KeyLogFile,
13 ProtocolVersion, SignatureScheme, SupportedProtocolVersion, sign::CertifiedKey,
14};
15
16use crate::certificate::rustls_certified_key;
17use crate::connection::{Connection, rustls_connection};
18use crate::crypto_provider::{self, rustls_crypto_provider, rustls_hpke};
19use crate::error::{self, map_error, rustls_result};
20use crate::ffi::{
21 Castable, OwnershipArc, OwnershipBox, free_arc, free_box, set_arc_mut_ptr, set_boxed_mut_ptr,
22 to_boxed_mut_ptr, try_box_from_ptr, try_clone_arc, try_mut_from_ptr, try_mut_from_ptr_ptr,
23 try_ref_from_ptr, try_ref_from_ptr_ptr, try_slice,
24};
25use crate::keylog::{CallbackKeyLog, rustls_keylog_log_callback, rustls_keylog_will_log_callback};
26use crate::panic::ffi_panic_boundary;
27use crate::rslice::NulByte;
28use crate::rslice::{rustls_slice_bytes, rustls_slice_slice_bytes, rustls_str};
29use crate::userdata::userdata_get;
30use crate::verifier::rustls_server_cert_verifier;
31
32pub struct rustls_client_config_builder {
45 _private: [u8; 0],
46}
47
48impl Castable for rustls_client_config_builder {
49 type Ownership = OwnershipBox;
50 type RustType = ClientConfigBuilder;
51}
52
53pub(crate) struct ClientConfigBuilder {
54 provider: Option<Arc<CryptoProvider>>,
55 versions: Vec<&'static SupportedProtocolVersion>,
56 verifier: Option<Arc<dyn ServerCertVerifier>>,
57 alpn_protocols: Vec<Vec<u8>>,
58 check_selected_alpn: bool,
59 enable_sni: bool,
60 cert_resolver: Option<Arc<dyn ResolvesClientCert>>,
61 key_log: Option<Arc<dyn KeyLog>>,
62 ech_mode: Option<EchMode>,
63}
64
65impl Default for ClientConfigBuilder {
66 fn default() -> Self {
67 Self {
68 provider: None,
69 versions: Vec::new(),
73 verifier: None,
74 alpn_protocols: Vec::new(),
75 check_selected_alpn: true,
76 enable_sni: true,
79 cert_resolver: None,
80 key_log: None,
81 ech_mode: None,
82 }
83 }
84}
85
86pub struct rustls_client_config {
91 _private: [u8; 0],
92}
93
94impl Castable for rustls_client_config {
95 type Ownership = OwnershipArc;
96 type RustType = ClientConfig;
97}
98
99impl rustls_client_config_builder {
100 #[no_mangle]
114 pub extern "C" fn rustls_client_config_builder_new() -> *mut rustls_client_config_builder {
115 ffi_panic_boundary! {
116 let builder = ClientConfigBuilder {
117 provider: crypto_provider::get_default_or_install_from_crate_features(),
118 ..ClientConfigBuilder::default()
119 };
120 to_boxed_mut_ptr(builder)
121 }
122 }
123
124 #[no_mangle]
145 pub extern "C" fn rustls_client_config_builder_new_custom(
146 provider: *const rustls_crypto_provider,
147 tls_versions: *const u16,
148 tls_versions_len: size_t,
149 builder_out: *mut *mut rustls_client_config_builder,
150 ) -> rustls_result {
151 ffi_panic_boundary! {
152 let provider = try_clone_arc!(provider);
153 let tls_versions = try_slice!(tls_versions, tls_versions_len);
154 let mut versions = vec![];
155 for version_number in tls_versions {
156 let proto = ProtocolVersion::from(*version_number);
157 if proto == rustls::version::TLS12.version {
158 versions.push(&rustls::version::TLS12);
159 } else if proto == rustls::version::TLS13.version {
160 versions.push(&rustls::version::TLS13);
161 }
162 }
163 let builder_out = try_mut_from_ptr_ptr!(builder_out);
164
165 let config_builder = ClientConfigBuilder {
166 provider: Some(provider),
167 versions,
168 ..ClientConfigBuilder::default()
169 };
170
171 set_boxed_mut_ptr(builder_out, config_builder);
172 rustls_result::Ok
173 }
174 }
175
176 #[no_mangle]
204 pub extern "C" fn rustls_client_config_builder_dangerous_set_certificate_verifier(
205 config_builder: *mut rustls_client_config_builder,
206 callback: rustls_verify_server_cert_callback,
207 ) -> rustls_result {
208 ffi_panic_boundary! {
209 let config_builder = try_mut_from_ptr!(config_builder);
210 let callback = match callback {
211 Some(cb) => cb,
212 None => return rustls_result::InvalidParameter,
213 };
214
215 let provider = match &config_builder.provider {
216 Some(provider) => provider.clone(),
217 None => return rustls_result::NoDefaultCryptoProvider,
218 };
219
220 config_builder.verifier = Some(Arc::new(Verifier { provider, callback }));
221 rustls_result::Ok
222 }
223 }
224
225 #[no_mangle]
229 pub extern "C" fn rustls_client_config_builder_set_server_verifier(
230 builder: *mut rustls_client_config_builder,
231 verifier: *const rustls_server_cert_verifier,
232 ) {
233 ffi_panic_boundary! {
234 let builder = try_mut_from_ptr!(builder);
235 builder.verifier = Some(try_ref_from_ptr!(verifier).clone());
236 }
237 }
238
239 #[no_mangle]
255 pub extern "C" fn rustls_client_config_builder_set_alpn_protocols(
256 builder: *mut rustls_client_config_builder,
257 protocols: *const rustls_slice_bytes,
258 len: size_t,
259 ) -> rustls_result {
260 ffi_panic_boundary! {
261 let config = try_mut_from_ptr!(builder);
262 let protocols = try_slice!(protocols, len);
263
264 let mut vv = Vec::with_capacity(protocols.len());
265 for p in protocols {
266 let v = try_slice!(p.data, p.len);
267 vv.push(v.to_vec());
268 }
269 config.alpn_protocols = vv;
270 rustls_result::Ok
271 }
272 }
273
274 #[no_mangle]
280 pub extern "C" fn rustls_client_config_builder_set_check_selected_alpn(
281 config: *mut rustls_client_config_builder,
282 enable: bool,
283 ) {
284 ffi_panic_boundary! {
285 let config = try_mut_from_ptr!(config);
286 config.check_selected_alpn = enable;
287 }
288 }
289
290 #[no_mangle]
293 pub extern "C" fn rustls_client_config_builder_set_enable_sni(
294 config: *mut rustls_client_config_builder,
295 enable: bool,
296 ) {
297 ffi_panic_boundary! {
298 let config = try_mut_from_ptr!(config);
299 config.enable_sni = enable;
300 }
301 }
302
303 #[no_mangle]
318 pub extern "C" fn rustls_client_config_builder_set_certified_key(
319 builder: *mut rustls_client_config_builder,
320 certified_keys: *const *const rustls_certified_key,
321 certified_keys_len: size_t,
322 ) -> rustls_result {
323 ffi_panic_boundary! {
324 let config = try_mut_from_ptr!(builder);
325 let keys_ptrs = try_slice!(certified_keys, certified_keys_len);
326 let mut keys = Vec::new();
327 for &key_ptr in keys_ptrs {
328 let certified_key = try_clone_arc!(key_ptr);
329 keys.push(certified_key);
330 }
331 config.cert_resolver = Some(Arc::new(ResolvesClientCertFromChoices { keys }));
332 rustls_result::Ok
333 }
334 }
335
336 #[no_mangle]
348 pub extern "C" fn rustls_client_config_builder_set_key_log_file(
349 builder: *mut rustls_client_config_builder,
350 ) -> rustls_result {
351 ffi_panic_boundary! {
352 let builder = try_mut_from_ptr!(builder);
353 builder.key_log = Some(Arc::new(KeyLogFile::new()));
354 rustls_result::Ok
355 }
356 }
357
358 #[no_mangle]
380 pub extern "C" fn rustls_client_config_builder_set_key_log(
381 builder: *mut rustls_client_config_builder,
382 log_cb: rustls_keylog_log_callback,
383 will_log_cb: rustls_keylog_will_log_callback,
384 ) -> rustls_result {
385 ffi_panic_boundary! {
386 let builder = try_mut_from_ptr!(builder);
387 let log_cb = match log_cb {
388 Some(cb) => cb,
389 None => return rustls_result::NullParameter,
390 };
391
392 builder.key_log = Some(Arc::new(CallbackKeyLog {
393 log_cb,
394 will_log_cb,
395 }));
396
397 rustls_result::Ok
398 }
399 }
400
401 #[no_mangle]
424 pub extern "C" fn rustls_client_config_builder_enable_ech(
425 builder: *mut rustls_client_config_builder,
426 ech_config_list_bytes: *const u8,
427 ech_config_list_bytes_size: size_t,
428 hpke: *const rustls_hpke,
429 ) -> rustls_result {
430 ffi_panic_boundary! {
431 let builder = try_mut_from_ptr!(builder);
432 let ech_config_list_bytes =
433 try_slice!(ech_config_list_bytes, ech_config_list_bytes_size);
434 let hpke = try_ref_from_ptr!(hpke);
435
436 if !builder.versions.is_empty() && builder.versions != [&rustls::version::TLS13] {
439 return rustls_result::BuilderIncompatibleTlsVersions;
440 }
441
442 builder.ech_mode = match EchConfig::new(
446 EchConfigListBytes::from(ech_config_list_bytes),
447 hpke.suites,
448 ) {
449 Ok(ech_config) => Some(ech_config.into()),
450 Err(err) => {
451 return map_error(err);
452 }
453 };
454
455 rustls_result::Ok
456 }
457 }
458
459 #[no_mangle]
477 pub extern "C" fn rustls_client_config_builder_enable_ech_grease(
478 builder: *mut rustls_client_config_builder,
479 hpke: *const rustls_hpke,
480 ) -> rustls_result {
481 ffi_panic_boundary! {
482 let builder = try_mut_from_ptr!(builder);
483 let hpke = try_ref_from_ptr!(hpke);
484
485 let provider = match &builder.provider {
486 Some(provider) => provider,
487 None => return rustls_result::NoDefaultCryptoProvider,
488 };
489
490 let Some((suite, placeholder_pk)) = hpke.grease_public_key(provider) else {
491 return rustls_result::HpkeError;
492 };
493
494 if !builder.versions.is_empty() && builder.versions != [&rustls::version::TLS13] {
497 return rustls_result::BuilderIncompatibleTlsVersions;
498 }
499 builder.ech_mode = Some(EchMode::Grease(EchGreaseConfig::new(suite, placeholder_pk)));
500
501 rustls_result::Ok
502 }
503 }
504
505 #[no_mangle]
508 pub extern "C" fn rustls_client_config_builder_build(
509 builder: *mut rustls_client_config_builder,
510 config_out: *mut *const rustls_client_config,
511 ) -> rustls_result {
512 ffi_panic_boundary! {
513 let builder = try_box_from_ptr!(builder);
514 let config_out = try_ref_from_ptr_ptr!(config_out);
515
516 let provider = match builder.provider {
517 Some(provider) => provider,
518 None => return rustls_result::NoDefaultCryptoProvider,
519 };
520
521 let verifier = match builder.verifier {
522 Some(v) => v,
523 None => return rustls_result::NoServerCertVerifier,
524 };
525
526 let config = ClientConfig::builder_with_provider(provider);
527
528 let wants_verifier;
535 if let Some(ech_mode) = builder.ech_mode {
536 wants_verifier = match config.with_ech(ech_mode) {
537 Ok(config) => config,
538 Err(err) => return map_error(err),
539 }
540 } else {
541 let versions = match builder.versions.is_empty() {
542 true => rustls::DEFAULT_VERSIONS,
543 false => builder.versions.as_slice(),
544 };
545 wants_verifier = match config.with_protocol_versions(versions) {
546 Ok(config) => config,
547 Err(err) => return map_error(err),
548 };
549 }
550
551 let config = wants_verifier
552 .dangerous()
553 .with_custom_certificate_verifier(verifier);
554 let mut config = match builder.cert_resolver {
555 Some(r) => config.with_client_cert_resolver(r),
556 None => config.with_no_client_auth(),
557 };
558 config.alpn_protocols = builder.alpn_protocols;
559 config.enable_sni = builder.enable_sni;
560
561 if let Some(key_log) = builder.key_log {
562 config.key_log = key_log;
563 }
564
565 set_arc_mut_ptr(config_out, config);
566 rustls_result::Ok
567 }
568 }
569
570 #[no_mangle]
578 pub extern "C" fn rustls_client_config_builder_free(config: *mut rustls_client_config_builder) {
579 ffi_panic_boundary! {
580 free_box(config);
581 }
582 }
583}
584
585#[allow(non_camel_case_types)]
592#[repr(C)]
593pub struct rustls_verify_server_cert_params<'a> {
594 pub end_entity_cert_der: rustls_slice_bytes<'a>,
595 pub intermediate_certs_der: &'a rustls_slice_slice_bytes<'a>,
596 pub server_name: rustls_str<'a>,
597 pub ocsp_response: rustls_slice_bytes<'a>,
598}
599
600#[allow(non_camel_case_types)]
604pub type rustls_verify_server_cert_user_data = *mut libc::c_void;
605
606#[allow(non_camel_case_types)]
612pub type rustls_verify_server_cert_callback = Option<
613 unsafe extern "C" fn(
614 userdata: rustls_verify_server_cert_user_data,
615 params: *const rustls_verify_server_cert_params,
616 ) -> u32,
617>;
618
619type VerifyCallback = unsafe extern "C" fn(
622 userdata: rustls_verify_server_cert_user_data,
623 params: *const rustls_verify_server_cert_params,
624) -> u32;
625
626struct Verifier {
628 provider: Arc<CryptoProvider>,
629 callback: VerifyCallback,
630}
631
632unsafe impl Send for Verifier {}
635
636unsafe impl Sync for Verifier {}
640
641impl ServerCertVerifier for Verifier {
642 fn verify_server_cert(
643 &self,
644 end_entity: &CertificateDer,
645 intermediates: &[CertificateDer],
646 server_name: &ServerName<'_>,
647 ocsp_response: &[u8],
648 _now: UnixTime,
649 ) -> Result<ServerCertVerified, Error> {
650 let cb = self.callback;
651 let server_name = server_name.to_str();
652 let server_name = match server_name.as_ref().try_into() {
653 Ok(r) => r,
654 Err(NulByte {}) => return Err(Error::General("NUL byte in SNI".to_string())),
655 };
656
657 let intermediates: Vec<_> = intermediates.iter().map(|cert| cert.as_ref()).collect();
658
659 let intermediates = rustls_slice_slice_bytes {
660 inner: &intermediates,
661 };
662
663 let params = rustls_verify_server_cert_params {
664 end_entity_cert_der: end_entity.as_ref().into(),
665 intermediate_certs_der: &intermediates,
666 server_name,
667 ocsp_response: ocsp_response.into(),
668 };
669 let userdata = userdata_get()
670 .map_err(|_| Error::General("internal error with thread-local storage".to_string()))?;
671 let result = unsafe { cb(userdata, ¶ms) };
672 match rustls_result::from(result) {
673 rustls_result::Ok => Ok(ServerCertVerified::assertion()),
674 r => Err(error::cert_result_to_error(r)),
675 }
676 }
677
678 fn verify_tls12_signature(
679 &self,
680 message: &[u8],
681 cert: &CertificateDer,
682 dss: &DigitallySignedStruct,
683 ) -> Result<HandshakeSignatureValid, Error> {
684 verify_tls12_signature(
685 message,
686 cert,
687 dss,
688 &self.provider.signature_verification_algorithms,
689 )
690 }
691
692 fn verify_tls13_signature(
693 &self,
694 message: &[u8],
695 cert: &CertificateDer,
696 dss: &DigitallySignedStruct,
697 ) -> Result<HandshakeSignatureValid, Error> {
698 verify_tls13_signature(
699 message,
700 cert,
701 dss,
702 &self.provider.signature_verification_algorithms,
703 )
704 }
705
706 fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
707 self.provider
708 .signature_verification_algorithms
709 .supported_schemes()
710 }
711}
712
713impl Debug for Verifier {
714 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
715 f.debug_struct("Verifier").finish()
716 }
717}
718
719#[derive(Debug)]
721struct ResolvesClientCertFromChoices {
722 keys: Vec<Arc<CertifiedKey>>,
723}
724
725impl ResolvesClientCert for ResolvesClientCertFromChoices {
726 fn resolve(
727 &self,
728 _acceptable_issuers: &[&[u8]],
729 sig_schemes: &[SignatureScheme],
730 ) -> Option<Arc<CertifiedKey>> {
731 for key in self.keys.iter() {
732 if key.key.choose_scheme(sig_schemes).is_some() {
733 return Some(key.clone());
734 }
735 }
736 None
737 }
738
739 fn has_certs(&self) -> bool {
740 !self.keys.is_empty()
741 }
742}
743
744impl rustls_client_config {
745 #[no_mangle]
752 pub extern "C" fn rustls_client_config_fips(config: *const rustls_client_config) -> bool {
753 ffi_panic_boundary! {
754 try_ref_from_ptr!(config).fips()
755 }
756 }
757
758 #[no_mangle]
768 pub extern "C" fn rustls_client_config_free(config: *const rustls_client_config) {
769 ffi_panic_boundary! {
770 free_arc(config);
771 }
772 }
773
774 #[no_mangle]
790 pub extern "C" fn rustls_client_connection_new(
791 config: *const rustls_client_config,
792 server_name: *const c_char,
793 conn_out: *mut *mut rustls_connection,
794 ) -> rustls_result {
795 ffi_panic_boundary! {
796 Self::rustls_client_connection_new_alpn_inner(
797 config,
798 server_name,
799 try_clone_arc!(config).alpn_protocols.clone(),
800 conn_out,
801 )
802 }
803 }
804
805 #[no_mangle]
831 pub extern "C" fn rustls_client_connection_new_alpn(
832 config: *const rustls_client_config,
833 server_name: *const c_char,
834 alpn_protocols: *const rustls_slice_bytes,
835 alpn_protocols_len: size_t,
836 conn_out: *mut *mut rustls_connection,
837 ) -> rustls_result {
838 ffi_panic_boundary! {
839 let raw_protocols = try_slice!(alpn_protocols, alpn_protocols_len);
840 let mut alpn_protocols = Vec::with_capacity(raw_protocols.len());
841 for p in raw_protocols {
842 alpn_protocols.push(try_slice!(p.data, p.len).to_vec());
843 }
844
845 Self::rustls_client_connection_new_alpn_inner(
846 config,
847 server_name,
848 alpn_protocols,
849 conn_out,
850 )
851 }
852 }
853
854 fn rustls_client_connection_new_alpn_inner(
855 config: *const rustls_client_config,
856 server_name: *const c_char,
857 alpn_protocols: Vec<Vec<u8>>,
858 conn_out: *mut *mut rustls_connection,
859 ) -> rustls_result {
860 let server_name = unsafe {
861 if server_name.is_null() {
862 return rustls_result::NullParameter;
863 }
864 CStr::from_ptr(server_name)
865 };
866 let Ok(server_name) = server_name.to_str() else {
867 return rustls_result::InvalidDnsNameError;
868 };
869 let Ok(server_name) = server_name.try_into() else {
870 return rustls_result::InvalidDnsNameError;
871 };
872
873 set_boxed_mut_ptr(
874 try_mut_from_ptr_ptr!(conn_out),
875 Connection::from_client(
876 ClientConnection::new_with_alpn(
877 try_clone_arc!(config),
878 server_name,
879 alpn_protocols,
880 )
881 .unwrap(),
882 ),
883 );
884 rustls_result::Ok
885 }
886}
887
888#[cfg(all(test, any(feature = "ring", feature = "aws-lc-rs")))]
889mod tests {
890 use std::ptr::{null, null_mut};
891
892 use super::*;
893
894 #[test]
895 fn test_config_builder() {
896 let builder = rustls_client_config_builder::rustls_client_config_builder_new();
897 let mut verifier = null_mut();
898 let result =
899 rustls_server_cert_verifier::rustls_platform_server_cert_verifier(&mut verifier);
900 assert_eq!(result, rustls_result::Ok);
901 assert!(!verifier.is_null());
902 rustls_client_config_builder::rustls_client_config_builder_set_server_verifier(
903 builder, verifier,
904 );
905 let h1 = "http/1.1".as_bytes();
906 let h2 = "h2".as_bytes();
907 let alpn = [h1.into(), h2.into()];
908 rustls_client_config_builder::rustls_client_config_builder_set_alpn_protocols(
909 builder,
910 alpn.as_ptr(),
911 alpn.len(),
912 );
913 rustls_client_config_builder::rustls_client_config_builder_set_enable_sni(builder, false);
914 let mut config = null();
915 let result =
916 rustls_client_config_builder::rustls_client_config_builder_build(builder, &mut config);
917 assert_eq!(result, rustls_result::Ok);
918 assert!(!config.is_null());
919 {
920 let config2 = try_ref_from_ptr!(config);
921 assert!(!config2.enable_sni);
922 assert_eq!(config2.alpn_protocols, vec![h1, h2]);
923 }
924 rustls_client_config::rustls_client_config_free(config);
925 rustls_server_cert_verifier::rustls_server_cert_verifier_free(verifier);
926 }
927
928 #[test]
930 #[cfg_attr(miri, ignore)]
931 fn test_client_connection_new() {
932 let (config, verifier) = test_config();
933
934 let mut conn = null_mut();
935 let result = rustls_client_config::rustls_client_connection_new(
936 config,
937 c"example.com".as_ptr() as *const c_char,
938 &mut conn,
939 );
940 if !matches!(result, rustls_result::Ok) {
941 panic!("expected RUSTLS_RESULT_OK, got {result:?}");
942 }
943 assert!(!rustls_connection::rustls_connection_wants_read(conn));
944 assert!(rustls_connection::rustls_connection_wants_write(conn));
945 assert!(rustls_connection::rustls_connection_is_handshaking(conn));
946
947 let some_byte = 42u8;
948 let mut alpn_protocol: *const u8 = &some_byte;
949 let mut alpn_protocol_len = 1;
950 rustls_connection::rustls_connection_get_alpn_protocol(
951 conn,
952 &mut alpn_protocol,
953 &mut alpn_protocol_len,
954 );
955 assert_eq!(alpn_protocol, null());
956 assert_eq!(alpn_protocol_len, 0);
957
958 assert_eq!(
959 rustls_connection::rustls_connection_get_negotiated_ciphersuite(conn),
960 0
961 );
962 let cs_name = rustls_connection::rustls_connection_get_negotiated_ciphersuite_name(conn);
963 assert_eq!(unsafe { cs_name.to_str() }, "");
964 assert_eq!(
965 rustls_connection::rustls_connection_get_peer_certificate(conn, 0),
966 null()
967 );
968
969 assert_eq!(
970 rustls_connection::rustls_connection_get_protocol_version(conn),
971 0
972 );
973 rustls_connection::rustls_connection_free(conn);
974 rustls_server_cert_verifier::rustls_server_cert_verifier_free(verifier);
975 }
976
977 #[test]
979 #[cfg_attr(miri, ignore)]
980 fn test_client_connection_new_alpn() {
981 let (config, verifier) = test_config();
982 let alpn_protocols = [
983 rustls_slice_bytes::from(b"h2".as_ref()),
984 rustls_slice_bytes::from(b"http/1.1".as_ref()),
985 ];
986
987 let mut conn = null_mut();
988 let result = rustls_client_config::rustls_client_connection_new_alpn(
989 config,
990 c"example.com".as_ptr() as *const c_char,
991 alpn_protocols.as_ptr(),
992 alpn_protocols.len() as size_t,
993 &mut conn,
994 );
995 if !matches!(result, rustls_result::Ok) {
996 panic!("expected RUSTLS_RESULT_OK, got {result:?}");
997 }
998
999 rustls_connection::rustls_connection_free(conn);
1000 rustls_server_cert_verifier::rustls_server_cert_verifier_free(verifier);
1001 }
1002
1003 fn test_config() -> (
1004 *const rustls_client_config,
1005 *mut rustls_server_cert_verifier,
1006 ) {
1007 let builder = rustls_client_config_builder::rustls_client_config_builder_new();
1008 let mut verifier = null_mut();
1009 let result =
1010 rustls_server_cert_verifier::rustls_platform_server_cert_verifier(&mut verifier);
1011 assert_eq!(result, rustls_result::Ok);
1012 assert!(!verifier.is_null());
1013 rustls_client_config_builder::rustls_client_config_builder_set_server_verifier(
1014 builder, verifier,
1015 );
1016 let mut config = null();
1017 let result =
1018 rustls_client_config_builder::rustls_client_config_builder_build(builder, &mut config);
1019 assert_eq!(result, rustls_result::Ok);
1020 assert!(!config.is_null());
1021 (config, verifier)
1022 }
1023
1024 #[test]
1025 #[cfg_attr(miri, ignore)]
1026 fn test_client_connection_new_ipaddress() {
1027 let builder = rustls_client_config_builder::rustls_client_config_builder_new();
1028 let mut verifier = null_mut();
1029 let result =
1030 rustls_server_cert_verifier::rustls_platform_server_cert_verifier(&mut verifier);
1031 assert_eq!(result, rustls_result::Ok);
1032 assert!(!verifier.is_null());
1033 rustls_client_config_builder::rustls_client_config_builder_set_server_verifier(
1034 builder, verifier,
1035 );
1036 let mut config = null();
1037 let result =
1038 rustls_client_config_builder::rustls_client_config_builder_build(builder, &mut config);
1039 assert_eq!(result, rustls_result::Ok);
1040 assert!(!config.is_null());
1041 let mut conn = null_mut();
1042 let result = rustls_client_config::rustls_client_connection_new(
1043 config,
1044 c"198.51.100.198".as_ptr() as *const c_char,
1045 &mut conn,
1046 );
1047 if !matches!(result, rustls_result::Ok) {
1048 panic!("expected RUSTLS_RESULT_OK, got {result:?}");
1049 }
1050 rustls_server_cert_verifier::rustls_server_cert_verifier_free(verifier);
1051 }
1052
1053 #[test]
1054 fn test_client_builder_no_verifier_err() {
1055 let builder = rustls_client_config_builder::rustls_client_config_builder_new();
1056 let mut config = null();
1057 let result =
1058 rustls_client_config_builder::rustls_client_config_builder_build(builder, &mut config);
1059 assert_eq!(result, rustls_result::NoServerCertVerifier);
1060 }
1061}