Skip to main content

rustls/crypto/cipher/
messages.rs

1use alloc::vec::Vec;
2use core::ops::{Deref, DerefMut, Range};
3use core::{fmt, slice};
4
5use crate::Protocol;
6use crate::crypto::cipher::EncryptionState;
7use crate::enums::{ContentType, ProtocolVersion};
8use crate::error::{ApiMisuse, Error, InvalidMessage, PeerMisbehaved};
9use crate::msgs::{Codec, HEADER_SIZE, MAX_FRAGMENT_LEN, Reader, hex, read_opaque_message_header};
10
11/// A TLS message with encoded (but not necessarily encrypted) payload.
12#[expect(clippy::exhaustive_structs)]
13#[derive(Clone, Debug)]
14pub struct EncodedMessage<P> {
15    /// The content type of this message.
16    pub typ: ContentType,
17    /// The protocol version of this message.
18    pub version: EncodableVersion,
19    /// The payload of this message.
20    pub payload: P,
21}
22
23impl<P> EncodedMessage<P> {
24    /// Create a new `EncodedMessage` with the given fields.
25    pub fn new(typ: ContentType, version: EncodableVersion, payload: P) -> Self {
26        Self {
27            typ,
28            version,
29            payload,
30        }
31    }
32}
33
34impl<'a> EncodedMessage<Payload<'a>> {
35    /// Construct by decoding from a [`Reader`].
36    ///
37    /// `MessageError` allows callers to distinguish between valid prefixes (might
38    /// become valid if we read more data) and invalid data.
39    pub(crate) fn read(r: &mut Reader<'a>) -> Result<Self, MessageError> {
40        let (typ, version, len) = read_opaque_message_header(r)?;
41
42        let content = r
43            .take(len as usize)
44            .ok_or(MessageError::TooShortForLength)?;
45
46        Ok(Self {
47            typ,
48            version: EncodableVersion::Legacy(version),
49            payload: Payload::Borrowed(content),
50        })
51    }
52
53    /// Borrow as an [`EncodedMessage<OutboundPlain<'a>>`].
54    pub fn borrow_outbound(&'a self) -> EncodedMessage<OutboundPlain<'a>> {
55        EncodedMessage {
56            typ: self.typ,
57            version: self.version,
58            payload: self.payload.bytes().into(),
59        }
60    }
61
62    /// Convert into an owned `EncodedMessage<Plain<'static>>`.
63    pub fn into_owned(self) -> Self {
64        Self {
65            typ: self.typ,
66            version: self.version,
67            payload: self.payload.into_owned(),
68        }
69    }
70}
71
72impl EncodedMessage<&'_ [u8]> {
73    /// Returns true if the payload is a CCS message.
74    ///
75    /// We passthrough ChangeCipherSpec messages in the deframer without decrypting them.
76    /// Note: this is prior to the record layer, so is unencrypted. See
77    /// third paragraph of section 5 in RFC 9846.
78    pub(crate) fn is_valid_ccs(&self) -> bool {
79        self.typ == ContentType::ChangeCipherSpec && self.payload == [0x01]
80    }
81}
82
83impl<'a> EncodedMessage<InboundOpaque<'a>> {
84    /// For TLS1.3 (only), checks the length msg.payload is valid and removes the padding.
85    ///
86    /// Returns an error if the message (pre-unpadding) is too long, or the padding is invalid,
87    /// or the message (post-unpadding) is too long.
88    pub fn into_tls13_unpadded_message(mut self) -> Result<EncodedMessage<&'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 payload.len() > MAX_FRAGMENT_LEN.get() {
105            return Err(Error::PeerSentOversizedRecord);
106        }
107
108        self.version = EncodableVersion::Legacy(ProtocolVersion::TLSv1_3);
109        Ok(self.into_plain_message())
110    }
111
112    /// Force conversion into a plaintext message.
113    ///
114    /// `range` restricts the resulting message: this function panics if it is out of range for
115    /// the underlying message payload.
116    ///
117    /// This should only be used for messages that are known to be in plaintext. Otherwise, the
118    /// [`EncodedMessage<InboundOpaque<'_>>`] should be decrypted into an
119    /// `EncodedMessage<&'_ [u8]>` using a `MessageDecrypter`.
120    pub fn into_plain_message_range(self, range: Range<usize>) -> EncodedMessage<&'a [u8]> {
121        EncodedMessage {
122            typ: self.typ,
123            version: self.version,
124            payload: &self.payload.into_inner()[range],
125        }
126    }
127
128    /// Force conversion into a plaintext message.
129    ///
130    /// This should only be used for messages that are known to be in plaintext. Otherwise, the
131    /// [`EncodedMessage<InboundOpaque<'a>>`] should be decrypted into a
132    /// `EncodedMessage<&'a [u8]>` using a `MessageDecrypter`.
133    pub fn into_plain_message(self) -> EncodedMessage<&'a [u8]> {
134        EncodedMessage {
135            typ: self.typ,
136            version: self.version,
137            payload: self.payload.into_inner(),
138        }
139    }
140}
141
142impl EncodedMessage<OutboundPlain<'_>> {
143    /// Encode this message into its unencrypted wire representation, including
144    /// its record header.
145    pub(crate) fn to_unencrypted_bytes(&self) -> Vec<u8> {
146        let len = self.payload.len();
147        debug_assert!(len <= usize::from(u16::MAX));
148        let mut buf = Vec::with_capacity(HEADER_SIZE + len);
149        self.encode_unencrypted(&mut buf);
150        buf
151    }
152
153    pub(crate) fn encode_unencrypted(&self, buf: &mut Vec<u8>) {
154        let len = self.payload.len();
155        debug_assert!(len <= usize::from(u16::MAX));
156        buf.extend_from_slice(&encode_record_header(self.typ, self.version, len as u16));
157        self.payload.copy_to_vec(buf);
158    }
159
160    #[expect(dead_code)]
161    pub(crate) fn encoded_len(&self, record_layer: &EncryptionState) -> usize {
162        HEADER_SIZE + record_layer.encrypted_len(self.payload.len())
163    }
164}
165
166/// Encode a TLS record header.
167///
168/// `typ`, `version` and `len` describe the record's payload.
169pub(crate) fn encode_record_header(
170    typ: ContentType,
171    version: EncodableVersion,
172    len: u16,
173) -> [u8; HEADER_SIZE] {
174    let [version_hi, version_lo] = version.encode().to_array();
175    let [len_hi, len_lo] = len.to_be_bytes();
176    [typ.into(), version_hi, version_lo, len_hi, len_lo]
177}
178
179/// A collection of borrowed plaintext slices.
180///
181/// Warning: OutboundPlain does not guarantee that the simplest variant is used.
182/// Multiple can hold non fragmented or empty payloads.
183#[non_exhaustive]
184#[derive(Debug, Clone)]
185pub enum OutboundPlain<'a> {
186    /// A single byte slice.
187    ///
188    /// Contrary to `Multiple`, this uses a single pointer indirection
189    Single(&'a [u8]),
190    /// A collection of chunks (byte slices).
191    Multiple {
192        /// A collection of byte slices that hold the buffered data.
193        chunks: &'a [&'a [u8]],
194        /// Offset of the payload's first byte within the logical
195        /// concatenation of all `chunks`.
196        ///
197        /// This may point beyond the first chunk (for example, after
198        /// `split_at()`).
199        start: usize,
200        /// Offset one past the payload's last byte within the logical
201        /// concatenation of all `chunks`, so `end - start` is the payload's
202        /// length in bytes.
203        end: usize,
204    },
205}
206
207impl<'a> OutboundPlain<'a> {
208    /// Create a payload from a slice of byte slices.
209    /// If fragmented the cursors are added by default: start = 0, end = length
210    pub fn new(chunks: &'a [&'a [u8]]) -> Self {
211        if chunks.len() == 1 {
212            Self::Single(chunks[0])
213        } else {
214            Self::Multiple {
215                chunks,
216                start: 0,
217                end: chunks
218                    .iter()
219                    .map(|chunk| chunk.len())
220                    .sum(),
221            }
222        }
223    }
224
225    /// Create a payload with a single empty slice
226    pub fn new_empty() -> Self {
227        Self::Single(&[])
228    }
229
230    /// Flatten the slice of byte slices to an owned vector of bytes
231    pub fn to_vec(&self) -> Vec<u8> {
232        let mut vec = Vec::with_capacity(self.len());
233        self.copy_to_vec(&mut vec);
234        vec
235    }
236
237    /// Append all bytes to a vector
238    pub fn copy_to_vec(&self, vec: &mut Vec<u8>) {
239        for chunk in self.chunks() {
240            vec.extend_from_slice(chunk);
241        }
242    }
243
244    /// Iterate over the payload's chunks of bytes, in order.
245    ///
246    /// Empty chunks are not yielded.
247    pub fn chunks(&self) -> impl Iterator<Item = &[u8]> + '_ {
248        match self {
249            Self::Single(chunk) => Chunks::Single((!chunk.is_empty()).then_some(*chunk)),
250            Self::Multiple { chunks, start, end } => Chunks::Multiple {
251                chunks: chunks.iter(),
252                skip: *start,
253                remaining: end - start,
254            },
255        }
256    }
257
258    /// The payload's single contiguous chunk, or `None` if it is fragmented.
259    ///
260    /// An empty payload is treated as a single empty chunk, and a [`Self::Multiple`]
261    /// payload yields `None` even when its chunks happen to form a contiguous whole.
262    pub fn single_chunk(&self) -> Option<&'a [u8]> {
263        match *self {
264            Self::Single(chunk) => Some(chunk),
265            Self::Multiple { .. } => None,
266        }
267    }
268
269    /// Split self in two, around an index
270    /// Works similarly to `split_at` in the core library, except it doesn't panic if out of bound
271    pub(crate) fn split_at(&self, mid: usize) -> (Self, Self) {
272        match *self {
273            Self::Single(chunk) => {
274                let mid = Ord::min(mid, chunk.len());
275                (Self::Single(&chunk[..mid]), Self::Single(&chunk[mid..]))
276            }
277            Self::Multiple { chunks, start, end } => {
278                let mid = Ord::min(start + mid, end);
279                (
280                    Self::Multiple {
281                        chunks,
282                        start,
283                        end: mid,
284                    },
285                    Self::Multiple {
286                        chunks,
287                        start: mid,
288                        end,
289                    },
290                )
291            }
292        }
293    }
294
295    /// Returns true if the payload is empty
296    pub(crate) fn is_empty(&self) -> bool {
297        self.len() == 0
298    }
299
300    /// Returns the cumulative length of all chunks
301    #[expect(clippy::len_without_is_empty)]
302    pub fn len(&self) -> usize {
303        match self {
304            Self::Single(chunk) => chunk.len(),
305            Self::Multiple { start, end, .. } => end - start,
306        }
307    }
308}
309
310/// Iterator over an [`OutboundPlain`]'s chunks, returned by [`OutboundPlain::chunks()`].
311enum Chunks<'a> {
312    Single(Option<&'a [u8]>),
313    Multiple {
314        /// Chunks not yet visited, including any leading ones `skip` covers.
315        chunks: slice::Iter<'a, &'a [u8]>,
316        /// How many leading bytes remain to be skipped.
317        skip: usize,
318        /// How many bytes remain to be yielded.
319        remaining: usize,
320    },
321}
322
323impl<'a> Iterator for Chunks<'a> {
324    type Item = &'a [u8];
325
326    fn next(&mut self) -> Option<Self::Item> {
327        let (chunks, skip, remaining) = match self {
328            Self::Single(chunk) => return chunk.take(),
329            Self::Multiple {
330                chunks,
331                skip,
332                remaining,
333            } => (chunks, skip, remaining),
334        };
335
336        loop {
337            if *remaining == 0 {
338                return None;
339            }
340
341            let chunk = chunks.next()?;
342            let Some((_, chunk)) = chunk.split_at_checked(*skip) else {
343                *skip -= chunk.len();
344                continue;
345            };
346
347            *skip = 0;
348            if chunk.is_empty() {
349                continue;
350            }
351
352            let take = Ord::min(chunk.len(), *remaining);
353            *remaining -= take;
354            return Some(&chunk[..take]);
355        }
356    }
357}
358
359impl<'a> From<&'a [u8]> for OutboundPlain<'a> {
360    fn from(payload: &'a [u8]) -> Self {
361        Self::Single(payload)
362    }
363}
364
365impl<'a, const N: usize> From<&'a [u8; N]> for OutboundPlain<'a> {
366    fn from(payload: &'a [u8; N]) -> Self {
367        Self::Single(payload)
368    }
369}
370
371impl<'a> From<&'a Vec<u8>> for OutboundPlain<'a> {
372    fn from(payload: &'a Vec<u8>) -> Self {
373        Self::Single(payload)
374    }
375}
376
377/// A fixed-size buffer into which a [`MessageEncrypter`][] writes an encrypted message payload.
378///
379/// This wraps the output buffer passed to [`MessageEncrypter::encrypt()`][], tracking how
380/// much of it has been written as the append methods fill it front-to-back. It writes
381/// into caller-owned memory and cannot grow. [`Self::new()`] checks that the caller's
382/// buffer can hold the `len` bytes the encrypter declared, and the append methods then
383/// panic if the writes exceed that length.
384///
385/// Such a panic always indicates a bug in the `MessageEncrypter` implementation, not a
386/// runtime condition the caller can handle. The same implementation declares the total
387/// length up front (via [`MessageEncrypter::encrypted_payload_len()`]) and performs the
388/// writes, so overflowing the buffer means the two disagree. The record layer also
389/// relies on that declared length for framing, so there is no way to recover from the
390/// mismatch after the fact.
391///
392/// [`MessageEncrypter`]: crate::crypto::cipher::MessageEncrypter
393/// [`MessageEncrypter::encrypt()`]: crate::crypto::cipher::MessageEncrypter::encrypt()
394/// [`MessageEncrypter::encrypted_payload_len()`]: crate::crypto::cipher::MessageEncrypter::encrypted_payload_len()
395pub struct EncryptBuffer<'a> {
396    buf: &'a mut [u8],
397    used: usize,
398}
399
400impl<'a> EncryptBuffer<'a> {
401    /// Wrap the first `len` bytes of `out`, all of which are as yet unwritten.
402    ///
403    /// Returns [`ApiMisuse::EncryptBufferTooSmall`] if `out` is shorter than `len` bytes.
404    pub fn new(out: &'a mut [u8], len: usize) -> Result<Self, Error> {
405        let provided = out.len();
406        match out.get_mut(..len) {
407            Some(buf) => Ok(Self { buf, used: 0 }),
408            None => Err(ApiMisuse::EncryptBufferTooSmall {
409                required: len,
410                provided,
411            }
412            .into()),
413        }
414    }
415
416    /// Append bytes from an `OutboundPlain`'s chunks.
417    ///
418    /// Panics if the write would extend beyond the `len` given to [`Self::new()`],
419    /// which indicates a bug in the calling `MessageEncrypter` implementation (see
420    /// the type-level documentation).
421    pub fn extend_from_chunks(&mut self, chunks: &OutboundPlain<'_>) {
422        match chunks {
423            // for the common case with a single chunk we want to avoid iteration overhead.
424            OutboundPlain::Single(chunk) => self.extend_from_slice(chunk),
425            chunks => {
426                for chunk in chunks.chunks() {
427                    self.extend_from_slice(chunk);
428                }
429            }
430        }
431    }
432
433    /// Append bytes from a slice.
434    ///
435    /// Panics if the write would extend beyond the `len` given to [`Self::new()`],
436    /// which indicates a bug in the calling `MessageEncrypter` implementation (see
437    /// the type-level documentation).
438    pub fn extend_from_slice(&mut self, slice: &[u8]) {
439        self.buf[self.used..self.used + slice.len()].copy_from_slice(slice);
440        self.used += slice.len();
441    }
442
443    /// Consume this value, returning the written prefix of the wrapped buffer.
444    pub fn into_written(self) -> &'a [u8] {
445        &self.buf[..self.used]
446    }
447}
448
449impl AsMut<[u8]> for EncryptBuffer<'_> {
450    fn as_mut(&mut self) -> &mut [u8] {
451        &mut self.buf[..self.used]
452    }
453}
454
455/// An externally length'd payload
456///
457/// When encountered in an [`EncodedMessage`], it represents a plaintext payload. It can be
458/// decrypted from an [`InboundOpaque`] or encrypted by a
459/// [`MessageEncrypter`](crate::crypto::cipher::MessageEncrypter), and it is also used for
460/// joining and fragmenting.
461#[non_exhaustive]
462#[derive(Clone, Eq, PartialEq)]
463pub enum Payload<'a> {
464    /// Borrowed payload
465    Borrowed(&'a [u8]),
466    /// Owned payload
467    Owned(Vec<u8>),
468}
469
470impl<'a> Payload<'a> {
471    /// A reference to the payload's bytes
472    pub fn bytes(&'a self) -> &'a [u8] {
473        match self {
474            Self::Borrowed(bytes) => bytes,
475            Self::Owned(bytes) => bytes,
476        }
477    }
478
479    pub(crate) fn into_owned(self) -> Payload<'static> {
480        Payload::Owned(self.into_vec())
481    }
482
483    pub(crate) fn into_vec(self) -> Vec<u8> {
484        match self {
485            Self::Borrowed(bytes) => bytes.to_vec(),
486            Self::Owned(bytes) => bytes,
487        }
488    }
489
490    pub(crate) fn read(r: &mut Reader<'a>) -> Self {
491        Self::Borrowed(r.rest())
492    }
493}
494
495impl Payload<'static> {
496    /// Create a new owned payload from the given `bytes`.
497    pub fn new(bytes: impl Into<Vec<u8>>) -> Self {
498        Self::Owned(bytes.into())
499    }
500}
501
502impl<'a> Codec<'a> for Payload<'a> {
503    fn encode(&self, bytes: &mut Vec<u8>) {
504        bytes.extend_from_slice(self.bytes());
505    }
506
507    fn read(r: &mut Reader<'a>) -> Result<Self, InvalidMessage> {
508        Ok(Self::read(r))
509    }
510}
511
512impl fmt::Debug for Payload<'_> {
513    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
514        hex(f, self.bytes())
515    }
516}
517
518/// A borrowed payload buffer.
519#[expect(clippy::exhaustive_structs)]
520pub struct InboundOpaque<'a>(pub &'a mut [u8]);
521
522impl<'a> InboundOpaque<'a> {
523    /// Truncate the payload to `len` bytes.
524    pub fn truncate(&mut self, len: usize) {
525        if len >= self.len() {
526            return;
527        }
528
529        self.0 = core::mem::take(&mut self.0)
530            .split_at_mut(len)
531            .0;
532    }
533
534    pub(crate) fn into_inner(self) -> &'a mut [u8] {
535        self.0
536    }
537
538    pub(crate) fn pop(&mut self) -> Option<u8> {
539        if self.is_empty() {
540            return None;
541        }
542
543        let len = self.len();
544        let last = self[len - 1];
545        self.truncate(len - 1);
546        Some(last)
547    }
548}
549
550impl Deref for InboundOpaque<'_> {
551    type Target = [u8];
552
553    fn deref(&self) -> &Self::Target {
554        self.0
555    }
556}
557
558impl DerefMut for InboundOpaque<'_> {
559    fn deref_mut(&mut self) -> &mut Self::Target {
560        self.0
561    }
562}
563
564/// A protocol version that can be encoded.
565#[derive(Clone, Copy, Debug, PartialEq, Eq)]
566#[non_exhaustive]
567pub enum EncodableVersion {
568    /// Encode the version in legacy, backward-compatible form.
569    ///
570    /// > MUST be set to 0x0303 for all records generated by a TLS 1.3
571    /// > implementation...
572    ///
573    /// <https://www.rfc-editor.org/info/rfc9846/#section-5.1>
574    Legacy(ProtocolVersion),
575    /// Encode the version as an initial client hello, not a retry.
576    ///
577    /// > ...other than an initial ClientHello (i.e., one not generated after a HelloRetryRequest),
578    /// > where it MAY also be 0x0301 for compatibility purposes.
579    ///
580    /// <https://www.rfc-editor.org/info/rfc9846/#section-5.1>
581    InitialClientHello(Protocol),
582}
583
584impl EncodableVersion {
585    /// Encode the protocol version.
586    pub fn encode(&self) -> ProtocolVersion {
587        match self {
588            Self::Legacy(_) => ProtocolVersion::TLSv1_2,
589            Self::InitialClientHello(Protocol::Tcp | Protocol::Quic(_)) => ProtocolVersion::TLSv1_0,
590        }
591    }
592
593    /// The actual protocol version in use.
594    pub fn version(&self) -> ProtocolVersion {
595        match self {
596            Self::Legacy(v) => *v,
597            Self::InitialClientHello(Protocol::Tcp | Protocol::Quic(_)) => ProtocolVersion::TLSv1_2,
598        }
599    }
600}
601
602/// Decode a TLS1.3 `TLSInnerPlaintext` encoding.
603///
604/// `p` is a message payload, immediately post-decryption.  This function
605/// removes zero padding bytes, until a non-zero byte is encountered which is
606/// the content type, which is returned.  See RFC 9846 s5.2.
607///
608/// ContentType(0) is returned if the message payload is empty or all zeroes.
609fn unpad_tls13_payload(p: &mut InboundOpaque<'_>) -> ContentType {
610    loop {
611        match p.pop() {
612            Some(0) => {}
613            Some(content_type) => return ContentType::from(content_type),
614            None => return ContentType(0),
615        }
616    }
617}
618
619/// Errors from trying to parse a TLS message.
620#[expect(missing_docs)]
621#[non_exhaustive]
622#[derive(Debug)]
623pub enum MessageError {
624    TooShortForHeader,
625    TooShortForLength,
626    InvalidEmptyPayload,
627    MessageTooLarge,
628    InvalidContentType,
629    UnknownProtocolVersion,
630}
631
632#[cfg(test)]
633mod tests {
634    use std::{println, vec};
635
636    use super::*;
637    use crate::quic;
638
639    #[test]
640    fn encrypt_buffer_appends() {
641        let mut space = [0u8; 8];
642        let mut buf = EncryptBuffer::new(&mut space[..], 6).unwrap();
643        buf.extend_from_slice(&[1, 2]);
644        buf.extend_from_chunks(&OutboundPlain::new(&[&[3u8, 4][..], &[5][..]]));
645        buf.extend_from_slice(&[6]);
646        assert_eq!(buf.as_mut(), &mut [1, 2, 3, 4, 5, 6]);
647        assert_eq!(buf.into_written(), &[1, 2, 3, 4, 5, 6]);
648        assert_eq!(space, [1, 2, 3, 4, 5, 6, 0, 0]);
649    }
650
651    #[test]
652    fn encrypt_buffer_rejects_short_buffer() {
653        let mut space = [0u8; 4];
654        assert!(matches!(
655            EncryptBuffer::new(&mut space[..], 5),
656            Err(Error::ApiMisuse(ApiMisuse::EncryptBufferTooSmall {
657                required: 5,
658                provided: 4,
659            }))
660        ));
661    }
662
663    #[test]
664    fn chunks_iteration() {
665        // `Single` yields its chunk, unless empty
666        assert_eq!(
667            OutboundPlain::Single(&[1, 2, 3])
668                .chunks()
669                .collect::<Vec<_>>(),
670            [&[1u8, 2, 3][..]],
671        );
672        assert_eq!(
673            OutboundPlain::new_empty()
674                .chunks()
675                .count(),
676            0
677        );
678
679        // `Multiple` yields the in-window part of each chunk, skipping
680        // empty chunks
681        let owner: Vec<&[u8]> = vec![&[], &[1, 2, 3], &[], &[4, 5], &[], &[6, 7], &[]];
682        let (_, tail) = OutboundPlain::new(&owner).split_at(1);
683        let (window, _) = tail.split_at(5);
684        assert_eq!(
685            window.chunks().collect::<Vec<_>>(),
686            [&[2u8, 3][..], &[4, 5][..], &[6][..]],
687        );
688    }
689
690    #[test]
691    fn split_at_with_single_slice() {
692        let owner: &[u8] = &[0, 1, 2, 3, 4, 5, 6, 7];
693        let borrowed_payload = OutboundPlain::Single(owner);
694
695        let (before, after) = borrowed_payload.split_at(6);
696        println!("before:{before:?}\nafter:{after:?}");
697        assert_eq!(before.to_vec(), &[0, 1, 2, 3, 4, 5]);
698        assert_eq!(after.to_vec(), &[6, 7]);
699    }
700
701    #[test]
702    fn split_at_with_multiple_slices() {
703        let owner: Vec<&[u8]> = vec![&[0, 1, 2, 3], &[4, 5], &[6, 7, 8], &[9, 10, 11, 12]];
704        let borrowed_payload = OutboundPlain::new(&owner);
705
706        let (before, after) = borrowed_payload.split_at(3);
707        println!("before:{before:?}\nafter:{after:?}");
708        assert_eq!(before.to_vec(), &[0, 1, 2]);
709        assert_eq!(after.to_vec(), &[3, 4, 5, 6, 7, 8, 9, 10, 11, 12]);
710
711        let (before, after) = borrowed_payload.split_at(8);
712        println!("before:{before:?}\nafter:{after:?}");
713        assert_eq!(before.to_vec(), &[0, 1, 2, 3, 4, 5, 6, 7]);
714        assert_eq!(after.to_vec(), &[8, 9, 10, 11, 12]);
715
716        let (before, after) = borrowed_payload.split_at(11);
717        println!("before:{before:?}\nafter:{after:?}");
718        assert_eq!(before.to_vec(), &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
719        assert_eq!(after.to_vec(), &[11, 12]);
720    }
721
722    #[test]
723    fn split_out_of_bounds() {
724        let owner: Vec<&[u8]> = vec![&[0, 1, 2, 3], &[4, 5], &[6, 7, 8], &[9, 10, 11, 12]];
725
726        let single_payload = OutboundPlain::Single(owner[0]);
727        let (before, after) = single_payload.split_at(17);
728        println!("before:{before:?}\nafter:{after:?}");
729        assert_eq!(before.to_vec(), &[0, 1, 2, 3]);
730        assert!(after.is_empty());
731
732        let multiple_payload = OutboundPlain::new(&owner);
733        let (before, after) = multiple_payload.split_at(17);
734        println!("before:{before:?}\nafter:{after:?}");
735        assert_eq!(before.to_vec(), &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]);
736        assert!(after.is_empty());
737
738        let empty_payload = OutboundPlain::new_empty();
739        let (before, after) = empty_payload.split_at(17);
740        println!("before:{before:?}\nafter:{after:?}");
741        assert!(before.is_empty());
742        assert!(after.is_empty());
743    }
744
745    #[test]
746    fn empty_slices_mixed() {
747        let owner: Vec<&[u8]> = vec![&[], &[], &[0], &[], &[1, 2], &[], &[3], &[4], &[], &[]];
748        let mut borrowed_payload = OutboundPlain::new(&owner);
749        let mut fragment_count = 0;
750        let mut fragment;
751        let expected_fragments: &[&[u8]] = &[&[0, 1], &[2, 3], &[4]];
752
753        while !borrowed_payload.is_empty() {
754            (fragment, borrowed_payload) = borrowed_payload.split_at(2);
755            println!("{fragment:?}");
756            assert_eq!(&expected_fragments[fragment_count], &fragment.to_vec());
757            fragment_count += 1;
758        }
759        assert_eq!(fragment_count, expected_fragments.len());
760    }
761
762    #[test]
763    fn exhaustive_splitting() {
764        let owner: Vec<u8> = (0..127).collect();
765        let slices = (0..7)
766            .map(|i| &owner[((1 << i) - 1)..((1 << (i + 1)) - 1)])
767            .collect::<Vec<_>>();
768        let payload = OutboundPlain::new(&slices);
769
770        assert_eq!(payload.to_vec(), owner);
771        println!("{payload:#?}");
772
773        for start in 0..128 {
774            for end in start..128 {
775                for mid in 0..(end - start) {
776                    let witness = owner[start..end].split_at(mid);
777                    let split_payload = payload
778                        .split_at(end)
779                        .0
780                        .split_at(start)
781                        .1
782                        .split_at(mid);
783                    assert_eq!(
784                        witness.0,
785                        split_payload.0.to_vec(),
786                        "start: {start}, mid:{mid}, end:{end}"
787                    );
788                    assert_eq!(
789                        witness.1,
790                        split_payload.1.to_vec(),
791                        "start: {start}, mid:{mid}, end:{end}"
792                    );
793                }
794            }
795        }
796    }
797
798    #[test]
799    fn encoded_message_encoding_version() {
800        for (version, expect) in [
801            (
802                EncodableVersion::InitialClientHello(Protocol::Tcp),
803                ProtocolVersion::TLSv1_0,
804            ),
805            (
806                EncodableVersion::InitialClientHello(Protocol::Quic(quic::Version::V2)),
807                ProtocolVersion::TLSv1_0,
808            ),
809            (
810                EncodableVersion::Legacy(ProtocolVersion::TLSv1_3),
811                ProtocolVersion::TLSv1_2,
812            ),
813            (
814                EncodableVersion::Legacy(ProtocolVersion::TLSv1_2),
815                ProtocolVersion::TLSv1_2,
816            ),
817        ] {
818            let encoded_message = EncodedMessage {
819                typ: ContentType::Handshake,
820                version,
821                payload: OutboundPlain::Single(&[0, 1, 2, 3, 4]),
822            };
823            let encoded = encoded_message.to_unencrypted_bytes();
824            let decoded = EncodedMessage::<Payload<'_>>::read(&mut Reader::new(&encoded)).unwrap();
825            assert_eq!(decoded.version.version(), expect);
826        }
827    }
828}