Skip to main content

rustls_ffi/
crypto_provider.rs

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
25/// A `rustls_crypto_provider` builder.
26pub 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/// A builder for customizing a `CryptoProvider`. Can be used to install a process-wide default.
36#[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        // Unfortunately we can't use the `..` syntax to fill in the rest of the provider
50        // fields, because we're working with `Arc<CryptoProvider>` as the base,
51        // not `CryptoProvider`.
52        // TODO(#450): once MSRV is 1.76+, use `Arc::unwrap_or_clone`.
53        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/// Constructs a new `rustls_crypto_provider_builder` using the process-wide default crypto
64/// provider as the base crypto provider to be customized.
65///
66/// When this function returns `rustls_result::Ok` a pointer to the `rustls_crypto_provider_builder`
67/// is written to `builder_out`. It returns `rustls_result::NoDefaultCryptoProvider` if no default
68/// provider has been registered.
69///
70/// The caller owns the returned `rustls_crypto_provider_builder` and must free it using
71/// `rustls_crypto_provider_builder_free`.
72///
73/// This function is typically used for customizing the default crypto provider for specific
74/// connections. For example, a typical workflow might be to:
75///
76/// * Either:
77///   * Use the default `aws-lc-rs` or `*ring*` provider that rustls-ffi is built with based on
78///     the `CRYPTO_PROVIDER` build variable.
79///   * Call `rustls_crypto_provider_builder_new_with_base` with the desired provider, and
80///     then install it as the process default with
81///     `rustls_crypto_provider_builder_build_as_default`.
82/// * Afterward, as required for customization:
83///   * Use `rustls_crypto_provider_builder_new_from_default` to get a builder backed by the
84///     default crypto provider.
85///   * Use `rustls_crypto_provider_builder_set_cipher_suites` to customize the supported
86///     ciphersuites.
87///   * Use `rustls_crypto_provider_builder_build` to build a customized provider.
88///   * Provide that customized provider to client or server configuration builders.
89#[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/// Constructs a new `rustls_crypto_provider_builder` using the given `rustls_crypto_provider`
114/// as the base crypto provider to be customized.
115///
116/// The caller owns the returned `rustls_crypto_provider_builder` and must free it using
117/// `rustls_crypto_provider_builder_free`.
118///
119/// This function can be used for setting the default process wide crypto provider,
120/// or for constructing a custom crypto provider for a specific connection. A typical
121/// workflow could be to:
122///
123/// * Call `rustls_crypto_provider_builder_new_with_base` with a custom provider
124/// * Install the custom provider as the process-wide default with
125///   `rustls_crypto_provider_builder_build_as_default`.
126///
127/// Or, for per-connection customization:
128///
129/// * Call `rustls_crypto_provider_builder_new_with_base` with a custom provider
130/// * Use `rustls_crypto_provider_builder_set_cipher_suites` to customize the supported
131///   ciphersuites.
132/// * Use `rustls_crypto_provider_builder_build` to build a customized provider.
133/// * Provide that customized provider to client or server configuration builders.
134#[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/// Customize the supported ciphersuites of the `rustls_crypto_provider_builder`.
147///
148/// Returns an error if the builder has already been built. Overwrites any previously
149/// set ciphersuites.
150#[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/// Builds a `rustls_crypto_provider` from the builder and returns it. Returns an error if the
177/// builder has already been built.
178///
179/// The `rustls_crypto_provider_builder` builder is consumed and should not be used
180/// for further calls, except to `rustls_crypto_provider_builder_free`. The caller must
181/// still free the builder after a successful build.
182#[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/// Builds a `rustls_crypto_provider` from the builder and sets it as the
198/// process-wide default crypto provider.
199///
200/// Afterward, the default provider can be retrieved using `rustls_crypto_provider_default`.
201///
202/// This can only be done once per process, and will return an error if a
203/// default provider has already been set, or if the builder has already been built.
204///
205/// The `rustls_crypto_provider_builder` builder is consumed and should not be used
206/// for further calls, except to `rustls_crypto_provider_builder_free`. The caller must
207/// still free the builder after a successful build.
208#[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/// Free the `rustls_crypto_provider_builder`.
220///
221/// Calling with `NULL` is fine.
222/// Must not be called twice with the same value.
223#[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/// Return the `rustls_crypto_provider` backed by the `*ring*` cryptography library.
233///
234/// The caller owns the returned `rustls_crypto_provider` and must free it using
235/// `rustls_crypto_provider_free`.
236#[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/// Return the `rustls_crypto_provider` backed by the `aws-lc-rs` cryptography library.
245///
246/// The caller owns the returned `rustls_crypto_provider` and must free it using
247/// `rustls_crypto_provider_free`.
248#[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/// Return a `rustls_crypto_provider` that uses FIPS140-3 approved cryptography.
257///
258/// Using this function expresses in your code that you require FIPS-approved cryptography,
259/// and will not compile if you make a mistake with cargo features.
260///
261/// See the upstream [rustls FIPS documentation][FIPS] for more information.
262///
263/// The caller owns the returned `rustls_crypto_provider` and must free it using
264/// `rustls_crypto_provider_free`.
265///
266/// [FIPS]: https://docs.rs/rustls/latest/rustls/manual/_06_fips/index.html
267#[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/// Retrieve a pointer to the process default `rustls_crypto_provider`.
277///
278/// This may return `NULL` if no process default provider has been set using
279/// `rustls_crypto_provider_builder_build_default`.
280///
281/// Caller owns the returned `rustls_crypto_provider` and must free it w/ `rustls_crypto_provider_free`.
282#[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
292/// A C representation of a Rustls [`CryptoProvider`].
293pub 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/// Returns the number of ciphersuites the `rustls_crypto_provider` supports.
303///
304/// You can use this to know the maximum allowed index for use with
305/// `rustls_crypto_provider_ciphersuites_get`.
306///
307/// This function will return 0 if the `provider` is NULL.
308#[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/// Retrieve a pointer to a supported ciphersuite of the `rustls_crypto_provider`.
318///
319/// This function will return NULL if the `provider` is NULL, or if the index is out of bounds
320/// with respect to `rustls_crypto_provider_ciphersuites_len`.
321///
322/// The lifetime of the returned `rustls_supported_ciphersuite` is equal to the lifetime of the
323/// `provider` and should not be used after the `provider` is freed.
324#[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/// Load a private key from the provided PEM content using the crypto provider.
338///
339/// `private_key` must point to a buffer of `private_key_len` bytes, containing
340/// a PEM-encoded private key. The exact formats supported will differ based on
341/// the crypto provider in use. The default providers support PKCS#1, PKCS#8 or
342/// SEC1 formats.
343///
344/// When this function returns `rustls_result::Ok` a pointer to a `rustls_signing_key`
345/// is written to `signing_key_out`. The caller owns the returned `rustls_signing_key`
346/// and must free it with `rustls_signing_key_free`.
347#[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/// Write `len` bytes of cryptographically secure random data to `buff` using the crypto provider.
375///
376/// `buff` must point to a buffer of at least `len` bytes. The caller maintains ownership
377/// of the buffer.
378///
379/// Returns `RUSTLS_RESULT_OK` on success, or `RUSTLS_RESULT_GET_RANDOM_FAILED` on failure.
380#[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/// Returns true if the `rustls_crypto_provider` is operating in FIPS mode.
398///
399/// This covers only the cryptographic parts of FIPS approval. There are also
400/// TLS protocol-level recommendations made by NIST. You should prefer to call
401/// `rustls_client_config_fips` or `rustls_server_config_fips` which take these
402/// into account.
403#[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/// Frees the `rustls_crypto_provider`.
411///
412/// Calling with `NULL` is fine.
413/// Must not be called twice with the same value.
414#[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/// Returns the number of ciphersuites the default process-wide crypto provider supports.
422///
423/// You can use this to know the maximum allowed index for use with
424/// `rustls_default_crypto_provider_ciphersuites_get`.
425///
426/// This function will return 0 if no process-wide default `rustls_crypto_provider` is available.
427#[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/// Retrieve a pointer to a supported ciphersuite of the default process-wide crypto provider.
438///
439/// This function will return NULL if the `provider` is NULL, or if the index is out of bounds
440/// with respect to `rustls_default_crypto_provider_ciphersuites_len`.
441///
442/// The lifetime of the returned `rustls_supported_ciphersuite` is static, as the process-wide
443/// default provider lives for as long as the process.
444#[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/// Write `len` bytes of cryptographically secure random data to `buff` using the process-wide
461/// default crypto provider.
462///
463/// `buff` must point to a buffer of at least `len` bytes. The caller maintains ownership
464/// of the buffer.
465///
466/// Returns `RUSTLS_RESULT_OK` on success, and one of `RUSTLS_RESULT_NO_DEFAULT_CRYPTO_PROVIDER`
467/// or `RUSTLS_RESULT_GET_RANDOM_FAILED` on failure.
468#[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
484/// A signing key that can be used to construct a certified key.
485// NOTE: we box cast an arc over the dyn trait per the pattern described
486//   in our docs[0] for dynamically sized types.
487//   [0]: <https://github.com/rustls/rustls-ffi/blob/main/CONTRIBUTING.md#dynamically-sized-types>
488pub 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    /// Frees the `rustls_signing_key`. This is safe to call with a `NULL` argument, but
499    /// must not be called twice with the same value.
500    #[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
508/// A collection of supported Hybrid Public Key Encryption (HPKE) suites.
509///
510/// `rustls_hpke` can be provided to `rustls_client_config_builder_enable_ech` and
511/// `rustls_client_config_builder_enable_ech_grease()` to customize a
512/// `rustls_client_config_builder` to use Encrypted Client Hello (ECH).
513pub 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    /// Chooses a random supported HPKE suite and generates a throw-away public key.
528    ///
529    /// Returns both the selected Rustls `hpke::Hpke` suite and the `hpke::HpkePublicKey`
530    /// or `None` if an error occurs.
531    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/// Returns a pointer to the supported `rustls_hpke` Hybrid Public Key Encryption (HPKE)
562/// suites, or `NULL` if HPKE is not supported.
563///
564/// HPKE is only supported with the `aws-lc-rs` cryptography provider.
565///
566/// The returned pointer has a static lifetime equal to that of the program and does not
567/// need to be freed.
568#[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 a process-wide default has already been installed, return it.
584    if let Some(provider) = CryptoProvider::get_default() {
585        return Some(provider.clone());
586    }
587
588    // Ignore the error resulting from us losing a race to install the default,
589    // and accept the outcome.
590    let _ = provider_from_crate_features()?.install_default();
591
592    // Safety: we can unwrap safely here knowing we've just set the default, or
593    // lost a race to something else setting the default.
594    Some(CryptoProvider::get_default().unwrap().clone())
595}
596
597fn provider_from_crate_features() -> Option<CryptoProvider> {
598    // Provider default is unambiguously aws-lc-rs
599    #[cfg(all(feature = "aws-lc-rs", not(feature = "ring")))]
600    {
601        return Some(aws_lc_rs::default_provider());
602    }
603
604    // Provider default is unambiguously ring
605    #[cfg(all(feature = "ring", not(feature = "aws-lc-rs")))]
606    {
607        return Some(ring::default_provider());
608    }
609
610    // Both features activated - no clear default provider based on
611    // crate features.
612    #[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    /// Simple smoketest of CSRNG fill with specific provider.
625    #[test]
626    fn random_data() {
627        let provider = rustls_crypto_provider_default();
628        assert!(!provider.is_null());
629
630        // NULL buffer should return an error.
631        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        // NULL provider should return an error and not touch buff.
637        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        // Proper parameters should return OK and overwrite the buffer.
642        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    /// Simple smoketest of CSRNG fill with default provider.
648    #[test]
649    fn default_random_data() {
650        // NULL buffer should return an error.
651        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        // Proper parameters should return OK and overwrite the buffer.
657        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        // We should be able to pick an HPKE suite and a pubkey for ECH GREASE.
675        let (suite, pk) = hpke.grease_public_key(&provider).unwrap();
676        // The PK and the suite should be compatible. Setup a sealer to check.
677        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}