rustls_cng_crypto/lib.rs
1//! # rustls-cng-crypto
2//!
3//! A [rustls crypto provider](https://docs.rs/rustls/latest/rustls/crypto/struct.CryptoProvider.html) for Windows that uses CNG for crypto.
4//!
5//! ## Supported Ciphers
6//!
7//! Supported cipher suites are listed below, in descending order of preference.
8//!
9//! If the `tls12` feature is disabled then the TLS 1.2 cipher suites will not be available.
10//!
11//! ### TLS 1.3
12//!
13//! * `TLS13_AES_256_GCM_SHA384`
14//! * `TLS13_AES_128_GCM_SHA256`
15//! * `TLS13_CHACHA20_POLY1305_SHA256`
16//!
17//! ### TLS 1.2
18//!
19//! * `TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384`
20//! * `TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256`
21//! * `TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256`
22//! * `TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256`
23//! * `TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384`
24//! * `TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256`
25//!
26//! ## Supported Key Exchanges
27//!
28//! In descending order of preference:
29//!
30//! * X25519
31//! * SECP256R1
32//! * SECP384R1
33//!
34//! ## Usage
35//!
36//! Add `rustls-cng-crypto` to your `Cargo.toml`:
37//!
38//! ```toml
39//! [dependencies]
40//! rustls = { version = "0.23.0", features = ["tls12", "std"], default-features = false }
41//! rustls_cng_crypto = "0.1.0"
42//! ```
43//!
44//! ### Configuration
45//!
46//! Use [`default_provider()`] to create a provider using cipher suites and key exchange groups listed above.
47//! Use [`custom_provider()`] to specify custom cipher suites and key exchange groups.
48//!
49//! # Features
50//! - `tls12`: Enables TLS 1.2 cipher suites. Enabled by default.
51//! - `fips`: Changes the default provider to use FIPS-approved cipher suites and key exchange groups. See [fips].
52#![warn(missing_docs)]
53use rustls::crypto::{CryptoProvider, GetRandomFailed, SupportedKxGroup};
54use rustls::SupportedCipherSuite;
55
56use windows::Win32::Security::Cryptography::{
57 BCryptGenRandom, BCRYPT_ALG_HANDLE, BCRYPT_USE_SYSTEM_PREFERRED_RNG,
58};
59
60mod aead;
61mod alg;
62mod fips;
63mod hash;
64mod hkdf;
65mod hmac;
66mod keys;
67mod kx;
68#[cfg(feature = "tls12")]
69mod prf;
70mod quic;
71mod signer;
72#[cfg(feature = "tls12")]
73mod tls12;
74mod tls13;
75mod verify;
76
77pub mod cipher_suite {
78 //! Supported cipher suites.
79 #[cfg(feature = "tls12")]
80 pub use super::tls12::{
81 TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
82 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
83 };
84 #[cfg(feature = "tls12")]
85 pub use super::tls12::{
86 TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
87 };
88 pub use super::tls13::{TLS13_AES_128_GCM_SHA256, TLS13_AES_256_GCM_SHA384};
89}
90
91pub use alg::ShutdownHandle;
92#[cfg(feature = "fips")]
93pub use fips::provider as default_provider;
94pub use fips::provider as fips_provider;
95pub use kx::ALL_KX_GROUPS;
96pub mod kx_group {
97 //! Supported key exchange groups.
98 pub use super::kx::{SECP256R1, SECP384R1, X25519};
99}
100pub use signer::KeyProvider;
101pub use verify::SUPPORTED_SIG_ALGS;
102
103/// Returns a CNG-based [`CryptoProvider`] using all available cipher suites ([`ALL_CIPHER_SUITES`]) and key exchange groups ([`ALL_KX_GROUPS`]).
104///
105/// Sample usage:
106/// ```rust
107/// use rustls::{ClientConfig, RootCertStore};
108/// use rustls_cng_crypto::default_provider;
109/// use std::sync::Arc;
110/// use webpki_roots;
111///
112/// let mut root_store = RootCertStore {
113/// roots: webpki_roots::TLS_SERVER_ROOTS.iter().cloned().collect(),
114/// };
115///
116/// let mut config =
117/// ClientConfig::builder_with_provider(Arc::new(default_provider()))
118/// .with_safe_default_protocol_versions()
119/// .unwrap()
120/// .with_root_certificates(root_store)
121/// .with_no_client_auth();
122///
123/// ```
124///
125/// When the `fips` feature is enabled, this function will return the provider created by [`fips_provider()`].
126#[cfg(not(feature = "fips"))]
127pub fn default_provider() -> CryptoProvider {
128 CryptoProvider {
129 cipher_suites: ALL_CIPHER_SUITES.to_vec(),
130 kx_groups: ALL_KX_GROUPS.to_vec(),
131 signature_verification_algorithms: SUPPORTED_SIG_ALGS,
132 secure_random: &SecureRandom,
133 key_provider: &KeyProvider,
134 }
135}
136
137/// Create a [`CryptoProvider`] with specific cipher suites and key exchange groups
138///
139/// The specified cipher suites and key exchange groups should be defined in descending order of preference.
140/// i.e the first elements have the highest priority during negotiation.
141///
142/// Sample usage:
143/// ```rust
144/// use rustls::{ClientConfig, RootCertStore};
145/// use rustls_cng_crypto::custom_provider;
146/// use rustls_cng_crypto::cipher_suite::TLS13_AES_128_GCM_SHA256;
147/// use rustls_cng_crypto::kx_group::SECP256R1;
148/// use std::sync::Arc;
149/// use webpki_roots;
150///
151/// let mut root_store = RootCertStore {
152/// roots: webpki_roots::TLS_SERVER_ROOTS.iter().cloned().collect(),
153/// };
154///
155/// // Set custom config of cipher suites that have been imported from rustls_cng_crypto.
156/// let cipher_suites = vec![TLS13_AES_128_GCM_SHA256];
157/// let kx_group = vec![SECP256R1];
158///
159/// let mut config =
160/// ClientConfig::builder_with_provider(Arc::new(custom_provider(
161/// cipher_suites, kx_group)))
162/// .with_safe_default_protocol_versions()
163/// .unwrap()
164/// .with_root_certificates(root_store)
165/// .with_no_client_auth();
166///
167///
168/// ```
169#[must_use]
170pub fn custom_provider(
171 cipher_suites: Vec<SupportedCipherSuite>,
172 kx_groups: Vec<&'static dyn SupportedKxGroup>,
173) -> CryptoProvider {
174 CryptoProvider {
175 cipher_suites,
176 kx_groups,
177 signature_verification_algorithms: SUPPORTED_SIG_ALGS,
178 secure_random: &SecureRandom,
179 key_provider: &KeyProvider,
180 }
181}
182
183/// All supported cipher suites in descending order of preference:
184/// * `TLS13_AES_256_GCM_SHA384`
185/// * `TLS13_AES_128_GCM_SHA256`
186/// * `TLS13_CHACHA20_POLY1305_SHA256`
187/// * `TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384`
188/// * `TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256`
189/// * `TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256`
190/// * `TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256`
191/// * `TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384`
192/// * `TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256`
193///
194/// If the default `tls12` feature is disabled then the TLS 1.2 cipher suites will not be included.
195pub static ALL_CIPHER_SUITES: &[SupportedCipherSuite] = &[
196 tls13::TLS13_AES_256_GCM_SHA384,
197 tls13::TLS13_AES_128_GCM_SHA256,
198 tls13::TLS13_CHACHA20_POLY1305_SHA256,
199 #[cfg(feature = "tls12")]
200 tls12::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
201 #[cfg(feature = "tls12")]
202 tls12::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
203 #[cfg(feature = "tls12")]
204 tls12::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
205 #[cfg(feature = "tls12")]
206 tls12::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
207 #[cfg(feature = "tls12")]
208 tls12::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
209 #[cfg(feature = "tls12")]
210 tls12::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
211];
212
213/// A struct that implements [`rustls::crypto::SecureRandom`] using CNG.
214#[derive(Debug)]
215pub struct SecureRandom;
216
217impl rustls::crypto::SecureRandom for SecureRandom {
218 fn fill(&self, buf: &mut [u8]) -> Result<(), GetRandomFailed> {
219 unsafe {
220 BCryptGenRandom(
221 BCRYPT_ALG_HANDLE::default(),
222 buf,
223 BCRYPT_USE_SYSTEM_PREFERRED_RNG,
224 )
225 .ok()
226 .map_err(|_| GetRandomFailed)
227 }
228 }
229
230 fn fips(&self) -> bool {
231 fips::enabled()
232 }
233}