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    arc_castable, box_castable, free_arc, free_box, ref_castable, 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
25box_castable! {
26    /// A `rustls_crypto_provider` builder.
27    pub struct rustls_crypto_provider_builder(Option<CryptoProviderBuilder>);
28}
29
30/// A builder for customizing a `CryptoProvider`. Can be used to install a process-wide default.
31#[derive(Debug)]
32pub struct CryptoProviderBuilder {
33    base: Arc<CryptoProvider>,
34    cipher_suites: Vec<SupportedCipherSuite>,
35}
36
37impl CryptoProviderBuilder {
38    fn build_provider(self) -> CryptoProvider {
39        let cipher_suites = match self.cipher_suites.is_empty() {
40            true => self.base.cipher_suites.clone(),
41            false => self.cipher_suites,
42        };
43
44        // Unfortunately we can't use the `..` syntax to fill in the rest of the provider
45        // fields, because we're working with `Arc<CryptoProvider>` as the base,
46        // not `CryptoProvider`.
47        // TODO(#450): once MSRV is 1.76+, use `Arc::unwrap_or_clone`.
48        CryptoProvider {
49            cipher_suites,
50            kx_groups: self.base.kx_groups.clone(),
51            signature_verification_algorithms: self.base.signature_verification_algorithms,
52            secure_random: self.base.secure_random,
53            key_provider: self.base.key_provider,
54        }
55    }
56}
57
58/// Constructs a new `rustls_crypto_provider_builder` using the process-wide default crypto
59/// provider as the base crypto provider to be customized.
60///
61/// When this function returns `rustls_result::Ok` a pointer to the `rustls_crypto_provider_builder`
62/// is written to `builder_out`. It returns `rustls_result::NoDefaultCryptoProvider` if no default
63/// provider has been registered.
64///
65/// The caller owns the returned `rustls_crypto_provider_builder` and must free it using
66/// `rustls_crypto_provider_builder_free`.
67///
68/// This function is typically used for customizing the default crypto provider for specific
69/// connections. For example, a typical workflow might be to:
70///
71/// * Either:
72///   * Use the default `aws-lc-rs` or `*ring*` provider that rustls-ffi is built with based on
73///     the `CRYPTO_PROVIDER` build variable.
74///   * Call `rustls_crypto_provider_builder_new_with_base` with the desired provider, and
75///     then install it as the process default with
76///     `rustls_crypto_provider_builder_build_as_default`.
77/// * Afterward, as required for customization:
78///   * Use `rustls_crypto_provider_builder_new_from_default` to get a builder backed by the
79///     default crypto provider.
80///   * Use `rustls_crypto_provider_builder_set_cipher_suites` to customize the supported
81///     ciphersuites.
82///   * Use `rustls_crypto_provider_builder_build` to build a customized provider.
83///   * Provide that customized provider to client or server configuration builders.
84#[no_mangle]
85pub extern "C" fn rustls_crypto_provider_builder_new_from_default(
86    builder_out: *mut *mut rustls_crypto_provider_builder,
87) -> rustls_result {
88    ffi_panic_boundary! {
89        let provider_out = try_mut_from_ptr_ptr!(builder_out);
90
91        let base = match get_default_or_install_from_crate_features() {
92            Some(provider) => provider,
93            None => return rustls_result::NoDefaultCryptoProvider,
94        };
95
96        set_boxed_mut_ptr(
97            provider_out,
98            Some(CryptoProviderBuilder {
99                base,
100                cipher_suites: Vec::default(),
101            }),
102        );
103
104        rustls_result::Ok
105    }
106}
107
108/// Constructs a new `rustls_crypto_provider_builder` using the given `rustls_crypto_provider`
109/// as the base crypto provider to be customized.
110///
111/// The caller owns the returned `rustls_crypto_provider_builder` and must free it using
112/// `rustls_crypto_provider_builder_free`.
113///
114/// This function can be used for setting the default process wide crypto provider,
115/// or for constructing a custom crypto provider for a specific connection. A typical
116/// workflow could be to:
117///
118/// * Call `rustls_crypto_provider_builder_new_with_base` with a custom provider
119/// * Install the custom provider as the process-wide default with
120///   `rustls_crypto_provider_builder_build_as_default`.
121///
122/// Or, for per-connection customization:
123///
124/// * Call `rustls_crypto_provider_builder_new_with_base` with a custom provider
125/// * Use `rustls_crypto_provider_builder_set_cipher_suites` to customize the supported
126///   ciphersuites.
127/// * Use `rustls_crypto_provider_builder_build` to build a customized provider.
128/// * Provide that customized provider to client or server configuration builders.
129#[no_mangle]
130pub extern "C" fn rustls_crypto_provider_builder_new_with_base(
131    base: *const rustls_crypto_provider,
132) -> *mut rustls_crypto_provider_builder {
133    ffi_panic_boundary! {
134        to_boxed_mut_ptr(Some(CryptoProviderBuilder {
135            base: try_clone_arc!(base),
136            cipher_suites: Vec::default(),
137        }))
138    }
139}
140
141/// Customize the supported ciphersuites of the `rustls_crypto_provider_builder`.
142///
143/// Returns an error if the builder has already been built. Overwrites any previously
144/// set ciphersuites.
145#[no_mangle]
146pub extern "C" fn rustls_crypto_provider_builder_set_cipher_suites(
147    builder: *mut rustls_crypto_provider_builder,
148    cipher_suites: *const *const rustls_supported_ciphersuite,
149    cipher_suites_len: size_t,
150) -> rustls_result {
151    ffi_panic_boundary! {
152        let builder = try_mut_from_ptr!(builder);
153        let builder = match builder {
154            Some(builder) => builder,
155            None => return rustls_result::AlreadyUsed,
156        };
157
158        let cipher_suites = try_slice!(cipher_suites, cipher_suites_len);
159        let mut supported_cipher_suites = Vec::new();
160        for cs in cipher_suites {
161            let cs = *cs;
162            let cs = try_ref_from_ptr!(cs);
163            supported_cipher_suites.push(*cs);
164        }
165
166        builder.cipher_suites = supported_cipher_suites;
167        rustls_result::Ok
168    }
169}
170
171/// Builds a `rustls_crypto_provider` from the builder and returns it. Returns an error if the
172/// builder has already been built.
173///
174/// The `rustls_crypto_provider_builder` builder is consumed and should not be used
175/// for further calls, except to `rustls_crypto_provider_builder_free`. The caller must
176/// still free the builder after a successful build.
177#[no_mangle]
178pub extern "C" fn rustls_crypto_provider_builder_build(
179    builder: *mut rustls_crypto_provider_builder,
180    provider_out: *mut *const rustls_crypto_provider,
181) -> rustls_result {
182    ffi_panic_boundary! {
183        let builder = try_mut_from_ptr!(builder);
184        set_arc_mut_ptr(
185            try_ref_from_ptr_ptr!(provider_out),
186            try_take!(builder).build_provider(),
187        );
188        rustls_result::Ok
189    }
190}
191
192/// Builds a `rustls_crypto_provider` from the builder and sets it as the
193/// process-wide default crypto provider.
194///
195/// Afterward, the default provider can be retrieved using `rustls_crypto_provider_default`.
196///
197/// This can only be done once per process, and will return an error if a
198/// default provider has already been set, or if the builder has already been built.
199///
200/// The `rustls_crypto_provider_builder` builder is consumed and should not be used
201/// for further calls, except to `rustls_crypto_provider_builder_free`. The caller must
202/// still free the builder after a successful build.
203#[no_mangle]
204pub extern "C" fn rustls_crypto_provider_builder_build_as_default(
205    builder: *mut rustls_crypto_provider_builder,
206) -> rustls_result {
207    let builder = try_mut_from_ptr!(builder);
208    match try_take!(builder).build_provider().install_default() {
209        Ok(_) => rustls_result::Ok,
210        Err(_) => rustls_result::AlreadyUsed,
211    }
212}
213
214/// Free the `rustls_crypto_provider_builder`.
215///
216/// Calling with `NULL` is fine.
217/// Must not be called twice with the same value.
218#[no_mangle]
219pub extern "C" fn rustls_crypto_provider_builder_free(
220    builder: *mut rustls_crypto_provider_builder,
221) {
222    ffi_panic_boundary! {
223        free_box(builder);
224    }
225}
226
227/// Return the `rustls_crypto_provider` backed by the `*ring*` cryptography library.
228///
229/// The caller owns the returned `rustls_crypto_provider` and must free it using
230/// `rustls_crypto_provider_free`.
231#[no_mangle]
232#[cfg(feature = "ring")]
233pub extern "C" fn rustls_ring_crypto_provider() -> *const rustls_crypto_provider {
234    ffi_panic_boundary! {
235        Arc::into_raw(Arc::new(ring::default_provider())) as *const rustls_crypto_provider
236    }
237}
238
239/// Return the `rustls_crypto_provider` backed by the `aws-lc-rs` cryptography library.
240///
241/// The caller owns the returned `rustls_crypto_provider` and must free it using
242/// `rustls_crypto_provider_free`.
243#[no_mangle]
244#[cfg(feature = "aws-lc-rs")]
245pub extern "C" fn rustls_aws_lc_rs_crypto_provider() -> *const rustls_crypto_provider {
246    ffi_panic_boundary! {
247        Arc::into_raw(Arc::new(aws_lc_rs::default_provider())) as *const rustls_crypto_provider
248    }
249}
250
251/// Return a `rustls_crypto_provider` that uses FIPS140-3 approved cryptography.
252///
253/// Using this function expresses in your code that you require FIPS-approved cryptography,
254/// and will not compile if you make a mistake with cargo features.
255///
256/// See the upstream [rustls FIPS documentation][FIPS] for more information.
257///
258/// The caller owns the returned `rustls_crypto_provider` and must free it using
259/// `rustls_crypto_provider_free`.
260///
261/// [FIPS]: https://docs.rs/rustls/latest/rustls/manual/_06_fips/index.html
262#[no_mangle]
263#[cfg(feature = "fips")]
264pub extern "C" fn rustls_default_fips_provider() -> *const rustls_crypto_provider {
265    ffi_panic_boundary! {
266        Arc::into_raw(Arc::new(rustls::crypto::default_fips_provider()))
267            as *const rustls_crypto_provider
268    }
269}
270
271/// Retrieve a pointer to the process default `rustls_crypto_provider`.
272///
273/// This may return `NULL` if no process default provider has been set using
274/// `rustls_crypto_provider_builder_build_default`.
275///
276/// Caller owns the returned `rustls_crypto_provider` and must free it w/ `rustls_crypto_provider_free`.
277#[no_mangle]
278pub extern "C" fn rustls_crypto_provider_default() -> *const rustls_crypto_provider {
279    ffi_panic_boundary! {
280        match CryptoProvider::get_default() {
281            Some(provider) => Arc::into_raw(provider.clone()) as *const rustls_crypto_provider,
282            None => core::ptr::null(),
283        }
284    }
285}
286
287arc_castable! {
288    /// A C representation of a Rustls [`CryptoProvider`].
289    pub struct rustls_crypto_provider(CryptoProvider);
290}
291
292/// Returns the number of ciphersuites the `rustls_crypto_provider` supports.
293///
294/// You can use this to know the maximum allowed index for use with
295/// `rustls_crypto_provider_ciphersuites_get`.
296///
297/// This function will return 0 if the `provider` is NULL.
298#[no_mangle]
299pub extern "C" fn rustls_crypto_provider_ciphersuites_len(
300    provider: *const rustls_crypto_provider,
301) -> usize {
302    ffi_panic_boundary! {
303        try_clone_arc!(provider).cipher_suites.len()
304    }
305}
306
307/// Retrieve a pointer to a supported ciphersuite of the `rustls_crypto_provider`.
308///
309/// This function will return NULL if the `provider` is NULL, or if the index is out of bounds
310/// with respect to `rustls_crypto_provider_ciphersuites_len`.
311///
312/// The lifetime of the returned `rustls_supported_ciphersuite` is equal to the lifetime of the
313/// `provider` and should not be used after the `provider` is freed.
314#[no_mangle]
315pub extern "C" fn rustls_crypto_provider_ciphersuites_get(
316    provider: *const rustls_crypto_provider,
317    index: usize,
318) -> *const rustls_supported_ciphersuite {
319    ffi_panic_boundary! {
320        match try_clone_arc!(provider).cipher_suites.get(index) {
321            Some(ciphersuite) => ciphersuite as *const SupportedCipherSuite as *const _,
322            None => core::ptr::null(),
323        }
324    }
325}
326
327/// Load a private key from the provided PEM content using the crypto provider.
328///
329/// `private_key` must point to a buffer of `private_key_len` bytes, containing
330/// a PEM-encoded private key. The exact formats supported will differ based on
331/// the crypto provider in use. The default providers support PKCS#1, PKCS#8 or
332/// SEC1 formats.
333///
334/// When this function returns `rustls_result::Ok` a pointer to a `rustls_signing_key`
335/// is written to `signing_key_out`. The caller owns the returned `rustls_signing_key`
336/// and must free it with `rustls_signing_key_free`.
337#[no_mangle]
338pub extern "C" fn rustls_crypto_provider_load_key(
339    provider: *const rustls_crypto_provider,
340    private_key: *const u8,
341    private_key_len: size_t,
342    signing_key_out: *mut *mut rustls_signing_key,
343) -> rustls_result {
344    ffi_panic_boundary! {
345        let provider = try_clone_arc!(provider);
346        let private_key_pem = try_slice!(private_key, private_key_len);
347        let signing_key_out = try_mut_from_ptr_ptr!(signing_key_out);
348
349        let private_key_der = match PrivateKeyDer::from_pem_slice(private_key_pem) {
350            Ok(der) => der,
351            Err(_) => return rustls_result::PrivateKeyParseError,
352        };
353
354        let private_key = match provider.key_provider.load_private_key(private_key_der) {
355            Ok(key) => key,
356            Err(e) => return map_error(e),
357        };
358
359        set_boxed_mut_ptr(signing_key_out, private_key);
360        rustls_result::Ok
361    }
362}
363
364/// Write `len` bytes of cryptographically secure random data to `buff` using the crypto provider.
365///
366/// `buff` must point to a buffer of at least `len` bytes. The caller maintains ownership
367/// of the buffer.
368///
369/// Returns `RUSTLS_RESULT_OK` on success, or `RUSTLS_RESULT_GET_RANDOM_FAILED` on failure.
370#[no_mangle]
371pub extern "C" fn rustls_crypto_provider_random(
372    provider: *const rustls_crypto_provider,
373    buff: *mut u8,
374    len: size_t,
375) -> rustls_result {
376    ffi_panic_boundary! {
377        match try_clone_arc!(provider)
378            .secure_random
379            .fill(try_slice_mut!(buff, len))
380        {
381            Ok(_) => rustls_result::Ok,
382            Err(_) => rustls_result::GetRandomFailed,
383        }
384    }
385}
386
387/// Returns true if the `rustls_crypto_provider` is operating in FIPS mode.
388///
389/// This covers only the cryptographic parts of FIPS approval. There are also
390/// TLS protocol-level recommendations made by NIST. You should prefer to call
391/// `rustls_client_config_fips` or `rustls_server_config_fips` which take these
392/// into account.
393#[no_mangle]
394pub extern "C" fn rustls_crypto_provider_fips(provider: *const rustls_crypto_provider) -> bool {
395    ffi_panic_boundary! {
396        try_ref_from_ptr!(provider).fips()
397    }
398}
399
400/// Frees the `rustls_crypto_provider`.
401///
402/// Calling with `NULL` is fine.
403/// Must not be called twice with the same value.
404#[no_mangle]
405pub extern "C" fn rustls_crypto_provider_free(provider: *const rustls_crypto_provider) {
406    ffi_panic_boundary! {
407        free_arc(provider);
408    }
409}
410
411/// Returns the number of ciphersuites the default process-wide crypto provider supports.
412///
413/// You can use this to know the maximum allowed index for use with
414/// `rustls_default_crypto_provider_ciphersuites_get`.
415///
416/// This function will return 0 if no process-wide default `rustls_crypto_provider` is available.
417#[no_mangle]
418pub extern "C" fn rustls_default_crypto_provider_ciphersuites_len() -> usize {
419    ffi_panic_boundary! {
420        match get_default_or_install_from_crate_features() {
421            Some(provider) => provider.cipher_suites.len(),
422            None => return 0,
423        }
424    }
425}
426
427/// Retrieve a pointer to a supported ciphersuite of the default process-wide crypto provider.
428///
429/// This function will return NULL if the `provider` is NULL, or if the index is out of bounds
430/// with respect to `rustls_default_crypto_provider_ciphersuites_len`.
431///
432/// The lifetime of the returned `rustls_supported_ciphersuite` is static, as the process-wide
433/// default provider lives for as long as the process.
434#[no_mangle]
435pub extern "C" fn rustls_default_crypto_provider_ciphersuites_get(
436    index: usize,
437) -> *const rustls_supported_ciphersuite {
438    ffi_panic_boundary! {
439        let default_provider = match get_default_or_install_from_crate_features() {
440            Some(provider) => provider,
441            None => return core::ptr::null(),
442        };
443        match default_provider.cipher_suites.get(index) {
444            Some(ciphersuite) => ciphersuite as *const SupportedCipherSuite as *const _,
445            None => core::ptr::null(),
446        }
447    }
448}
449
450/// Write `len` bytes of cryptographically secure random data to `buff` using the process-wide
451/// default crypto provider.
452///
453/// `buff` must point to a buffer of at least `len` bytes. The caller maintains ownership
454/// of the buffer.
455///
456/// Returns `RUSTLS_RESULT_OK` on success, and one of `RUSTLS_RESULT_NO_DEFAULT_CRYPTO_PROVIDER`
457/// or `RUSTLS_RESULT_GET_RANDOM_FAILED` on failure.
458#[no_mangle]
459pub extern "C" fn rustls_default_crypto_provider_random(
460    buff: *mut u8,
461    len: size_t,
462) -> rustls_result {
463    ffi_panic_boundary! {
464        match get_default_or_install_from_crate_features() {
465            Some(provider) => match provider.secure_random.fill(try_slice_mut!(buff, len)) {
466                Ok(_) => rustls_result::Ok,
467                Err(_) => rustls_result::GetRandomFailed,
468            },
469            None => rustls_result::NoDefaultCryptoProvider,
470        }
471    }
472}
473
474box_castable! {
475    /// A signing key that can be used to construct a certified key.
476    // NOTE: we box cast an arc over the dyn trait per the pattern described
477    //   in our docs[0] for dynamically sized types.
478    //   [0]: <https://github.com/rustls/rustls-ffi/blob/main/CONTRIBUTING.md#dynamically-sized-types>
479    pub struct rustls_signing_key(Arc<dyn SigningKey>);
480}
481
482impl rustls_signing_key {
483    /// Frees the `rustls_signing_key`. This is safe to call with a `NULL` argument, but
484    /// must not be called twice with the same value.
485    #[no_mangle]
486    pub extern "C" fn rustls_signing_key_free(signing_key: *mut rustls_signing_key) {
487        ffi_panic_boundary! {
488            free_box(signing_key);
489        }
490    }
491}
492
493ref_castable! {
494    /// A collection of supported Hybrid Public Key Encryption (HPKE) suites.
495    ///
496    /// `rustls_hpke` can be provided to `rustls_client_config_builder_enable_ech` and
497    /// `rustls_client_config_builder_enable_ech_grease()` to customize a
498    /// `rustls_client_config_builder` to use Encrypted Client Hello (ECH).
499    pub struct rustls_hpke(Hpke);
500}
501
502pub(crate) struct Hpke {
503    pub(crate) suites: &'static [&'static dyn hpke::Hpke],
504}
505
506impl Hpke {
507    /// Chooses a random supported HPKE suite and generates a throw-away public key.
508    ///
509    /// Returns both the selected Rustls `hpke::Hpke` suite and the `hpke::HpkePublicKey`
510    /// or `None` if an error occurs.
511    pub(crate) fn grease_public_key(
512        &self,
513        provider: &CryptoProvider,
514    ) -> Option<(&dyn hpke::Hpke, hpke::HpkePublicKey)> {
515        let num_suites = self.suites.len();
516        if num_suites == 0 {
517            return None;
518        }
519        debug_assert!(num_suites < u32::MAX as usize);
520
521        let mut buf = [0u8; 4];
522        let threshold = u32::MAX - (u32::MAX % num_suites as u32);
523        let suite = loop {
524            provider.secure_random.fill(&mut buf).ok()?;
525            let value = u32::from_ne_bytes(buf);
526            if value < threshold {
527                break self.suites[value as usize / (threshold as usize / num_suites)];
528            }
529        };
530
531        let pk = suite.generate_key_pair().map(|pair| pair.0).ok()?;
532        Some((suite, pk))
533    }
534}
535
536#[cfg(feature = "aws-lc-rs")]
537static AWS_LC_RS_HPKE: &Hpke = &Hpke {
538    suites: aws_lc_rs::hpke::ALL_SUPPORTED_SUITES,
539};
540
541/// Returns a pointer to the supported `rustls_hpke` Hybrid Public Key Encryption (HPKE)
542/// suites, or `NULL` if HPKE is not supported.
543///
544/// HPKE is only supported with the `aws-lc-rs` cryptography provider.
545///
546/// The returned pointer has a static lifetime equal to that of the program and does not
547/// need to be freed.
548#[no_mangle]
549pub extern "C" fn rustls_supported_hpke() -> *const rustls_hpke {
550    ffi_panic_boundary! {
551        #[cfg(feature = "aws-lc-rs")]
552        {
553            AWS_LC_RS_HPKE as *const _ as _
554        }
555        #[cfg(not(feature = "aws-lc-rs"))]
556        {
557            core::ptr::null()
558        }
559    }
560}
561
562pub(crate) fn get_default_or_install_from_crate_features() -> Option<Arc<CryptoProvider>> {
563    // If a process-wide default has already been installed, return it.
564    if let Some(provider) = CryptoProvider::get_default() {
565        return Some(provider.clone());
566    }
567
568    // Ignore the error resulting from us losing a race to install the default,
569    // and accept the outcome.
570    let _ = provider_from_crate_features()?.install_default();
571
572    // Safety: we can unwrap safely here knowing we've just set the default, or
573    // lost a race to something else setting the default.
574    Some(CryptoProvider::get_default().unwrap().clone())
575}
576
577fn provider_from_crate_features() -> Option<CryptoProvider> {
578    // Provider default is unambiguously aws-lc-rs
579    #[cfg(all(feature = "aws-lc-rs", not(feature = "ring")))]
580    {
581        return Some(aws_lc_rs::default_provider());
582    }
583
584    // Provider default is unambiguously ring
585    #[cfg(all(feature = "ring", not(feature = "aws-lc-rs")))]
586    {
587        return Some(ring::default_provider());
588    }
589
590    // Both features activated - no clear default provider based on
591    // crate features.
592    #[allow(unreachable_code)]
593    None
594}
595
596#[cfg(all(test, not(miri), any(feature = "aws-lc-rs", feature = "ring")))]
597mod tests {
598    use std::ptr;
599
600    use crate::rustls_result;
601
602    use super::*;
603
604    /// Simple smoketest of CSRNG fill with specific provider.
605    #[test]
606    fn random_data() {
607        let provider = rustls_crypto_provider_default();
608        assert!(!provider.is_null());
609
610        // NULL buffer should return an error.
611        let result = rustls_crypto_provider_random(provider, ptr::null_mut(), 1337);
612        assert_eq!(result, rustls_result::NullParameter);
613
614        let mut buff = vec![0; 32];
615
616        // NULL provider should return an error and not touch buff.
617        let result = rustls_crypto_provider_random(ptr::null(), buff.as_mut_ptr(), buff.len());
618        assert_eq!(buff, vec![0; 32]);
619        assert_eq!(result, rustls_result::NullParameter);
620
621        // Proper parameters should return OK and overwrite the buffer.
622        let result = rustls_crypto_provider_random(provider, buff.as_mut_ptr(), buff.len());
623        assert_eq!(result, rustls_result::Ok);
624        assert_ne!(buff, vec![0; 32]);
625    }
626
627    /// Simple smoketest of CSRNG fill with default provider.
628    #[test]
629    fn default_random_data() {
630        // NULL buffer should return an error.
631        let result = rustls_default_crypto_provider_random(ptr::null_mut(), 1337);
632        assert_eq!(result, rustls_result::NullParameter);
633
634        let mut buff = vec![0; 32];
635
636        // Proper parameters should return OK and overwrite the buffer.
637        let result = rustls_default_crypto_provider_random(buff.as_mut_ptr(), buff.len());
638        assert_eq!(result, rustls_result::Ok);
639        assert_ne!(buff, vec![0; 32]);
640    }
641
642    #[test]
643    #[cfg(feature = "aws-lc-rs")]
644    fn test_hpke_aws_lc_rs() {
645        let provider = rustls_crypto_provider_default();
646        assert!(!provider.is_null());
647        let provider = try_clone_arc!(provider);
648
649        let hpke = rustls_supported_hpke();
650        assert!(!hpke.is_null());
651
652        let hpke = try_ref_from_ptr!(hpke);
653
654        // We should be able to pick an HPKE suite and a pubkey for ECH GREASE.
655        let (suite, pk) = hpke.grease_public_key(&provider).unwrap();
656        // The PK and the suite should be compatible. Setup a sealer to check.
657        let (_, _) = suite.setup_sealer(&[0xC0, 0xFF, 0xEE], &pk).unwrap();
658    }
659
660    #[test]
661    #[cfg(not(feature = "aws-lc-rs"))]
662    fn test_hpke_not_aws_lc_rs() {
663        assert!(rustls_supported_hpke().is_null());
664    }
665}