1use std::slice;
2use std::sync::Arc;
3
4use libc::size_t;
5
6use rustls::SupportedCipherSuite;
7#[cfg(feature = "aws-lc-rs")]
8use rustls::crypto::aws_lc_rs;
9#[cfg(feature = "ring")]
10use rustls::crypto::ring;
11use rustls::crypto::{CryptoProvider, hpke};
12use rustls::pki_types::PrivateKeyDer;
13use rustls::pki_types::pem::PemObject;
14use rustls::sign::SigningKey;
15
16use crate::cipher::rustls_supported_ciphersuite;
17use crate::error::{map_error, rustls_result};
18use crate::ffi::{
19 Castable, OwnershipArc, OwnershipBox, OwnershipRef, free_arc, free_box, set_arc_mut_ptr,
20 set_boxed_mut_ptr, to_boxed_mut_ptr, try_clone_arc, try_mut_from_ptr, try_mut_from_ptr_ptr,
21 try_ref_from_ptr, try_ref_from_ptr_ptr, try_slice, try_slice_mut, try_take,
22};
23use crate::panic::ffi_panic_boundary;
24
25pub struct rustls_crypto_provider_builder {
27 _private: [u8; 0],
28}
29
30impl Castable for rustls_crypto_provider_builder {
31 type Ownership = OwnershipBox;
32 type RustType = Option<CryptoProviderBuilder>;
33}
34
35#[derive(Debug)]
37pub struct CryptoProviderBuilder {
38 base: Arc<CryptoProvider>,
39 cipher_suites: Vec<SupportedCipherSuite>,
40}
41
42impl CryptoProviderBuilder {
43 fn build_provider(self) -> CryptoProvider {
44 let cipher_suites = match self.cipher_suites.is_empty() {
45 true => self.base.cipher_suites.clone(),
46 false => self.cipher_suites,
47 };
48
49 CryptoProvider {
54 cipher_suites,
55 kx_groups: self.base.kx_groups.clone(),
56 signature_verification_algorithms: self.base.signature_verification_algorithms,
57 secure_random: self.base.secure_random,
58 key_provider: self.base.key_provider,
59 }
60 }
61}
62
63#[no_mangle]
90pub extern "C" fn rustls_crypto_provider_builder_new_from_default(
91 builder_out: *mut *mut rustls_crypto_provider_builder,
92) -> rustls_result {
93 ffi_panic_boundary! {
94 let provider_out = try_mut_from_ptr_ptr!(builder_out);
95
96 let base = match get_default_or_install_from_crate_features() {
97 Some(provider) => provider,
98 None => return rustls_result::NoDefaultCryptoProvider,
99 };
100
101 set_boxed_mut_ptr(
102 provider_out,
103 Some(CryptoProviderBuilder {
104 base,
105 cipher_suites: Vec::default(),
106 }),
107 );
108
109 rustls_result::Ok
110 }
111}
112
113#[no_mangle]
135pub extern "C" fn rustls_crypto_provider_builder_new_with_base(
136 base: *const rustls_crypto_provider,
137) -> *mut rustls_crypto_provider_builder {
138 ffi_panic_boundary! {
139 to_boxed_mut_ptr(Some(CryptoProviderBuilder {
140 base: try_clone_arc!(base),
141 cipher_suites: Vec::default(),
142 }))
143 }
144}
145
146#[no_mangle]
151pub extern "C" fn rustls_crypto_provider_builder_set_cipher_suites(
152 builder: *mut rustls_crypto_provider_builder,
153 cipher_suites: *const *const rustls_supported_ciphersuite,
154 cipher_suites_len: size_t,
155) -> rustls_result {
156 ffi_panic_boundary! {
157 let builder = try_mut_from_ptr!(builder);
158 let builder = match builder {
159 Some(builder) => builder,
160 None => return rustls_result::AlreadyUsed,
161 };
162
163 let cipher_suites = try_slice!(cipher_suites, cipher_suites_len);
164 let mut supported_cipher_suites = Vec::new();
165 for cs in cipher_suites {
166 let cs = *cs;
167 let cs = try_ref_from_ptr!(cs);
168 supported_cipher_suites.push(*cs);
169 }
170
171 builder.cipher_suites = supported_cipher_suites;
172 rustls_result::Ok
173 }
174}
175
176#[no_mangle]
183pub extern "C" fn rustls_crypto_provider_builder_build(
184 builder: *mut rustls_crypto_provider_builder,
185 provider_out: *mut *const rustls_crypto_provider,
186) -> rustls_result {
187 ffi_panic_boundary! {
188 let builder = try_mut_from_ptr!(builder);
189 set_arc_mut_ptr(
190 try_ref_from_ptr_ptr!(provider_out),
191 try_take!(builder).build_provider(),
192 );
193 rustls_result::Ok
194 }
195}
196
197#[no_mangle]
209pub extern "C" fn rustls_crypto_provider_builder_build_as_default(
210 builder: *mut rustls_crypto_provider_builder,
211) -> rustls_result {
212 let builder = try_mut_from_ptr!(builder);
213 match try_take!(builder).build_provider().install_default() {
214 Ok(_) => rustls_result::Ok,
215 Err(_) => rustls_result::AlreadyUsed,
216 }
217}
218
219#[no_mangle]
224pub extern "C" fn rustls_crypto_provider_builder_free(
225 builder: *mut rustls_crypto_provider_builder,
226) {
227 ffi_panic_boundary! {
228 free_box(builder);
229 }
230}
231
232#[no_mangle]
237#[cfg(feature = "ring")]
238pub extern "C" fn rustls_ring_crypto_provider() -> *const rustls_crypto_provider {
239 ffi_panic_boundary! {
240 Arc::into_raw(Arc::new(ring::default_provider())) as *const rustls_crypto_provider
241 }
242}
243
244#[no_mangle]
249#[cfg(feature = "aws-lc-rs")]
250pub extern "C" fn rustls_aws_lc_rs_crypto_provider() -> *const rustls_crypto_provider {
251 ffi_panic_boundary! {
252 Arc::into_raw(Arc::new(aws_lc_rs::default_provider())) as *const rustls_crypto_provider
253 }
254}
255
256#[no_mangle]
268#[cfg(feature = "fips")]
269pub extern "C" fn rustls_default_fips_provider() -> *const rustls_crypto_provider {
270 ffi_panic_boundary! {
271 Arc::into_raw(Arc::new(rustls::crypto::default_fips_provider()))
272 as *const rustls_crypto_provider
273 }
274}
275
276#[no_mangle]
283pub extern "C" fn rustls_crypto_provider_default() -> *const rustls_crypto_provider {
284 ffi_panic_boundary! {
285 match CryptoProvider::get_default() {
286 Some(provider) => Arc::into_raw(provider.clone()) as *const rustls_crypto_provider,
287 None => core::ptr::null(),
288 }
289 }
290}
291
292pub struct rustls_crypto_provider {
294 _private: [u8; 0],
295}
296
297impl Castable for rustls_crypto_provider {
298 type Ownership = OwnershipArc;
299 type RustType = CryptoProvider;
300}
301
302#[no_mangle]
309pub extern "C" fn rustls_crypto_provider_ciphersuites_len(
310 provider: *const rustls_crypto_provider,
311) -> usize {
312 ffi_panic_boundary! {
313 try_clone_arc!(provider).cipher_suites.len()
314 }
315}
316
317#[no_mangle]
325pub extern "C" fn rustls_crypto_provider_ciphersuites_get(
326 provider: *const rustls_crypto_provider,
327 index: usize,
328) -> *const rustls_supported_ciphersuite {
329 ffi_panic_boundary! {
330 match try_clone_arc!(provider).cipher_suites.get(index) {
331 Some(ciphersuite) => ciphersuite as *const SupportedCipherSuite as *const _,
332 None => core::ptr::null(),
333 }
334 }
335}
336
337#[no_mangle]
348pub extern "C" fn rustls_crypto_provider_load_key(
349 provider: *const rustls_crypto_provider,
350 private_key: *const u8,
351 private_key_len: size_t,
352 signing_key_out: *mut *mut rustls_signing_key,
353) -> rustls_result {
354 ffi_panic_boundary! {
355 let provider = try_clone_arc!(provider);
356 let private_key_pem = try_slice!(private_key, private_key_len);
357 let signing_key_out = try_mut_from_ptr_ptr!(signing_key_out);
358
359 let private_key_der = match PrivateKeyDer::from_pem_slice(private_key_pem) {
360 Ok(der) => der,
361 Err(_) => return rustls_result::PrivateKeyParseError,
362 };
363
364 let private_key = match provider.key_provider.load_private_key(private_key_der) {
365 Ok(key) => key,
366 Err(e) => return map_error(e),
367 };
368
369 set_boxed_mut_ptr(signing_key_out, private_key);
370 rustls_result::Ok
371 }
372}
373
374#[no_mangle]
381pub extern "C" fn rustls_crypto_provider_random(
382 provider: *const rustls_crypto_provider,
383 buff: *mut u8,
384 len: size_t,
385) -> rustls_result {
386 ffi_panic_boundary! {
387 match try_clone_arc!(provider)
388 .secure_random
389 .fill(try_slice_mut!(buff, len))
390 {
391 Ok(_) => rustls_result::Ok,
392 Err(_) => rustls_result::GetRandomFailed,
393 }
394 }
395}
396
397#[no_mangle]
404pub extern "C" fn rustls_crypto_provider_fips(provider: *const rustls_crypto_provider) -> bool {
405 ffi_panic_boundary! {
406 try_ref_from_ptr!(provider).fips()
407 }
408}
409
410#[no_mangle]
415pub extern "C" fn rustls_crypto_provider_free(provider: *const rustls_crypto_provider) {
416 ffi_panic_boundary! {
417 free_arc(provider);
418 }
419}
420
421#[no_mangle]
428pub extern "C" fn rustls_default_crypto_provider_ciphersuites_len() -> usize {
429 ffi_panic_boundary! {
430 match get_default_or_install_from_crate_features() {
431 Some(provider) => provider.cipher_suites.len(),
432 None => return 0,
433 }
434 }
435}
436
437#[no_mangle]
445pub extern "C" fn rustls_default_crypto_provider_ciphersuites_get(
446 index: usize,
447) -> *const rustls_supported_ciphersuite {
448 ffi_panic_boundary! {
449 let default_provider = match get_default_or_install_from_crate_features() {
450 Some(provider) => provider,
451 None => return core::ptr::null(),
452 };
453 match default_provider.cipher_suites.get(index) {
454 Some(ciphersuite) => ciphersuite as *const SupportedCipherSuite as *const _,
455 None => core::ptr::null(),
456 }
457 }
458}
459
460#[no_mangle]
469pub extern "C" fn rustls_default_crypto_provider_random(
470 buff: *mut u8,
471 len: size_t,
472) -> rustls_result {
473 ffi_panic_boundary! {
474 match get_default_or_install_from_crate_features() {
475 Some(provider) => match provider.secure_random.fill(try_slice_mut!(buff, len)) {
476 Ok(_) => rustls_result::Ok,
477 Err(_) => rustls_result::GetRandomFailed,
478 },
479 None => rustls_result::NoDefaultCryptoProvider,
480 }
481 }
482}
483
484pub struct rustls_signing_key {
489 _private: [u8; 0],
490}
491
492impl Castable for rustls_signing_key {
493 type Ownership = OwnershipBox;
494 type RustType = Arc<dyn SigningKey>;
495}
496
497impl rustls_signing_key {
498 #[no_mangle]
501 pub extern "C" fn rustls_signing_key_free(signing_key: *mut rustls_signing_key) {
502 ffi_panic_boundary! {
503 free_box(signing_key);
504 }
505 }
506}
507
508pub struct rustls_hpke {
514 _private: [u8; 0],
515}
516
517impl Castable for rustls_hpke {
518 type Ownership = OwnershipRef;
519 type RustType = Hpke;
520}
521
522pub(crate) struct Hpke {
523 pub(crate) suites: &'static [&'static dyn hpke::Hpke],
524}
525
526impl Hpke {
527 pub(crate) fn grease_public_key(
532 &self,
533 provider: &CryptoProvider,
534 ) -> Option<(&dyn hpke::Hpke, hpke::HpkePublicKey)> {
535 let num_suites = self.suites.len();
536 if num_suites == 0 {
537 return None;
538 }
539 debug_assert!(num_suites < u32::MAX as usize);
540
541 let mut buf = [0u8; 4];
542 let threshold = u32::MAX - (u32::MAX % num_suites as u32);
543 let suite = loop {
544 provider.secure_random.fill(&mut buf).ok()?;
545 let value = u32::from_ne_bytes(buf);
546 if value < threshold {
547 break self.suites[value as usize / (threshold as usize / num_suites)];
548 }
549 };
550
551 let pk = suite.generate_key_pair().map(|pair| pair.0).ok()?;
552 Some((suite, pk))
553 }
554}
555
556#[cfg(feature = "aws-lc-rs")]
557static AWS_LC_RS_HPKE: &Hpke = &Hpke {
558 suites: aws_lc_rs::hpke::ALL_SUPPORTED_SUITES,
559};
560
561#[no_mangle]
569pub extern "C" fn rustls_supported_hpke() -> *const rustls_hpke {
570 ffi_panic_boundary! {
571 #[cfg(feature = "aws-lc-rs")]
572 {
573 AWS_LC_RS_HPKE as *const _ as _
574 }
575 #[cfg(not(feature = "aws-lc-rs"))]
576 {
577 core::ptr::null()
578 }
579 }
580}
581
582pub(crate) fn get_default_or_install_from_crate_features() -> Option<Arc<CryptoProvider>> {
583 if let Some(provider) = CryptoProvider::get_default() {
585 return Some(provider.clone());
586 }
587
588 let _ = provider_from_crate_features()?.install_default();
591
592 Some(CryptoProvider::get_default().unwrap().clone())
595}
596
597fn provider_from_crate_features() -> Option<CryptoProvider> {
598 #[cfg(all(feature = "aws-lc-rs", not(feature = "ring")))]
600 {
601 return Some(aws_lc_rs::default_provider());
602 }
603
604 #[cfg(all(feature = "ring", not(feature = "aws-lc-rs")))]
606 {
607 return Some(ring::default_provider());
608 }
609
610 #[allow(unreachable_code)]
613 None
614}
615
616#[cfg(all(test, not(miri), any(feature = "aws-lc-rs", feature = "ring")))]
617mod tests {
618 use std::ptr;
619
620 use crate::rustls_result;
621
622 use super::*;
623
624 #[test]
626 fn random_data() {
627 let provider = rustls_crypto_provider_default();
628 assert!(!provider.is_null());
629
630 let result = rustls_crypto_provider_random(provider, ptr::null_mut(), 1337);
632 assert_eq!(result, rustls_result::NullParameter);
633
634 let mut buff = vec![0; 32];
635
636 let result = rustls_crypto_provider_random(ptr::null(), buff.as_mut_ptr(), buff.len());
638 assert_eq!(buff, vec![0; 32]);
639 assert_eq!(result, rustls_result::NullParameter);
640
641 let result = rustls_crypto_provider_random(provider, buff.as_mut_ptr(), buff.len());
643 assert_eq!(result, rustls_result::Ok);
644 assert_ne!(buff, vec![0; 32]);
645 }
646
647 #[test]
649 fn default_random_data() {
650 let result = rustls_default_crypto_provider_random(ptr::null_mut(), 1337);
652 assert_eq!(result, rustls_result::NullParameter);
653
654 let mut buff = vec![0; 32];
655
656 let result = rustls_default_crypto_provider_random(buff.as_mut_ptr(), buff.len());
658 assert_eq!(result, rustls_result::Ok);
659 assert_ne!(buff, vec![0; 32]);
660 }
661
662 #[test]
663 #[cfg(feature = "aws-lc-rs")]
664 fn test_hpke_aws_lc_rs() {
665 let provider = rustls_crypto_provider_default();
666 assert!(!provider.is_null());
667 let provider = try_clone_arc!(provider);
668
669 let hpke = rustls_supported_hpke();
670 assert!(!hpke.is_null());
671
672 let hpke = try_ref_from_ptr!(hpke);
673
674 let (suite, pk) = hpke.grease_public_key(&provider).unwrap();
676 let (_, _) = suite.setup_sealer(&[0xC0, 0xFF, 0xEE], &pk).unwrap();
678 }
679
680 #[test]
681 #[cfg(not(feature = "aws-lc-rs"))]
682 fn test_hpke_not_aws_lc_rs() {
683 assert!(rustls_supported_hpke().is_null());
684 }
685}