Skip to content

Commit 26e4d8f

Browse files
Modularize rustls as work towards providers
`rustls`'s architecture is very clean and trait-driven. There are many providers for `rustls` including the built-in `aws-lc-rs` and `ring` as well as backends for `boringssl`, `graviola`, `openssl`, `mbedtls`, etc. This commit removes the hard dependency on `aws-lc-rs` and adds support for `ring`. It works towards #7059 as well.
1 parent b18b71b commit 26e4d8f

8 files changed

Lines changed: 65 additions & 44 deletions

File tree

Cargo.lock

Lines changed: 3 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ jit = ["rustpython-vm/jit"]
2222
threading = ["rustpython-vm/threading", "rustpython-stdlib/threading"]
2323
sqlite = ["rustpython-stdlib/sqlite"]
2424
ssl = []
25-
ssl-rustls = ["ssl", "rustpython-stdlib/ssl-rustls"]
25+
ssl-rustls = ["ssl", "rustpython-stdlib/ssl-rustls-aws-lc-rs"]
26+
ssl-rustls-ring = ["ssl", "rustpython-stdlib/ssl-rustls-ring"]
2627
ssl-openssl = ["ssl", "rustpython-stdlib/ssl-openssl"]
2728
ssl-vendor = ["ssl-openssl", "rustpython-stdlib/ssl-vendor"]
2829
tkinter = ["rustpython-stdlib/tkinter"]

crates/stdlib/Cargo.toml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,16 @@ threading = ["rustpython-common/threading", "rustpython-vm/threading"]
1818
sqlite = ["dep:libsqlite3-sys"]
1919
# SSL backends - default to rustls
2020
ssl = []
21-
ssl-rustls = ["ssl", "rustls", "rustls-native-certs", "rustls-pemfile", "rustls-platform-verifier", "x509-cert", "x509-parser", "der", "pem-rfc7468", "webpki-roots", "aws-lc-rs", "oid-registry", "pkcs8"]
22-
ssl-rustls-fips = ["ssl-rustls", "aws-lc-rs/fips"]
21+
ssl-rustls-aws-lc-rs = ["ssl", "__ssl-rustls", "rustls/aws_lc_rs"]
22+
ssl-rustls-fips = ["ssl-rustls-aws-lc-rs", "rustls/fips"]
23+
ssl-rustls-ring = ["ssl", "__ssl-rustls", "rustls/ring"]
2324
ssl-openssl = ["ssl", "openssl", "openssl-sys", "foreign-types-shared", "openssl-probe"]
2425
ssl-vendor = ["ssl-openssl", "openssl/vendored"]
2526
tkinter = ["dep:tk-sys", "dep:tcl-sys", "dep:widestring"]
2627
flame-it = ["flame"]
2728

29+
__ssl-rustls = ["ssl", "rustls", "rustls-native-certs", "rustls-pemfile", "rustls-platform-verifier", "x509-cert", "x509-parser", "der", "pem-rfc7468", "webpki-roots", "oid-registry", "pkcs8"]
30+
2831
[dependencies]
2932
# rustpython crates
3033
rustpython-derive = { workspace = true }
@@ -122,7 +125,7 @@ openssl-probe = { version = "0.2.1", optional = true }
122125
foreign-types-shared = { version = "0.1.1", optional = true }
123126

124127
# Rustls dependencies (optional, for ssl-rustls feature)
125-
rustls = { version = "0.23.37", default-features = false, features = ["std", "tls12", "aws_lc_rs"], optional = true }
128+
rustls = { version = "0.23.37", default-features = false, features = ["std", "tls12"], optional = true }
126129
rustls-native-certs = { version = "0.8", optional = true }
127130
rustls-pemfile = { version = "2.2", optional = true }
128131
rustls-platform-verifier = { version = "0.6", optional = true }
@@ -131,7 +134,6 @@ x509-parser = { version = "0.18", optional = true }
131134
der = { version = "0.7", features = ["alloc", "oid"], optional = true }
132135
pem-rfc7468 = { version = "1.0", features = ["alloc"], optional = true }
133136
webpki-roots = { version = "1.0", optional = true }
134-
aws-lc-rs = { version = "1.16.2", optional = true }
135137
oid-registry = { version = "0.8", features = ["x509", "pkcs1", "nist_algs"], optional = true }
136138
pkcs8 = { version = "0.10", features = ["encryption", "pkcs5", "pem"], optional = true }
137139

crates/stdlib/src/lib.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -106,11 +106,13 @@ mod openssl;
106106
#[cfg(all(
107107
feature = "host_env",
108108
not(target_arch = "wasm32"),
109-
feature = "ssl-rustls"
109+
feature = "__ssl-rustls"
110110
))]
111111
mod ssl;
112-
#[cfg(all(feature = "ssl-openssl", feature = "ssl-rustls"))]
113-
compile_error!("features \"ssl-openssl\" and \"ssl-rustls\" are mutually exclusive");
112+
#[cfg(all(feature = "ssl-openssl", feature = "__ssl-rustls"))]
113+
compile_error!(
114+
"features \"ssl-openssl\", \"ssl-rustls-aws-lc-rs\", and \"ssl-rustls-ring\" are mutually exclusive"
115+
);
114116

115117
#[cfg(all(
116118
feature = "host_env",
@@ -222,7 +224,7 @@ pub fn stdlib_module_defs(ctx: &Context) -> Vec<&'static builtins::PyModuleDef>
222224
#[cfg(all(
223225
feature = "host_env",
224226
not(target_arch = "wasm32"),
225-
feature = "ssl-rustls"
227+
feature = "__ssl-rustls"
226228
))]
227229
ssl::module_def(ctx),
228230
statistics::module_def(ctx),

crates/stdlib/src/ssl.rs

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ mod _ssl {
3737
lock::{PyMutex, PyRwLock},
3838
},
3939
socket::{PySocket, SelectKind, sock_select, timeout_error_msg},
40+
ssl::compat,
4041
vm::{
4142
AsObject, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject,
4243
VirtualMachine,
@@ -64,7 +65,6 @@ mod _ssl {
6465
sync::atomic::{AtomicUsize, Ordering},
6566
time::Duration,
6667
};
67-
use rustls::crypto::aws_lc_rs::ALL_CIPHER_SUITES;
6868
use std::{
6969
collections::{HashMap, hash_map::DefaultHasher},
7070
io::BufRead,
@@ -77,14 +77,20 @@ mod _ssl {
7777
use rustls::{
7878
ClientConfig, ClientConnection, RootCertStore, ServerConfig, ServerConnection,
7979
client::{ClientSessionMemoryCache, ClientSessionStore},
80-
crypto::SupportedKxGroup,
80+
crypto::{CryptoProvider, SupportedKxGroup},
8181
pki_types::{CertificateDer, CertificateRevocationListDer, PrivateKeyDer, ServerName},
8282
server::{ClientHello, ResolvesServerCert},
8383
sign::CertifiedKey,
8484
version::{TLS12, TLS13},
8585
};
8686
use sha2::{Digest, Sha256};
8787

88+
#[cfg(feature = "ssl-rustls-aws-lc-rs")]
89+
use rustls::crypto::aws_lc_rs::{ALL_CIPHER_SUITES, Ticketer, sign};
90+
91+
#[cfg(feature = "ssl-rustls-ring")]
92+
use rustls::crypto::ring::{ALL_CIPHER_SUITES, Ticketer, sign};
93+
8894
// Import certificate operations module
8995
use super::cert;
9096

@@ -1189,15 +1195,14 @@ mod _ssl {
11891195
}
11901196

11911197
// Additional validation: Create CertifiedKey to ensure rustls accepts it
1192-
let signing_key =
1193-
rustls::crypto::aws_lc_rs::sign::any_supported_type(&key).map_err(|_| {
1194-
vm.new_os_subtype_error(
1195-
PySSLError::class(&vm.ctx).to_owned(),
1196-
None,
1197-
"[SSL: KEY_VALUES_MISMATCH] key values mismatch",
1198-
)
1199-
.upcast()
1200-
})?;
1198+
let signing_key = sign::any_supported_type(&key).map_err(|_| {
1199+
vm.new_os_subtype_error(
1200+
PySSLError::class(&vm.ctx).to_owned(),
1201+
None,
1202+
"[SSL: KEY_VALUES_MISMATCH] key values mismatch",
1203+
)
1204+
.upcast()
1205+
})?;
12011206

12021207
let certified_key = CertifiedKey::new(full_chain.clone(), signing_key);
12031208
if certified_key.keys_match().is_err() {
@@ -2295,7 +2300,7 @@ mod _ssl {
22952300
rustls_server_session_store: rustls::server::ServerSessionMemoryCache::new(
22962301
SSL_SESSION_CACHE_SIZE,
22972302
),
2298-
server_ticketer: rustls::crypto::aws_lc_rs::Ticketer::new()
2303+
server_ticketer: Ticketer::new()
22992304
.expect("Failed to create shared ticketer for TLS 1.2 session resumption"),
23002305
accept_count: AtomicUsize::new(0),
23012306
session_hits: AtomicUsize::new(0),
@@ -4883,17 +4888,20 @@ mod _ssl {
48834888

48844889
#[pyfunction]
48854890
fn RAND_bytes(n: i64, vm: &VirtualMachine) -> PyResult<PyBytesRef> {
4886-
use aws_lc_rs::rand::{SecureRandom, SystemRandom};
4891+
compat::ensure_default_provider();
4892+
let default_provider =
4893+
CryptoProvider::get_default().expect("A CryptoProvider should have been set earlier");
48874894

48884895
// Validate n is not negative
48894896
if n < 0 {
48904897
return Err(vm.new_value_error("num must be positive"));
48914898
}
48924899

48934900
let n_usize = n as usize;
4894-
let rng = SystemRandom::new();
48954901
let mut buf = vec![0u8; n_usize];
4896-
rng.fill(&mut buf)
4902+
default_provider
4903+
.secure_random
4904+
.fill(&mut buf)
48974905
.map_err(|_| vm.new_os_error("Failed to generate random bytes"))?;
48984906
Ok(PyBytesRef::from(vm.ctx.new_bytes(buf)))
48994907
}

crates/stdlib/src/ssl/cert.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ use x509_parser::prelude::*;
2424

2525
use super::compat::{VERIFY_X509_PARTIAL_CHAIN, VERIFY_X509_STRICT};
2626

27+
#[cfg(feature = "ssl-rustls-aws-lc-rs")]
28+
use rustls::crypto::aws_lc_rs::sign;
29+
30+
#[cfg(feature = "ssl-rustls-ring")]
31+
use rustls::crypto::ring::sign;
32+
2733
// Certificate Verification Constants
2834

2935
/// All supported signature schemes for certificate verification
@@ -1265,9 +1271,7 @@ pub fn validate_cert_key_match(
12651271

12661272
// For rustls, the actual validation happens when creating CertifiedKey
12671273
// We can attempt to create a signing key to verify the key is valid
1268-
use rustls::crypto::aws_lc_rs::sign::any_supported_type;
1269-
1270-
match any_supported_type(private_key) {
1274+
match sign::any_supported_type(private_key) {
12711275
Ok(_signing_key) => {
12721276
// If we can create a signing key, the private key is valid
12731277
// Rustls will validate the cert-key match when building config

crates/stdlib/src/ssl/compat.rs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,17 @@ pub const VERIFY_X509_PARTIAL_CHAIN: i32 = 0x80000;
5959
/// happens exactly once, even if called from multiple threads.
6060
static INIT_PROVIDER: Once = Once::new();
6161

62-
fn ensure_default_provider() {
62+
pub(super) fn ensure_default_provider() {
6363
INIT_PROVIDER.call_once(|| {
64+
#[cfg(feature = "ssl-rustls-aws-lc-rs")]
6465
let _ = rustls::crypto::CryptoProvider::install_default(
6566
rustls::crypto::aws_lc_rs::default_provider(),
6667
);
68+
69+
#[cfg(feature = "ssl-rustls-ring")]
70+
let _ = rustls::crypto::CryptoProvider::install_default(
71+
rustls::crypto::ring::default_provider(),
72+
);
6773
});
6874
}
6975

@@ -663,12 +669,12 @@ fn create_custom_crypto_provider(
663669
cipher_suites: Option<Vec<rustls::SupportedCipherSuite>>,
664670
kx_groups: Option<Vec<&'static dyn rustls::crypto::SupportedKxGroup>>,
665671
) -> Arc<rustls::crypto::CryptoProvider> {
666-
use rustls::crypto::aws_lc_rs::{ALL_CIPHER_SUITES, ALL_KX_GROUPS};
667-
let default_provider = rustls::crypto::aws_lc_rs::default_provider();
672+
let default_provider = rustls::crypto::CryptoProvider::get_default()
673+
.expect("A CryptoProvider should have been set earlier");
668674

669675
Arc::new(rustls::crypto::CryptoProvider {
670-
cipher_suites: cipher_suites.unwrap_or_else(|| ALL_CIPHER_SUITES.to_vec()),
671-
kx_groups: kx_groups.unwrap_or_else(|| ALL_KX_GROUPS.to_vec()),
676+
cipher_suites: cipher_suites.unwrap_or_else(|| default_provider.cipher_suites.clone()),
677+
kx_groups: kx_groups.unwrap_or_else(|| default_provider.kx_groups.clone()),
672678
signature_verification_algorithms: default_provider.signature_verification_algorithms,
673679
secure_random: default_provider.secure_random,
674680
key_provider: default_provider.key_provider,
@@ -2365,7 +2371,8 @@ pub(super) fn curve_name_to_kx_group(
23652371
curve: &str,
23662372
) -> Result<Vec<&'static dyn SupportedKxGroup>, String> {
23672373
// Get the default crypto provider's key exchange groups
2368-
let provider = rustls::crypto::aws_lc_rs::default_provider();
2374+
let provider = rustls::crypto::CryptoProvider::get_default()
2375+
.expect("A CryptoProvider should have been set earlier");
23692376
let all_groups = &provider.kx_groups;
23702377

23712378
match curve {

src/lib.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,11 @@ pub use shell::run_shell;
7171

7272
#[cfg(all(
7373
feature = "ssl",
74-
not(any(feature = "ssl-rustls", feature = "ssl-openssl"))
74+
not(any(
75+
feature = "ssl-rustls",
76+
feature = "ssl-rustls-ring",
77+
feature = "ssl-openssl"
78+
))
7579
))]
7680
compile_error!(
7781
"Feature \"ssl\" is now enabled by either \"ssl-rustls\" or \"ssl-openssl\" to be enabled. Do not manually pass \"ssl\" feature. To enable ssl-openssl, use --no-default-features to disable ssl-rustls"

0 commit comments

Comments
 (0)