summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel McCarney <daniel@binaryparadox.net>2024-09-09 15:42:37 -0400
committerDaniel McCarney <daniel@binaryparadox.net>2024-09-10 08:09:21 -0400
commit99f40a231704b7df7969411052a4e4e13b331ad1 (patch)
tree7591d49cbe6a491c9b0aac50db7f66c4b4cd6813
parent781cadb424e2aa77770c4021c707f5be3cd9e1f1 (diff)
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.
-rw-r--r--CHANGELOG.md5
-rw-r--r--src/crypto_provider.rs96
-rw-r--r--src/error.rs4
-rw-r--r--src/rustls.h25
4 files changed, 128 insertions, 2 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d8a713f..8885431 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,6 @@
# Changelog
-## 0.14.0 (2024-08-01)
+## 0.14.0-rc1 (2024-09-09)
This release updates to [Rustls 0.23.12][] and changes the rustls-ffi API to allow
choosing a cryptography provider to use with Rustls.
@@ -30,6 +30,9 @@ requirements.
* Ciphersuites supported by the current process-wide default crypto provider (if any) can
be retrieved with `rustls_default_crypto_provider_ciphersuites_len()` and
`rustls_default_crypto_provider_ciphersuites_get()`.
+ * A buffer can be filled with cryptographically secure random data from
+ a specific `rustls_crypto_provider` using `rustls_crypto_provider_random()`,
+ or the process-wide default provider using `rustls_default_crypto_provider_random()`.
* A new `RUSTLS_RESULT_NO_DEFAULT_CRYPTO_PROVIDER` `rustls_result` was added to
indicate when an operation that requires a process-wide default crypto
diff --git a/src/crypto_provider.rs b/src/crypto_provider.rs
index e61e36d..fc99986 100644
--- a/src/crypto_provider.rs
+++ b/src/crypto_provider.rs
@@ -16,7 +16,8 @@ use crate::error::map_error;
use crate::{
arc_castable, box_castable, ffi_panic_boundary, free_arc, free_box, rustls_result,
set_arc_mut_ptr, set_boxed_mut_ptr, to_boxed_mut_ptr, try_clone_arc, try_mut_from_ptr,
- try_mut_from_ptr_ptr, try_ref_from_ptr, try_ref_from_ptr_ptr, try_slice, try_take,
+ try_mut_from_ptr_ptr, try_ref_from_ptr, try_ref_from_ptr_ptr, try_slice, try_slice_mut,
+ try_take,
};
box_castable! {
@@ -338,6 +339,29 @@ pub extern "C" fn rustls_crypto_provider_load_key(
}
}
+/// Write `len` bytes of cryptographically secure random data to `buff` using the crypto provider.
+///
+/// `buff` must point to a buffer of at least `len` bytes. The caller maintains ownership
+/// of the buffer.
+///
+/// Returns `RUSTLS_RESULT_OK` on success, or `RUSTLS_RESULT_GET_RANDOM_FAILED` on failure.
+#[no_mangle]
+pub extern "C" fn rustls_crypto_provider_random(
+ provider: *const rustls_crypto_provider,
+ buff: *mut u8,
+ len: size_t,
+) -> rustls_result {
+ ffi_panic_boundary! {
+ match try_clone_arc!(provider)
+ .secure_random
+ .fill(try_slice_mut!(buff, len))
+ {
+ Ok(_) => rustls_result::Ok,
+ Err(_) => rustls_result::GetRandomFailed,
+ }
+ }
+}
+
/// Frees the `rustls_crypto_provider`.
///
/// Calling with `NULL` is fine.
@@ -388,6 +412,30 @@ pub extern "C" fn rustls_default_crypto_provider_ciphersuites_get(
}
}
+/// Write `len` bytes of cryptographically secure random data to `buff` using the process-wide
+/// default crypto provider.
+///
+/// `buff` must point to a buffer of at least `len` bytes. The caller maintains ownership
+/// of the buffer.
+///
+/// Returns `RUSTLS_RESULT_OK` on success, and one of `RUSTLS_RESULT_NO_DEFAULT_CRYPTO_PROVIDER`
+/// or `RUSTLS_RESULT_GET_RANDOM_FAILED` on failure.
+#[no_mangle]
+pub extern "C" fn rustls_default_crypto_provider_random(
+ buff: *mut u8,
+ len: size_t,
+) -> rustls_result {
+ ffi_panic_boundary! {
+ match get_default_or_install_from_crate_features() {
+ Some(provider) => match provider.secure_random.fill(try_slice_mut!(buff, len)) {
+ Ok(_) => rustls_result::Ok,
+ Err(_) => rustls_result::GetRandomFailed,
+ },
+ None => rustls_result::NoDefaultCryptoProvider,
+ }
+ }
+}
+
box_castable! {
/// A signing key that can be used to construct a certified key.
// 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> {
#[allow(unreachable_code)]
None
}
+
+#[cfg(all(test, not(miri)))]
+mod tests {
+ use std::ptr;
+
+ use super::*;
+ use rustls_result;
+
+ /// Simple smoketest of CSRNG fill with specific provider.
+ #[test]
+ fn random_data() {
+ let provider = rustls_crypto_provider_default();
+ assert!(!provider.is_null());
+
+ // NULL buffer should return an error.
+ let result = rustls_crypto_provider_random(provider, ptr::null_mut(), 1337);
+ assert_eq!(result, rustls_result::NullParameter);
+
+ let mut buff = vec![0; 32];
+
+ // NULL provider should return an error and not touch buff.
+ let result = rustls_crypto_provider_random(ptr::null(), buff.as_mut_ptr(), buff.len());
+ assert_eq!(buff, vec![0; 32]);
+ assert_eq!(result, rustls_result::NullParameter);
+
+ // Proper parameters should return OK and overwrite the buffer.
+ let result = rustls_crypto_provider_random(provider, buff.as_mut_ptr(), buff.len());
+ assert_eq!(result, rustls_result::Ok);
+ assert_ne!(buff, vec![0; 32]);
+ }
+
+ /// Simple smoketest of CSRNG fill with default provider.
+ #[test]
+ fn default_random_data() {
+ // NULL buffer should return an error.
+ let result = rustls_default_crypto_provider_random(ptr::null_mut(), 1337);
+ assert_eq!(result, rustls_result::NullParameter);
+
+ let mut buff = vec![0; 32];
+
+ // Proper parameters should return OK and overwrite the buffer.
+ let result = rustls_default_crypto_provider_random(buff.as_mut_ptr(), buff.len());
+ assert_eq!(result, rustls_result::Ok);
+ assert_ne!(buff, vec![0; 32]);
+ }
+}
diff --git a/src/error.rs b/src/error.rs
index 0dbcb92..af9d466 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -62,6 +62,7 @@ u32_enum_builder! {
CertificateRevocationListParseError => 7014,
NoServerCertVerifier => 7015,
NoDefaultCryptoProvider => 7016,
+ GetRandomFailed => 7017,
// From https://docs.rs/rustls/latest/rustls/enum.Error.html
NoCertificatesPresented => 7101,
@@ -495,6 +496,9 @@ impl Display for rustls_result {
"no default process-wide crypto provider has been installed"
)
}
+ GetRandomFailed => {
+ write!(f, "failed to get random bytes from the crypto provider")
+ }
CertEncodingBad => Error::InvalidCertificate(CertificateError::BadEncoding).fmt(f),
CertExpired => Error::InvalidCertificate(CertificateError::Expired).fmt(f),
diff --git a/src/rustls.h b/src/rustls.h
index 711cb4f..207e3ce 100644
--- a/src/rustls.h
+++ b/src/rustls.h
@@ -25,6 +25,7 @@ enum rustls_result {
RUSTLS_RESULT_CERTIFICATE_REVOCATION_LIST_PARSE_ERROR = 7014,
RUSTLS_RESULT_NO_SERVER_CERT_VERIFIER = 7015,
RUSTLS_RESULT_NO_DEFAULT_CRYPTO_PROVIDER = 7016,
+ RUSTLS_RESULT_GET_RANDOM_FAILED = 7017,
RUSTLS_RESULT_NO_CERTIFICATES_PRESENTED = 7101,
RUSTLS_RESULT_DECRYPT_ERROR = 7102,
RUSTLS_RESULT_FAILED_TO_GET_CURRENT_TIME = 7103,
@@ -2054,6 +2055,18 @@ rustls_result rustls_crypto_provider_load_key(const struct rustls_crypto_provide
struct rustls_signing_key **signing_key_out);
/**
+ * Write `len` bytes of cryptographically secure random data to `buff` using the crypto provider.
+ *
+ * `buff` must point to a buffer of at least `len` bytes. The caller maintains ownership
+ * of the buffer.
+ *
+ * Returns `RUSTLS_RESULT_OK` on success, or `RUSTLS_RESULT_GET_RANDOM_FAILED` on failure.
+ */
+rustls_result rustls_crypto_provider_random(const struct rustls_crypto_provider *provider,
+ uint8_t *buff,
+ size_t len);
+
+/**
* Frees the `rustls_crypto_provider`.
*
* Calling with `NULL` is fine.
@@ -2083,6 +2096,18 @@ size_t rustls_default_crypto_provider_ciphersuites_len(void);
const struct rustls_supported_ciphersuite *rustls_default_crypto_provider_ciphersuites_get(size_t index);
/**
+ * Write `len` bytes of cryptographically secure random data to `buff` using the process-wide
+ * default crypto provider.
+ *
+ * `buff` must point to a buffer of at least `len` bytes. The caller maintains ownership
+ * of the buffer.
+ *
+ * Returns `RUSTLS_RESULT_OK` on success, and one of `RUSTLS_RESULT_NO_DEFAULT_CRYPTO_PROVIDER`
+ * or `RUSTLS_RESULT_GET_RANDOM_FAILED` on failure.
+ */
+rustls_result rustls_default_crypto_provider_random(uint8_t *buff, size_t len);
+
+/**
* Frees the `rustls_signing_key`. This is safe to call with a `NULL` argument, but
* must not be called twice with the same value.
*/