Skip to content

Commit 51dbb7f

Browse files
committed
crypto_provider: expose a way to get CSRNG data
This commit adds a `rustls_crypto_provider_random()` fn for filling a buffer with cryptographically secure random data using a specific `rustls_crypto_provider`, and `rustls_default_crypto_provider_random()` for doing the same with the process-wide default.
1 parent 60915ee commit 51dbb7f

File tree

4 files changed

+128
-2
lines changed

4 files changed

+128
-2
lines changed

CHANGELOG.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Changelog
22

3-
## 0.14.0 (2024-08-01)
3+
## 0.14.0-rc1 (2024-09-09)
44

55
This release updates to [Rustls 0.23.12][] and changes the rustls-ffi API to allow
66
choosing a cryptography provider to use with Rustls.
@@ -30,6 +30,9 @@ requirements.
3030
* Ciphersuites supported by the current process-wide default crypto provider (if any) can
3131
be retrieved with `rustls_default_crypto_provider_ciphersuites_len()` and
3232
`rustls_default_crypto_provider_ciphersuites_get()`.
33+
* A buffer can be filled with cryptographically secure random data from
34+
a specific `rustls_crypto_provider` using `rustls_crypto_provider_random()`,
35+
or the process-wide default provider using `rustls_default_crypto_provider_random()`.
3336

3437
* A new `RUSTLS_RESULT_NO_DEFAULT_CRYPTO_PROVIDER` `rustls_result` was added to
3538
indicate when an operation that requires a process-wide default crypto

src/crypto_provider.rs

Lines changed: 95 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ use crate::error::map_error;
1616
use crate::{
1717
arc_castable, box_castable, ffi_panic_boundary, free_arc, free_box, rustls_result,
1818
set_arc_mut_ptr, set_boxed_mut_ptr, to_boxed_mut_ptr, try_clone_arc, try_mut_from_ptr,
19-
try_mut_from_ptr_ptr, try_ref_from_ptr, try_ref_from_ptr_ptr, try_slice, try_take,
19+
try_mut_from_ptr_ptr, try_ref_from_ptr, try_ref_from_ptr_ptr, try_slice, try_slice_mut,
20+
try_take,
2021
};
2122

2223
box_castable! {
@@ -338,6 +339,29 @@ pub extern "C" fn rustls_crypto_provider_load_key(
338339
}
339340
}
340341

342+
/// Write `len` bytes of cryptographically secure random data to `buff` using the crypto provider.
343+
///
344+
/// `buff` must point to a buffer of at least `len` bytes. The caller maintains ownership
345+
/// of the buffer.
346+
///
347+
/// Returns `RUSTLS_RESULT_OK` on success, or `RUSTLS_RESULT_GET_RANDOM_FAILED` on failure.
348+
#[no_mangle]
349+
pub extern "C" fn rustls_crypto_provider_random(
350+
provider: *const rustls_crypto_provider,
351+
buff: *mut u8,
352+
len: size_t,
353+
) -> rustls_result {
354+
ffi_panic_boundary! {
355+
match try_clone_arc!(provider)
356+
.secure_random
357+
.fill(try_slice_mut!(buff, len))
358+
{
359+
Ok(_) => rustls_result::Ok,
360+
Err(_) => rustls_result::GetRandomFailed,
361+
}
362+
}
363+
}
364+
341365
/// Frees the `rustls_crypto_provider`.
342366
///
343367
/// Calling with `NULL` is fine.
@@ -388,6 +412,30 @@ pub extern "C" fn rustls_default_crypto_provider_ciphersuites_get(
388412
}
389413
}
390414

415+
/// Write `len` bytes of cryptographically secure random data to `buff` using the process-wide
416+
/// default crypto provider.
417+
///
418+
/// `buff` must point to a buffer of at least `len` bytes. The caller maintains ownership
419+
/// of the buffer.
420+
///
421+
/// Returns `RUSTLS_RESULT_OK` on success, and one of `RUSTLS_RESULT_NO_DEFAULT_CRYPTO_PROVIDER`
422+
/// or `RUSTLS_RESULT_GET_RANDOM_FAILED` on failure.
423+
#[no_mangle]
424+
pub extern "C" fn rustls_default_crypto_provider_random(
425+
buff: *mut u8,
426+
len: size_t,
427+
) -> rustls_result {
428+
ffi_panic_boundary! {
429+
match get_default_or_install_from_crate_features() {
430+
Some(provider) => match provider.secure_random.fill(try_slice_mut!(buff, len)) {
431+
Ok(_) => rustls_result::Ok,
432+
Err(_) => rustls_result::GetRandomFailed,
433+
},
434+
None => rustls_result::NoDefaultCryptoProvider,
435+
}
436+
}
437+
}
438+
391439
box_castable! {
392440
/// A signing key that can be used to construct a certified key.
393441
// NOTE: we box cast an arc over the dyn trait per the pattern described
@@ -445,3 +493,49 @@ fn provider_from_crate_features() -> Option<CryptoProvider> {
445493
#[allow(unreachable_code)]
446494
None
447495
}
496+
497+
#[cfg(all(test, not(miri)))]
498+
mod tests {
499+
use std::ptr;
500+
501+
use super::*;
502+
use rustls_result;
503+
504+
/// Simple smoketest of CSRNG fill with specific provider.
505+
#[test]
506+
fn random_data() {
507+
let provider = rustls_crypto_provider_default();
508+
assert!(!provider.is_null());
509+
510+
// NULL buffer should return an error.
511+
let result = rustls_crypto_provider_random(provider, ptr::null_mut(), 1337);
512+
assert_eq!(result, rustls_result::NullParameter);
513+
514+
let mut buff = vec![0; 32];
515+
516+
// NULL provider should return an error and not touch buff.
517+
let result = rustls_crypto_provider_random(ptr::null(), buff.as_mut_ptr(), buff.len());
518+
assert_eq!(buff, vec![0; 32]);
519+
assert_eq!(result, rustls_result::NullParameter);
520+
521+
// Proper parameters should return OK and overwrite the buffer.
522+
let result = rustls_crypto_provider_random(provider, buff.as_mut_ptr(), buff.len());
523+
assert_eq!(result, rustls_result::Ok);
524+
assert_ne!(buff, vec![0; 32]);
525+
}
526+
527+
/// Simple smoketest of CSRNG fill with default provider.
528+
#[test]
529+
fn default_random_data() {
530+
// NULL buffer should return an error.
531+
let result = rustls_default_crypto_provider_random(ptr::null_mut(), 1337);
532+
assert_eq!(result, rustls_result::NullParameter);
533+
534+
let mut buff = vec![0; 32];
535+
536+
// Proper parameters should return OK and overwrite the buffer.
537+
let result = rustls_default_crypto_provider_random(buff.as_mut_ptr(), buff.len());
538+
assert_eq!(result, rustls_result::Ok);
539+
assert_ne!(buff, vec![0; 32]);
540+
}
541+
}

src/error.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ u32_enum_builder! {
6262
CertificateRevocationListParseError => 7014,
6363
NoServerCertVerifier => 7015,
6464
NoDefaultCryptoProvider => 7016,
65+
GetRandomFailed => 7017,
6566

6667
// From https://docs.rs/rustls/latest/rustls/enum.Error.html
6768
NoCertificatesPresented => 7101,
@@ -495,6 +496,9 @@ impl Display for rustls_result {
495496
"no default process-wide crypto provider has been installed"
496497
)
497498
}
499+
GetRandomFailed => {
500+
write!(f, "failed to get random bytes from the crypto provider")
501+
}
498502

499503
CertEncodingBad => Error::InvalidCertificate(CertificateError::BadEncoding).fmt(f),
500504
CertExpired => Error::InvalidCertificate(CertificateError::Expired).fmt(f),

src/rustls.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ enum rustls_result {
2525
RUSTLS_RESULT_CERTIFICATE_REVOCATION_LIST_PARSE_ERROR = 7014,
2626
RUSTLS_RESULT_NO_SERVER_CERT_VERIFIER = 7015,
2727
RUSTLS_RESULT_NO_DEFAULT_CRYPTO_PROVIDER = 7016,
28+
RUSTLS_RESULT_GET_RANDOM_FAILED = 7017,
2829
RUSTLS_RESULT_NO_CERTIFICATES_PRESENTED = 7101,
2930
RUSTLS_RESULT_DECRYPT_ERROR = 7102,
3031
RUSTLS_RESULT_FAILED_TO_GET_CURRENT_TIME = 7103,
@@ -2053,6 +2054,18 @@ rustls_result rustls_crypto_provider_load_key(const struct rustls_crypto_provide
20532054
size_t private_key_len,
20542055
struct rustls_signing_key **signing_key_out);
20552056

2057+
/**
2058+
* Write `len` bytes of cryptographically secure random data to `buff` using the crypto provider.
2059+
*
2060+
* `buff` must point to a buffer of at least `len` bytes. The caller maintains ownership
2061+
* of the buffer.
2062+
*
2063+
* Returns `RUSTLS_RESULT_OK` on success, or `RUSTLS_RESULT_GET_RANDOM_FAILED` on failure.
2064+
*/
2065+
rustls_result rustls_crypto_provider_random(const struct rustls_crypto_provider *provider,
2066+
uint8_t *buff,
2067+
size_t len);
2068+
20562069
/**
20572070
* Frees the `rustls_crypto_provider`.
20582071
*
@@ -2082,6 +2095,18 @@ size_t rustls_default_crypto_provider_ciphersuites_len(void);
20822095
*/
20832096
const struct rustls_supported_ciphersuite *rustls_default_crypto_provider_ciphersuites_get(size_t index);
20842097

2098+
/**
2099+
* Write `len` bytes of cryptographically secure random data to `buff` using the process-wide
2100+
* default crypto provider.
2101+
*
2102+
* `buff` must point to a buffer of at least `len` bytes. The caller maintains ownership
2103+
* of the buffer.
2104+
*
2105+
* Returns `RUSTLS_RESULT_OK` on success, and one of `RUSTLS_RESULT_NO_DEFAULT_CRYPTO_PROVIDER`
2106+
* or `RUSTLS_RESULT_GET_RANDOM_FAILED` on failure.
2107+
*/
2108+
rustls_result rustls_default_crypto_provider_random(uint8_t *buff, size_t len);
2109+
20852110
/**
20862111
* Frees the `rustls_signing_key`. This is safe to call with a `NULL` argument, but
20872112
* must not be called twice with the same value.

0 commit comments

Comments
 (0)