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