1use 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
30pub 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#[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#[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
204const TAG_LEN: usize = 16;
209
210pub(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
217enum 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 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#[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#[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 Err(UnsupportedOperationError)
558 }
559}
560
561pub(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 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 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 quic: None,
616};
617
618pub fn tls13_aes_128_gcm_sha256() -> SupportedCipherSuite {
620 SupportedCipherSuite::Tls13(&TLS13_AES_128_GCM_SHA256)
621}
622
623pub fn tls13_aes_256_gcm_sha384() -> SupportedCipherSuite {
625 SupportedCipherSuite::Tls13(&TLS13_AES_256_GCM_SHA384)
626}
627
628pub fn tls13_chacha20_poly1305_sha256() -> SupportedCipherSuite {
630 SupportedCipherSuite::Tls13(&TLS13_CHACHA20_POLY1305_SHA256)
631}
632
633pub fn tls13_aes_128_ccm_sha256() -> SupportedCipherSuite {
635 SupportedCipherSuite::Tls13(&TLS13_AES_128_CCM_SHA256)
636}
637
638pub 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
648pub 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}