Skip to main content

rustls_ring/
lib.rs

1//! A `CryptoProvider` implementation backed by *ring*.
2
3#![no_std]
4#![warn(clippy::exhaustive_enums, clippy::exhaustive_structs, missing_docs)]
5#![cfg_attr(bench, feature(test))]
6
7extern crate alloc;
8#[cfg(any(feature = "std", test))]
9extern crate std;
10
11// Import `test` sysroot crate for `Bencher` definitions.
12#[cfg(bench)]
13#[expect(unused_extern_crates)]
14extern crate test;
15
16use alloc::borrow::Cow;
17use alloc::boxed::Box;
18use alloc::sync::Arc;
19#[cfg(feature = "std")]
20use core::time::Duration;
21
22use pki_types::{FipsStatus, PrivateKeyDer};
23use rustls::crypto::kx::SupportedKxGroup;
24use rustls::crypto::{
25    CryptoProvider, GetRandomFailed, KeyProvider, SecureRandom, SignatureScheme, SigningKey,
26    TicketProducer, TicketerFactory, WebPkiSupportedAlgorithms,
27};
28use rustls::error::Error;
29#[cfg(feature = "std")]
30use rustls::ticketer::TicketRotator;
31use rustls::{Tls12CipherSuite, Tls13CipherSuite};
32
33/// Using software keys for authentication.
34pub mod sign;
35use sign::{EcdsaSigner, Ed25519Signer, RsaSigningKey};
36
37pub(crate) mod hash;
38pub(crate) mod hmac;
39pub(crate) mod kx;
40pub(crate) mod quic;
41#[cfg(feature = "std")]
42pub(crate) mod ticketer;
43#[cfg(feature = "std")]
44use ticketer::AeadTicketer;
45pub(crate) mod tls12;
46pub(crate) mod tls13;
47mod verify;
48pub use verify::{
49    ALL_VERIFICATION_ALGS, ECDSA_P256_SHA256, ECDSA_P256_SHA384, ECDSA_P384_SHA256,
50    ECDSA_P384_SHA384, ED25519, RSA_PKCS1_2048_8192_SHA256,
51    RSA_PKCS1_2048_8192_SHA256_ABSENT_PARAMS, RSA_PKCS1_2048_8192_SHA384,
52    RSA_PKCS1_2048_8192_SHA384_ABSENT_PARAMS, RSA_PKCS1_2048_8192_SHA512,
53    RSA_PKCS1_2048_8192_SHA512_ABSENT_PARAMS, RSA_PKCS1_3072_8192_SHA384,
54    RSA_PSS_2048_8192_SHA256_LEGACY_KEY, RSA_PSS_2048_8192_SHA384_LEGACY_KEY,
55    RSA_PSS_2048_8192_SHA512_LEGACY_KEY,
56};
57
58/// The default `CryptoProvider` backed by [*ring*].
59///
60/// [*ring*]: https://github.com/briansmith/ring
61pub const DEFAULT_PROVIDER: CryptoProvider = CryptoProvider {
62    tls12_cipher_suites: Cow::Borrowed(DEFAULT_TLS12_CIPHER_SUITES),
63    tls13_cipher_suites: Cow::Borrowed(DEFAULT_TLS13_CIPHER_SUITES),
64    kx_groups: Cow::Borrowed(DEFAULT_KX_GROUPS),
65    signature_verification_algorithms: SUPPORTED_SIG_ALGS,
66    secure_random: &Ring,
67    key_provider: &Ring,
68    ticketer_factory: &Ring,
69};
70
71/// The default `CryptoProvider` backed by *ring* that only supports TLS1.3.
72pub const DEFAULT_TLS13_PROVIDER: CryptoProvider = CryptoProvider {
73    tls12_cipher_suites: Cow::Borrowed(&[]),
74    ..DEFAULT_PROVIDER
75};
76
77/// The default `CryptoProvider` backed by *ring* that only supports TLS1.2.
78///
79/// Use of TLS1.3 is **strongly** recommended.
80pub const DEFAULT_TLS12_PROVIDER: CryptoProvider = CryptoProvider {
81    tls13_cipher_suites: Cow::Borrowed(&[]),
82    ..DEFAULT_PROVIDER
83};
84
85/// Default crypto provider.
86#[derive(Debug)]
87struct Ring;
88
89impl SecureRandom for Ring {
90    fn fill(&self, buf: &mut [u8]) -> Result<(), GetRandomFailed> {
91        use ring::rand::SecureRandom;
92        ring::rand::SystemRandom::new()
93            .fill(buf)
94            .map_err(|_| GetRandomFailed)
95    }
96}
97
98impl KeyProvider for Ring {
99    fn load_private_key(
100        &self,
101        key_der: PrivateKeyDer<'static>,
102    ) -> Result<Box<dyn SigningKey>, Error> {
103        if let Ok(rsa) = RsaSigningKey::try_from(&key_der) {
104            return Ok(Box::new(rsa));
105        }
106
107        if let Ok(ecdsa) = EcdsaSigner::try_from(&key_der) {
108            return Ok(Box::new(ecdsa));
109        }
110
111        if let PrivateKeyDer::Pkcs8(pkcs8) = key_der {
112            if let Ok(eddsa) = Ed25519Signer::try_from(&pkcs8) {
113                return Ok(Box::new(eddsa));
114            }
115        }
116
117        Err(Error::General(
118            "failed to parse private key as RSA, ECDSA, or EdDSA".into(),
119        ))
120    }
121}
122
123impl TicketerFactory for Ring {
124    /// Make the recommended `Ticketer`.
125    ///
126    /// This produces tickets:
127    ///
128    /// - where each lasts for at least 6 hours,
129    /// - with randomly generated keys, and
130    /// - where keys are rotated every 6 hours.
131    ///
132    /// The encryption mechanism used is Chacha20Poly1305.
133    fn ticketer(&self) -> Result<Arc<dyn TicketProducer>, Error> {
134        #[cfg(feature = "std")]
135        {
136            Ok(Arc::new(TicketRotator::new(SIX_HOURS, AeadTicketer::new)?))
137        }
138        #[cfg(not(feature = "std"))]
139        {
140            Err(Error::General(
141                "Ring::ticketer() relies on std-only RwLock via TicketRotator".into(),
142            ))
143        }
144    }
145
146    fn fips(&self) -> FipsStatus {
147        fips()
148    }
149}
150
151/// The TLS1.2 cipher suite configuration that an application should use by default.
152///
153/// This will be [`ALL_TLS12_CIPHER_SUITES`] sans any supported cipher suites that
154/// shouldn't be enabled by most applications.
155pub static DEFAULT_TLS12_CIPHER_SUITES: &[&Tls12CipherSuite] = ALL_TLS12_CIPHER_SUITES;
156
157/// A list of all the TLS1.2 cipher suites supported by the rustls *ring* provider.
158pub static ALL_TLS12_CIPHER_SUITES: &[&Tls12CipherSuite] = &[
159    tls12::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
160    tls12::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
161    tls12::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
162    tls12::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
163    tls12::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
164    tls12::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
165];
166
167/// The TLS1.3 cipher suite configuration that an application should use by default.
168///
169/// This will be [`ALL_TLS13_CIPHER_SUITES`] sans any supported cipher suites that
170/// shouldn't be enabled by most applications.
171pub static DEFAULT_TLS13_CIPHER_SUITES: &[&Tls13CipherSuite] = ALL_TLS13_CIPHER_SUITES;
172
173/// A list of all the TLS1.3 cipher suites supported by the rustls *ring* provider.
174pub static ALL_TLS13_CIPHER_SUITES: &[&Tls13CipherSuite] = &[
175    tls13::TLS13_AES_128_GCM_SHA256,
176    tls13::TLS13_AES_256_GCM_SHA384,
177    tls13::TLS13_CHACHA20_POLY1305_SHA256,
178];
179
180/// All defined cipher suites supported by *ring* appear in this module.
181pub mod cipher_suite {
182    pub use super::tls12::{
183        TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
184        TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
185        TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
186    };
187    pub use super::tls13::{
188        TLS13_AES_128_GCM_SHA256, TLS13_AES_256_GCM_SHA384, TLS13_CHACHA20_POLY1305_SHA256,
189    };
190}
191
192/// A `WebPkiSupportedAlgorithms` value that reflects webpki's capabilities when
193/// compiled against *ring*.
194static SUPPORTED_SIG_ALGS: WebPkiSupportedAlgorithms = WebPkiSupportedAlgorithms {
195    all: &[
196        ECDSA_P256_SHA256,
197        ECDSA_P256_SHA384,
198        ECDSA_P384_SHA256,
199        ECDSA_P384_SHA384,
200        ED25519,
201        RSA_PSS_2048_8192_SHA256_LEGACY_KEY,
202        RSA_PSS_2048_8192_SHA384_LEGACY_KEY,
203        RSA_PSS_2048_8192_SHA512_LEGACY_KEY,
204        RSA_PKCS1_2048_8192_SHA256,
205        RSA_PKCS1_2048_8192_SHA384,
206        RSA_PKCS1_2048_8192_SHA512,
207        RSA_PKCS1_2048_8192_SHA256_ABSENT_PARAMS,
208        RSA_PKCS1_2048_8192_SHA384_ABSENT_PARAMS,
209        RSA_PKCS1_2048_8192_SHA512_ABSENT_PARAMS,
210    ],
211    mapping: &[
212        // Note: for TLS1.2 the curve is not fixed by SignatureScheme. For TLS1.3 it is.
213        (
214            SignatureScheme::ECDSA_NISTP384_SHA384,
215            &[ECDSA_P384_SHA384, ECDSA_P256_SHA384],
216        ),
217        (
218            SignatureScheme::ECDSA_NISTP256_SHA256,
219            &[ECDSA_P256_SHA256, ECDSA_P384_SHA256],
220        ),
221        (SignatureScheme::ED25519, &[ED25519]),
222        (
223            SignatureScheme::RSA_PSS_SHA512,
224            &[RSA_PSS_2048_8192_SHA512_LEGACY_KEY],
225        ),
226        (
227            SignatureScheme::RSA_PSS_SHA384,
228            &[RSA_PSS_2048_8192_SHA384_LEGACY_KEY],
229        ),
230        (
231            SignatureScheme::RSA_PSS_SHA256,
232            &[RSA_PSS_2048_8192_SHA256_LEGACY_KEY],
233        ),
234        (
235            SignatureScheme::RSA_PKCS1_SHA512,
236            &[RSA_PKCS1_2048_8192_SHA512],
237        ),
238        (
239            SignatureScheme::RSA_PKCS1_SHA384,
240            &[RSA_PKCS1_2048_8192_SHA384],
241        ),
242        (
243            SignatureScheme::RSA_PKCS1_SHA256,
244            &[RSA_PKCS1_2048_8192_SHA256],
245        ),
246    ],
247};
248
249/// All defined key exchange groups supported by *ring* appear in this module.
250///
251/// [`ALL_KX_GROUPS`] is provided as an array of all of these values.
252/// [`DEFAULT_KX_GROUPS`] is provided as an array of this provider's defaults.
253pub mod kx_group {
254    pub use super::kx::{SECP256R1, SECP384R1, X25519};
255}
256
257/// A list of the default key exchange groups supported by this provider.
258pub static DEFAULT_KX_GROUPS: &[&dyn SupportedKxGroup] = ALL_KX_GROUPS;
259
260/// A list of all the key exchange groups supported by this provider.
261pub static ALL_KX_GROUPS: &[&dyn SupportedKxGroup] =
262    &[kx_group::X25519, kx_group::SECP256R1, kx_group::SECP384R1];
263
264/// Compatibility shims between ring 0.16.x and 0.17.x API
265mod ring_shim {
266    use ring::agreement::{self, EphemeralPrivateKey, UnparsedPublicKey};
267    use rustls::crypto::kx::SharedSecret;
268
269    pub(super) fn agree_ephemeral(
270        priv_key: EphemeralPrivateKey,
271        peer_key: &UnparsedPublicKey<&[u8]>,
272    ) -> Result<SharedSecret, ()> {
273        agreement::agree_ephemeral(priv_key, peer_key, |secret| SharedSecret::from(secret))
274            .map_err(|_| ())
275    }
276}
277
278/// Return the FIPS validation status of this implementation.
279pub fn fips() -> FipsStatus {
280    FipsStatus::Unvalidated
281}
282
283#[cfg(feature = "std")]
284const SIX_HOURS: Duration = Duration::from_secs(6 * 60 * 60);