dimpl/crypto/provider.rs
1//! Cryptographic provider traits for pluggable crypto backends.
2//!
3//! This module defines the trait-based interface for cryptographic operations
4//! in dimpl, allowing users to provide custom crypto implementations.
5//!
6//! # Overview
7//!
8//! The crypto provider system is inspired by rustls's design and uses a component-based
9//! approach where the [`CryptoProvider`] struct holds static references to various
10//! trait objects, each representing a specific cryptographic capability.
11//!
12//! # Architecture
13//!
14//! The provider system is organized into these main components:
15//!
16//! - **Cipher Suites** ([`SupportedCipherSuite`]): Factory for AEAD ciphers
17//! - **Key Exchange Groups** ([`SupportedKxGroup`]): Factory for ECDHE key exchanges
18//! - **Signature Verification** ([`SignatureVerifier`]): Verify signatures in certificates
19//! - **Key Provider** ([`KeyProvider`]): Parse and load private keys
20//! - **Secure Random** ([`SecureRandom`]): Cryptographically secure RNG
21//! - **Hash Provider** ([`HashProvider`]): Factory for hash contexts
22//! - **PRF Provider** ([`PrfProvider`]): TLS 1.2 PRF for key derivation
23//! - **HMAC Provider** ([`HmacProvider`]): Compute HMAC signatures
24//!
25//! # Using a Custom Provider
26//!
27//! To use a custom crypto provider, create one and pass it to the [`Config`](crate::Config):
28//!
29//! ```rust,ignore
30//! use std::sync::Arc;
31//! use dimpl::{Config, Dtls};
32//! use dimpl::crypto::aws_lc_rs;
33//!
34//! // Use the default aws-lc-rs provider (implicit)
35//! let config = Arc::new(Config::default());
36//!
37//! // Or explicitly set the provider
38//! let config = Arc::new(
39//! Config::builder()
40//! .with_crypto_provider(aws_lc_rs::default_provider())
41//! .build()
42//! .unwrap()
43//! );
44//!
45//! // Or use your own custom provider
46//! // let config = Arc::new(
47//! // Config::builder()
48//! // .with_crypto_provider(my_custom_provider())
49//! // .build()
50//! // .unwrap()
51//! // );
52//!
53//! let dtls = Dtls::new(config, cert);
54//! ```
55//!
56//! # Implementing a Custom Provider
57//!
58//! To implement a custom provider, you need to:
59//!
60//! 1. Implement the required traits for your crypto backend
61//! 2. Create static instances of your implementations
62//! 3. Build a [`CryptoProvider`] struct with references to those statics
63//!
64//! ## Example: Custom Cipher Suite
65//!
66//! ```rust,ignore
67//! use dimpl::crypto::{SupportedCipherSuite, Cipher, CipherSuite, HashAlgorithm};
68//!
69//! #[derive(Debug)]
70//! struct MyCipherSuite;
71//!
72//! impl SupportedCipherSuite for MyCipherSuite {
73//! fn suite(&self) -> CipherSuite {
74//! CipherSuite::ECDHE_ECDSA_AES128_GCM_SHA256
75//! }
76//!
77//! fn hash_algorithm(&self) -> HashAlgorithm {
78//! HashAlgorithm::SHA256
79//! }
80//!
81//! fn key_lengths(&self) -> (usize, usize, usize) {
82//! (0, 16, 4) // (mac_key_len, enc_key_len, fixed_iv_len)
83//! }
84//!
85//! fn create_cipher(&self, key: &[u8]) -> Result<Box<dyn Cipher>, String> {
86//! // Create your cipher implementation here
87//! Ok(Box::new(MyCipher::new(key)?))
88//! }
89//! }
90//!
91//! static MY_CIPHER_SUITE: MyCipherSuite = MyCipherSuite;
92//! static ALL_CIPHER_SUITES: &[&dyn SupportedCipherSuite] = &[&MY_CIPHER_SUITE];
93//! ```
94//!
95//! # Requirements
96//!
97//! For DTLS 1.2, implementations must support:
98//!
99//! - **Cipher suites**: ECDHE_ECDSA with AES-128-GCM or AES-256-GCM
100//! - **Key exchange**: ECDHE with P-256 or P-384 curves
101//! - **Signatures**: ECDSA with P-256/SHA-256 or P-384/SHA-384
102//! - **Hash**: SHA-256 and SHA-384
103//! - **PRF**: TLS 1.2 PRF (using HMAC-SHA256 or HMAC-SHA384)
104//!
105//! # Thread Safety
106//!
107//! All provider traits require `Send + Sync + UnwindSafe + RefUnwindSafe` to ensure
108//! safe usage across threads and panic boundaries.
109
110use std::fmt::Debug;
111use std::panic::{RefUnwindSafe, UnwindSafe};
112use std::sync::OnceLock;
113
114use crate::buffer::{Buf, TmpBuf};
115use crate::crypto::{Aad, Nonce};
116use crate::message::{CipherSuite, HashAlgorithm, NamedGroup, SignatureAlgorithm};
117
118// ============================================================================
119// Marker Trait
120// ============================================================================
121
122/// Marker trait for types that are safe to use in crypto provider components.
123///
124/// This trait combines the common bounds required for crypto provider trait objects:
125/// - [`Send`] + [`Sync`]: Thread-safe
126/// - [`Debug`]: Support debugging
127/// - [`UnwindSafe`] + [`RefUnwindSafe`]: Panic-safe
128///
129/// This trait is automatically implemented for all types that satisfy these bounds.
130pub trait CryptoSafe: Send + Sync + Debug + UnwindSafe + RefUnwindSafe {}
131
132/// Blanket implementation: any type satisfying the bounds implements [`CryptoSafe`].
133impl<T: Send + Sync + Debug + UnwindSafe + RefUnwindSafe> CryptoSafe for T {}
134
135// ============================================================================
136// Instance Traits (Level 2 - created by factories)
137// ============================================================================
138
139/// AEAD cipher for in-place encryption/decryption.
140pub trait Cipher: CryptoSafe {
141 /// Encrypt plaintext in-place, appending authentication tag.
142 fn encrypt(&mut self, plaintext: &mut Buf, aad: Aad, nonce: Nonce) -> Result<(), String>;
143
144 /// Decrypt ciphertext in-place, verifying and removing authentication tag.
145 fn decrypt(&mut self, ciphertext: &mut TmpBuf, aad: Aad, nonce: Nonce) -> Result<(), String>;
146}
147
148/// Stateful hash context for incremental hashing.
149pub trait HashContext {
150 /// Update the hash with new data.
151 fn update(&mut self, data: &[u8]);
152
153 /// Clone the context and finalize it, writing the hash to `out`.
154 /// The original context can continue to be updated.
155 fn clone_and_finalize(&self, out: &mut Buf);
156}
157
158/// Signing key for generating digital signatures.
159pub trait SigningKey: CryptoSafe {
160 /// Sign data and return the signature.
161 fn sign(&mut self, data: &[u8], out: &mut Buf) -> Result<(), String>;
162
163 /// Signature algorithm used by this key.
164 fn algorithm(&self) -> SignatureAlgorithm;
165
166 /// Default hash algorithm for this key.
167 fn hash_algorithm(&self) -> HashAlgorithm;
168
169 /// Check if this key is compatible with a cipher suite.
170 fn is_compatible(&self, cipher_suite: CipherSuite) -> bool;
171}
172
173/// Active key exchange instance (ephemeral keypair for one handshake).
174pub trait ActiveKeyExchange: CryptoSafe {
175 /// Get the public key for this exchange.
176 fn pub_key(&self) -> &[u8];
177
178 /// Complete exchange with peer's public key, returning shared secret.
179 fn complete(self: Box<Self>, peer_pub: &[u8], out: &mut Buf) -> Result<(), String>;
180
181 /// Get the named group for this exchange.
182 fn group(&self) -> NamedGroup;
183}
184
185// ============================================================================
186// Factory Traits (Level 1 - used by CryptoProvider)
187// ============================================================================
188
189/// Cipher suite support (factory for Cipher instances).
190pub trait SupportedCipherSuite: CryptoSafe {
191 /// The cipher suite this supports.
192 fn suite(&self) -> CipherSuite;
193
194 /// Hash algorithm used by this suite.
195 fn hash_algorithm(&self) -> HashAlgorithm;
196
197 /// Key material lengths: (mac_key_len, enc_key_len, fixed_iv_len).
198 fn key_lengths(&self) -> (usize, usize, usize);
199
200 /// Create a cipher instance with the given key.
201 fn create_cipher(&self, key: &[u8]) -> Result<Box<dyn Cipher>, String>;
202}
203
204/// Key exchange group support (factory for ActiveKeyExchange).
205pub trait SupportedKxGroup: CryptoSafe {
206 /// Named group for this key exchange group.
207 fn name(&self) -> NamedGroup;
208
209 /// Start a new key exchange, generating ephemeral keypair.
210 /// The provided `buf` will be used to store the public key.
211 fn start_exchange(&self, buf: Buf) -> Result<Box<dyn ActiveKeyExchange>, String>;
212}
213
214/// Signature verification against certificates.
215pub trait SignatureVerifier: CryptoSafe {
216 /// Verify a signature on data using a DER-encoded X.509 certificate.
217 fn verify_signature(
218 &self,
219 cert_der: &[u8],
220 data: &[u8],
221 signature: &[u8],
222 hash_alg: HashAlgorithm,
223 sig_alg: SignatureAlgorithm,
224 ) -> Result<(), String>;
225}
226
227/// Private key parser (factory for SigningKey).
228pub trait KeyProvider: CryptoSafe {
229 /// Parse and load a private key from DER/PEM bytes.
230 fn load_private_key(&self, key_der: &[u8]) -> Result<Box<dyn SigningKey>, String>;
231}
232
233/// Secure random number generator.
234pub trait SecureRandom: CryptoSafe {
235 /// Fill buffer with cryptographically secure random bytes.
236 fn fill(&self, buf: &mut [u8]) -> Result<(), String>;
237}
238
239/// Hash provider (factory for HashContext).
240pub trait HashProvider: CryptoSafe {
241 /// Create a new hash context for the specified algorithm.
242 fn create_hash(&self, algorithm: HashAlgorithm) -> Box<dyn HashContext>;
243}
244
245/// PRF (Pseudo-Random Function) for TLS 1.2 key derivation.
246pub trait PrfProvider: CryptoSafe {
247 /// TLS 1.2 PRF: PRF(secret, label, seed) writing output to `out`.
248 /// Uses `scratch` for temporary concatenation of label+seed.
249 #[allow(clippy::too_many_arguments)]
250 fn prf_tls12(
251 &self,
252 secret: &[u8],
253 label: &str,
254 seed: &[u8],
255 out: &mut Buf,
256 output_len: usize,
257 scratch: &mut Buf,
258 hash: HashAlgorithm,
259 ) -> Result<(), String>;
260}
261
262/// HMAC provider for computing HMAC signatures.
263pub trait HmacProvider: CryptoSafe {
264 /// Compute HMAC-SHA256(key, data) and return the result.
265 fn hmac_sha256(&self, key: &[u8], data: &[u8]) -> Result<[u8; 32], String>;
266}
267
268// ============================================================================
269// Core Provider Struct
270// ============================================================================
271
272/// Cryptographic provider for DTLS operations.
273///
274/// This struct holds references to all cryptographic components needed
275/// for DTLS 1.2. Users can provide custom implementations of each component
276/// to replace the default aws-lc-rs-based provider.
277///
278/// # Design
279///
280/// The provider uses static trait object references (`&'static dyn Trait`) which
281/// provides zero runtime overhead for trait dispatch. This design is inspired by
282/// rustls's CryptoProvider and ensures efficient crypto operations.
283///
284/// # Example
285///
286/// ```rust,ignore
287/// use dimpl::crypto::{CryptoProvider, aws_lc_rs};
288///
289/// // Use the default provider
290/// let provider = aws_lc_rs::default_provider();
291///
292/// // Or build a custom one
293/// let custom_provider = CryptoProvider {
294/// cipher_suites: my_cipher_suites::ALL,
295/// kx_groups: my_kx_groups::ALL,
296/// signature_verification: &my_verifier::VERIFIER,
297/// key_provider: &my_keys::KEY_PROVIDER,
298/// secure_random: &my_rng::RNG,
299/// hash_provider: &my_hash::HASH_PROVIDER,
300/// prf_provider: &my_prf::PRF_PROVIDER,
301/// hmac_provider: &my_hmac::HMAC_PROVIDER,
302/// };
303/// ```
304#[derive(Debug, Clone)]
305pub struct CryptoProvider {
306 /// Supported cipher suites (for negotiation).
307 pub cipher_suites: &'static [&'static dyn SupportedCipherSuite],
308
309 /// Supported key exchange groups (P-256, P-384).
310 pub kx_groups: &'static [&'static dyn SupportedKxGroup],
311
312 /// Signature verification for certificates.
313 pub signature_verification: &'static dyn SignatureVerifier,
314
315 /// Key provider for parsing private keys.
316 pub key_provider: &'static dyn KeyProvider,
317
318 /// Secure random number generator.
319 pub secure_random: &'static dyn SecureRandom,
320
321 /// Hash provider for handshake hashing.
322 pub hash_provider: &'static dyn HashProvider,
323
324 /// PRF for TLS 1.2 key derivation.
325 pub prf_provider: &'static dyn PrfProvider,
326
327 /// HMAC provider for computing HMAC signatures.
328 pub hmac_provider: &'static dyn HmacProvider,
329}
330
331/// Static storage for the default crypto provider.
332///
333/// This is set by `install_default()` and retrieved by `get_default()`.
334static DEFAULT: OnceLock<CryptoProvider> = OnceLock::new();
335
336impl CryptoProvider {
337 /// Install a default crypto provider for the process.
338 ///
339 /// This sets a global default provider that will be used by
340 /// [`Config::builder()`](crate::Config::builder)
341 /// when no explicit provider is specified. This is useful for applications that want
342 /// to override the default provider per process.
343 ///
344 /// # Panics
345 ///
346 /// Panics if called more than once. The default provider can only be set once per process.
347 ///
348 /// # Example
349 ///
350 /// ```rust,ignore
351 /// use dimpl::crypto::{CryptoProvider, aws_lc_rs};
352 ///
353 /// // Install a custom default provider
354 /// CryptoProvider::install_default(my_custom_provider());
355 ///
356 /// // Now Config::default() will use the installed provider
357 /// ```
358 pub fn install_default(provider: CryptoProvider) {
359 DEFAULT
360 .set(provider)
361 .expect("CryptoProvider::install_default() called more than once");
362 }
363
364 /// Get the default crypto provider, if one has been installed.
365 ///
366 /// Returns `Some(&provider)` if a default provider has been installed via
367 /// [`Self::install_default()`], or `None` if no default provider is available.
368 ///
369 /// This method does not panic. Use [`Config::builder()`](crate::Config::builder) which will handle
370 /// the fallback logic automatically.
371 ///
372 /// # Example
373 ///
374 /// ```rust,ignore
375 /// use dimpl::crypto::CryptoProvider;
376 ///
377 /// if let Some(provider) = CryptoProvider::get_default() {
378 /// // Use the installed default provider
379 /// }
380 /// ```
381 pub fn get_default() -> Option<&'static CryptoProvider> {
382 DEFAULT.get()
383 }
384}