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 {
158 has_pqc: bool,
159 pqc_kex: bool,
160 #[allow(dead_code)]
161 pqc_sig: bool,
162}
163
164impl CryptoInfo {
165 pub fn has_pqc_support(&self) -> bool {
167 self.has_pqc
168 }
169
170 pub fn used_pqc_kex(&self) -> bool {
172 self.pqc_kex
173 }
174
175 pub fn used_classical_kex(&self) -> bool {
177 !self.pqc_kex
178 }
179}
180
181pub fn with_pqc_support(config: crate::ClientConfig) -> Result<crate::ClientConfig, PqcError> {
183 Ok(config)
186}
187
188pub fn with_pqc_support_server(
190 config: crate::ServerConfig,
191) -> Result<crate::ServerConfig, PqcError> {
192 Ok(config)
195}
196
197impl PqcConfigExt for crate::ClientConfig {
199 fn has_pqc_support(&self) -> bool {
200 true }
205
206 fn crypto_config(&self) -> CryptoInfo {
207 CryptoInfo {
209 has_pqc: true,
210 pqc_kex: true, pqc_sig: true,
212 }
213 }
214}
215
216impl PqcConfigExt for crate::ServerConfig {
218 fn has_pqc_support(&self) -> bool {
219 true
221 }
222
223 fn crypto_config(&self) -> CryptoInfo {
224 CryptoInfo {
226 has_pqc: true,
227 pqc_kex: true, pqc_sig: true,
229 }
230 }
231}
232
233#[cfg(test)]
234mod tests {
235 use super::*;
236
237 #[test]
238 fn test_pqc_config_default() {
239 let config = PqcConfig::default();
240 assert!(config.enable_ml_kem);
241 assert!(config.enable_ml_dsa);
242 assert!(config.prefer_pqc);
243 assert!(config.allow_downgrade);
244 }
245
246 #[test]
247 fn test_config_validation() {
248 let valid = PqcConfig::default();
250 assert!(validate_config(&valid).is_ok());
251
252 let invalid = PqcConfig {
254 enable_ml_kem: false,
255 enable_ml_dsa: false,
256 prefer_pqc: false,
257 allow_downgrade: false,
258 };
259 assert!(validate_config(&invalid).is_err());
260 }
261
262 #[test]
263 fn test_provider_creation() {
264 let provider = PqcCryptoProvider::new();
265 assert!(provider.is_ok());
266
267 let provider = provider.unwrap();
268 assert_eq!(provider.cipher_suites().len(), 3);
270 assert!(
271 provider
272 .cipher_suites()
273 .contains(&rustls::CipherSuite::TLS13_AES_128_GCM_SHA256)
274 );
275 }
276}