summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel McCarney <daniel@binaryparadox.net>2024-07-05 15:35:20 -0400
committerDaniel McCarney <daniel@binaryparadox.net>2024-09-09 11:42:49 -0400
commit34510dacb4fc158d99880115cc6ef5fcac795f15 (patch)
treeed70c33cb2d9e720c15908a4a74ea3d9233ec186
parent0b8bc1fbe4e37333b4a6e41b6827bc610b866d16 (diff)
client: convert client config/builder to provider
* `rustls_client_config_builder_new()` now uses the process default crypto provider instead of being hardcoded to `*ring*`. We defer constructing the `ClientConfig` to avoid a panic in the event the process default isn't constructed. This will be surfaced as an error at build time instead. Like the upstream `ClientConfig::builder()` if no process default provider has been set when `rustls_client_config_builder_new()` is called we try to set one based on an unambiguous default implied by crate features. * `rustls_client_config_builder_new_custom()` now takes a `rustls_crypto_provider` as an argument in place of the list of custom ciphersuites. The ciphersuites can be customized when the provider is constructed. * `rustls_client_config_builder_build()` now uses an out param for the `ClientConfig` so we can return a suitable error if there is no crypto provider (e.g. because `rustls_client_config_builder_new()` was used but the process default wasn't set and couldn't be inferred from crate features). * The `client.c` test binary is updated to account for the breaking change in the client config builder out-param.
-rw-r--r--src/client.rs99
-rw-r--r--src/rustls.h25
2 files changed, 49 insertions, 75 deletions
diff --git a/src/client.rs b/src/client.rs
index 48cbdd2..7c87378 100644
--- a/src/client.rs
+++ b/src/client.rs
@@ -7,24 +7,24 @@ use libc::{c_char, size_t};
use pki_types::{CertificateDer, UnixTime};
use rustls::client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier};
use rustls::client::ResolvesClientCert;
-use rustls::crypto::ring::ALL_CIPHER_SUITES;
+use rustls::crypto::CryptoProvider;
use rustls::{
sign::CertifiedKey, ClientConfig, ClientConnection, DigitallySignedStruct, Error,
- ProtocolVersion, SignatureScheme, WantsVerifier,
+ ProtocolVersion, SignatureScheme, SupportedProtocolVersion,
};
-use crate::cipher::{
- rustls_certified_key, rustls_server_cert_verifier, rustls_supported_ciphersuite,
-};
+use crate::cipher::{rustls_certified_key, rustls_server_cert_verifier};
use crate::connection::{rustls_connection, Connection};
+use crate::crypto_provider::rustls_crypto_provider;
use crate::error::rustls_result::{InvalidParameter, NullParameter};
-use crate::error::{self, rustls_result};
+use crate::error::{self, map_error, rustls_result};
use crate::rslice::NulByte;
use crate::rslice::{rustls_slice_bytes, rustls_slice_slice_bytes, rustls_str};
use crate::{
- arc_castable, box_castable, ffi_panic_boundary, free_arc, free_box, set_arc_mut_ptr,
- set_boxed_mut_ptr, to_boxed_mut_ptr, try_box_from_ptr, try_clone_arc, try_mut_from_ptr,
- try_mut_from_ptr_ptr, try_ref_from_ptr, try_ref_from_ptr_ptr, try_slice, userdata_get,
+ arc_castable, box_castable, crypto_provider, ffi_panic_boundary, free_arc, free_box,
+ set_arc_mut_ptr, set_boxed_mut_ptr, to_boxed_mut_ptr, try_box_from_ptr, try_clone_arc,
+ try_mut_from_ptr, try_mut_from_ptr_ptr, try_ref_from_ptr, try_ref_from_ptr_ptr, try_slice,
+ userdata_get,
};
box_castable! {
@@ -44,7 +44,8 @@ box_castable! {
}
pub(crate) struct ClientConfigBuilder {
- base: rustls::ConfigBuilder<ClientConfig, WantsVerifier>,
+ provider: Option<Arc<CryptoProvider>>,
+ versions: Vec<&'static SupportedProtocolVersion>,
verifier: Option<Arc<dyn ServerCertVerifier>>,
alpn_protocols: Vec<Vec<u8>>,
enable_sni: bool,
@@ -60,7 +61,7 @@ arc_castable! {
}
impl rustls_client_config_builder {
- /// Create a rustls_client_config_builder.
+ /// Create a rustls_client_config_builder using the process default crypto provider.
///
/// Caller owns the memory and must eventually call `rustls_client_config_builder_build`,
/// then free the resulting `rustls_client_config`.
@@ -68,24 +69,17 @@ impl rustls_client_config_builder {
/// Alternatively, if an error occurs or, you don't wish to build a config,
/// call `rustls_client_config_builder_free` to free the builder directly.
///
- /// This uses rustls safe default values for the cipher suites, key exchange
- /// groups and protocol versions.
+ /// This uses the process default provider's values for the cipher suites and key
+ /// exchange groups, as well as safe defaults for protocol versions.
///
/// This starts out with no trusted roots. Caller must add roots with
- /// rustls_client_config_builder_load_roots_from_file or provide a custom
- /// verifier.
+ /// rustls_client_config_builder_load_roots_from_file or provide a custom verifier.
#[no_mangle]
pub extern "C" fn rustls_client_config_builder_new() -> *mut rustls_client_config_builder {
ffi_panic_boundary! {
- // Unwrap safety: *ring* default provider always has ciphersuites compatible with the
- // default protocol versions.
- let base = ClientConfig::builder_with_provider(
- rustls::crypto::ring::default_provider().into(),
- )
- .with_safe_default_protocol_versions()
- .unwrap();
let builder = ClientConfigBuilder {
- base,
+ provider: crypto_provider::get_default_or_install_from_crate_features(),
+ versions: rustls::DEFAULT_VERSIONS.to_vec(),
verifier: None,
cert_resolver: None,
alpn_protocols: vec![],
@@ -95,7 +89,7 @@ impl rustls_client_config_builder {
}
}
- /// Create a rustls_client_config_builder.
+ /// Create a rustls_client_config_builder using the specified crypto provider.
///
/// Caller owns the memory and must eventually call `rustls_client_config_builder_build`,
/// then free the resulting `rustls_client_config`.
@@ -103,13 +97,7 @@ impl rustls_client_config_builder {
/// Alternatively, if an error occurs or, you don't wish to build a config,
/// call `rustls_client_config_builder_free` to free the builder directly.
///
- /// Specify cipher suites in preference order; the `cipher_suites` parameter
- /// must point to an array containing `cipher_suites_len` pointers to
- /// `rustls_supported_ciphersuite` previously obtained from
- /// `rustls_all_ciphersuites_get_entry()`, or to a provided array,
- /// RUSTLS_DEFAULT_CIPHER_SUITES or RUSTLS_ALL_CIPHER_SUITES.
- ///
- /// Set the TLS protocol versions to use when negotiating a TLS session.
+ /// `tls_version` sets the TLS protocol versions to use when negotiating a TLS session.
/// `tls_version` is the version of the protocol, as defined in rfc8446,
/// ch. 4.2.1 and end of ch. 5.1. Some values are defined in
/// `rustls_tls_version` for convenience, and the arrays
@@ -118,28 +106,18 @@ impl rustls_client_config_builder {
/// `tls_versions` will only be used during the call and the application retains
/// ownership. `tls_versions_len` is the number of consecutive `uint16_t`
/// pointed to by `tls_versions`.
+ ///
+ /// Ciphersuites are configured separately via the crypto provider. See
+ /// `rustls_crypto_provider_builder_set_cipher_suites` for more information.
#[no_mangle]
pub extern "C" fn rustls_client_config_builder_new_custom(
- cipher_suites: *const *const rustls_supported_ciphersuite,
- cipher_suites_len: size_t,
+ provider: *const rustls_crypto_provider,
tls_versions: *const u16,
tls_versions_len: size_t,
builder_out: *mut *mut rustls_client_config_builder,
) -> rustls_result {
ffi_panic_boundary! {
- if builder_out.is_null() {
- return NullParameter;
- }
- let cipher_suites = try_slice!(cipher_suites, cipher_suites_len);
- let mut cs_vec = Vec::new();
- for &cs in cipher_suites.iter() {
- let cs = try_ref_from_ptr!(cs);
- match ALL_CIPHER_SUITES.iter().find(|&acs| cs.eq(acs)) {
- Some(scs) => cs_vec.push(*scs),
- None => return InvalidParameter,
- }
- }
-
+ let provider = try_clone_arc!(provider);
let tls_versions = try_slice!(tls_versions, tls_versions_len);
let mut versions = vec![];
for version_number in tls_versions {
@@ -150,21 +128,11 @@ impl rustls_client_config_builder {
versions.push(&rustls::version::TLS13);
}
}
-
let builder_out = try_mut_from_ptr_ptr!(builder_out);
- let provider = rustls::crypto::CryptoProvider {
- cipher_suites: cs_vec,
- ..rustls::crypto::ring::default_provider()
- };
- let result = ClientConfig::builder_with_provider(provider.into())
- .with_protocol_versions(&versions);
- let base = match result {
- Ok(new) => new,
- Err(_) => return InvalidParameter,
- };
let config_builder = ClientConfigBuilder {
- base,
+ provider: Some(provider),
+ versions,
verifier: None,
cert_resolver: None,
alpn_protocols: vec![],
@@ -484,13 +452,24 @@ impl rustls_client_config_builder {
let builder = try_box_from_ptr!(builder);
let config_out = try_ref_from_ptr_ptr!(config_out);
+ let provider = match builder.provider {
+ Some(provider) => provider,
+ None => return rustls_result::NoDefaultCryptoProvider,
+ };
+
let verifier = match builder.verifier {
Some(v) => v,
None => return rustls_result::NoServerCertVerifier,
};
- let config = builder
- .base
+ let config = match ClientConfig::builder_with_provider(provider)
+ .with_protocol_versions(&builder.versions)
+ {
+ Ok(c) => c,
+ Err(err) => return map_error(err),
+ };
+
+ let config = config
.dangerous()
.with_custom_certificate_verifier(verifier);
let mut config = match builder.cert_resolver {
diff --git a/src/rustls.h b/src/rustls.h
index 29d4420..aee8494 100644
--- a/src/rustls.h
+++ b/src/rustls.h
@@ -1419,7 +1419,7 @@ struct rustls_server_cert_verifier *rustls_platform_server_cert_verifier(void);
void rustls_server_cert_verifier_free(struct rustls_server_cert_verifier *verifier);
/**
- * Create a rustls_client_config_builder.
+ * Create a rustls_client_config_builder using the process default crypto provider.
*
* Caller owns the memory and must eventually call `rustls_client_config_builder_build`,
* then free the resulting `rustls_client_config`.
@@ -1427,17 +1427,16 @@ void rustls_server_cert_verifier_free(struct rustls_server_cert_verifier *verifi
* Alternatively, if an error occurs or, you don't wish to build a config,
* call `rustls_client_config_builder_free` to free the builder directly.
*
- * This uses rustls safe default values for the cipher suites, key exchange
- * groups and protocol versions.
+ * This uses the process default provider's values for the cipher suites and key
+ * exchange groups, as well as safe defaults for protocol versions.
*
* This starts out with no trusted roots. Caller must add roots with
- * rustls_client_config_builder_load_roots_from_file or provide a custom
- * verifier.
+ * rustls_client_config_builder_load_roots_from_file or provide a custom verifier.
*/
struct rustls_client_config_builder *rustls_client_config_builder_new(void);
/**
- * Create a rustls_client_config_builder.
+ * Create a rustls_client_config_builder using the specified crypto provider.
*
* Caller owns the memory and must eventually call `rustls_client_config_builder_build`,
* then free the resulting `rustls_client_config`.
@@ -1445,13 +1444,7 @@ struct rustls_client_config_builder *rustls_client_config_builder_new(void);
* Alternatively, if an error occurs or, you don't wish to build a config,
* call `rustls_client_config_builder_free` to free the builder directly.
*
- * Specify cipher suites in preference order; the `cipher_suites` parameter
- * must point to an array containing `cipher_suites_len` pointers to
- * `rustls_supported_ciphersuite` previously obtained from
- * `rustls_all_ciphersuites_get_entry()`, or to a provided array,
- * RUSTLS_DEFAULT_CIPHER_SUITES or RUSTLS_ALL_CIPHER_SUITES.
- *
- * Set the TLS protocol versions to use when negotiating a TLS session.
+ * `tls_version` sets the TLS protocol versions to use when negotiating a TLS session.
* `tls_version` is the version of the protocol, as defined in rfc8446,
* ch. 4.2.1 and end of ch. 5.1. Some values are defined in
* `rustls_tls_version` for convenience, and the arrays
@@ -1460,9 +1453,11 @@ struct rustls_client_config_builder *rustls_client_config_builder_new(void);
* `tls_versions` will only be used during the call and the application retains
* ownership. `tls_versions_len` is the number of consecutive `uint16_t`
* pointed to by `tls_versions`.
+ *
+ * Ciphersuites are configured separately via the crypto provider. See
+ * `rustls_crypto_provider_builder_set_cipher_suites` for more information.
*/
-rustls_result rustls_client_config_builder_new_custom(const struct rustls_supported_ciphersuite *const *cipher_suites,
- size_t cipher_suites_len,
+rustls_result rustls_client_config_builder_new_custom(const struct rustls_crypto_provider *provider,
const uint16_t *tls_versions,
size_t tls_versions_len,
struct rustls_client_config_builder **builder_out);