1use rustls::crypto::CipherSuiteCommon;
17use rustls::crypto::cipher::{
18 AeadKey, InboundOpaqueMessage, InboundPlainMessage, Iv, MessageDecrypter, MessageEncrypter,
19 Nonce, PrefixedPayload, Tls13AeadAlgorithm, UnsupportedOperationError, make_tls13_aad,
20};
21use rustls::crypto::hash::{Context, Hash, HashAlgorithm, Output};
22use rustls::crypto::hmac::{self, Hmac, Key};
23use rustls::crypto::tls13::HkdfUsingHmac;
24use rustls::{
25 ConnectionTrafficSecrets, ContentType, Error, ProtocolVersion, SupportedCipherSuite,
26 Tls13CipherSuite,
27};
28
29use ferritls_core::chacha20poly1305::ChaCha20Poly1305;
30use ferritls_core::gcm::{Aes128Gcm, Aes256Gcm};
31
32use ferritls_core::ccm::Aes128CcmAny;
33
34pub const TLS13_SUITE_NAMES: &[&str] = &[
37 "TLS_AES_128_GCM_SHA256",
38 "TLS_AES_256_GCM_SHA384",
39 "TLS_CHACHA20_POLY1305_SHA256",
40 "TLS_AES_128_CCM_SHA256",
41 "TLS_AES_128_CCM_8_SHA256",
42];
43
44#[derive(Debug)]
49struct Sha256Hash;
50
51struct Sha256Ctx(ferritls_core::sha2::Sha256);
52
53impl Context for Sha256Ctx {
54 fn fork_finish(&self) -> Output {
55 Output::new(&self.0.clone().finalize())
56 }
57
58 fn fork(&self) -> Box<dyn Context> {
59 Box::new(Self(self.0.clone()))
60 }
61
62 fn finish(self: Box<Self>) -> Output {
63 Output::new(&self.0.finalize())
64 }
65
66 fn update(&mut self, data: &[u8]) {
67 self.0.update(data);
68 }
69}
70
71impl Hash for Sha256Hash {
72 fn start(&self) -> Box<dyn Context> {
73 Box::new(Sha256Ctx(ferritls_core::sha2::Sha256::new()))
74 }
75
76 fn hash(&self, data: &[u8]) -> Output {
77 Output::new(&ferritls_core::sha2::Sha256::one_shot(data))
78 }
79
80 fn output_len(&self) -> usize {
81 32
82 }
83
84 fn algorithm(&self) -> HashAlgorithm {
85 HashAlgorithm::SHA256
86 }
87}
88
89#[derive(Debug)]
90struct Sha384Hash;
91
92struct Sha384Ctx(ferritls_core::sha2::Sha384);
93
94impl Context for Sha384Ctx {
95 fn fork_finish(&self) -> Output {
96 Output::new(&self.0.clone().finalize())
97 }
98
99 fn fork(&self) -> Box<dyn Context> {
100 Box::new(Self(self.0.clone()))
101 }
102
103 fn finish(self: Box<Self>) -> Output {
104 Output::new(&self.0.finalize())
105 }
106
107 fn update(&mut self, data: &[u8]) {
108 self.0.update(data);
109 }
110}
111
112impl Hash for Sha384Hash {
113 fn start(&self) -> Box<dyn Context> {
114 Box::new(Sha384Ctx(ferritls_core::sha2::Sha384::new()))
115 }
116
117 fn hash(&self, data: &[u8]) -> Output {
118 Output::new(&ferritls_core::sha2::Sha384::one_shot(data))
119 }
120
121 fn output_len(&self) -> usize {
122 48
123 }
124
125 fn algorithm(&self) -> HashAlgorithm {
126 HashAlgorithm::SHA384
127 }
128}
129
130pub(crate) static SHA256_HASH: &dyn Hash = &Sha256Hash;
131pub(crate) static SHA384_HASH: &dyn Hash = &Sha384Hash;
132
133#[derive(Debug)]
138struct HmacSha256Impl;
139
140#[derive(Debug)]
141struct HmacSha256Key(Vec<u8>);
142
143impl Key for HmacSha256Key {
144 fn sign_concat(&self, first: &[u8], middle: &[&[u8]], last: &[u8]) -> hmac::Tag {
145 let mut buf = Vec::with_capacity(first.len() + 16 * middle.len() + last.len());
146 buf.extend_from_slice(first);
147 for m in middle {
148 buf.extend_from_slice(m);
149 }
150 buf.extend_from_slice(last);
151 hmac::Tag::new(&ferritls_core::hmac::HmacSha256::one_shot(&self.0, &buf))
152 }
153
154 fn tag_len(&self) -> usize {
155 32
156 }
157}
158
159impl Hmac for HmacSha256Impl {
160 fn with_key(&self, key: &[u8]) -> Box<dyn Key> {
161 Box::new(HmacSha256Key(key.to_vec()))
162 }
163
164 fn hash_output_len(&self) -> usize {
165 32
166 }
167}
168
169#[derive(Debug)]
170struct HmacSha384Impl;
171
172#[derive(Debug)]
173struct HmacSha384Key(Vec<u8>);
174
175impl Key for HmacSha384Key {
176 fn sign_concat(&self, first: &[u8], middle: &[&[u8]], last: &[u8]) -> hmac::Tag {
177 let mut buf = Vec::with_capacity(first.len() + 16 * middle.len() + last.len());
178 buf.extend_from_slice(first);
179 for m in middle {
180 buf.extend_from_slice(m);
181 }
182 buf.extend_from_slice(last);
183 hmac::Tag::new(&ferritls_core::hmac::HmacSha384::one_shot(&self.0, &buf))
184 }
185
186 fn tag_len(&self) -> usize {
187 48
188 }
189}
190
191impl Hmac for HmacSha384Impl {
192 fn with_key(&self, key: &[u8]) -> Box<dyn Key> {
193 Box::new(HmacSha384Key(key.to_vec()))
194 }
195
196 fn hash_output_len(&self) -> usize {
197 48
198 }
199}
200
201static HMAC_SHA256_IMPL: HmacSha256Impl = HmacSha256Impl;
202static HMAC_SHA384_IMPL: HmacSha384Impl = HmacSha384Impl;
203static HKDF_USING_HMAC_SHA256: HkdfUsingHmac<'static> = HkdfUsingHmac(&HMAC_SHA256_IMPL);
204static HKDF_USING_HMAC_SHA384: HkdfUsingHmac<'static> = HkdfUsingHmac(&HMAC_SHA384_IMPL);
205
206pub(crate) static HKDF_SHA256_PROVIDER: &dyn rustls::crypto::tls13::Hkdf = &HKDF_USING_HMAC_SHA256;
207pub(crate) static HKDF_SHA384_PROVIDER: &dyn rustls::crypto::tls13::Hkdf = &HKDF_USING_HMAC_SHA384;
208
209const TAG_LEN: usize = 16;
214
215pub(crate) fn key_bytes<const N: usize>(key: &AeadKey) -> [u8; N] {
217 let mut out = [0u8; N];
218 out.copy_from_slice(key.as_ref());
219 out
220}
221
222enum GcmInstance {
224 Aes128(Aes128Gcm),
225 Aes256(Aes256Gcm),
226}
227
228impl GcmInstance {
229 fn seal(&self, nonce: &Nonce, aad: &[u8], plaintext: &[u8]) -> Vec<u8> {
230 match self {
231 GcmInstance::Aes128(g) => g.seal(&nonce.0, aad, plaintext),
232 GcmInstance::Aes256(g) => g.seal(&nonce.0, aad, plaintext),
233 }
234 }
235
236 fn open(&self, nonce: &Nonce, aad: &[u8], ct_tag: &[u8]) -> Result<Vec<u8>, Error> {
237 match self {
238 GcmInstance::Aes128(g) => g.open(&nonce.0, aad, ct_tag),
239 GcmInstance::Aes256(g) => g.open(&nonce.0, aad, ct_tag),
240 }
241 .map_err(|_| Error::DecryptError)
242 }
243}
244
245fn gcm_of<const N: usize>(key: &AeadKey) -> GcmInstance {
246 if N == 32 {
247 GcmInstance::Aes256(Aes256Gcm::new(&key_bytes::<32>(key)))
248 } else {
249 GcmInstance::Aes128(Aes128Gcm::new(&key_bytes::<16>(key)))
250 }
251}
252
253struct GcmEncrypter<const N: usize> {
254 gcm: GcmInstance,
255 iv: Iv,
256 _n: std::marker::PhantomData<[u8; N]>,
257}
258
259struct GcmDecrypter<const N: usize> {
260 gcm: GcmInstance,
261 iv: Iv,
262 _n: std::marker::PhantomData<[u8; N]>,
263}
264
265impl<const N: usize> GcmEncrypter<N> {
266 fn seal(&self, nonce: &Nonce, aad: &[u8], plaintext: &[u8]) -> Vec<u8> {
267 self.gcm.seal(nonce, aad, plaintext)
268 }
269}
270
271impl<const N: usize> GcmDecrypter<N> {
272 fn open(&self, nonce: &Nonce, aad: &[u8], ct_tag: &[u8]) -> Result<Vec<u8>, Error> {
273 self.gcm.open(nonce, aad, ct_tag)
274 }
275}
276
277impl<const N: usize> MessageEncrypter for GcmEncrypter<N> {
278 fn encrypt(
279 &mut self,
280 msg: rustls::crypto::cipher::OutboundPlainMessage<'_>,
281 seq: u64,
282 ) -> Result<rustls::crypto::cipher::OutboundOpaqueMessage, Error> {
283 let total_len = self.encrypted_payload_len(msg.payload.len());
284 let nonce = Nonce::new(&self.iv, seq);
285 let aad = make_tls13_aad(total_len);
286
287 let mut plain = msg.payload.to_vec();
288 plain.push(msg.typ.to_array()[0]);
289 let sealed = self.seal(&nonce, &aad, &plain);
290
291 let mut payload = PrefixedPayload::with_capacity(total_len);
292 payload.extend_from_slice(&sealed);
293 Ok(rustls::crypto::cipher::OutboundOpaqueMessage::new(
294 ContentType::ApplicationData,
295 ProtocolVersion::TLSv1_2,
297 payload,
298 ))
299 }
300
301 fn encrypted_payload_len(&self, payload_len: usize) -> usize {
302 payload_len + 1 + TAG_LEN
303 }
304}
305
306impl<const N: usize> MessageDecrypter for GcmDecrypter<N> {
307 fn decrypt<'a>(
308 &mut self,
309 mut msg: InboundOpaqueMessage<'a>,
310 seq: u64,
311 ) -> Result<InboundPlainMessage<'a>, Error> {
312 let payload = &mut msg.payload;
313 if payload.len() < TAG_LEN + 1 {
314 return Err(Error::DecryptError);
315 }
316 let nonce = Nonce::new(&self.iv, seq);
317 let aad = make_tls13_aad(payload.len());
318 let plain = self
319 .open(&nonce, &aad, payload)
320 .map_err(|_| Error::DecryptError)?;
321 let plain_len = plain.len();
322 payload[..plain_len].copy_from_slice(&plain);
323 payload.truncate(plain_len);
324 msg.into_tls13_unpadded_message()
325 }
326}
327
328macro_rules! gcm_aead {
329 ($name:ident, $key_len:expr, $secret:ident, $doc:expr) => {
330 #[doc = $doc]
331 #[derive(Debug)]
332 pub struct $name;
333
334 impl Tls13AeadAlgorithm for $name {
335 fn encrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageEncrypter> {
336 Box::new(GcmEncrypter::<$key_len> {
337 gcm: gcm_of::<$key_len>(&key),
338 iv,
339 _n: std::marker::PhantomData,
340 })
341 }
342
343 fn decrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageDecrypter> {
344 Box::new(GcmDecrypter::<$key_len> {
345 gcm: gcm_of::<$key_len>(&key),
346 iv,
347 _n: std::marker::PhantomData,
348 })
349 }
350
351 fn key_len(&self) -> usize {
352 $key_len
353 }
354
355 fn extract_keys(
356 &self,
357 key: AeadKey,
358 iv: Iv,
359 ) -> Result<ConnectionTrafficSecrets, UnsupportedOperationError> {
360 Ok(ConnectionTrafficSecrets::$secret { key, iv })
361 }
362 }
363 };
364}
365
366gcm_aead!(Gcm128Aead, 16, Aes128Gcm, "AES-128-GCM AEAD 适配(批准)。");
367gcm_aead!(Gcm256Aead, 32, Aes256Gcm, "AES-256-GCM AEAD 适配(批准)。");
368
369#[derive(Debug)]
374pub struct Chacha20Poly1305Aead;
375
376struct ChachaEncrypter {
377 aead: ChaCha20Poly1305,
378 iv: Iv,
379}
380
381struct ChachaDecrypter {
382 aead: ChaCha20Poly1305,
383 iv: Iv,
384}
385
386impl MessageEncrypter for ChachaEncrypter {
387 fn encrypt(
388 &mut self,
389 msg: rustls::crypto::cipher::OutboundPlainMessage<'_>,
390 seq: u64,
391 ) -> Result<rustls::crypto::cipher::OutboundOpaqueMessage, Error> {
392 let total_len = self.encrypted_payload_len(msg.payload.len());
393 let nonce = Nonce::new(&self.iv, seq);
394 let aad = make_tls13_aad(total_len);
395
396 let mut plain = msg.payload.to_vec();
397 plain.push(msg.typ.to_array()[0]);
398 let sealed = self.aead.seal(&nonce.0, &aad, &plain);
399
400 let mut payload = PrefixedPayload::with_capacity(total_len);
401 payload.extend_from_slice(&sealed);
402 Ok(rustls::crypto::cipher::OutboundOpaqueMessage::new(
403 ContentType::ApplicationData,
404 ProtocolVersion::TLSv1_2,
405 payload,
406 ))
407 }
408
409 fn encrypted_payload_len(&self, payload_len: usize) -> usize {
410 payload_len + 1 + TAG_LEN
411 }
412}
413
414impl MessageDecrypter for ChachaDecrypter {
415 fn decrypt<'a>(
416 &mut self,
417 mut msg: InboundOpaqueMessage<'a>,
418 seq: u64,
419 ) -> Result<InboundPlainMessage<'a>, Error> {
420 let payload = &mut msg.payload;
421 if payload.len() < TAG_LEN + 1 {
422 return Err(Error::DecryptError);
423 }
424 let nonce = Nonce::new(&self.iv, seq);
425 let aad = make_tls13_aad(payload.len());
426 let plain = self
427 .aead
428 .open(&nonce.0, &aad, payload)
429 .map_err(|_| Error::DecryptError)?;
430 let plain_len = plain.len();
431 payload[..plain_len].copy_from_slice(&plain);
432 payload.truncate(plain_len);
433 msg.into_tls13_unpadded_message()
434 }
435}
436
437impl Tls13AeadAlgorithm for Chacha20Poly1305Aead {
438 fn encrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageEncrypter> {
439 Box::new(ChachaEncrypter {
440 aead: ChaCha20Poly1305::new(&key_bytes::<32>(&key)),
441 iv,
442 })
443 }
444
445 fn decrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageDecrypter> {
446 Box::new(ChachaDecrypter {
447 aead: ChaCha20Poly1305::new(&key_bytes::<32>(&key)),
448 iv,
449 })
450 }
451
452 fn key_len(&self) -> usize {
453 32
454 }
455
456 fn extract_keys(
457 &self,
458 key: AeadKey,
459 iv: Iv,
460 ) -> Result<ConnectionTrafficSecrets, UnsupportedOperationError> {
461 Ok(ConnectionTrafficSecrets::Chacha20Poly1305 { key, iv })
462 }
463}
464
465#[derive(Debug)]
472pub struct Ccm128Aead;
473
474#[derive(Debug)]
477pub struct Ccm8TlsAead;
478
479fn ccm_engine<const M: usize>(key: &AeadKey) -> Aes128CcmAny {
480 Aes128CcmAny::new(&key_bytes::<16>(key), M).expect("fixed tag length")
482}
483
484struct CcmEncrypter<const M: usize> {
485 ccm: Aes128CcmAny,
486 iv: Iv,
487}
488
489struct CcmDecrypter<const M: usize> {
490 ccm: Aes128CcmAny,
491 iv: Iv,
492}
493
494impl<const M: usize> MessageEncrypter for CcmEncrypter<M> {
495 fn encrypt(
496 &mut self,
497 msg: rustls::crypto::cipher::OutboundPlainMessage<'_>,
498 seq: u64,
499 ) -> Result<rustls::crypto::cipher::OutboundOpaqueMessage, Error> {
500 let total_len = self.encrypted_payload_len(msg.payload.len());
501 let nonce = Nonce::new(&self.iv, seq);
502 let aad = make_tls13_aad(total_len);
503
504 let mut plain = msg.payload.to_vec();
505 plain.push(msg.typ.to_array()[0]);
506 let sealed = self
507 .ccm
508 .seal(&nonce.0, &aad, &plain)
509 .map_err(|_| Error::EncryptError)?;
510
511 let mut payload = PrefixedPayload::with_capacity(total_len);
512 payload.extend_from_slice(&sealed);
513 Ok(rustls::crypto::cipher::OutboundOpaqueMessage::new(
514 ContentType::ApplicationData,
515 ProtocolVersion::TLSv1_2,
516 payload,
517 ))
518 }
519
520 fn encrypted_payload_len(&self, payload_len: usize) -> usize {
521 payload_len + 1 + M
522 }
523}
524
525impl<const M: usize> MessageDecrypter for CcmDecrypter<M> {
526 fn decrypt<'a>(
527 &mut self,
528 mut msg: InboundOpaqueMessage<'a>,
529 seq: u64,
530 ) -> Result<InboundPlainMessage<'a>, Error> {
531 let payload = &mut msg.payload;
532 if payload.len() < M + 1 {
533 return Err(Error::DecryptError);
534 }
535 let nonce = Nonce::new(&self.iv, seq);
536 let aad = make_tls13_aad(payload.len());
537 let plain = self
538 .ccm
539 .open(&nonce.0, &aad, payload)
540 .map_err(|_| Error::DecryptError)?;
541 let plain_len = plain.len();
542 payload[..plain_len].copy_from_slice(&plain);
543 payload.truncate(plain_len);
544 msg.into_tls13_unpadded_message()
545 }
546}
547
548macro_rules! ccm_aead_impl {
550 ($name:ident, $tag_len:expr) => {
551 impl Tls13AeadAlgorithm for $name {
552 fn encrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageEncrypter> {
553 Box::new(CcmEncrypter::<$tag_len> {
554 ccm: ccm_engine::<$tag_len>(&key),
555 iv,
556 })
557 }
558
559 fn decrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageDecrypter> {
560 Box::new(CcmDecrypter::<$tag_len> {
561 ccm: ccm_engine::<$tag_len>(&key),
562 iv,
563 })
564 }
565
566 fn key_len(&self) -> usize {
567 16
568 }
569
570 fn extract_keys(
571 &self,
572 _key: AeadKey,
573 _iv: Iv,
574 ) -> Result<ConnectionTrafficSecrets, UnsupportedOperationError> {
575 Err(UnsupportedOperationError)
578 }
579 }
580 };
581}
582
583ccm_aead_impl!(Ccm128Aead, 16);
584ccm_aead_impl!(Ccm8TlsAead, 8);
585
586pub(crate) static GCM128_AEAD: Gcm128Aead = Gcm128Aead;
591pub(crate) static GCM256_AEAD: Gcm256Aead = Gcm256Aead;
592pub(crate) static CHACHA_AEAD: Chacha20Poly1305Aead = Chacha20Poly1305Aead;
593static CCM128_AEAD: Ccm128Aead = Ccm128Aead;
594static CCM8_AEAD: Ccm8TlsAead = Ccm8TlsAead;
595
596pub(crate) static TLS13_AES_128_GCM_SHA256: Tls13CipherSuite = Tls13CipherSuite {
597 common: CipherSuiteCommon {
598 suite: rustls::CipherSuite::TLS13_AES_128_GCM_SHA256,
599 hash_provider: SHA256_HASH,
600 confidentiality_limit: 1 << 24,
602 },
603 hkdf_provider: HKDF_SHA256_PROVIDER,
604 aead_alg: &GCM128_AEAD,
605 quic: Some(&crate::quic::QUIC_AES_128_GCM),
606};
607
608pub(crate) static TLS13_AES_256_GCM_SHA384: Tls13CipherSuite = Tls13CipherSuite {
609 common: CipherSuiteCommon {
610 suite: rustls::CipherSuite::TLS13_AES_256_GCM_SHA384,
611 hash_provider: SHA384_HASH,
612 confidentiality_limit: 1 << 24,
613 },
614 hkdf_provider: HKDF_SHA384_PROVIDER,
615 aead_alg: &GCM256_AEAD,
616 quic: Some(&crate::quic::QUIC_AES_256_GCM),
617};
618
619pub(crate) static TLS13_CHACHA20_POLY1305_SHA256: Tls13CipherSuite = Tls13CipherSuite {
620 common: CipherSuiteCommon {
621 suite: rustls::CipherSuite::TLS13_CHACHA20_POLY1305_SHA256,
622 hash_provider: SHA256_HASH,
623 confidentiality_limit: u64::MAX,
625 },
626 hkdf_provider: HKDF_SHA256_PROVIDER,
627 aead_alg: &CHACHA_AEAD,
628 quic: Some(&crate::quic::QUIC_CHACHA20_POLY1305),
629};
630
631static TLS13_AES_128_CCM_SHA256: Tls13CipherSuite = Tls13CipherSuite {
632 common: CipherSuiteCommon {
633 suite: rustls::CipherSuite::TLS13_AES_128_CCM_SHA256,
634 hash_provider: SHA256_HASH,
635 confidentiality_limit: 1 << 23,
636 },
637 hkdf_provider: HKDF_SHA256_PROVIDER,
638 aead_alg: &CCM128_AEAD,
639 quic: None,
642};
643
644static TLS13_AES_128_CCM_8_SHA256: Tls13CipherSuite = Tls13CipherSuite {
645 common: CipherSuiteCommon {
646 suite: rustls::CipherSuite::TLS13_AES_128_CCM_8_SHA256,
647 hash_provider: SHA256_HASH,
648 confidentiality_limit: 1 << 23,
650 },
651 hkdf_provider: HKDF_SHA256_PROVIDER,
652 aead_alg: &CCM8_AEAD,
653 quic: None,
655};
656
657pub fn tls13_aes_128_gcm_sha256() -> SupportedCipherSuite {
659 SupportedCipherSuite::Tls13(&TLS13_AES_128_GCM_SHA256)
660}
661
662pub fn tls13_aes_256_gcm_sha384() -> SupportedCipherSuite {
664 SupportedCipherSuite::Tls13(&TLS13_AES_256_GCM_SHA384)
665}
666
667pub fn tls13_chacha20_poly1305_sha256() -> SupportedCipherSuite {
669 SupportedCipherSuite::Tls13(&TLS13_CHACHA20_POLY1305_SHA256)
670}
671
672pub fn tls13_aes_128_ccm_sha256() -> SupportedCipherSuite {
674 SupportedCipherSuite::Tls13(&TLS13_AES_128_CCM_SHA256)
675}
676
677pub fn tls13_aes_128_ccm_8_sha256() -> SupportedCipherSuite {
680 SupportedCipherSuite::Tls13(&TLS13_AES_128_CCM_8_SHA256)
681}
682
683pub fn all_tls13_suites() -> Vec<SupportedCipherSuite> {
685 vec![
686 tls13_aes_128_gcm_sha256(),
687 tls13_aes_256_gcm_sha384(),
688 tls13_chacha20_poly1305_sha256(),
689 tls13_aes_128_ccm_sha256(),
690 tls13_aes_128_ccm_8_sha256(),
691 ]
692}
693
694pub fn fips_tls13_suites() -> Vec<SupportedCipherSuite> {
696 vec![
697 tls13_aes_128_gcm_sha256(),
698 tls13_aes_256_gcm_sha384(),
699 tls13_aes_128_ccm_sha256(),
700 ]
701}