1use alloc::vec::Vec;
2use core::ops::{Deref, DerefMut, Range};
3use core::{fmt, slice};
4
5use crate::Protocol;
6use crate::enums::{ContentType, ProtocolVersion};
7use crate::error::{ApiMisuse, Error, InvalidMessage, PeerMisbehaved};
8use crate::msgs::{Codec, HEADER_SIZE, MAX_FRAGMENT_LEN, Reader, hex, read_record_header};
9
10#[expect(clippy::exhaustive_structs)]
12#[derive(Clone, Debug)]
13pub struct Record<P> {
14 pub typ: ContentType,
16 pub version: EncodableVersion,
18 pub payload: P,
20}
21
22impl<P> Record<P> {
23 pub fn new(typ: ContentType, version: EncodableVersion, payload: P) -> Self {
25 Self {
26 typ,
27 version,
28 payload,
29 }
30 }
31}
32
33impl<'a> Record<Payload<'a>> {
34 pub(crate) fn read(r: &mut Reader<'a>) -> Result<Self, RecordError> {
39 let (typ, version, len) = read_record_header(r)?;
40
41 let content = r
42 .take(len as usize)
43 .ok_or(RecordError::TooShortForLength)?;
44
45 Ok(Self {
46 typ,
47 version: EncodableVersion::Legacy(version),
48 payload: Payload::Borrowed(content),
49 })
50 }
51
52 pub fn borrow_outbound(&'a self) -> Record<OutboundPlain<'a>> {
54 Record {
55 typ: self.typ,
56 version: self.version,
57 payload: self.payload.bytes().into(),
58 }
59 }
60
61 pub fn into_owned(self) -> Self {
63 Self {
64 typ: self.typ,
65 version: self.version,
66 payload: self.payload.into_owned(),
67 }
68 }
69}
70
71impl Record<&'_ [u8]> {
72 pub(crate) fn is_valid_ccs(&self) -> bool {
78 self.typ == ContentType::ChangeCipherSpec && self.payload == [0x01]
79 }
80}
81
82impl<'a> Record<InboundOpaque<'a>> {
83 pub fn into_tls13_unpadded_record(mut self) -> Result<Record<&'a [u8]>, Error> {
89 let payload = &mut self.payload;
90
91 if self.typ != ContentType::ApplicationData {
92 return Err(PeerMisbehaved::IllegalTls13ContentType.into());
93 }
94
95 if payload.len() > MAX_FRAGMENT_LEN.get() + 1 {
96 return Err(Error::PeerSentOversizedRecord);
97 }
98
99 self.typ = unpad_tls13_payload(payload);
100 if self.typ == ContentType(0) {
101 return Err(PeerMisbehaved::IllegalTlsInnerPlaintext.into());
102 }
103
104 if self.typ == ContentType::ChangeCipherSpec {
109 return Err(PeerMisbehaved::IllegalMiddleboxChangeCipherSpec.into());
110 }
111
112 if payload.len() > MAX_FRAGMENT_LEN.get() {
113 return Err(Error::PeerSentOversizedRecord);
114 }
115
116 self.version = EncodableVersion::Legacy(ProtocolVersion::TLSv1_3);
117 Ok(self.into_plain_record())
118 }
119
120 pub fn into_plain_record_range(self, range: Range<usize>) -> Record<&'a [u8]> {
129 Record {
130 typ: self.typ,
131 version: self.version,
132 payload: &self.payload.into_inner()[range],
133 }
134 }
135
136 pub fn into_plain_record(self) -> Record<&'a [u8]> {
142 Record {
143 typ: self.typ,
144 version: self.version,
145 payload: self.payload.into_inner(),
146 }
147 }
148}
149
150impl Record<OutboundPlain<'_>> {
151 pub(crate) fn to_unencrypted_bytes(&self) -> Vec<u8> {
154 let len = self.payload.len();
155 debug_assert!(len <= usize::from(u16::MAX));
156 let mut buf = Vec::with_capacity(HEADER_SIZE + len);
157 self.encode_unencrypted(&mut buf);
158 buf
159 }
160
161 pub(crate) fn encode_unencrypted(&self, buf: &mut Vec<u8>) {
162 let len = self.payload.len();
163 debug_assert!(len <= usize::from(u16::MAX));
164 buf.extend_from_slice(&encode_record_header(self.typ, self.version, len as u16));
165 self.payload.copy_to_vec(buf);
166 }
167}
168
169pub(crate) fn encode_record_header(
173 typ: ContentType,
174 version: EncodableVersion,
175 len: u16,
176) -> [u8; HEADER_SIZE] {
177 let [version_hi, version_lo] = version.encode().to_array();
178 let [len_hi, len_lo] = len.to_be_bytes();
179 [typ.into(), version_hi, version_lo, len_hi, len_lo]
180}
181
182#[non_exhaustive]
187#[derive(Debug, Clone)]
188pub enum OutboundPlain<'a> {
189 Single(&'a [u8]),
193 Multiple {
195 chunks: &'a [&'a [u8]],
197 start: usize,
202 end: usize,
206 },
207}
208
209impl<'a> OutboundPlain<'a> {
210 pub fn new(chunks: &'a [&'a [u8]]) -> Self {
213 if chunks.len() == 1 {
214 Self::Single(chunks[0])
215 } else {
216 Self::Multiple {
217 chunks,
218 start: 0,
219 end: chunks
220 .iter()
221 .map(|chunk| chunk.len())
222 .sum(),
223 }
224 }
225 }
226
227 pub fn new_empty() -> Self {
229 Self::Single(&[])
230 }
231
232 pub fn to_vec(&self) -> Vec<u8> {
234 let mut vec = Vec::with_capacity(self.len());
235 self.copy_to_vec(&mut vec);
236 vec
237 }
238
239 pub fn copy_to_vec(&self, vec: &mut Vec<u8>) {
241 for chunk in self.chunks() {
242 vec.extend_from_slice(chunk);
243 }
244 }
245
246 pub fn chunks(&self) -> impl Iterator<Item = &'a [u8]> + '_ {
250 match self {
251 Self::Single(chunk) => Chunks::Single((!chunk.is_empty()).then_some(*chunk)),
252 Self::Multiple { chunks, start, end } => Chunks::Multiple {
253 chunks: chunks.iter(),
254 skip: *start,
255 remaining: end - start,
256 },
257 }
258 }
259
260 pub fn single_chunk(&self) -> Option<&'a [u8]> {
266 if let Self::Single(chunk) = self {
267 return Some(chunk);
268 }
269 if self.is_empty() {
270 return Some(&[]);
271 }
272 let mut chunks = self.chunks();
273 let chunk = chunks.next()?;
274 (chunk.len() == self.len() && chunks.next().is_none()).then_some(chunk)
275 }
276
277 pub(crate) fn split_at(&self, mid: usize) -> (Self, Self) {
280 let (chunks, start, end) = match *self {
281 Self::Multiple { chunks, start, end } => (chunks, start, end),
282 Self::Single(chunk) => {
283 let mid = Ord::min(mid, chunk.len());
284 return (Self::Single(&chunk[..mid]), Self::Single(&chunk[mid..]));
285 }
286 };
287
288 let mid = Ord::min(start + mid, end);
289 let mut skip = 0;
290 let mut consumed = 0;
291 for chunk in chunks {
292 if consumed + chunk.len() > mid {
293 break;
294 }
295 consumed += chunk.len();
296 skip += 1;
297 }
298
299 (
300 Self::Multiple {
301 chunks,
302 start,
303 end: mid,
304 },
305 Self::Multiple {
306 chunks: &chunks[skip..],
307 start: mid - consumed,
308 end: end - consumed,
309 },
310 )
311 }
312
313 pub(crate) fn is_empty(&self) -> bool {
315 self.len() == 0
316 }
317
318 #[expect(clippy::len_without_is_empty)]
320 pub fn len(&self) -> usize {
321 match self {
322 Self::Single(chunk) => chunk.len(),
323 Self::Multiple { start, end, .. } => end - start,
324 }
325 }
326}
327
328enum Chunks<'a> {
330 Single(Option<&'a [u8]>),
331 Multiple {
332 chunks: slice::Iter<'a, &'a [u8]>,
334 skip: usize,
336 remaining: usize,
338 },
339}
340
341impl<'a> Iterator for Chunks<'a> {
342 type Item = &'a [u8];
343
344 fn next(&mut self) -> Option<Self::Item> {
345 let (chunks, skip, remaining) = match self {
346 Self::Single(chunk) => return chunk.take(),
347 Self::Multiple {
348 chunks,
349 skip,
350 remaining,
351 } => (chunks, skip, remaining),
352 };
353
354 loop {
355 if *remaining == 0 {
356 return None;
357 }
358
359 let chunk = chunks.next()?;
360 let Some((_, chunk)) = chunk.split_at_checked(*skip) else {
361 *skip -= chunk.len();
362 continue;
363 };
364
365 *skip = 0;
366 if chunk.is_empty() {
367 continue;
368 }
369
370 let take = Ord::min(chunk.len(), *remaining);
371 *remaining -= take;
372 return Some(&chunk[..take]);
373 }
374 }
375}
376
377impl<'a> From<&'a [u8]> for OutboundPlain<'a> {
378 fn from(payload: &'a [u8]) -> Self {
379 Self::Single(payload)
380 }
381}
382
383impl<'a, const N: usize> From<&'a [u8; N]> for OutboundPlain<'a> {
384 fn from(payload: &'a [u8; N]) -> Self {
385 Self::Single(payload)
386 }
387}
388
389impl<'a> From<&'a Vec<u8>> for OutboundPlain<'a> {
390 fn from(payload: &'a Vec<u8>) -> Self {
391 Self::Single(payload)
392 }
393}
394
395pub struct EncryptBuffer<'a> {
414 buf: &'a mut [u8],
415 used: usize,
416}
417
418impl<'a> EncryptBuffer<'a> {
419 pub fn new(out: &'a mut [u8], len: usize) -> Result<Self, Error> {
423 let provided = out.len();
424 match out.get_mut(..len) {
425 Some(buf) => Ok(Self { buf, used: 0 }),
426 None => Err(ApiMisuse::EncryptBufferTooSmall {
427 required: len,
428 provided,
429 }
430 .into()),
431 }
432 }
433
434 pub fn extend_from_chunks(&mut self, chunks: &OutboundPlain<'_>) {
440 match chunks {
441 OutboundPlain::Single(chunk) => self.extend_from_slice(chunk),
443 chunks => {
444 for chunk in chunks.chunks() {
445 self.extend_from_slice(chunk);
446 }
447 }
448 }
449 }
450
451 pub fn extend_from_slice(&mut self, slice: &[u8]) {
457 self.buf[self.used..self.used + slice.len()].copy_from_slice(slice);
458 self.used += slice.len();
459 }
460
461 pub fn into_written(self) -> &'a [u8] {
463 &self.buf[..self.used]
464 }
465}
466
467impl AsMut<[u8]> for EncryptBuffer<'_> {
468 fn as_mut(&mut self) -> &mut [u8] {
469 &mut self.buf[..self.used]
470 }
471}
472
473#[non_exhaustive]
480#[derive(Clone, Eq, PartialEq)]
481pub enum Payload<'a> {
482 Borrowed(&'a [u8]),
484 Owned(Vec<u8>),
486}
487
488impl<'a> Payload<'a> {
489 pub fn bytes(&'a self) -> &'a [u8] {
491 match self {
492 Self::Borrowed(bytes) => bytes,
493 Self::Owned(bytes) => bytes,
494 }
495 }
496
497 pub(crate) fn into_owned(self) -> Payload<'static> {
498 Payload::Owned(self.into_vec())
499 }
500
501 pub(crate) fn into_vec(self) -> Vec<u8> {
502 match self {
503 Self::Borrowed(bytes) => bytes.to_vec(),
504 Self::Owned(bytes) => bytes,
505 }
506 }
507
508 pub(crate) fn read(r: &mut Reader<'a>) -> Self {
509 Self::Borrowed(r.rest())
510 }
511}
512
513impl Payload<'static> {
514 pub fn new(bytes: impl Into<Vec<u8>>) -> Self {
516 Self::Owned(bytes.into())
517 }
518}
519
520impl<'a> Codec<'a> for Payload<'a> {
521 fn encode(&self, bytes: &mut Vec<u8>) {
522 bytes.extend_from_slice(self.bytes());
523 }
524
525 fn read(r: &mut Reader<'a>) -> Result<Self, InvalidMessage> {
526 Ok(Self::read(r))
527 }
528}
529
530impl fmt::Debug for Payload<'_> {
531 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
532 hex(f, self.bytes())
533 }
534}
535
536#[expect(clippy::exhaustive_structs)]
538pub struct InboundOpaque<'a>(pub &'a mut [u8]);
539
540impl<'a> InboundOpaque<'a> {
541 pub fn truncate(&mut self, len: usize) {
543 if len >= self.len() {
544 return;
545 }
546
547 self.0 = core::mem::take(&mut self.0)
548 .split_at_mut(len)
549 .0;
550 }
551
552 pub(crate) fn into_inner(self) -> &'a mut [u8] {
553 self.0
554 }
555
556 pub(crate) fn pop(&mut self) -> Option<u8> {
557 if self.is_empty() {
558 return None;
559 }
560
561 let len = self.len();
562 let last = self[len - 1];
563 self.truncate(len - 1);
564 Some(last)
565 }
566}
567
568impl Deref for InboundOpaque<'_> {
569 type Target = [u8];
570
571 fn deref(&self) -> &Self::Target {
572 self.0
573 }
574}
575
576impl DerefMut for InboundOpaque<'_> {
577 fn deref_mut(&mut self) -> &mut Self::Target {
578 self.0
579 }
580}
581
582#[derive(Clone, Copy, Debug, PartialEq, Eq)]
584#[non_exhaustive]
585pub enum EncodableVersion {
586 Legacy(ProtocolVersion),
593 InitialClientHello(Protocol),
600}
601
602impl EncodableVersion {
603 pub fn encode(&self) -> ProtocolVersion {
605 match self {
606 Self::Legacy(_) => ProtocolVersion::TLSv1_2,
607 Self::InitialClientHello(Protocol::Tcp | Protocol::Quic(_)) => ProtocolVersion::TLSv1_0,
608 }
609 }
610
611 pub fn version(&self) -> ProtocolVersion {
613 match self {
614 Self::Legacy(v) => *v,
615 Self::InitialClientHello(Protocol::Tcp | Protocol::Quic(_)) => ProtocolVersion::TLSv1_2,
616 }
617 }
618}
619
620fn unpad_tls13_payload(p: &mut InboundOpaque<'_>) -> ContentType {
628 loop {
629 match p.pop() {
630 Some(0) => {}
631 Some(content_type) => return ContentType::from(content_type),
632 None => return ContentType(0),
633 }
634 }
635}
636
637#[expect(missing_docs)]
639#[non_exhaustive]
640#[derive(Debug)]
641pub enum RecordError {
642 TooShortForHeader,
643 TooShortForLength,
644 InvalidEmptyPayload,
645 MessageTooLarge,
646 InvalidContentType,
647 UnknownProtocolVersion,
648}
649
650#[cfg(test)]
651mod tests {
652 use std::{println, vec};
653
654 use super::*;
655 use crate::quic;
656
657 #[test]
658 fn single_chunk_with_multiple_slices() {
659 let chunks: &[&[u8]] = &[&[], &[1, 2, 3], &[], &[4, 5, 6, 7], &[]];
660 let expected = [1, 2, 3, 4, 5, 6, 7];
661 for start in 0..=7 {
662 for end in start..=7 {
663 let (_, tail) = OutboundPlain::new(chunks).split_at(start);
664 let (plain, _) = tail.split_at(end - start);
665 let contiguous = start == end || end <= 3 || start >= 3;
666 let single_chunk = plain.single_chunk();
667 assert_eq!(single_chunk.is_some(), contiguous);
668 let Some(slice) = single_chunk else {
669 continue;
670 };
671 assert_eq!(slice, &expected[start..end]);
672 if !slice.is_empty() {
673 let source = if end <= 3 { chunks[1] } else { chunks[3] };
674 let offset = if end <= 3 { start } else { start - 3 };
675 assert_eq!(slice.as_ptr(), source[offset..].as_ptr());
676 }
677 }
678 }
679 }
680
681 #[test]
682 fn single_chunk_with_out_of_bounds_range() {
683 for start in [3, 5, 6] {
684 let plain = OutboundPlain::Multiple {
685 chunks: &[&[1, 2, 3], &[], &[4, 5], &[]],
686 start,
687 end: 7,
688 };
689 assert!(plain.single_chunk().is_none());
690 }
691 }
692
693 #[test]
694 fn single_chunk_borrows_payload() {
695 let data = [1, 2, 3];
696 let chunks: &[&[u8]] = &[&[], &data, &[]];
697 let slice = {
698 let plain = OutboundPlain::Multiple {
699 chunks,
700 start: 1,
701 end: 3,
702 };
703 plain.single_chunk().unwrap()
704 };
705 assert_eq!(slice, &data[1..]);
706 assert_eq!(slice.as_ptr(), data[1..].as_ptr());
707 }
708
709 #[test]
710 fn single_chunk_does_not_join_adjacent_slices() {
711 let owner = [1, 2, 3, 4];
712 let adjacent = [&owner[..2], &owner[2..]];
713 assert!(
714 OutboundPlain::new(&adjacent)
715 .single_chunk()
716 .is_none()
717 );
718 }
719
720 #[test]
721 fn single_chunk_empty_and_single_payloads() {
722 for plain in [
723 OutboundPlain::new_empty(),
724 OutboundPlain::new(&[]),
725 OutboundPlain::new(&[&[], &[]]),
726 ] {
727 assert_eq!(plain.single_chunk(), Some(&[][..]));
728 }
729 let data = [1, 2, 3];
730 for plain in [
731 OutboundPlain::from(data.as_slice()),
732 OutboundPlain::new(&[&data]),
733 ] {
734 let slice = plain.single_chunk().unwrap();
735 assert_eq!(slice, data);
736 assert_eq!(slice.as_ptr(), data.as_ptr());
737 }
738 }
739
740 #[test]
741 fn encrypt_buffer_appends() {
742 let mut space = [0u8; 8];
743 let mut buf = EncryptBuffer::new(&mut space[..], 6).unwrap();
744 buf.extend_from_slice(&[1, 2]);
745 buf.extend_from_chunks(&OutboundPlain::new(&[&[3u8, 4][..], &[5][..]]));
746 buf.extend_from_slice(&[6]);
747 assert_eq!(buf.as_mut(), &mut [1, 2, 3, 4, 5, 6]);
748 assert_eq!(buf.into_written(), &[1, 2, 3, 4, 5, 6]);
749 assert_eq!(space, [1, 2, 3, 4, 5, 6, 0, 0]);
750 }
751
752 #[test]
753 fn encrypt_buffer_rejects_short_buffer() {
754 let mut space = [0u8; 4];
755 assert!(matches!(
756 EncryptBuffer::new(&mut space[..], 5),
757 Err(Error::ApiMisuse(ApiMisuse::EncryptBufferTooSmall {
758 required: 5,
759 provided: 4,
760 }))
761 ));
762 }
763
764 #[test]
765 fn chunks_iteration() {
766 assert_eq!(
768 OutboundPlain::Single(&[1, 2, 3])
769 .chunks()
770 .collect::<Vec<_>>(),
771 [&[1u8, 2, 3][..]],
772 );
773 assert_eq!(
774 OutboundPlain::new_empty()
775 .chunks()
776 .count(),
777 0
778 );
779
780 let owner: Vec<&[u8]> = vec![&[], &[1, 2, 3], &[], &[4, 5], &[], &[6, 7], &[]];
783 let (_, tail) = OutboundPlain::new(&owner).split_at(1);
784 let (window, _) = tail.split_at(5);
785 assert_eq!(
786 window.chunks().collect::<Vec<_>>(),
787 [&[2u8, 3][..], &[4, 5][..], &[6][..]],
788 );
789 }
790
791 #[test]
792 fn split_at_with_single_slice() {
793 let owner: &[u8] = &[0, 1, 2, 3, 4, 5, 6, 7];
794 let borrowed_payload = OutboundPlain::Single(owner);
795
796 let (before, after) = borrowed_payload.split_at(6);
797 println!("before:{before:?}\nafter:{after:?}");
798 assert_eq!(before.to_vec(), &[0, 1, 2, 3, 4, 5]);
799 assert_eq!(after.to_vec(), &[6, 7]);
800 }
801
802 #[test]
803 fn split_at_with_multiple_slices() {
804 let owner: Vec<&[u8]> = vec![&[0, 1, 2, 3], &[4, 5], &[6, 7, 8], &[9, 10, 11, 12]];
805 let borrowed_payload = OutboundPlain::new(&owner);
806
807 let (before, after) = borrowed_payload.split_at(3);
808 println!("before:{before:?}\nafter:{after:?}");
809 assert_eq!(before.to_vec(), &[0, 1, 2]);
810 assert_eq!(after.to_vec(), &[3, 4, 5, 6, 7, 8, 9, 10, 11, 12]);
811
812 let (before, after) = borrowed_payload.split_at(8);
813 println!("before:{before:?}\nafter:{after:?}");
814 assert_eq!(before.to_vec(), &[0, 1, 2, 3, 4, 5, 6, 7]);
815 assert_eq!(after.to_vec(), &[8, 9, 10, 11, 12]);
816
817 let (before, after) = borrowed_payload.split_at(11);
818 println!("before:{before:?}\nafter:{after:?}");
819 assert_eq!(before.to_vec(), &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
820 assert_eq!(after.to_vec(), &[11, 12]);
821 }
822
823 #[test]
824 fn split_at_drops_consumed_chunks() {
825 let owner = vec![&[0, 1, 2][..], &[], &[3, 4], &[5], &[]];
826 let payload = OutboundPlain::new(&owner);
827
828 let (before, after) = payload.split_at(4);
829 assert_eq!(before.to_vec(), &[0, 1, 2, 3]);
830 assert_eq!(after.to_vec(), &[4, 5]);
831 let OutboundPlain::Multiple { chunks, start, end } = after else {
832 panic!("expected multiple chunks");
833 };
834 assert_eq!(chunks, &owner[2..]);
835 assert_eq!((start, end), (1, 3));
836
837 let (before, after) = after.split_at(1);
838 assert_eq!(before.to_vec(), &[4]);
839 assert_eq!(after.to_vec(), &[5]);
840 let OutboundPlain::Multiple { chunks, start, end } = after else {
841 panic!("expected multiple chunks");
842 };
843 assert_eq!(chunks, &owner[3..]);
844 assert_eq!((start, end), (0, 1));
845
846 let (before, after) = after.split_at(1);
847 assert_eq!(before.to_vec(), &[5]);
848 assert!(after.is_empty());
849 let OutboundPlain::Multiple { chunks, start, end } = after else {
850 panic!("expected multiple chunks");
851 };
852 assert!(chunks.is_empty());
853 assert_eq!((start, end), (0, 0));
854 }
855
856 #[test]
857 fn split_out_of_bounds() {
858 let owner: Vec<&[u8]> = vec![&[0, 1, 2, 3], &[4, 5], &[6, 7, 8], &[9, 10, 11, 12]];
859
860 let single_payload = OutboundPlain::Single(owner[0]);
861 let (before, after) = single_payload.split_at(17);
862 println!("before:{before:?}\nafter:{after:?}");
863 assert_eq!(before.to_vec(), &[0, 1, 2, 3]);
864 assert!(after.is_empty());
865
866 let multiple_payload = OutboundPlain::new(&owner);
867 let (before, after) = multiple_payload.split_at(17);
868 println!("before:{before:?}\nafter:{after:?}");
869 assert_eq!(before.to_vec(), &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]);
870 assert!(after.is_empty());
871
872 let empty_payload = OutboundPlain::new_empty();
873 let (before, after) = empty_payload.split_at(17);
874 println!("before:{before:?}\nafter:{after:?}");
875 assert!(before.is_empty());
876 assert!(after.is_empty());
877 }
878
879 #[test]
880 fn empty_slices_mixed() {
881 let owner: Vec<&[u8]> = vec![&[], &[], &[0], &[], &[1, 2], &[], &[3], &[4], &[], &[]];
882 let mut borrowed_payload = OutboundPlain::new(&owner);
883 let mut fragment_count = 0;
884 let mut fragment;
885 let expected_fragments: &[&[u8]] = &[&[0, 1], &[2, 3], &[4]];
886
887 while !borrowed_payload.is_empty() {
888 (fragment, borrowed_payload) = borrowed_payload.split_at(2);
889 println!("{fragment:?}");
890 assert_eq!(&expected_fragments[fragment_count], &fragment.to_vec());
891 fragment_count += 1;
892 }
893 assert_eq!(fragment_count, expected_fragments.len());
894 }
895
896 #[test]
897 fn exhaustive_splitting() {
898 let owner: Vec<u8> = (0..127).collect();
899 let slices = (0..7)
900 .map(|i| &owner[((1 << i) - 1)..((1 << (i + 1)) - 1)])
901 .collect::<Vec<_>>();
902 let payload = OutboundPlain::new(&slices);
903
904 assert_eq!(payload.to_vec(), owner);
905 println!("{payload:#?}");
906
907 for start in 0..128 {
908 for end in start..128 {
909 for mid in 0..(end - start) {
910 let witness = owner[start..end].split_at(mid);
911 let split_payload = payload
912 .split_at(end)
913 .0
914 .split_at(start)
915 .1
916 .split_at(mid);
917 assert_eq!(
918 witness.0,
919 split_payload.0.to_vec(),
920 "start: {start}, mid:{mid}, end:{end}"
921 );
922 assert_eq!(
923 witness.1,
924 split_payload.1.to_vec(),
925 "start: {start}, mid:{mid}, end:{end}"
926 );
927 }
928 }
929 }
930 }
931
932 #[test]
933 fn tls13_unpadded_record_rejects_protected_change_cipher_spec() {
934 let mut payload = [0x01u8, ContentType::ChangeCipherSpec.into(), 0x00];
935 let record = Record {
936 typ: ContentType::ApplicationData,
937 version: EncodableVersion::Legacy(ProtocolVersion::TLSv1_2),
938 payload: InboundOpaque(&mut payload),
939 };
940 assert_eq!(
941 record
942 .into_tls13_unpadded_record()
943 .unwrap_err(),
944 Error::PeerMisbehaved(PeerMisbehaved::IllegalMiddleboxChangeCipherSpec)
945 );
946 }
947
948 #[test]
949 fn record_encoding_version() {
950 for (version, expect) in [
951 (
952 EncodableVersion::InitialClientHello(Protocol::Tcp),
953 ProtocolVersion::TLSv1_0,
954 ),
955 (
956 EncodableVersion::InitialClientHello(Protocol::Quic(quic::Version::V2)),
957 ProtocolVersion::TLSv1_0,
958 ),
959 (
960 EncodableVersion::Legacy(ProtocolVersion::TLSv1_3),
961 ProtocolVersion::TLSv1_2,
962 ),
963 (
964 EncodableVersion::Legacy(ProtocolVersion::TLSv1_2),
965 ProtocolVersion::TLSv1_2,
966 ),
967 ] {
968 let record = Record {
969 typ: ContentType::Handshake,
970 version,
971 payload: OutboundPlain::Single(&[0, 1, 2, 3, 4]),
972 };
973 let encoded = record.to_unencrypted_bytes();
974 let decoded = Record::<Payload<'_>>::read(&mut Reader::new(&encoded)).unwrap();
975 assert_eq!(decoded.version.version(), expect);
976 }
977 }
978}