ant_quic/crypto/pqc/
rustls_provider.rs1use std::sync::Arc;
14
15use rustls::{
16 CipherSuite, Error as TlsError, NamedGroup, SignatureScheme,
17 crypto::{CryptoProvider, SupportedKxGroup},
18};
19
20use crate::crypto::pqc::types::PqcError;
21
22#[derive(Debug, Clone)]
24pub struct PqcConfig {
25 pub enable_ml_kem: bool,
27 pub enable_ml_dsa: bool,
29 pub prefer_pqc: bool,
31 pub allow_downgrade: bool,
33}
34
35impl Default for PqcConfig {
36 fn default() -> Self {
37 Self {
38 enable_ml_kem: true,
39 enable_ml_dsa: true,
40 prefer_pqc: true,
41 allow_downgrade: true,
42 }
43 }
44}
45
46pub struct PqcCryptoProvider {
48 #[allow(dead_code)]
50 base_provider: Arc<CryptoProvider>,
51 #[allow(dead_code)]
53 config: PqcConfig,
54 #[allow(dead_code)]
56 cipher_suites: Vec<rustls::CipherSuite>,
57}
58
59impl PqcCryptoProvider {
60 pub fn new() -> Result<Self, PqcError> {
62 Self::with_config(Some(PqcConfig::default()))
63 }
64
65 pub fn with_config(config: Option<PqcConfig>) -> Result<Self, PqcError> {
67 let config =
68 config.ok_or_else(|| PqcError::CryptoError("PQC config is required".to_string()))?;
69
70 validate_config(&config)?;
72
73 let base_provider = crate::crypto::rustls::configured_provider();
75
76 let cipher_suites = create_hybrid_cipher_suites(&base_provider)?;
78
79 Ok(Self {
80 base_provider,
81 config,
82 cipher_suites,
83 })
84 }
85
86 pub fn cipher_suites(&self) -> Vec<rustls::CipherSuite> {
88 vec![
90 rustls::CipherSuite::TLS13_AES_128_GCM_SHA256,
91 rustls::CipherSuite::TLS13_AES_256_GCM_SHA384,
92 rustls::CipherSuite::TLS13_CHACHA20_POLY1305_SHA256,
93 ]
94 }
95
96 pub fn validate_cipher_suites(suites: &[rustls::CipherSuite]) -> Result<(), PqcError> {
98 if suites.is_empty() {
99 return Err(PqcError::CryptoError(
100 "No cipher suites provided".to_string(),
101 ));
102 }
103 Ok(())
104 }
105}
106
107pub fn validate_config(config: &PqcConfig) -> Result<(), PqcError> {
109 if !config.enable_ml_kem && !config.enable_ml_dsa {
110 return Err(PqcError::CryptoError(
111 "At least one PQC algorithm must be enabled".to_string(),
112 ));
113 }
114
115 if config.prefer_pqc && !config.allow_downgrade && !config.enable_ml_kem {
116 return Err(PqcError::CryptoError(
117 "Cannot prefer PQC without ML-KEM enabled or downgrade allowed".to_string(),
118 ));
119 }
120
121 Ok(())
122}
123
124fn create_hybrid_cipher_suites(
126 _base_provider: &Arc<CryptoProvider>,
127) -> Result<Vec<rustls::CipherSuite>, PqcError> {
128 Ok(vec![
140 rustls::CipherSuite::TLS13_AES_128_GCM_SHA256,
141 rustls::CipherSuite::TLS13_AES_256_GCM_SHA384,
142 rustls::CipherSuite::TLS13_CHACHA20_POLY1305_SHA256,
143 ])
144}
145
146pub trait PqcConfigExt {
148 fn has_pqc_support(&self) -> bool;
150
151 fn crypto_config(&self) -> CryptoInfo;
153}
154
155pub struct CryptoInfo {
157 has_pqc: bool,
158 hybrid_kex: bool,
159 #[allow(dead_code)]
160 hybrid_sig: bool,
161}
162
163impl CryptoInfo {
164 pub fn has_pqc_support(&self) -> bool {
166 self.has_pqc
167 }
168
169 pub fn used_hybrid_kex(&self) -> bool {
171 self.hybrid_kex
172 }
173
174 pub fn used_classical_kex(&self) -> bool {
176 !self.hybrid_kex
177 }
178}
179
180pub fn with_pqc_support(config: crate::ClientConfig) -> Result<crate::ClientConfig, PqcError> {
182 Ok(config)
185}
186
187pub fn with_pqc_support_server(
189 config: crate::ServerConfig,
190) -> Result<crate::ServerConfig, PqcError> {
191 Ok(config)
194}
195
196impl PqcConfigExt for crate::ClientConfig {
198 fn has_pqc_support(&self) -> bool {
199 true }
204
205 fn crypto_config(&self) -> CryptoInfo {
206 CryptoInfo {
207 has_pqc: true, hybrid_kex: false,
209 hybrid_sig: false,
210 }
211 }
212}
213
214impl PqcConfigExt for crate::ServerConfig {
216 fn has_pqc_support(&self) -> bool {
217 true }
222
223 fn crypto_config(&self) -> CryptoInfo {
224 CryptoInfo {
225 has_pqc: true, hybrid_kex: false,
227 hybrid_sig: false,
228 }
229 }
230}
231
232#[cfg(all(test, feature = "pqc"))]
233mod tests {
234 use super::*;
235
236 #[test]
237 fn test_pqc_config_default() {
238 let config = PqcConfig::default();
239 assert!(config.enable_ml_kem);
240 assert!(config.enable_ml_dsa);
241 assert!(config.prefer_pqc);
242 assert!(config.allow_downgrade);
243 }
244
245 #[test]
246 fn test_config_validation() {
247 let valid = PqcConfig::default();
249 assert!(validate_config(&valid).is_ok());
250
251 let invalid = PqcConfig {
253 enable_ml_kem: false,
254 enable_ml_dsa: false,
255 prefer_pqc: false,
256 allow_downgrade: false,
257 };
258 assert!(validate_config(&invalid).is_err());
259 }
260
261 #[test]
262 fn test_provider_creation() {
263 let provider = PqcCryptoProvider::new();
264 assert!(provider.is_ok());
265
266 let provider = provider.unwrap();
267 assert_eq!(provider.cipher_suites().len(), 3);
269 assert!(
270 provider
271 .cipher_suites()
272 .contains(&rustls::CipherSuite::TLS13_AES_128_GCM_SHA256)
273 );
274 }
275}