Skip to main content

ferritls_rustls/
cipher.rs

1//! TLS 1.3 密码套件装配(M6;QUIC 接线 M8.5)。
2//!
3//! HKDF 复用 rustls 内建 [`rustls::crypto::tls13::HkdfUsingHmac`],包装
4//! 本 crate 实现的 [`rustls::crypto::hmac::Hmac`](不在边界内重写密钥
5//! 调度);AEAD 为 ferritls-core 的 GCM/CCM/ChaCha20-Poly1305 适配。
6//!
7//! QUIC:AES-128-GCM / AES-256-GCM / ChaCha20-Poly1305 三套件经
8//! [`crate::quic`] 的 `quic::Algorithm` 参与 QUIC 包保护;CCM 保持
9//! `None`(RFC 9001 §5.1 以 AES-GCM 为强制基准,`ConnectionTrafficSecrets`
10//! 亦无 CCM 变体)。
11
12use rustls::crypto::CipherSuiteCommon;
13use rustls::crypto::cipher::{
14    AeadKey, InboundOpaqueMessage, InboundPlainMessage, Iv, MessageDecrypter, MessageEncrypter,
15    Nonce, PrefixedPayload, Tls13AeadAlgorithm, UnsupportedOperationError, make_tls13_aad,
16};
17use rustls::crypto::hash::{Context, Hash, HashAlgorithm, Output};
18use rustls::crypto::hmac::{self, Hmac, Key};
19use rustls::crypto::tls13::HkdfUsingHmac;
20use rustls::{
21    ConnectionTrafficSecrets, ContentType, Error, ProtocolVersion, SupportedCipherSuite,
22    Tls13CipherSuite,
23};
24
25use ferritls_core::chacha20poly1305::ChaCha20Poly1305;
26use ferritls_core::gcm::{Aes128Gcm, Aes256Gcm};
27
28use ferritls_core::ccm::Aes128CcmTls;
29
30/// 套件清单(顺序即偏好)。同时被 `tests/api.rs` 断言,防止清单与
31/// 文档漂移。
32pub const TLS13_SUITE_NAMES: &[&str] = &[
33    "TLS_AES_128_GCM_SHA256",
34    "TLS_AES_256_GCM_SHA384",
35    "TLS_CHACHA20_POLY1305_SHA256",
36    "TLS_AES_128_CCM_SHA256",
37];
38
39// ---------------------------------------------------------------------------
40// Hash 适配(SHA-256 / SHA-384)
41// ---------------------------------------------------------------------------
42
43#[derive(Debug)]
44struct Sha256Hash;
45
46struct Sha256Ctx(ferritls_core::sha2::Sha256);
47
48impl Context for Sha256Ctx {
49    fn fork_finish(&self) -> Output {
50        Output::new(&self.0.clone().finalize())
51    }
52
53    fn fork(&self) -> Box<dyn Context> {
54        Box::new(Self(self.0.clone()))
55    }
56
57    fn finish(self: Box<Self>) -> Output {
58        Output::new(&self.0.finalize())
59    }
60
61    fn update(&mut self, data: &[u8]) {
62        self.0.update(data);
63    }
64}
65
66impl Hash for Sha256Hash {
67    fn start(&self) -> Box<dyn Context> {
68        Box::new(Sha256Ctx(ferritls_core::sha2::Sha256::new()))
69    }
70
71    fn hash(&self, data: &[u8]) -> Output {
72        Output::new(&ferritls_core::sha2::Sha256::one_shot(data))
73    }
74
75    fn output_len(&self) -> usize {
76        32
77    }
78
79    fn algorithm(&self) -> HashAlgorithm {
80        HashAlgorithm::SHA256
81    }
82}
83
84#[derive(Debug)]
85struct Sha384Hash;
86
87struct Sha384Ctx(ferritls_core::sha2::Sha384);
88
89impl Context for Sha384Ctx {
90    fn fork_finish(&self) -> Output {
91        Output::new(&self.0.clone().finalize())
92    }
93
94    fn fork(&self) -> Box<dyn Context> {
95        Box::new(Self(self.0.clone()))
96    }
97
98    fn finish(self: Box<Self>) -> Output {
99        Output::new(&self.0.finalize())
100    }
101
102    fn update(&mut self, data: &[u8]) {
103        self.0.update(data);
104    }
105}
106
107impl Hash for Sha384Hash {
108    fn start(&self) -> Box<dyn Context> {
109        Box::new(Sha384Ctx(ferritls_core::sha2::Sha384::new()))
110    }
111
112    fn hash(&self, data: &[u8]) -> Output {
113        Output::new(&ferritls_core::sha2::Sha384::one_shot(data))
114    }
115
116    fn output_len(&self) -> usize {
117        48
118    }
119
120    fn algorithm(&self) -> HashAlgorithm {
121        HashAlgorithm::SHA384
122    }
123}
124
125pub(crate) static SHA256_HASH: &dyn Hash = &Sha256Hash;
126pub(crate) static SHA384_HASH: &dyn Hash = &Sha384Hash;
127
128// ---------------------------------------------------------------------------
129// Hmac 适配(rustls::crypto::hmac;供 HkdfUsingHmac 复用)
130// ---------------------------------------------------------------------------
131
132#[derive(Debug)]
133struct HmacSha256Impl;
134
135#[derive(Debug)]
136struct HmacSha256Key(Vec<u8>);
137
138impl Key for HmacSha256Key {
139    fn sign_concat(&self, first: &[u8], middle: &[&[u8]], last: &[u8]) -> hmac::Tag {
140        let mut buf = Vec::with_capacity(first.len() + 16 * middle.len() + last.len());
141        buf.extend_from_slice(first);
142        for m in middle {
143            buf.extend_from_slice(m);
144        }
145        buf.extend_from_slice(last);
146        hmac::Tag::new(&ferritls_core::hmac::HmacSha256::one_shot(&self.0, &buf))
147    }
148
149    fn tag_len(&self) -> usize {
150        32
151    }
152}
153
154impl Hmac for HmacSha256Impl {
155    fn with_key(&self, key: &[u8]) -> Box<dyn Key> {
156        Box::new(HmacSha256Key(key.to_vec()))
157    }
158
159    fn hash_output_len(&self) -> usize {
160        32
161    }
162}
163
164#[derive(Debug)]
165struct HmacSha384Impl;
166
167#[derive(Debug)]
168struct HmacSha384Key(Vec<u8>);
169
170impl Key for HmacSha384Key {
171    fn sign_concat(&self, first: &[u8], middle: &[&[u8]], last: &[u8]) -> hmac::Tag {
172        let mut buf = Vec::with_capacity(first.len() + 16 * middle.len() + last.len());
173        buf.extend_from_slice(first);
174        for m in middle {
175            buf.extend_from_slice(m);
176        }
177        buf.extend_from_slice(last);
178        hmac::Tag::new(&ferritls_core::hmac::HmacSha384::one_shot(&self.0, &buf))
179    }
180
181    fn tag_len(&self) -> usize {
182        48
183    }
184}
185
186impl Hmac for HmacSha384Impl {
187    fn with_key(&self, key: &[u8]) -> Box<dyn Key> {
188        Box::new(HmacSha384Key(key.to_vec()))
189    }
190
191    fn hash_output_len(&self) -> usize {
192        48
193    }
194}
195
196static HMAC_SHA256_IMPL: HmacSha256Impl = HmacSha256Impl;
197static HMAC_SHA384_IMPL: HmacSha384Impl = HmacSha384Impl;
198static HKDF_USING_HMAC_SHA256: HkdfUsingHmac<'static> = HkdfUsingHmac(&HMAC_SHA256_IMPL);
199static HKDF_USING_HMAC_SHA384: HkdfUsingHmac<'static> = HkdfUsingHmac(&HMAC_SHA384_IMPL);
200
201pub(crate) static HKDF_SHA256_PROVIDER: &dyn rustls::crypto::tls13::Hkdf = &HKDF_USING_HMAC_SHA256;
202pub(crate) static HKDF_SHA384_PROVIDER: &dyn rustls::crypto::tls13::Hkdf = &HKDF_USING_HMAC_SHA384;
203
204// ---------------------------------------------------------------------------
205// AEAD 适配:GCM
206// ---------------------------------------------------------------------------
207
208const TAG_LEN: usize = 16;
209
210/// 从 `AeadKey` 提取定长密钥字节。
211pub(crate) fn key_bytes<const N: usize>(key: &AeadKey) -> [u8; N] {
212    let mut out = [0u8; N];
213    out.copy_from_slice(key.as_ref());
214    out
215}
216
217/// GCM 实例(按密钥长度选择 AES-128/256)。
218enum GcmInstance {
219    Aes128(Aes128Gcm),
220    Aes256(Aes256Gcm),
221}
222
223impl GcmInstance {
224    fn seal(&self, nonce: &Nonce, aad: &[u8], plaintext: &[u8]) -> Vec<u8> {
225        match self {
226            GcmInstance::Aes128(g) => g.seal(&nonce.0, aad, plaintext),
227            GcmInstance::Aes256(g) => g.seal(&nonce.0, aad, plaintext),
228        }
229    }
230
231    fn open(&self, nonce: &Nonce, aad: &[u8], ct_tag: &[u8]) -> Result<Vec<u8>, Error> {
232        match self {
233            GcmInstance::Aes128(g) => g.open(&nonce.0, aad, ct_tag),
234            GcmInstance::Aes256(g) => g.open(&nonce.0, aad, ct_tag),
235        }
236        .map_err(|_| Error::DecryptError)
237    }
238}
239
240fn gcm_of<const N: usize>(key: &AeadKey) -> GcmInstance {
241    if N == 32 {
242        GcmInstance::Aes256(Aes256Gcm::new(&key_bytes::<32>(key)))
243    } else {
244        GcmInstance::Aes128(Aes128Gcm::new(&key_bytes::<16>(key)))
245    }
246}
247
248struct GcmEncrypter<const N: usize> {
249    gcm: GcmInstance,
250    iv: Iv,
251    _n: std::marker::PhantomData<[u8; N]>,
252}
253
254struct GcmDecrypter<const N: usize> {
255    gcm: GcmInstance,
256    iv: Iv,
257    _n: std::marker::PhantomData<[u8; N]>,
258}
259
260impl<const N: usize> GcmEncrypter<N> {
261    fn seal(&self, nonce: &Nonce, aad: &[u8], plaintext: &[u8]) -> Vec<u8> {
262        self.gcm.seal(nonce, aad, plaintext)
263    }
264}
265
266impl<const N: usize> GcmDecrypter<N> {
267    fn open(&self, nonce: &Nonce, aad: &[u8], ct_tag: &[u8]) -> Result<Vec<u8>, Error> {
268        self.gcm.open(nonce, aad, ct_tag)
269    }
270}
271
272impl<const N: usize> MessageEncrypter for GcmEncrypter<N> {
273    fn encrypt(
274        &mut self,
275        msg: rustls::crypto::cipher::OutboundPlainMessage<'_>,
276        seq: u64,
277    ) -> Result<rustls::crypto::cipher::OutboundOpaqueMessage, Error> {
278        let total_len = self.encrypted_payload_len(msg.payload.len());
279        let nonce = Nonce::new(&self.iv, seq);
280        let aad = make_tls13_aad(total_len);
281
282        let mut plain = msg.payload.to_vec();
283        plain.push(msg.typ.to_array()[0]);
284        let sealed = self.seal(&nonce, &aad, &plain);
285
286        let mut payload = PrefixedPayload::with_capacity(total_len);
287        payload.extend_from_slice(&sealed);
288        Ok(rustls::crypto::cipher::OutboundOpaqueMessage::new(
289            ContentType::ApplicationData,
290            // RFC 8446 §5.1:TLS 1.3 应用数据记录沿用 legacy 版本 0x0303
291            ProtocolVersion::TLSv1_2,
292            payload,
293        ))
294    }
295
296    fn encrypted_payload_len(&self, payload_len: usize) -> usize {
297        payload_len + 1 + TAG_LEN
298    }
299}
300
301impl<const N: usize> MessageDecrypter for GcmDecrypter<N> {
302    fn decrypt<'a>(
303        &mut self,
304        mut msg: InboundOpaqueMessage<'a>,
305        seq: u64,
306    ) -> Result<InboundPlainMessage<'a>, Error> {
307        let payload = &mut msg.payload;
308        if payload.len() < TAG_LEN + 1 {
309            return Err(Error::DecryptError);
310        }
311        let nonce = Nonce::new(&self.iv, seq);
312        let aad = make_tls13_aad(payload.len());
313        let plain = self
314            .open(&nonce, &aad, payload)
315            .map_err(|_| Error::DecryptError)?;
316        let plain_len = plain.len();
317        payload[..plain_len].copy_from_slice(&plain);
318        payload.truncate(plain_len);
319        msg.into_tls13_unpadded_message()
320    }
321}
322
323macro_rules! gcm_aead {
324    ($name:ident, $key_len:expr, $secret:ident, $doc:expr) => {
325        #[doc = $doc]
326        #[derive(Debug)]
327        pub struct $name;
328
329        impl Tls13AeadAlgorithm for $name {
330            fn encrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageEncrypter> {
331                Box::new(GcmEncrypter::<$key_len> {
332                    gcm: gcm_of::<$key_len>(&key),
333                    iv,
334                    _n: std::marker::PhantomData,
335                })
336            }
337
338            fn decrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageDecrypter> {
339                Box::new(GcmDecrypter::<$key_len> {
340                    gcm: gcm_of::<$key_len>(&key),
341                    iv,
342                    _n: std::marker::PhantomData,
343                })
344            }
345
346            fn key_len(&self) -> usize {
347                $key_len
348            }
349
350            fn extract_keys(
351                &self,
352                key: AeadKey,
353                iv: Iv,
354            ) -> Result<ConnectionTrafficSecrets, UnsupportedOperationError> {
355                Ok(ConnectionTrafficSecrets::$secret { key, iv })
356            }
357        }
358    };
359}
360
361gcm_aead!(Gcm128Aead, 16, Aes128Gcm, "AES-128-GCM AEAD 适配(批准)。");
362gcm_aead!(Gcm256Aead, 32, Aes256Gcm, "AES-256-GCM AEAD 适配(批准)。");
363
364// ---------------------------------------------------------------------------
365// AEAD 适配:ChaCha20-Poly1305(非批准,仅默认模式)
366// ---------------------------------------------------------------------------
367
368#[derive(Debug)]
369pub struct Chacha20Poly1305Aead;
370
371struct ChachaEncrypter {
372    aead: ChaCha20Poly1305,
373    iv: Iv,
374}
375
376struct ChachaDecrypter {
377    aead: ChaCha20Poly1305,
378    iv: Iv,
379}
380
381impl MessageEncrypter for ChachaEncrypter {
382    fn encrypt(
383        &mut self,
384        msg: rustls::crypto::cipher::OutboundPlainMessage<'_>,
385        seq: u64,
386    ) -> Result<rustls::crypto::cipher::OutboundOpaqueMessage, Error> {
387        let total_len = self.encrypted_payload_len(msg.payload.len());
388        let nonce = Nonce::new(&self.iv, seq);
389        let aad = make_tls13_aad(total_len);
390
391        let mut plain = msg.payload.to_vec();
392        plain.push(msg.typ.to_array()[0]);
393        let sealed = self.aead.seal(&nonce.0, &aad, &plain);
394
395        let mut payload = PrefixedPayload::with_capacity(total_len);
396        payload.extend_from_slice(&sealed);
397        Ok(rustls::crypto::cipher::OutboundOpaqueMessage::new(
398            ContentType::ApplicationData,
399            ProtocolVersion::TLSv1_2,
400            payload,
401        ))
402    }
403
404    fn encrypted_payload_len(&self, payload_len: usize) -> usize {
405        payload_len + 1 + TAG_LEN
406    }
407}
408
409impl MessageDecrypter for ChachaDecrypter {
410    fn decrypt<'a>(
411        &mut self,
412        mut msg: InboundOpaqueMessage<'a>,
413        seq: u64,
414    ) -> Result<InboundPlainMessage<'a>, Error> {
415        let payload = &mut msg.payload;
416        if payload.len() < TAG_LEN + 1 {
417            return Err(Error::DecryptError);
418        }
419        let nonce = Nonce::new(&self.iv, seq);
420        let aad = make_tls13_aad(payload.len());
421        let plain = self
422            .aead
423            .open(&nonce.0, &aad, payload)
424            .map_err(|_| Error::DecryptError)?;
425        let plain_len = plain.len();
426        payload[..plain_len].copy_from_slice(&plain);
427        payload.truncate(plain_len);
428        msg.into_tls13_unpadded_message()
429    }
430}
431
432impl Tls13AeadAlgorithm for Chacha20Poly1305Aead {
433    fn encrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageEncrypter> {
434        Box::new(ChachaEncrypter {
435            aead: ChaCha20Poly1305::new(&key_bytes::<32>(&key)),
436            iv,
437        })
438    }
439
440    fn decrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageDecrypter> {
441        Box::new(ChachaDecrypter {
442            aead: ChaCha20Poly1305::new(&key_bytes::<32>(&key)),
443            iv,
444        })
445    }
446
447    fn key_len(&self) -> usize {
448        32
449    }
450
451    fn extract_keys(
452        &self,
453        key: AeadKey,
454        iv: Iv,
455    ) -> Result<ConnectionTrafficSecrets, UnsupportedOperationError> {
456        Ok(ConnectionTrafficSecrets::Chacha20Poly1305 { key, iv })
457    }
458}
459
460// ---------------------------------------------------------------------------
461// AEAD 适配:AES-128-CCM(TLS 1.3 参数集,nonce 12 / L=3)
462// ---------------------------------------------------------------------------
463
464#[derive(Debug)]
465pub struct Ccm128Aead;
466
467struct CcmEncrypter {
468    ccm: Aes128CcmTls,
469    iv: Iv,
470}
471
472struct CcmDecrypter {
473    ccm: Aes128CcmTls,
474    iv: Iv,
475}
476
477impl MessageEncrypter for CcmEncrypter {
478    fn encrypt(
479        &mut self,
480        msg: rustls::crypto::cipher::OutboundPlainMessage<'_>,
481        seq: u64,
482    ) -> Result<rustls::crypto::cipher::OutboundOpaqueMessage, Error> {
483        let total_len = self.encrypted_payload_len(msg.payload.len());
484        let nonce = Nonce::new(&self.iv, seq);
485        let aad = make_tls13_aad(total_len);
486
487        let mut plain = msg.payload.to_vec();
488        plain.push(msg.typ.to_array()[0]);
489        let sealed = self
490            .ccm
491            .seal(&nonce.0, &aad, &plain)
492            .map_err(|_| Error::EncryptError)?;
493
494        let mut payload = PrefixedPayload::with_capacity(total_len);
495        payload.extend_from_slice(&sealed);
496        Ok(rustls::crypto::cipher::OutboundOpaqueMessage::new(
497            ContentType::ApplicationData,
498            ProtocolVersion::TLSv1_2,
499            payload,
500        ))
501    }
502
503    fn encrypted_payload_len(&self, payload_len: usize) -> usize {
504        payload_len + 1 + TAG_LEN
505    }
506}
507
508impl MessageDecrypter for CcmDecrypter {
509    fn decrypt<'a>(
510        &mut self,
511        mut msg: InboundOpaqueMessage<'a>,
512        seq: u64,
513    ) -> Result<InboundPlainMessage<'a>, Error> {
514        let payload = &mut msg.payload;
515        if payload.len() < TAG_LEN + 1 {
516            return Err(Error::DecryptError);
517        }
518        let nonce = Nonce::new(&self.iv, seq);
519        let aad = make_tls13_aad(payload.len());
520        let plain = self
521            .ccm
522            .open(&nonce.0, &aad, payload)
523            .map_err(|_| Error::DecryptError)?;
524        let plain_len = plain.len();
525        payload[..plain_len].copy_from_slice(&plain);
526        payload.truncate(plain_len);
527        msg.into_tls13_unpadded_message()
528    }
529}
530
531impl Tls13AeadAlgorithm for Ccm128Aead {
532    fn encrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageEncrypter> {
533        Box::new(CcmEncrypter {
534            ccm: Aes128CcmTls::new(&key_bytes::<16>(&key)),
535            iv,
536        })
537    }
538
539    fn decrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageDecrypter> {
540        Box::new(CcmDecrypter {
541            ccm: Aes128CcmTls::new(&key_bytes::<16>(&key)),
542            iv,
543        })
544    }
545
546    fn key_len(&self) -> usize {
547        16
548    }
549
550    fn extract_keys(
551        &self,
552        _key: AeadKey,
553        _iv: Iv,
554    ) -> Result<ConnectionTrafficSecrets, UnsupportedOperationError> {
555        // ConnectionTrafficSecrets 无 CCM 变体:导出 traffic secrets(key
556        // exporter / key log)对 CCM 套件不可用——与 AGENTS.md §4 记载一致
557        Err(UnsupportedOperationError)
558    }
559}
560
561// ---------------------------------------------------------------------------
562// 套件静态表与装配
563// ---------------------------------------------------------------------------
564
565pub(crate) static GCM128_AEAD: Gcm128Aead = Gcm128Aead;
566pub(crate) static GCM256_AEAD: Gcm256Aead = Gcm256Aead;
567pub(crate) static CHACHA_AEAD: Chacha20Poly1305Aead = Chacha20Poly1305Aead;
568static CCM128_AEAD: Ccm128Aead = Ccm128Aead;
569
570pub(crate) static TLS13_AES_128_GCM_SHA256: Tls13CipherSuite = Tls13CipherSuite {
571    common: CipherSuiteCommon {
572        suite: rustls::CipherSuite::TLS13_AES_128_GCM_SHA256,
573        hash_provider: SHA256_HASH,
574        // draft-irtf-aead-limits-08 §5.1.1(与 rustls ring provider 一致)
575        confidentiality_limit: 1 << 24,
576    },
577    hkdf_provider: HKDF_SHA256_PROVIDER,
578    aead_alg: &GCM128_AEAD,
579    quic: Some(&crate::quic::QUIC_AES_128_GCM),
580};
581
582pub(crate) static TLS13_AES_256_GCM_SHA384: Tls13CipherSuite = Tls13CipherSuite {
583    common: CipherSuiteCommon {
584        suite: rustls::CipherSuite::TLS13_AES_256_GCM_SHA384,
585        hash_provider: SHA384_HASH,
586        confidentiality_limit: 1 << 24,
587    },
588    hkdf_provider: HKDF_SHA384_PROVIDER,
589    aead_alg: &GCM256_AEAD,
590    quic: Some(&crate::quic::QUIC_AES_256_GCM),
591};
592
593pub(crate) static TLS13_CHACHA20_POLY1305_SHA256: Tls13CipherSuite = Tls13CipherSuite {
594    common: CipherSuiteCommon {
595        suite: rustls::CipherSuite::TLS13_CHACHA20_POLY1305_SHA256,
596        hash_provider: SHA256_HASH,
597        // draft-irtf-aead-limits-08 §5.2.1
598        confidentiality_limit: u64::MAX,
599    },
600    hkdf_provider: HKDF_SHA256_PROVIDER,
601    aead_alg: &CHACHA_AEAD,
602    quic: Some(&crate::quic::QUIC_CHACHA20_POLY1305),
603};
604
605static TLS13_AES_128_CCM_SHA256: Tls13CipherSuite = Tls13CipherSuite {
606    common: CipherSuiteCommon {
607        suite: rustls::CipherSuite::TLS13_AES_128_CCM_SHA256,
608        hash_provider: SHA256_HASH,
609        confidentiality_limit: 1 << 23,
610    },
611    hkdf_provider: HKDF_SHA256_PROVIDER,
612    aead_alg: &CCM128_AEAD,
613    // CCM 不参与 QUIC:RFC 9001 §5.1 以 AES-GCM 为强制基准(ring 同),
614    // ConnectionTrafficSecrets 亦无 CCM 变体。
615    quic: None,
616};
617
618/// `TLS_AES_128_GCM_SHA256`(批准)。
619pub fn tls13_aes_128_gcm_sha256() -> SupportedCipherSuite {
620    SupportedCipherSuite::Tls13(&TLS13_AES_128_GCM_SHA256)
621}
622
623/// `TLS_AES_256_GCM_SHA384`(批准)。
624pub fn tls13_aes_256_gcm_sha384() -> SupportedCipherSuite {
625    SupportedCipherSuite::Tls13(&TLS13_AES_256_GCM_SHA384)
626}
627
628/// `TLS_CHACHA20_POLY1305_SHA256`(非批准,仅默认模式)。
629pub fn tls13_chacha20_poly1305_sha256() -> SupportedCipherSuite {
630    SupportedCipherSuite::Tls13(&TLS13_CHACHA20_POLY1305_SHA256)
631}
632
633/// `TLS_AES_128_CCM_SHA256`(批准,SP 800-52r2 面向受限环境)。
634pub fn tls13_aes_128_ccm_sha256() -> SupportedCipherSuite {
635    SupportedCipherSuite::Tls13(&TLS13_AES_128_CCM_SHA256)
636}
637
638/// 默认模式全部套件(偏好序)。
639pub fn all_tls13_suites() -> Vec<SupportedCipherSuite> {
640    vec![
641        tls13_aes_128_gcm_sha256(),
642        tls13_aes_256_gcm_sha384(),
643        tls13_chacha20_poly1305_sha256(),
644        tls13_aes_128_ccm_sha256(),
645    ]
646}
647
648/// 批准模式套件(无 ChaCha20-Poly1305)。
649pub fn fips_tls13_suites() -> Vec<SupportedCipherSuite> {
650    vec![
651        tls13_aes_128_gcm_sha256(),
652        tls13_aes_256_gcm_sha384(),
653        tls13_aes_128_ccm_sha256(),
654    ]
655}