|
1 | | -use std::sync::Arc; |
| 1 | +use std::io::{Read, Write}; |
| 2 | +use std::sync::{Arc, OnceLock}; |
2 | 3 |
|
3 | | -use rustls::ClientConfig as RusTlsClientConfig; |
4 | | -use rustls::ServerConfig as RusTlsServerConfig; |
5 | | - |
6 | | -use rustls_rustcrypto::provider as rustcrypto_provider; |
7 | | - |
8 | | -mod fake_time; |
| 4 | +use fake_cert_server_resolver::FakeServerCertResolver; |
9 | 5 | use fake_time::FakeTime; |
10 | | - |
11 | | -mod fake_cert_server_verifier; |
12 | | -use fake_cert_server_verifier::FakeServerCertVerifier; |
13 | | - |
14 | | -mod fake_cert_client_verifier; |
15 | | -use fake_cert_client_verifier::FakeClientCertVerifier; |
| 6 | +use itertools::iproduct; |
| 7 | +use mem_socket::MemorySocket; |
| 8 | +use rand_core::{OsRng, RngCore}; |
| 9 | +use rustls::crypto::CryptoProvider; |
| 10 | +use rustls::{ |
| 11 | + ClientConfig as RusTlsClientConfig, RootCertStore, ServerConfig as RusTlsServerConfig, |
| 12 | +}; |
| 13 | +use rustls_rustcrypto::{provider as rustcrypto_provider, verify, Provider}; |
16 | 14 |
|
17 | 15 | mod fake_cert_server_resolver; |
18 | | -use fake_cert_server_resolver::FakeServerCertResolver; |
| 16 | +mod fake_time; |
19 | 17 |
|
20 | | -// Test integration between rustls and rustls in Client builder context |
21 | | -#[test] |
22 | | -fn integrate_client_builder_with_details_fake() { |
23 | | - let provider = rustcrypto_provider(); |
24 | | - let time_provider = FakeTime {}; |
| 18 | +static SERVER_RESOLVER: OnceLock<Arc<FakeServerCertResolver>> = OnceLock::new(); |
25 | 19 |
|
26 | | - let fake_server_cert_verifier = FakeServerCertVerifier {}; |
| 20 | +fn make_client_config(provider: CryptoProvider) -> RusTlsClientConfig { |
| 21 | + let resolver = SERVER_RESOLVER.get_or_init(|| Arc::new(FakeServerCertResolver::new())); |
| 22 | + let mut store = RootCertStore::empty(); |
27 | 23 |
|
28 | | - let builder_init = |
29 | | - RusTlsClientConfig::builder_with_details(Arc::new(provider), Arc::new(time_provider)); |
| 24 | + store.add(resolver.rsa_root_cert()).unwrap(); |
| 25 | + store.add(resolver.ecdsa_root_cert()).unwrap(); |
30 | 26 |
|
31 | | - let builder_default_versions = builder_init |
| 27 | + RusTlsClientConfig::builder_with_details(Arc::new(provider), Arc::new(FakeTime {})) |
32 | 28 | .with_safe_default_protocol_versions() |
33 | | - .expect("Default protocol versions error?"); |
| 29 | + .expect("Default protocol versions error?") |
| 30 | + .with_root_certificates(store) |
| 31 | + // .dangerous() |
| 32 | + // .with_custom_certificate_verifier(Arc::new(FakeServerCertVerifier {})) |
| 33 | + .with_no_client_auth() |
| 34 | +} |
34 | 35 |
|
35 | | - let dangerous_verifier = builder_default_versions |
36 | | - .dangerous() |
37 | | - .with_custom_certificate_verifier(Arc::new(fake_server_cert_verifier)); |
| 36 | +fn make_server_config(provider: CryptoProvider) -> RusTlsServerConfig { |
| 37 | + let resolver = SERVER_RESOLVER |
| 38 | + .get_or_init(|| Arc::new(FakeServerCertResolver::new())) |
| 39 | + .clone(); |
| 40 | + RusTlsServerConfig::builder_with_details(Arc::new(provider), Arc::new(FakeTime {})) |
| 41 | + .with_safe_default_protocol_versions() |
| 42 | + .expect("Default protocol versions error?") |
| 43 | + .with_no_client_auth() |
| 44 | + .with_cert_resolver(resolver) |
| 45 | +} |
38 | 46 |
|
| 47 | +// Test integration between rustls and rustls in Client builder context |
| 48 | +#[test] |
| 49 | +fn integrate_client_builder_with_details_fake() { |
39 | 50 | // Out of scope |
40 | | - let rustls_client_config = dangerous_verifier.with_no_client_auth(); |
| 51 | + let rustls_client_config = make_client_config(rustcrypto_provider()); |
41 | 52 |
|
42 | 53 | // RustCrypto is not fips |
43 | 54 | assert!(!rustls_client_config.fips()); |
44 | 55 | } |
45 | 56 |
|
46 | | -use rustls::DistinguishedName; |
47 | | - |
48 | 57 | // Test integration between rustls and rustls in Server builder context |
49 | 58 | #[test] |
50 | 59 | fn integrate_server_builder_with_details_fake() { |
51 | | - let provider = rustcrypto_provider(); |
52 | | - let time_provider = FakeTime {}; |
53 | | - |
54 | | - let builder_init = |
55 | | - RusTlsServerConfig::builder_with_details(Arc::new(provider), Arc::new(time_provider)); |
56 | | - |
57 | | - let builder_default_versions = builder_init |
58 | | - .with_safe_default_protocol_versions() |
59 | | - .expect("Default protocol versions error?"); |
60 | | - |
61 | | - // A DistinguishedName is a Vec<u8> wrapped in internal types. |
62 | | - // DER or BER encoded Subject field from RFC 5280 for a single certificate. |
63 | | - // The Subject field is encoded as an RFC 5280 Name |
64 | | - //let b_wrap_in: &[u8] = b""; // TODO: should have constant somewhere |
65 | | - |
66 | | - let dummy_entry: &[u8] = b""; |
67 | | - |
68 | | - let client_dn = [DistinguishedName::in_sequence(dummy_entry)]; |
69 | | - |
70 | | - let client_cert_verifier = FakeClientCertVerifier { dn: client_dn }; |
| 60 | + let rustls_server_config = make_server_config(rustcrypto_provider()); |
71 | 61 |
|
72 | | - let dangerous_verifier = |
73 | | - builder_default_versions.with_client_cert_verifier(Arc::new(client_cert_verifier)); |
| 62 | + // RustCrypto is not fips |
| 63 | + assert!(!rustls_server_config.fips()); |
| 64 | +} |
74 | 65 |
|
75 | | - let server_cert_resolver = FakeServerCertResolver {}; |
| 66 | +const CLIENT_MAGIC: &[u8; 18] = b"Hello from Client!"; |
| 67 | +const SERVER_MAGIC: &[u8; 18] = b"Hello from Server!"; |
76 | 68 |
|
77 | | - // Out of scope |
78 | | - let rustls_client_config = |
79 | | - dangerous_verifier.with_cert_resolver(Arc::new(server_cert_resolver)); |
| 69 | +// Test integration |
| 70 | +#[test] |
| 71 | +fn test_basic_round_trip() { |
| 72 | + std::thread::scope(move |s| { |
| 73 | + for provider in generate_providers() { |
| 74 | + // Creates a pair of sockets that interconnect from client to server, and server to client |
| 75 | + let (socket_c2s, socket_s2c) = MemorySocket::new_pair(); |
| 76 | + |
| 77 | + let mut random_data: [u8; 8192] = [0; 8192]; |
| 78 | + OsRng.fill_bytes(&mut random_data); |
| 79 | + |
| 80 | + std::thread::Builder::new() |
| 81 | + .name(format!( |
| 82 | + "{:?}-{:?}-server", |
| 83 | + provider.cipher_suites[0], provider.kx_groups[0] |
| 84 | + )) |
| 85 | + .spawn_scoped(s, { |
| 86 | + let provider: CryptoProvider = provider.clone(); |
| 87 | + move || { |
| 88 | + let config = Arc::new(make_server_config(provider)); |
| 89 | + let mut stream = socket_s2c; |
| 90 | + let mut conn = rustls::ServerConnection::new(config.clone()) |
| 91 | + .expect("failed to create server config"); |
| 92 | + |
| 93 | + let mut tls = rustls::Stream::new(&mut conn, &mut stream); |
| 94 | + |
| 95 | + { |
| 96 | + let mut buf = [0; CLIENT_MAGIC.len()]; |
| 97 | + tls.read_exact(&mut buf).unwrap(); |
| 98 | + assert_eq!(&buf, CLIENT_MAGIC); |
| 99 | + } |
| 100 | + |
| 101 | + tls.write_all(SERVER_MAGIC) |
| 102 | + .expect("failed to write to client"); |
| 103 | + tls.write_all(&random_data) |
| 104 | + .expect("failed to write random data to client"); |
| 105 | + tls.conn.send_close_notify(); |
| 106 | + tls.flush().expect("failed to flush connection"); |
| 107 | + } |
| 108 | + }) |
| 109 | + .unwrap(); |
| 110 | + |
| 111 | + std::thread::Builder::new() |
| 112 | + .name(format!( |
| 113 | + "{:?}-{:?}-client", |
| 114 | + provider.cipher_suites[0], provider.kx_groups[0] |
| 115 | + )) |
| 116 | + .spawn_scoped(s, move || { |
| 117 | + let mut sock = socket_c2s; |
| 118 | + let server_name = "acme.com".try_into().expect("failed to get server name"); |
| 119 | + let mut conn = rustls::ClientConnection::new( |
| 120 | + Arc::new(make_client_config(provider)), |
| 121 | + server_name, |
| 122 | + ) |
| 123 | + .expect("failed to create client config"); |
| 124 | + let mut tls = rustls::Stream::new(&mut conn, &mut sock); |
| 125 | + tls.write_all(CLIENT_MAGIC) |
| 126 | + .expect("failed to write to server"); |
| 127 | + |
| 128 | + { |
| 129 | + let mut buf = [0; SERVER_MAGIC.len()]; |
| 130 | + tls.read_exact(&mut buf) |
| 131 | + .expect("failed to read from server"); |
| 132 | + assert_eq!(&buf, SERVER_MAGIC); |
| 133 | + } |
| 134 | + |
| 135 | + { |
| 136 | + let mut plaintext = Vec::new(); |
| 137 | + tls.write_all(&random_data) |
| 138 | + .expect("failed to write random data to server"); |
| 139 | + tls.read_to_end(&mut plaintext) |
| 140 | + .expect("failed to read from server"); |
| 141 | + assert_eq!(plaintext, random_data); |
| 142 | + } |
| 143 | + }) |
| 144 | + .unwrap(); |
| 145 | + } |
| 146 | + }); |
| 147 | +} |
80 | 148 |
|
81 | | - // RustCrypto is not fips |
82 | | - assert!(!rustls_client_config.fips()); |
| 149 | +fn generate_providers() -> impl Iterator<Item = CryptoProvider> { |
| 150 | + let CryptoProvider { |
| 151 | + cipher_suites, |
| 152 | + kx_groups, |
| 153 | + .. |
| 154 | + } = rustcrypto_provider(); |
| 155 | + |
| 156 | + iproduct!(cipher_suites, kx_groups).map(|(cipher_suite, kx_group)| CryptoProvider { |
| 157 | + cipher_suites: vec![cipher_suite], |
| 158 | + kx_groups: vec![kx_group], |
| 159 | + signature_verification_algorithms: verify::ALGORITHMS, |
| 160 | + secure_random: &Provider, |
| 161 | + key_provider: &Provider, |
| 162 | + }) |
83 | 163 | } |
| 164 | + |
| 165 | +mod mem_socket; |
0 commit comments