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** ([`SupportedDtls12CipherSuite`]): 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//! - **HMAC Provider** ([`HmacProvider`]): Compute HMAC signatures (also drives PRF and HKDF)
23//!
24//! # Using a Custom Provider
25//!
26//! To use a custom crypto provider, create one and pass it to the [`Config`](crate::Config):
27//!
28//! ```
29//! # #[cfg(all(feature = "aws-lc-rs", feature = "rcgen"))]
30//! # fn main() {
31//! use std::sync::Arc;
32//! use std::time::Instant;
33//! use dimpl::{Config, Dtls, certificate};
34//! use dimpl::crypto::aws_lc_rs;
35//!
36//! let cert = certificate::generate_self_signed_certificate().unwrap();
37//! // Use the default aws-lc-rs provider (implicit)
38//! let config = Arc::new(Config::default());
39//!
40//! // Or explicitly set the provider
41//! let config = Arc::new(
42//! Config::builder()
43//! .with_crypto_provider(aws_lc_rs::default_provider())
44//! .build()
45//! .unwrap()
46//! );
47//!
48//! // Or use your own custom provider
49//! // let config = Arc::new(
50//! // Config::builder()
51//! // .with_crypto_provider(my_custom_provider())
52//! // .build()
53//! // .unwrap()
54//! // );
55//!
56//! let dtls = Dtls::new_12(config, cert, Instant::now());
57//! # }
58//! # #[cfg(not(all(feature = "aws-lc-rs", feature = "rcgen")))]
59//! # fn main() {}
60//! ```
61//!
62//! # Implementing a Custom Provider
63//!
64//! To implement a custom provider, you need to:
65//!
66//! 1. Implement the required traits for your crypto backend
67//! 2. Create static instances of your implementations
68//! 3. Build a [`CryptoProvider`] struct with references to those statics
69//!
70//! ## Example: Custom Cipher Suite
71//!
72//! ```
73//! use dimpl::CryptoError;
74//! use dimpl::crypto::{SupportedDtls12CipherSuite, Cipher, Dtls12CipherSuite, HashAlgorithm};
75//! use dimpl::crypto::{Buf, TmpBuf};
76//! use dimpl::crypto::{Aad, Nonce};
77//!
78//! #[derive(Debug)]
79//! struct MyCipher;
80//!
81//! impl MyCipher {
82//! fn new(_key: &[u8]) -> Result<Self, CryptoError> {
83//! Ok(Self)
84//! }
85//! }
86//!
87//! impl Cipher for MyCipher {
88//! fn encrypt(&mut self, _: &mut Buf, _: Aad, _: Nonce) -> Result<(), CryptoError> {
89//! Ok(())
90//! }
91//! fn decrypt(&mut self, _: &mut TmpBuf, _: Aad, _: Nonce) -> Result<(), CryptoError> {
92//! Ok(())
93//! }
94//! }
95//!
96//! #[derive(Debug)]
97//! struct MyDtls12CipherSuite;
98//!
99//! impl SupportedDtls12CipherSuite for MyDtls12CipherSuite {
100//! fn suite(&self) -> Dtls12CipherSuite {
101//! Dtls12CipherSuite::ECDHE_ECDSA_AES128_GCM_SHA256
102//! }
103//!
104//! fn hash_algorithm(&self) -> HashAlgorithm {
105//! HashAlgorithm::SHA256
106//! }
107//!
108//! fn key_lengths(&self) -> (usize, usize, usize) {
109//! (0, 16, 4) // (mac_key_len, enc_key_len, fixed_iv_len)
110//! }
111//!
112//! fn explicit_nonce_len(&self) -> usize {
113//! 8 // AES-GCM: 8-byte explicit nonce per record
114//! }
115//!
116//! fn tag_len(&self) -> usize {
117//! 16 // 128-bit authentication tag
118//! }
119//!
120//! fn create_cipher(&self, key: &[u8]) -> Result<Box<dyn Cipher>, CryptoError> {
121//! // Create your cipher implementation here
122//! Ok(Box::new(MyCipher::new(key)?))
123//! }
124//! }
125//!
126//! static MY_CIPHER_SUITE: MyDtls12CipherSuite = MyDtls12CipherSuite;
127//! static ALL_CIPHER_SUITES: &[&dyn SupportedDtls12CipherSuite] = &[&MY_CIPHER_SUITE];
128//! ```
129//!
130//! # Requirements
131//!
132//! For DTLS 1.2, implementations must support:
133//!
134//! - **Cipher suites**: ECDHE_ECDSA with AES-128-GCM, AES-256-GCM, or CHACHA20_POLY1305
135//! - **Key exchange**: ECDHE with X25519, P-256, or P-384 curves
136//! - **Signatures**: ECDSA with P-256/SHA-256 or P-384/SHA-384
137//! - **Hash**: SHA-256 and SHA-384
138//! - **HMAC**: HMAC-SHA256 and HMAC-SHA384 (used for PRF, HKDF, and cookies)
139//!
140//! # Thread Safety
141//!
142//! All provider traits require `Send + Sync + UnwindSafe + RefUnwindSafe` to ensure
143//! safe usage across threads and panic boundaries.
144
145use std::fmt::Debug;
146use std::panic::{RefUnwindSafe, UnwindSafe};
147use std::sync::OnceLock;
148
149use crate::buffer::{Buf, TmpBuf};
150use crate::crypto::{Aad, Nonce};
151use crate::dtls12::message::Dtls12CipherSuite;
152use crate::types::{Dtls13CipherSuite, HashAlgorithm, NamedGroup, SignatureAlgorithm};
153use crate::{CertificateError, CryptoError};
154
155/// OID for the P-256 elliptic curve (secp256r1 / prime256v1).
156#[cfg(feature = "_crypto-common")]
157pub const OID_P256: spki::ObjectIdentifier =
158 spki::ObjectIdentifier::new_unwrap("1.2.840.10045.3.1.7");
159
160/// OID for the P-384 elliptic curve (secp384r1).
161#[cfg(feature = "_crypto-common")]
162pub const OID_P384: spki::ObjectIdentifier = spki::ObjectIdentifier::new_unwrap("1.3.132.0.34");
163
164// ============================================================================
165// Marker Trait
166// ============================================================================
167
168/// Marker trait for types that are safe to use in crypto provider components.
169///
170/// This trait combines the common bounds required for crypto provider trait objects:
171/// - [`Send`] + [`Sync`]: Thread-safe
172/// - [`Debug`]: Support debugging
173/// - [`UnwindSafe`] + [`RefUnwindSafe`]: Panic-safe
174///
175/// This trait is automatically implemented for all types that satisfy these bounds.
176pub trait CryptoSafe: Send + Sync + Debug + UnwindSafe + RefUnwindSafe {}
177
178/// Blanket implementation: any type satisfying the bounds implements [`CryptoSafe`].
179impl<T: Send + Sync + Debug + UnwindSafe + RefUnwindSafe> CryptoSafe for T {}
180
181// ============================================================================
182// Instance Traits (Level 2 - created by factories)
183// ============================================================================
184
185/// AEAD cipher for in-place encryption/decryption.
186pub trait Cipher: CryptoSafe {
187 /// Encrypt plaintext in-place, appending authentication tag.
188 fn encrypt(&mut self, plaintext: &mut Buf, aad: Aad, nonce: Nonce) -> Result<(), CryptoError>;
189
190 /// Decrypt ciphertext in-place, verifying and removing authentication tag.
191 fn decrypt(
192 &mut self,
193 ciphertext: &mut TmpBuf,
194 aad: Aad,
195 nonce: Nonce,
196 ) -> Result<(), CryptoError>;
197}
198
199/// Stateful hash context for incremental hashing.
200pub trait HashContext: CryptoSafe {
201 /// Update the hash with new data.
202 fn update(&mut self, data: &[u8]);
203
204 /// Clone the context and finalize it, writing the hash to `out`.
205 /// The original context can continue to be updated.
206 fn clone_and_finalize(&self, out: &mut Buf);
207}
208
209/// Signing key for generating digital signatures.
210pub trait SigningKey: CryptoSafe {
211 /// Sign data using the specified hash algorithm and return the signature.
212 fn sign(
213 &mut self,
214 data: &[u8],
215 hash_alg: HashAlgorithm,
216 out: &mut Buf,
217 ) -> Result<(), CryptoError>;
218
219 /// Signature algorithm used by this key.
220 fn algorithm(&self) -> SignatureAlgorithm;
221
222 /// Default hash algorithm for this key.
223 fn hash_algorithm(&self) -> HashAlgorithm;
224
225 /// Hash algorithms this key can sign with.
226 ///
227 /// Used during negotiation to intersect with the peer's offered
228 /// algorithms. Backends that lock the hash at key-load time (e.g.
229 /// aws-lc-rs) return only the locked hash; backends that support
230 /// arbitrary prehash signing (e.g. RustCrypto) may return several.
231 fn supported_hash_algorithms(&self) -> &[HashAlgorithm];
232}
233
234/// Active key exchange instance (ephemeral keypair for one handshake).
235pub trait ActiveKeyExchange: CryptoSafe {
236 /// Get the public key for this exchange.
237 fn pub_key(&self) -> &[u8];
238
239 /// Complete exchange with peer's public key, returning shared secret.
240 fn complete(self: Box<Self>, peer_pub: &[u8], out: &mut Buf) -> Result<(), CryptoError>;
241
242 /// Get the named group for this exchange.
243 fn group(&self) -> NamedGroup;
244}
245
246// ============================================================================
247// Factory Traits (Level 1 - used by CryptoProvider)
248// ============================================================================
249
250/// Cipher suite support (factory for Cipher instances).
251pub trait SupportedDtls12CipherSuite: CryptoSafe {
252 /// The cipher suite this supports.
253 fn suite(&self) -> Dtls12CipherSuite;
254
255 /// Hash algorithm used by this suite.
256 fn hash_algorithm(&self) -> HashAlgorithm;
257
258 /// Key material lengths: (mac_key_len, enc_key_len, fixed_iv_len).
259 fn key_lengths(&self) -> (usize, usize, usize);
260
261 /// Length in bytes of the per-record explicit nonce (carried in the record body).
262 ///
263 /// AES-GCM suites carry an 8-byte explicit nonce; ChaCha20-Poly1305 carries none.
264 fn explicit_nonce_len(&self) -> usize;
265
266 /// AEAD authentication tag length in bytes.
267 fn tag_len(&self) -> usize;
268
269 /// Minimum length, in bytes, of a protected record's encrypted fragment.
270 ///
271 /// For AEAD suites this equals explicit nonce + authentication tag; a CBC
272 /// suite would override this to `IV + MAC + 1` (one padding byte). Records
273 /// shorter than this cannot be valid regardless of cipher mode and are
274 /// rejected at the record boundary.
275 fn min_protected_fragment_len(&self) -> usize {
276 self.explicit_nonce_len() + self.tag_len()
277 }
278
279 /// Create a cipher instance with the given key.
280 fn create_cipher(&self, key: &[u8]) -> Result<Box<dyn Cipher>, CryptoError>;
281}
282
283/// Key exchange group support (factory for ActiveKeyExchange).
284pub trait SupportedKxGroup: CryptoSafe {
285 /// Named group for this key exchange group.
286 fn name(&self) -> NamedGroup;
287
288 /// Start a new key exchange, generating ephemeral keypair.
289 /// The provided `buf` will be used to store the public key.
290 fn start_exchange(&self, buf: Buf) -> Result<Box<dyn ActiveKeyExchange>, CryptoError>;
291}
292
293/// Signature verification against certificates.
294pub trait SignatureVerifier: CryptoSafe {
295 /// Verify a signature on data using a DER-encoded X.509 certificate.
296 fn verify_signature(
297 &self,
298 cert_der: &[u8],
299 data: &[u8],
300 signature: &[u8],
301 hash_alg: HashAlgorithm,
302 sig_alg: SignatureAlgorithm,
303 ) -> Result<(), CryptoError>;
304}
305
306/// Allow-list of supported (signature, hash, curve) combinations for
307/// DTLS 1.2 signature verification.
308///
309/// In DTLS 1.2 the hash algorithm and the certificate's curve are
310/// independent choices, so all cross-combinations are valid.
311///
312/// Signature | Hash | Curve
313/// -----------+---------+-----------
314/// ECDSA | SHA-256 | P-256
315/// ECDSA | SHA-256 | P-384
316/// ECDSA | SHA-384 | P-256
317/// ECDSA | SHA-384 | P-384
318const SUPPORTED_VERIFY_SCHEMES: &[(SignatureAlgorithm, HashAlgorithm, NamedGroup)] = &[
319 (
320 SignatureAlgorithm::ECDSA,
321 HashAlgorithm::SHA256,
322 NamedGroup::Secp256r1,
323 ),
324 (
325 SignatureAlgorithm::ECDSA,
326 HashAlgorithm::SHA256,
327 NamedGroup::Secp384r1,
328 ),
329 (
330 SignatureAlgorithm::ECDSA,
331 HashAlgorithm::SHA384,
332 NamedGroup::Secp256r1,
333 ),
334 (
335 SignatureAlgorithm::ECDSA,
336 HashAlgorithm::SHA384,
337 NamedGroup::Secp384r1,
338 ),
339];
340
341/// Check that a (signature, hash, curve) combination is in the allow-list.
342pub fn check_verify_scheme(
343 sig_alg: SignatureAlgorithm,
344 hash_alg: HashAlgorithm,
345 group: NamedGroup,
346) -> Result<(), CryptoError> {
347 if SUPPORTED_VERIFY_SCHEMES
348 .iter()
349 .any(|(s, h, g)| *s == sig_alg && *h == hash_alg && *g == group)
350 {
351 Ok(())
352 } else {
353 Err(CryptoError::UnsupportedSignatureVerification {
354 signature: sig_alg,
355 hash: hash_alg,
356 group,
357 })
358 }
359}
360
361/// Extract the EC curve ([`NamedGroup`]) from a DER-encoded X.509 certificate.
362///
363/// Used by DTLS 1.3 to verify that the [`SignatureScheme`](crate::types::SignatureScheme)
364/// in `CertificateVerify` is consistent with the peer's certificate key.
365#[cfg(feature = "_crypto-common")]
366pub fn cert_named_group(cert_der: &[u8]) -> Result<NamedGroup, CertificateError> {
367 use der::Decode;
368 use spki::ObjectIdentifier;
369 use x509_cert::Certificate as X509Certificate;
370
371 let cert = X509Certificate::from_der(cert_der).map_err(|_| CertificateError::ParseFailed)?;
372 let spki = &cert.tbs_certificate.subject_public_key_info;
373
374 let curve_oid: ObjectIdentifier = spki
375 .algorithm
376 .parameters
377 .as_ref()
378 .ok_or(CertificateError::MissingEcCurveParameter)?
379 .decode_as()
380 .map_err(|_| CertificateError::InvalidEcCurveParameter)?;
381
382 match curve_oid {
383 OID_P256 => Ok(NamedGroup::Secp256r1),
384 OID_P384 => Ok(NamedGroup::Secp384r1),
385 _ => Err(CertificateError::UnsupportedEcCurve),
386 }
387}
388
389/// Private key parser (factory for SigningKey).
390pub trait KeyProvider: CryptoSafe {
391 /// Parse and load a private key from DER/PEM bytes.
392 fn load_private_key(&self, key_der: &[u8]) -> Result<Box<dyn SigningKey>, CryptoError>;
393}
394
395/// Secure random number generator.
396pub trait SecureRandom: CryptoSafe {
397 /// Fill buffer with cryptographically secure random bytes.
398 fn fill(&self, buf: &mut [u8]) -> Result<(), CryptoError>;
399}
400
401/// Hash provider (factory for HashContext).
402pub trait HashProvider: CryptoSafe {
403 /// Create a new hash context for the specified algorithm.
404 fn create_hash(&self, algorithm: HashAlgorithm) -> Box<dyn HashContext>;
405}
406
407/// HMAC provider for computing HMAC signatures.
408pub trait HmacProvider: CryptoSafe {
409 /// Compute HMAC-SHA256(key, data) and return the result.
410 fn hmac_sha256(&self, key: &[u8], data: &[u8]) -> Result<[u8; 32], CryptoError> {
411 let mut out = [0u8; 32];
412 self.hmac(HashAlgorithm::SHA256, key, data, &mut out)?;
413 Ok(out)
414 }
415
416 /// Compute HMAC for the given hash algorithm, writing the result to `out`.
417 ///
418 /// Returns the number of bytes written.
419 fn hmac(
420 &self,
421 hash: HashAlgorithm,
422 key: &[u8],
423 data: &[u8],
424 out: &mut [u8],
425 ) -> Result<usize, CryptoError>;
426}
427
428// ============================================================================
429// DTLS 1.3 Factory Traits
430// ============================================================================
431
432/// Cipher suite support for DTLS 1.3 (factory for Cipher instances).
433///
434/// Unlike DTLS 1.2 cipher suites, TLS 1.3 cipher suites only specify the
435/// AEAD algorithm and hash function. Key exchange is negotiated separately.
436pub trait SupportedDtls13CipherSuite: CryptoSafe {
437 /// The cipher suite this supports.
438 fn suite(&self) -> Dtls13CipherSuite;
439
440 /// Hash algorithm used by this suite.
441 fn hash_algorithm(&self) -> HashAlgorithm;
442
443 /// AEAD key length in bytes.
444 fn key_len(&self) -> usize;
445
446 /// AEAD nonce/IV length in bytes.
447 fn iv_len(&self) -> usize;
448
449 /// AEAD tag length in bytes.
450 fn tag_len(&self) -> usize;
451
452 /// Minimum length, in bytes, of a protected record's encrypted fragment.
453 /// DTLS 1.3 has no explicit nonce in the record, so this equals
454 /// [`Self::tag_len`]. Records shorter than this cannot hold a valid
455 /// ciphertext + tag and are rejected at the record boundary.
456 fn min_protected_fragment_len(&self) -> usize {
457 self.tag_len()
458 }
459
460 /// Create a cipher instance with the given key.
461 fn create_cipher(&self, key: &[u8]) -> Result<Box<dyn Cipher>, CryptoError>;
462
463 /// Compute a mask for record number encryption (RFC 9147 Section 4.2.3).
464 ///
465 /// The mask is XORed over the sequence number bytes in the header.
466 /// `sample` is the first 16 bytes of the ciphertext.
467 ///
468 /// For AES-based suites: `mask = AES-ECB(sn_key, sample)`.
469 ///
470 /// For ChaCha20-based suites (RFC 9001 Section 5.4.4):
471 /// `counter = sample[0..4]` (LE u32), `nonce = sample[4..16]`,
472 /// `mask = ChaCha20(sn_key, counter, nonce, <zero bytes>)`.
473 fn encrypt_sn(&self, sn_key: &[u8], sample: &[u8; 16]) -> [u8; 16];
474}
475
476// ============================================================================
477// Core Provider Struct
478// ============================================================================
479
480/// Cryptographic provider for DTLS operations.
481///
482/// This struct holds references to all cryptographic components needed
483/// for DTLS. Users can provide custom implementations of each component
484/// to replace the default aws-lc-rs-based provider.
485///
486/// # Version-Specific Components
487///
488/// Shared components like `kx_groups`, `signature_verification`, `key_provider`,
489/// `secure_random`, `hash_provider`, and `hmac_provider` are used by both versions.
490/// PRF (TLS 1.2) and HKDF (TLS 1.3) key derivation are built generically on top
491/// of `hmac_provider` — see the [`prf_hkdf`](super::prf_hkdf) module.
492///
493/// # Design
494///
495/// The provider uses static trait object references (`&'static dyn Trait`) which
496/// provides zero runtime overhead for trait dispatch. This design is inspired by
497/// rustls's CryptoProvider and ensures efficient crypto operations.
498///
499/// # Example
500///
501/// ```
502/// # #[cfg(feature = "aws-lc-rs")]
503/// # fn main() {
504/// use dimpl::crypto::{CryptoProvider, aws_lc_rs};
505///
506/// // Use the default provider
507/// let provider = aws_lc_rs::default_provider();
508///
509/// // Or build a custom one (using defaults for demonstration)
510/// let custom_provider = CryptoProvider {
511/// // Shared components
512/// kx_groups: provider.kx_groups,
513/// signature_verification: provider.signature_verification,
514/// key_provider: provider.key_provider,
515/// secure_random: provider.secure_random,
516/// hash_provider: provider.hash_provider,
517/// hmac_provider: provider.hmac_provider,
518/// // DTLS 1.2 components
519/// cipher_suites: provider.cipher_suites,
520/// // DTLS 1.3 components
521/// dtls13_cipher_suites: provider.dtls13_cipher_suites,
522/// };
523/// # }
524/// # #[cfg(not(feature = "aws-lc-rs"))]
525/// # fn main() {}
526/// ```
527#[derive(Debug, Clone)]
528pub struct CryptoProvider {
529 // =========================================================================
530 // Shared components (used by both DTLS 1.2 and DTLS 1.3)
531 // =========================================================================
532 /// Supported key exchange groups (P-256, P-384, X25519).
533 ///
534 /// Used for ECDHE key exchange in both DTLS versions.
535 pub kx_groups: &'static [&'static dyn SupportedKxGroup],
536
537 /// Signature verification for certificates.
538 pub signature_verification: &'static dyn SignatureVerifier,
539
540 /// Key provider for parsing private keys.
541 pub key_provider: &'static dyn KeyProvider,
542
543 /// Secure random number generator.
544 pub secure_random: &'static dyn SecureRandom,
545
546 /// Hash provider for handshake hashing.
547 pub hash_provider: &'static dyn HashProvider,
548
549 /// HMAC provider for computing HMAC signatures.
550 pub hmac_provider: &'static dyn HmacProvider,
551
552 // =========================================================================
553 // DTLS 1.2 specific components
554 // =========================================================================
555 /// Supported DTLS 1.2 cipher suites (for negotiation).
556 ///
557 /// These cipher suites bundle key exchange, authentication, encryption,
558 /// and MAC algorithms together (e.g., TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256).
559 pub cipher_suites: &'static [&'static dyn SupportedDtls12CipherSuite],
560
561 // =========================================================================
562 // DTLS 1.3 specific components
563 // =========================================================================
564 /// Supported DTLS 1.3 cipher suites (for negotiation).
565 ///
566 /// TLS 1.3 cipher suites only specify the AEAD and hash algorithms
567 /// (e.g., TLS_AES_128_GCM_SHA256). Key exchange is negotiated separately.
568 pub dtls13_cipher_suites: &'static [&'static dyn SupportedDtls13CipherSuite],
569}
570
571/// Static storage for the default crypto provider.
572///
573/// This is set by `install_default()` and retrieved by `get_default()`.
574static DEFAULT: OnceLock<CryptoProvider> = OnceLock::new();
575
576impl CryptoProvider {
577 /// Install a default crypto provider for the process.
578 ///
579 /// This sets a global default provider that will be used by
580 /// [`Config::builder()`](crate::Config::builder)
581 /// when no explicit provider is specified. This is useful for applications that want
582 /// to override the default provider per process.
583 ///
584 /// # Panics
585 ///
586 /// Panics if called more than once. The default provider can only be set once per process.
587 ///
588 /// # Example
589 ///
590 /// ```
591 /// # #[cfg(feature = "aws-lc-rs")]
592 /// # fn main() {
593 /// use dimpl::crypto::{CryptoProvider, aws_lc_rs};
594 ///
595 /// // Install a default provider (can only be called once per process)
596 /// CryptoProvider::install_default(aws_lc_rs::default_provider());
597 /// # }
598 /// # #[cfg(not(feature = "aws-lc-rs"))]
599 /// # fn main() {}
600 /// ```
601 pub fn install_default(provider: CryptoProvider) {
602 DEFAULT
603 .set(provider)
604 .expect("CryptoProvider::install_default() called more than once");
605 }
606
607 /// Get the default crypto provider, if one has been installed.
608 ///
609 /// Returns `Some(&provider)` if a default provider has been installed via
610 /// [`Self::install_default()`], or `None` if no default provider is available.
611 ///
612 /// This method does not panic. Use [`Config::builder()`](crate::Config::builder) which will handle
613 /// the fallback logic automatically.
614 ///
615 /// # Example
616 ///
617 /// ```
618 /// use dimpl::crypto::CryptoProvider;
619 ///
620 /// if let Some(provider) = CryptoProvider::get_default() {
621 /// // Use the installed default provider
622 /// }
623 /// ```
624 pub fn get_default() -> Option<&'static CryptoProvider> {
625 DEFAULT.get()
626 }
627}
628
629#[cfg(test)]
630mod tests {
631 use super::*;
632
633 #[test]
634 #[cfg(feature = "rcgen")]
635 fn cert_named_group_p256() {
636 use rcgen::{CertificateParams, KeyPair, PKCS_ECDSA_P256_SHA256};
637
638 let key_pair = KeyPair::generate_for(&PKCS_ECDSA_P256_SHA256).unwrap();
639 let params = CertificateParams::new(Vec::<String>::new()).unwrap();
640 let cert = params.self_signed(&key_pair).unwrap();
641
642 let group = cert_named_group(cert.der()).unwrap();
643 assert_eq!(group, NamedGroup::Secp256r1);
644 }
645
646 #[test]
647 #[cfg(feature = "rcgen")]
648 fn cert_named_group_p384() {
649 use rcgen::{CertificateParams, KeyPair, PKCS_ECDSA_P384_SHA384};
650
651 let key_pair = KeyPair::generate_for(&PKCS_ECDSA_P384_SHA384).unwrap();
652 let params = CertificateParams::new(Vec::<String>::new()).unwrap();
653 let cert = params.self_signed(&key_pair).unwrap();
654
655 let group = cert_named_group(cert.der()).unwrap();
656 assert_eq!(group, NamedGroup::Secp384r1);
657 }
658
659 #[test]
660 #[cfg(feature = "rcgen")]
661 fn cert_named_group_invalid_der() {
662 let result = cert_named_group(&[0x00, 0x01, 0x02]);
663 assert!(result.is_err());
664 }
665}