1#![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#[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
33pub 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
58pub 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
71pub const DEFAULT_TLS13_PROVIDER: CryptoProvider = CryptoProvider {
73 tls12_cipher_suites: Cow::Borrowed(&[]),
74 ..DEFAULT_PROVIDER
75};
76
77pub const DEFAULT_TLS12_PROVIDER: CryptoProvider = CryptoProvider {
81 tls13_cipher_suites: Cow::Borrowed(&[]),
82 ..DEFAULT_PROVIDER
83};
84
85#[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 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
151pub static DEFAULT_TLS12_CIPHER_SUITES: &[&Tls12CipherSuite] = ALL_TLS12_CIPHER_SUITES;
156
157pub 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
167pub static DEFAULT_TLS13_CIPHER_SUITES: &[&Tls13CipherSuite] = ALL_TLS13_CIPHER_SUITES;
172
173pub 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
180pub 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
192static 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 (
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
249pub mod kx_group {
254 pub use super::kx::{SECP256R1, SECP384R1, X25519};
255}
256
257pub static DEFAULT_KX_GROUPS: &[&dyn SupportedKxGroup] = ALL_KX_GROUPS;
259
260pub static ALL_KX_GROUPS: &[&dyn SupportedKxGroup] =
262 &[kx_group::X25519, kx_group::SECP256R1, kx_group::SECP384R1];
263
264mod 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
278pub fn fips() -> FipsStatus {
280 FipsStatus::Unvalidated
281}
282
283#[cfg(feature = "std")]
284const SIX_HOURS: Duration = Duration::from_secs(6 * 60 * 60);