ant_quic/crypto/pqc/
rustls_provider.rs1use std::sync::Arc;
7
8use rustls::{
9 CipherSuite, Error as TlsError, NamedGroup, SignatureScheme,
10 crypto::{CryptoProvider, SupportedKxGroup},
11};
12
13use crate::crypto::pqc::types::PqcError;
14
15#[derive(Debug, Clone)]
17pub struct PqcConfig {
18 pub enable_ml_kem: bool,
20 pub enable_ml_dsa: bool,
22 pub prefer_pqc: bool,
24 pub allow_downgrade: bool,
26}
27
28impl Default for PqcConfig {
29 fn default() -> Self {
30 Self {
31 enable_ml_kem: true,
32 enable_ml_dsa: true,
33 prefer_pqc: true,
34 allow_downgrade: true,
35 }
36 }
37}
38
39pub struct PqcCryptoProvider {
41 base_provider: Arc<CryptoProvider>,
43 config: PqcConfig,
45 cipher_suites: Vec<rustls::CipherSuite>,
47}
48
49impl PqcCryptoProvider {
50 pub fn new() -> Result<Self, PqcError> {
52 Self::with_config(Some(PqcConfig::default()))
53 }
54
55 pub fn with_config(config: Option<PqcConfig>) -> Result<Self, PqcError> {
57 let config =
58 config.ok_or_else(|| PqcError::CryptoError("PQC config is required".to_string()))?;
59
60 validate_config(&config)?;
62
63 let base_provider = crate::crypto::rustls::configured_provider();
65
66 let cipher_suites = create_hybrid_cipher_suites(&base_provider)?;
68
69 Ok(Self {
70 base_provider,
71 config,
72 cipher_suites,
73 })
74 }
75
76 pub fn cipher_suites(&self) -> Vec<rustls::CipherSuite> {
78 vec![
80 rustls::CipherSuite::TLS13_AES_128_GCM_SHA256,
81 rustls::CipherSuite::TLS13_AES_256_GCM_SHA384,
82 rustls::CipherSuite::TLS13_CHACHA20_POLY1305_SHA256,
83 ]
84 }
85
86 pub fn validate_cipher_suites(suites: &[rustls::CipherSuite]) -> Result<(), PqcError> {
88 if suites.is_empty() {
89 return Err(PqcError::CryptoError(
90 "No cipher suites provided".to_string(),
91 ));
92 }
93 Ok(())
94 }
95}
96
97pub fn validate_config(config: &PqcConfig) -> Result<(), PqcError> {
99 if !config.enable_ml_kem && !config.enable_ml_dsa {
100 return Err(PqcError::CryptoError(
101 "At least one PQC algorithm must be enabled".to_string(),
102 ));
103 }
104
105 if config.prefer_pqc && !config.allow_downgrade && !config.enable_ml_kem {
106 return Err(PqcError::CryptoError(
107 "Cannot prefer PQC without ML-KEM enabled or downgrade allowed".to_string(),
108 ));
109 }
110
111 Ok(())
112}
113
114fn create_hybrid_cipher_suites(
116 _base_provider: &Arc<CryptoProvider>,
117) -> Result<Vec<rustls::CipherSuite>, PqcError> {
118 Ok(vec![
130 rustls::CipherSuite::TLS13_AES_128_GCM_SHA256,
131 rustls::CipherSuite::TLS13_AES_256_GCM_SHA384,
132 rustls::CipherSuite::TLS13_CHACHA20_POLY1305_SHA256,
133 ])
134}
135
136pub trait PqcConfigExt {
138 fn has_pqc_support(&self) -> bool;
140
141 fn crypto_config(&self) -> CryptoInfo;
143}
144
145pub struct CryptoInfo {
147 has_pqc: bool,
148 hybrid_kex: bool,
149 hybrid_sig: bool,
150}
151
152impl CryptoInfo {
153 pub fn has_pqc_support(&self) -> bool {
155 self.has_pqc
156 }
157
158 pub fn used_hybrid_kex(&self) -> bool {
160 self.hybrid_kex
161 }
162
163 pub fn used_classical_kex(&self) -> bool {
165 !self.hybrid_kex
166 }
167}
168
169pub fn with_pqc_support(config: crate::ClientConfig) -> Result<crate::ClientConfig, PqcError> {
171 Ok(config)
174}
175
176pub fn with_pqc_support_server(
178 config: crate::ServerConfig,
179) -> Result<crate::ServerConfig, PqcError> {
180 Ok(config)
183}
184
185impl PqcConfigExt for crate::ClientConfig {
187 fn has_pqc_support(&self) -> bool {
188 true }
193
194 fn crypto_config(&self) -> CryptoInfo {
195 CryptoInfo {
196 has_pqc: true, hybrid_kex: false,
198 hybrid_sig: false,
199 }
200 }
201}
202
203impl PqcConfigExt for crate::ServerConfig {
205 fn has_pqc_support(&self) -> bool {
206 true }
211
212 fn crypto_config(&self) -> CryptoInfo {
213 CryptoInfo {
214 has_pqc: true, hybrid_kex: false,
216 hybrid_sig: false,
217 }
218 }
219}
220
221#[cfg(test)]
222mod tests {
223 use super::*;
224
225 #[test]
226 fn test_pqc_config_default() {
227 let config = PqcConfig::default();
228 assert!(config.enable_ml_kem);
229 assert!(config.enable_ml_dsa);
230 assert!(config.prefer_pqc);
231 assert!(config.allow_downgrade);
232 }
233
234 #[test]
235 fn test_config_validation() {
236 let valid = PqcConfig::default();
238 assert!(validate_config(&valid).is_ok());
239
240 let invalid = PqcConfig {
242 enable_ml_kem: false,
243 enable_ml_dsa: false,
244 prefer_pqc: false,
245 allow_downgrade: false,
246 };
247 assert!(validate_config(&invalid).is_err());
248 }
249
250 #[test]
251 fn test_provider_creation() {
252 let provider = PqcCryptoProvider::new();
253 assert!(provider.is_ok());
254
255 let provider = provider.unwrap();
256 assert_eq!(provider.cipher_suites().len(), 3);
258 assert!(
259 provider
260 .cipher_suites()
261 .contains(&rustls::CipherSuite::TLS13_AES_128_GCM_SHA256)
262 );
263 }
264}