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 arc_castable, box_castable, 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
32box_castable! {
33 pub struct rustls_client_config_builder(ClientConfigBuilder);
46}
47
48pub(crate) struct ClientConfigBuilder {
49 provider: Option<Arc<CryptoProvider>>,
50 versions: Vec<&'static SupportedProtocolVersion>,
51 verifier: Option<Arc<dyn ServerCertVerifier>>,
52 alpn_protocols: Vec<Vec<u8>>,
53 enable_sni: bool,
54 cert_resolver: Option<Arc<dyn ResolvesClientCert>>,
55 key_log: Option<Arc<dyn KeyLog>>,
56 ech_mode: Option<EchMode>,
57}
58
59impl Default for ClientConfigBuilder {
60 fn default() -> Self {
61 Self {
62 provider: None,
63 versions: Vec::new(),
67 verifier: None,
68 alpn_protocols: Vec::new(),
69 enable_sni: true,
72 cert_resolver: None,
73 key_log: None,
74 ech_mode: None,
75 }
76 }
77}
78
79arc_castable! {
80 pub struct rustls_client_config(ClientConfig);
85}
86
87impl rustls_client_config_builder {
88 #[no_mangle]
102 pub extern "C" fn rustls_client_config_builder_new() -> *mut rustls_client_config_builder {
103 ffi_panic_boundary! {
104 let builder = ClientConfigBuilder {
105 provider: crypto_provider::get_default_or_install_from_crate_features(),
106 ..ClientConfigBuilder::default()
107 };
108 to_boxed_mut_ptr(builder)
109 }
110 }
111
112 #[no_mangle]
133 pub extern "C" fn rustls_client_config_builder_new_custom(
134 provider: *const rustls_crypto_provider,
135 tls_versions: *const u16,
136 tls_versions_len: size_t,
137 builder_out: *mut *mut rustls_client_config_builder,
138 ) -> rustls_result {
139 ffi_panic_boundary! {
140 let provider = try_clone_arc!(provider);
141 let tls_versions = try_slice!(tls_versions, tls_versions_len);
142 let mut versions = vec![];
143 for version_number in tls_versions {
144 let proto = ProtocolVersion::from(*version_number);
145 if proto == rustls::version::TLS12.version {
146 versions.push(&rustls::version::TLS12);
147 } else if proto == rustls::version::TLS13.version {
148 versions.push(&rustls::version::TLS13);
149 }
150 }
151 let builder_out = try_mut_from_ptr_ptr!(builder_out);
152
153 let config_builder = ClientConfigBuilder {
154 provider: Some(provider),
155 versions,
156 ..ClientConfigBuilder::default()
157 };
158
159 set_boxed_mut_ptr(builder_out, config_builder);
160 rustls_result::Ok
161 }
162 }
163
164 #[no_mangle]
192 pub extern "C" fn rustls_client_config_builder_dangerous_set_certificate_verifier(
193 config_builder: *mut rustls_client_config_builder,
194 callback: rustls_verify_server_cert_callback,
195 ) -> rustls_result {
196 ffi_panic_boundary! {
197 let config_builder = try_mut_from_ptr!(config_builder);
198 let callback = match callback {
199 Some(cb) => cb,
200 None => return rustls_result::InvalidParameter,
201 };
202
203 let provider = match &config_builder.provider {
204 Some(provider) => provider.clone(),
205 None => return rustls_result::NoDefaultCryptoProvider,
206 };
207
208 config_builder.verifier = Some(Arc::new(Verifier { provider, callback }));
209 rustls_result::Ok
210 }
211 }
212
213 #[no_mangle]
217 pub extern "C" fn rustls_client_config_builder_set_server_verifier(
218 builder: *mut rustls_client_config_builder,
219 verifier: *const rustls_server_cert_verifier,
220 ) {
221 ffi_panic_boundary! {
222 let builder = try_mut_from_ptr!(builder);
223 builder.verifier = Some(try_ref_from_ptr!(verifier).clone());
224 }
225 }
226
227 #[no_mangle]
243 pub extern "C" fn rustls_client_config_builder_set_alpn_protocols(
244 builder: *mut rustls_client_config_builder,
245 protocols: *const rustls_slice_bytes,
246 len: size_t,
247 ) -> rustls_result {
248 ffi_panic_boundary! {
249 let config = try_mut_from_ptr!(builder);
250 let protocols = try_slice!(protocols, len);
251
252 let mut vv = Vec::with_capacity(protocols.len());
253 for p in protocols {
254 let v = try_slice!(p.data, p.len);
255 vv.push(v.to_vec());
256 }
257 config.alpn_protocols = vv;
258 rustls_result::Ok
259 }
260 }
261
262 #[no_mangle]
265 pub extern "C" fn rustls_client_config_builder_set_enable_sni(
266 config: *mut rustls_client_config_builder,
267 enable: bool,
268 ) {
269 ffi_panic_boundary! {
270 let config = try_mut_from_ptr!(config);
271 config.enable_sni = enable;
272 }
273 }
274
275 #[no_mangle]
290 pub extern "C" fn rustls_client_config_builder_set_certified_key(
291 builder: *mut rustls_client_config_builder,
292 certified_keys: *const *const rustls_certified_key,
293 certified_keys_len: size_t,
294 ) -> rustls_result {
295 ffi_panic_boundary! {
296 let config = try_mut_from_ptr!(builder);
297 let keys_ptrs = try_slice!(certified_keys, certified_keys_len);
298 let mut keys = Vec::new();
299 for &key_ptr in keys_ptrs {
300 let certified_key = try_clone_arc!(key_ptr);
301 keys.push(certified_key);
302 }
303 config.cert_resolver = Some(Arc::new(ResolvesClientCertFromChoices { keys }));
304 rustls_result::Ok
305 }
306 }
307
308 #[no_mangle]
320 pub extern "C" fn rustls_client_config_builder_set_key_log_file(
321 builder: *mut rustls_client_config_builder,
322 ) -> rustls_result {
323 ffi_panic_boundary! {
324 let builder = try_mut_from_ptr!(builder);
325 builder.key_log = Some(Arc::new(KeyLogFile::new()));
326 rustls_result::Ok
327 }
328 }
329
330 #[no_mangle]
352 pub extern "C" fn rustls_client_config_builder_set_key_log(
353 builder: *mut rustls_client_config_builder,
354 log_cb: rustls_keylog_log_callback,
355 will_log_cb: rustls_keylog_will_log_callback,
356 ) -> rustls_result {
357 ffi_panic_boundary! {
358 let builder = try_mut_from_ptr!(builder);
359 let log_cb = match log_cb {
360 Some(cb) => cb,
361 None => return rustls_result::NullParameter,
362 };
363
364 builder.key_log = Some(Arc::new(CallbackKeyLog {
365 log_cb,
366 will_log_cb,
367 }));
368
369 rustls_result::Ok
370 }
371 }
372
373 #[no_mangle]
396 pub extern "C" fn rustls_client_config_builder_enable_ech(
397 builder: *mut rustls_client_config_builder,
398 ech_config_list_bytes: *const u8,
399 ech_config_list_bytes_size: size_t,
400 hpke: *const rustls_hpke,
401 ) -> rustls_result {
402 ffi_panic_boundary! {
403 let builder = try_mut_from_ptr!(builder);
404 let ech_config_list_bytes =
405 try_slice!(ech_config_list_bytes, ech_config_list_bytes_size);
406 let hpke = try_ref_from_ptr!(hpke);
407
408 if !builder.versions.is_empty() && builder.versions != [&rustls::version::TLS13] {
411 return rustls_result::BuilderIncompatibleTlsVersions;
412 }
413
414 builder.ech_mode = match EchConfig::new(
418 EchConfigListBytes::from(ech_config_list_bytes),
419 hpke.suites,
420 ) {
421 Ok(ech_config) => Some(ech_config.into()),
422 Err(err) => {
423 return map_error(err);
424 }
425 };
426
427 rustls_result::Ok
428 }
429 }
430
431 #[no_mangle]
449 pub extern "C" fn rustls_client_config_builder_enable_ech_grease(
450 builder: *mut rustls_client_config_builder,
451 hpke: *const rustls_hpke,
452 ) -> rustls_result {
453 ffi_panic_boundary! {
454 let builder = try_mut_from_ptr!(builder);
455 let hpke = try_ref_from_ptr!(hpke);
456
457 let provider = match &builder.provider {
458 Some(provider) => provider,
459 None => return rustls_result::NoDefaultCryptoProvider,
460 };
461
462 let Some((suite, placeholder_pk)) = hpke.grease_public_key(provider) else {
463 return rustls_result::HpkeError;
464 };
465
466 if !builder.versions.is_empty() && builder.versions != [&rustls::version::TLS13] {
469 return rustls_result::BuilderIncompatibleTlsVersions;
470 }
471 builder.ech_mode = Some(EchMode::Grease(EchGreaseConfig::new(suite, placeholder_pk)));
472
473 rustls_result::Ok
474 }
475 }
476
477 #[no_mangle]
480 pub extern "C" fn rustls_client_config_builder_build(
481 builder: *mut rustls_client_config_builder,
482 config_out: *mut *const rustls_client_config,
483 ) -> rustls_result {
484 ffi_panic_boundary! {
485 let builder = try_box_from_ptr!(builder);
486 let config_out = try_ref_from_ptr_ptr!(config_out);
487
488 let provider = match builder.provider {
489 Some(provider) => provider,
490 None => return rustls_result::NoDefaultCryptoProvider,
491 };
492
493 let verifier = match builder.verifier {
494 Some(v) => v,
495 None => return rustls_result::NoServerCertVerifier,
496 };
497
498 let config = ClientConfig::builder_with_provider(provider);
499
500 let wants_verifier;
507 if let Some(ech_mode) = builder.ech_mode {
508 wants_verifier = match config.with_ech(ech_mode) {
509 Ok(config) => config,
510 Err(err) => return map_error(err),
511 }
512 } else {
513 let versions = match builder.versions.is_empty() {
514 true => rustls::DEFAULT_VERSIONS,
515 false => builder.versions.as_slice(),
516 };
517 wants_verifier = match config.with_protocol_versions(versions) {
518 Ok(config) => config,
519 Err(err) => return map_error(err),
520 };
521 }
522
523 let config = wants_verifier
524 .dangerous()
525 .with_custom_certificate_verifier(verifier);
526 let mut config = match builder.cert_resolver {
527 Some(r) => config.with_client_cert_resolver(r),
528 None => config.with_no_client_auth(),
529 };
530 config.alpn_protocols = builder.alpn_protocols;
531 config.enable_sni = builder.enable_sni;
532
533 if let Some(key_log) = builder.key_log {
534 config.key_log = key_log;
535 }
536
537 set_arc_mut_ptr(config_out, config);
538 rustls_result::Ok
539 }
540 }
541
542 #[no_mangle]
550 pub extern "C" fn rustls_client_config_builder_free(config: *mut rustls_client_config_builder) {
551 ffi_panic_boundary! {
552 free_box(config);
553 }
554 }
555}
556
557#[allow(non_camel_case_types)]
564#[repr(C)]
565pub struct rustls_verify_server_cert_params<'a> {
566 pub end_entity_cert_der: rustls_slice_bytes<'a>,
567 pub intermediate_certs_der: &'a rustls_slice_slice_bytes<'a>,
568 pub server_name: rustls_str<'a>,
569 pub ocsp_response: rustls_slice_bytes<'a>,
570}
571
572#[allow(non_camel_case_types)]
576pub type rustls_verify_server_cert_user_data = *mut libc::c_void;
577
578#[allow(non_camel_case_types)]
584pub type rustls_verify_server_cert_callback = Option<
585 unsafe extern "C" fn(
586 userdata: rustls_verify_server_cert_user_data,
587 params: *const rustls_verify_server_cert_params,
588 ) -> u32,
589>;
590
591type VerifyCallback = unsafe extern "C" fn(
594 userdata: rustls_verify_server_cert_user_data,
595 params: *const rustls_verify_server_cert_params,
596) -> u32;
597
598struct Verifier {
600 provider: Arc<CryptoProvider>,
601 callback: VerifyCallback,
602}
603
604unsafe impl Send for Verifier {}
607
608unsafe impl Sync for Verifier {}
612
613impl ServerCertVerifier for Verifier {
614 fn verify_server_cert(
615 &self,
616 end_entity: &CertificateDer,
617 intermediates: &[CertificateDer],
618 server_name: &ServerName<'_>,
619 ocsp_response: &[u8],
620 _now: UnixTime,
621 ) -> Result<ServerCertVerified, Error> {
622 let cb = self.callback;
623 let server_name = server_name.to_str();
624 let server_name = match server_name.as_ref().try_into() {
625 Ok(r) => r,
626 Err(NulByte {}) => return Err(Error::General("NUL byte in SNI".to_string())),
627 };
628
629 let intermediates: Vec<_> = intermediates.iter().map(|cert| cert.as_ref()).collect();
630
631 let intermediates = rustls_slice_slice_bytes {
632 inner: &intermediates,
633 };
634
635 let params = rustls_verify_server_cert_params {
636 end_entity_cert_der: end_entity.as_ref().into(),
637 intermediate_certs_der: &intermediates,
638 server_name,
639 ocsp_response: ocsp_response.into(),
640 };
641 let userdata = userdata_get()
642 .map_err(|_| Error::General("internal error with thread-local storage".to_string()))?;
643 let result = unsafe { cb(userdata, ¶ms) };
644 match rustls_result::from(result) {
645 rustls_result::Ok => Ok(ServerCertVerified::assertion()),
646 r => Err(error::cert_result_to_error(r)),
647 }
648 }
649
650 fn verify_tls12_signature(
651 &self,
652 message: &[u8],
653 cert: &CertificateDer,
654 dss: &DigitallySignedStruct,
655 ) -> Result<HandshakeSignatureValid, Error> {
656 verify_tls12_signature(
657 message,
658 cert,
659 dss,
660 &self.provider.signature_verification_algorithms,
661 )
662 }
663
664 fn verify_tls13_signature(
665 &self,
666 message: &[u8],
667 cert: &CertificateDer,
668 dss: &DigitallySignedStruct,
669 ) -> Result<HandshakeSignatureValid, Error> {
670 verify_tls13_signature(
671 message,
672 cert,
673 dss,
674 &self.provider.signature_verification_algorithms,
675 )
676 }
677
678 fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
679 self.provider
680 .signature_verification_algorithms
681 .supported_schemes()
682 }
683}
684
685impl Debug for Verifier {
686 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
687 f.debug_struct("Verifier").finish()
688 }
689}
690
691#[derive(Debug)]
693struct ResolvesClientCertFromChoices {
694 keys: Vec<Arc<CertifiedKey>>,
695}
696
697impl ResolvesClientCert for ResolvesClientCertFromChoices {
698 fn resolve(
699 &self,
700 _acceptable_issuers: &[&[u8]],
701 sig_schemes: &[SignatureScheme],
702 ) -> Option<Arc<CertifiedKey>> {
703 for key in self.keys.iter() {
704 if key.key.choose_scheme(sig_schemes).is_some() {
705 return Some(key.clone());
706 }
707 }
708 None
709 }
710
711 fn has_certs(&self) -> bool {
712 !self.keys.is_empty()
713 }
714}
715
716impl rustls_client_config {
717 #[no_mangle]
724 pub extern "C" fn rustls_client_config_fips(config: *const rustls_client_config) -> bool {
725 ffi_panic_boundary! {
726 try_ref_from_ptr!(config).fips()
727 }
728 }
729
730 #[no_mangle]
740 pub extern "C" fn rustls_client_config_free(config: *const rustls_client_config) {
741 ffi_panic_boundary! {
742 free_arc(config);
743 }
744 }
745
746 #[no_mangle]
760 pub extern "C" fn rustls_client_connection_new(
761 config: *const rustls_client_config,
762 server_name: *const c_char,
763 conn_out: *mut *mut rustls_connection,
764 ) -> rustls_result {
765 ffi_panic_boundary! {
766 if conn_out.is_null() {
767 return rustls_result::NullParameter;
768 }
769 let server_name = unsafe {
770 if server_name.is_null() {
771 return rustls_result::NullParameter;
772 }
773 CStr::from_ptr(server_name)
774 };
775 let config = try_clone_arc!(config);
776 let conn_out = try_mut_from_ptr_ptr!(conn_out);
777 let server_name = match server_name.to_str() {
778 Ok(s) => s,
779 Err(std::str::Utf8Error { .. }) => return rustls_result::InvalidDnsNameError,
780 };
781 let server_name = match server_name.try_into() {
782 Ok(sn) => sn,
783 Err(_) => return rustls_result::InvalidDnsNameError,
784 };
785 let client = ClientConnection::new(config, server_name).unwrap();
786
787 let c = Connection::from_client(client);
791 set_boxed_mut_ptr(conn_out, c);
792 rustls_result::Ok
793 }
794 }
795}
796
797#[cfg(all(test, any(feature = "ring", feature = "aws-lc-rs")))]
798mod tests {
799 use std::ptr::{null, null_mut};
800
801 use super::*;
802
803 #[test]
804 fn test_config_builder() {
805 let builder = rustls_client_config_builder::rustls_client_config_builder_new();
806 let mut verifier = null_mut();
807 let result =
808 rustls_server_cert_verifier::rustls_platform_server_cert_verifier(&mut verifier);
809 assert_eq!(result, rustls_result::Ok);
810 assert!(!verifier.is_null());
811 rustls_client_config_builder::rustls_client_config_builder_set_server_verifier(
812 builder, verifier,
813 );
814 let h1 = "http/1.1".as_bytes();
815 let h2 = "h2".as_bytes();
816 let alpn = [h1.into(), h2.into()];
817 rustls_client_config_builder::rustls_client_config_builder_set_alpn_protocols(
818 builder,
819 alpn.as_ptr(),
820 alpn.len(),
821 );
822 rustls_client_config_builder::rustls_client_config_builder_set_enable_sni(builder, false);
823 let mut config = null();
824 let result =
825 rustls_client_config_builder::rustls_client_config_builder_build(builder, &mut config);
826 assert_eq!(result, rustls_result::Ok);
827 assert!(!config.is_null());
828 {
829 let config2 = try_ref_from_ptr!(config);
830 assert!(!config2.enable_sni);
831 assert_eq!(config2.alpn_protocols, vec![h1, h2]);
832 }
833 rustls_client_config::rustls_client_config_free(config);
834 rustls_server_cert_verifier::rustls_server_cert_verifier_free(verifier);
835 }
836
837 #[test]
839 #[cfg_attr(miri, ignore)]
840 fn test_client_connection_new() {
841 let builder = rustls_client_config_builder::rustls_client_config_builder_new();
842 let mut verifier = null_mut();
843 let result =
844 rustls_server_cert_verifier::rustls_platform_server_cert_verifier(&mut verifier);
845 assert_eq!(result, rustls_result::Ok);
846 assert!(!verifier.is_null());
847 rustls_client_config_builder::rustls_client_config_builder_set_server_verifier(
848 builder, verifier,
849 );
850 let mut config = null();
851 let result =
852 rustls_client_config_builder::rustls_client_config_builder_build(builder, &mut config);
853 assert_eq!(result, rustls_result::Ok);
854 assert!(!config.is_null());
855 let mut conn = null_mut();
856 let result = rustls_client_config::rustls_client_connection_new(
857 config,
858 "example.com\0".as_ptr() as *const c_char,
859 &mut conn,
860 );
861 if !matches!(result, rustls_result::Ok) {
862 panic!("expected RUSTLS_RESULT_OK, got {:?}", result);
863 }
864 assert!(!rustls_connection::rustls_connection_wants_read(conn));
865 assert!(rustls_connection::rustls_connection_wants_write(conn));
866 assert!(rustls_connection::rustls_connection_is_handshaking(conn));
867
868 let some_byte = 42u8;
869 let mut alpn_protocol: *const u8 = &some_byte;
870 let mut alpn_protocol_len = 1;
871 rustls_connection::rustls_connection_get_alpn_protocol(
872 conn,
873 &mut alpn_protocol,
874 &mut alpn_protocol_len,
875 );
876 assert_eq!(alpn_protocol, null());
877 assert_eq!(alpn_protocol_len, 0);
878
879 assert_eq!(
880 rustls_connection::rustls_connection_get_negotiated_ciphersuite(conn),
881 0
882 );
883 let cs_name = rustls_connection::rustls_connection_get_negotiated_ciphersuite_name(conn);
884 assert_eq!(unsafe { cs_name.to_str() }, "");
885 assert_eq!(
886 rustls_connection::rustls_connection_get_peer_certificate(conn, 0),
887 null()
888 );
889
890 assert_eq!(
891 rustls_connection::rustls_connection_get_protocol_version(conn),
892 0
893 );
894 rustls_connection::rustls_connection_free(conn);
895 rustls_server_cert_verifier::rustls_server_cert_verifier_free(verifier);
896 }
897
898 #[test]
899 #[cfg_attr(miri, ignore)]
900 fn test_client_connection_new_ipaddress() {
901 let builder = rustls_client_config_builder::rustls_client_config_builder_new();
902 let mut verifier = null_mut();
903 let result =
904 rustls_server_cert_verifier::rustls_platform_server_cert_verifier(&mut verifier);
905 assert_eq!(result, rustls_result::Ok);
906 assert!(!verifier.is_null());
907 rustls_client_config_builder::rustls_client_config_builder_set_server_verifier(
908 builder, verifier,
909 );
910 let mut config = null();
911 let result =
912 rustls_client_config_builder::rustls_client_config_builder_build(builder, &mut config);
913 assert_eq!(result, rustls_result::Ok);
914 assert!(!config.is_null());
915 let mut conn = null_mut();
916 let result = rustls_client_config::rustls_client_connection_new(
917 config,
918 "198.51.100.198\0".as_ptr() as *const c_char,
919 &mut conn,
920 );
921 if !matches!(result, rustls_result::Ok) {
922 panic!("expected RUSTLS_RESULT_OK, got {:?}", result);
923 }
924 rustls_server_cert_verifier::rustls_server_cert_verifier_free(verifier);
925 }
926
927 #[test]
928 fn test_client_builder_no_verifier_err() {
929 let builder = rustls_client_config_builder::rustls_client_config_builder_new();
930 let mut config = null();
931 let result =
932 rustls_client_config_builder::rustls_client_config_builder_build(builder, &mut config);
933 assert_eq!(result, rustls_result::NoServerCertVerifier);
934 }
935}