1use alloc::boxed::Box;
2use alloc::string::ToString;
3use core::fmt;
4
5use zeroize::Zeroize;
6
7use crate::enums::{ContentType, ProtocolVersion};
8use crate::error::{ApiMisuse, Error};
9use crate::msgs::codec;
10use crate::suites::ConnectionTrafficSecrets;
11
12mod messages;
13pub use messages::{
14 EncodedMessage, InboundOpaque, MessageError, OutboundOpaque, OutboundPlain, Payload,
15};
16
17mod record_layer;
18pub(crate) use record_layer::{Decrypted, PreEncryptAction, RecordLayer};
19
20pub trait Tls13AeadAlgorithm: Send + Sync {
22 fn encrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageEncrypter>;
24
25 fn decrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageDecrypter>;
27
28 fn key_len(&self) -> usize;
30
31 fn iv_len(&self) -> usize {
33 NONCE_LEN
34 }
35
36 fn extract_keys(
41 &self,
42 key: AeadKey,
43 iv: Iv,
44 ) -> Result<ConnectionTrafficSecrets, UnsupportedOperationError>;
45
46 fn fips(&self) -> bool {
48 false
49 }
50}
51
52pub trait Tls12AeadAlgorithm: Send + Sync + 'static {
54 fn encrypter(&self, key: AeadKey, iv: &[u8], extra: &[u8]) -> Box<dyn MessageEncrypter>;
63
64 fn decrypter(&self, key: AeadKey, iv: &[u8]) -> Box<dyn MessageDecrypter>;
70
71 fn key_block_shape(&self) -> KeyBlockShape;
74
75 fn extract_keys(
86 &self,
87 key: AeadKey,
88 iv: &[u8],
89 explicit: &[u8],
90 ) -> Result<ConnectionTrafficSecrets, UnsupportedOperationError>;
91
92 fn fips(&self) -> bool {
94 false
95 }
96}
97
98#[expect(clippy::exhaustive_structs)]
100#[derive(Debug, Eq, PartialEq, Clone, Copy)]
101pub struct UnsupportedOperationError;
102
103impl From<UnsupportedOperationError> for Error {
104 fn from(value: UnsupportedOperationError) -> Self {
105 Self::General(value.to_string())
106 }
107}
108
109impl fmt::Display for UnsupportedOperationError {
110 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
111 write!(f, "operation not supported")
112 }
113}
114
115#[cfg(feature = "std")]
116impl core::error::Error for UnsupportedOperationError {}
117
118#[expect(clippy::exhaustive_structs)]
122pub struct KeyBlockShape {
123 pub enc_key_len: usize,
129
130 pub fixed_iv_len: usize,
139
140 pub explicit_nonce_len: usize,
145}
146
147pub trait MessageDecrypter: Send + Sync {
149 fn decrypt<'a>(
152 &mut self,
153 msg: EncodedMessage<InboundOpaque<'a>>,
154 seq: u64,
155 ) -> Result<EncodedMessage<&'a [u8]>, Error>;
156}
157
158pub trait MessageEncrypter: Send + Sync {
160 fn encrypt(
163 &mut self,
164 msg: EncodedMessage<OutboundPlain<'_>>,
165 seq: u64,
166 ) -> Result<EncodedMessage<OutboundOpaque>, Error>;
167
168 fn encrypted_payload_len(&self, payload_len: usize) -> usize;
171}
172
173impl dyn MessageEncrypter {
174 pub(crate) fn invalid() -> Box<dyn MessageEncrypter> {
175 Box::new(InvalidMessageEncrypter {})
176 }
177}
178
179impl dyn MessageDecrypter {
180 pub(crate) fn invalid() -> Box<dyn MessageDecrypter> {
181 Box::new(InvalidMessageDecrypter {})
182 }
183}
184
185#[derive(Default, Clone)]
187pub struct Iv {
188 buf: [u8; Self::MAX_LEN],
189 used: usize,
190}
191
192impl Iv {
193 pub fn new(value: &[u8]) -> Result<Self, Error> {
197 if value.len() > Self::MAX_LEN {
198 return Err(ApiMisuse::IvLengthExceedsMaximum {
199 actual: value.len(),
200 maximum: Self::MAX_LEN,
201 }
202 .into());
203 }
204 let mut buf = [0u8; Self::MAX_LEN];
205 buf[..value.len()].copy_from_slice(value);
206 Ok(Self {
207 buf,
208 used: value.len(),
209 })
210 }
211
212 #[expect(clippy::len_without_is_empty)]
214 pub fn len(&self) -> usize {
215 self.used
216 }
217
218 pub const MAX_LEN: usize = 16;
220}
221
222impl From<[u8; NONCE_LEN]> for Iv {
223 fn from(bytes: [u8; NONCE_LEN]) -> Self {
224 Self::new(&bytes).expect("NONCE_LEN is within MAX_LEN")
225 }
226}
227
228impl AsRef<[u8]> for Iv {
229 fn as_ref(&self) -> &[u8] {
230 &self.buf[..self.used]
231 }
232}
233
234pub struct Nonce {
236 buf: [u8; Iv::MAX_LEN],
237 len: usize,
238}
239
240impl Nonce {
241 #[inline]
245 pub fn new(iv: &Iv, seq: u64) -> Self {
246 Self::new_inner(None, iv, seq)
247 }
248
249 pub fn quic(path_id: Option<u32>, iv: &Iv, pn: u64) -> Self {
254 Self::new_inner(path_id, iv, pn)
255 }
256
257 #[inline]
259 fn new_inner(path_id: Option<u32>, iv: &Iv, seq: u64) -> Self {
260 let iv_len = iv.len();
261 let mut buf = [0u8; Iv::MAX_LEN];
262
263 if iv_len >= 8 {
264 codec::put_u64(seq, &mut buf[iv_len - 8..iv_len]);
265 if let Some(path_id) = path_id {
266 if iv_len >= 12 {
267 buf[iv_len - 12..iv_len - 8].copy_from_slice(&path_id.to_be_bytes());
268 }
269 }
270 } else {
271 let seq_bytes = seq.to_be_bytes();
272 buf[..iv_len].copy_from_slice(&seq_bytes[8 - iv_len..]);
273 }
274
275 buf[..iv_len]
276 .iter_mut()
277 .zip(iv.as_ref())
278 .for_each(|(s, iv)| *s ^= *iv);
279
280 Self { buf, len: iv_len }
281 }
282
283 pub fn to_array<const N: usize>(&self) -> Result<[u8; N], Error> {
290 if self.len != N {
291 return Err(ApiMisuse::NonceArraySizeMismatch {
292 expected: N,
293 actual: self.len,
294 }
295 .into());
296 }
297 Ok(self.buf[..N]
298 .try_into()
299 .expect("nonce buffer conversion failed"))
300 }
301
302 pub fn as_bytes(&self) -> &[u8] {
304 &self.buf[..self.len]
305 }
306
307 #[expect(clippy::len_without_is_empty)]
309 pub fn len(&self) -> usize {
310 self.len
311 }
312}
313
314impl AsRef<[u8]> for Nonce {
315 fn as_ref(&self) -> &[u8] {
316 &self.buf[..self.len]
317 }
318}
319
320pub const NONCE_LEN: usize = 12;
323
324#[inline]
328pub fn make_tls13_aad(payload_len: usize) -> [u8; 5] {
329 let version = ProtocolVersion::TLSv1_2.to_array();
330 [
331 ContentType::ApplicationData.into(),
332 version[0],
334 version[1],
335 (payload_len >> 8) as u8,
336 (payload_len & 0xff) as u8,
337 ]
338}
339
340#[inline]
344pub fn make_tls12_aad(
345 seq: u64,
346 typ: ContentType,
347 vers: ProtocolVersion,
348 len: usize,
349) -> [u8; TLS12_AAD_SIZE] {
350 let mut out = [0; TLS12_AAD_SIZE];
351 codec::put_u64(seq, &mut out[0..]);
352 out[8] = typ.into();
353 codec::put_u16(vers.into(), &mut out[9..]);
354 codec::put_u16(len as u16, &mut out[11..]);
355 out
356}
357
358const TLS12_AAD_SIZE: usize = 8 + 1 + 2 + 2;
359
360pub struct AeadKey {
364 buf: [u8; Self::MAX_LEN],
365 used: usize,
366}
367
368impl AeadKey {
369 pub(crate) fn new(buf: &[u8]) -> Self {
370 debug_assert!(buf.len() <= Self::MAX_LEN);
371 let mut key = Self::from([0u8; Self::MAX_LEN]);
372 key.buf[..buf.len()].copy_from_slice(buf);
373 key.used = buf.len();
374 key
375 }
376
377 pub(crate) fn with_length(self, len: usize) -> Self {
378 assert!(len <= self.used);
379 Self {
380 buf: self.buf,
381 used: len,
382 }
383 }
384
385 pub(crate) const MAX_LEN: usize = 32;
387}
388
389impl Drop for AeadKey {
390 fn drop(&mut self) {
391 self.buf.zeroize();
392 }
393}
394
395impl AsRef<[u8]> for AeadKey {
396 fn as_ref(&self) -> &[u8] {
397 &self.buf[..self.used]
398 }
399}
400
401impl From<[u8; Self::MAX_LEN]> for AeadKey {
402 fn from(bytes: [u8; Self::MAX_LEN]) -> Self {
403 Self {
404 buf: bytes,
405 used: Self::MAX_LEN,
406 }
407 }
408}
409
410struct InvalidMessageEncrypter {}
412
413impl MessageEncrypter for InvalidMessageEncrypter {
414 fn encrypt(
415 &mut self,
416 _m: EncodedMessage<OutboundPlain<'_>>,
417 _seq: u64,
418 ) -> Result<EncodedMessage<OutboundOpaque>, Error> {
419 Err(Error::EncryptError)
420 }
421
422 fn encrypted_payload_len(&self, payload_len: usize) -> usize {
423 payload_len
424 }
425}
426
427struct InvalidMessageDecrypter {}
429
430impl MessageDecrypter for InvalidMessageDecrypter {
431 fn decrypt<'a>(
432 &mut self,
433 _m: EncodedMessage<InboundOpaque<'a>>,
434 _seq: u64,
435 ) -> Result<EncodedMessage<&'a [u8]>, Error> {
436 Err(Error::DecryptError)
437 }
438}
439
440#[cfg(all(test, feature = "aws-lc-rs"))]
441pub(crate) struct FakeAead;
442
443#[cfg(all(test, feature = "aws-lc-rs"))]
444impl Tls12AeadAlgorithm for FakeAead {
445 fn encrypter(&self, _: AeadKey, _: &[u8], _: &[u8]) -> Box<dyn MessageEncrypter> {
446 todo!()
447 }
448
449 fn decrypter(&self, _: AeadKey, _: &[u8]) -> Box<dyn MessageDecrypter> {
450 todo!()
451 }
452
453 fn key_block_shape(&self) -> KeyBlockShape {
454 todo!()
455 }
456
457 fn extract_keys(
458 &self,
459 _: AeadKey,
460 _: &[u8],
461 _: &[u8],
462 ) -> Result<ConnectionTrafficSecrets, UnsupportedOperationError> {
463 Err(UnsupportedOperationError)
464 }
465
466 fn fips(&self) -> bool {
467 false
468 }
469}
470
471#[cfg(test)]
472mod tests {
473 use super::*;
474
475 #[test]
478 fn multipath_nonce() {
479 const PATH_ID: u32 = 3;
480 const PN: u64 = 54321;
481 const IV: [u8; 16] = 0x6b26114b9cba2b63a9e8dd4fu128.to_be_bytes();
482 const EXPECTED_NONCE: [u8; 16] = 0x6b2611489cba2b63a9e8097eu128.to_be_bytes();
483 let nonce = Nonce::quic(Some(PATH_ID), &Iv::new(&IV[4..]).unwrap(), PN);
484 assert_eq!(&EXPECTED_NONCE[4..], nonce.as_bytes());
485 }
486
487 #[test]
488 fn iv_len() {
489 let iv = Iv::new(&[1u8; NONCE_LEN]).unwrap();
490 assert_eq!(iv.len(), NONCE_LEN);
491
492 let short_iv = Iv::new(&[1u8, 2, 3]).unwrap();
493 assert_eq!(short_iv.len(), 3);
494
495 let empty_iv = Iv::new(&[]).unwrap();
496 assert_eq!(empty_iv.len(), 0);
497 }
498
499 #[test]
500 fn iv_as_ref() {
501 let iv_data = [1u8, 2, 3, 4, 5];
502 let iv = Iv::new(&iv_data).unwrap();
503 let iv_ref: &[u8] = iv.as_ref();
504 assert_eq!(iv_ref, &iv_data);
505 }
506
507 #[test]
508 fn nonce_with_short_iv() {
509 let short_iv = Iv::new(&[0xAA, 0xBB, 0xCC, 0xDD]).unwrap();
510 let seq = 0x1122334455667788u64;
511 let nonce = Nonce::new(&short_iv, seq);
512
513 assert_eq!(nonce.len(), 4);
515 let seq_bytes = seq.to_be_bytes();
516 let expected = [
517 0xAA ^ seq_bytes[4],
518 0xBB ^ seq_bytes[5],
519 0xCC ^ seq_bytes[6],
520 0xDD ^ seq_bytes[7],
521 ];
522 assert_eq!(nonce.as_bytes(), &expected);
523 }
524
525 #[test]
526 fn nonce_len() {
527 let iv = Iv::new(&[1u8; NONCE_LEN]).unwrap();
528 let nonce = Nonce::new(&iv, 42);
529 assert_eq!(nonce.len(), NONCE_LEN);
530
531 let short_iv = Iv::new(&[1u8, 2]).unwrap();
532 let short_nonce = Nonce::new(&short_iv, 42);
533 assert_eq!(short_nonce.len(), 2);
534 }
535
536 #[test]
537 fn nonce_as_ref() {
538 let iv = Iv::new(&[1u8; NONCE_LEN]).unwrap();
539 let nonce = Nonce::new(&iv, 42);
540 let nonce_ref: &[u8] = nonce.as_ref();
541 assert_eq!(nonce_ref.len(), NONCE_LEN);
542 }
543
544 #[test]
545 fn nonce_to_array_correct_size() {
546 let iv = Iv::new(&[1u8; NONCE_LEN]).unwrap();
547 let nonce = Nonce::new(&iv, 42);
548 let array: [u8; NONCE_LEN] = nonce.to_array().unwrap();
549 assert_eq!(array.len(), NONCE_LEN);
550 }
551
552 #[test]
553 fn nonce_to_array_wrong_size() {
554 let iv = Iv::new(&[1u8; NONCE_LEN]).unwrap();
555 let nonce = Nonce::new(&iv, 42);
556 let result: Result<[u8; 16], Error> = nonce.to_array();
557 assert!(matches!(
558 result,
559 Err(Error::ApiMisuse(ApiMisuse::NonceArraySizeMismatch {
560 expected: 16,
561 actual: NONCE_LEN
562 }))
563 ));
564 }
565
566 #[test]
567 fn nonce_to_array_variable_length_error() {
568 let short_iv = Iv::new(&[0xAAu8; 8]).unwrap();
570 let nonce = Nonce::new(&short_iv, 42);
571
572 let result: Result<[u8; NONCE_LEN], Error> = nonce.to_array();
574 if let Err(Error::ApiMisuse(ApiMisuse::NonceArraySizeMismatch { expected, actual })) =
575 result
576 {
577 assert_eq!(expected, NONCE_LEN);
578 assert_eq!(actual, 8);
579 } else {
580 panic!("Expected Error::ApiMisuse(NonceArraySizeMismatch)");
581 }
582
583 let result_correct: Result<[u8; 8], Error> = nonce.to_array();
585 assert!(result_correct.is_ok());
586 }
587
588 #[test]
589 fn nonce_xor_with_iv() {
590 let iv_data = [0xFFu8; NONCE_LEN];
591 let iv = Iv::new(&iv_data).unwrap();
592 let seq = 0x0000000000000001u64;
593 let nonce = Nonce::new(&iv, seq);
594
595 let nonce_bytes = nonce.as_bytes();
597 assert_eq!(nonce_bytes[NONCE_LEN - 1], 0xFE);
598 }
599
600 #[test]
601 fn iv_length_exceeds_maximum() {
602 let too_long_iv = [0xAAu8; Iv::MAX_LEN + 1];
603 let result = Iv::new(&too_long_iv);
604
605 assert!(matches!(
606 result,
607 Err(Error::ApiMisuse(ApiMisuse::IvLengthExceedsMaximum {
608 actual: 17,
609 maximum: 16
610 }))
611 ));
612 }
613}