rustls/crypto/cipher/
messages.rs

1use alloc::vec::Vec;
2use core::fmt;
3use core::ops::{Deref, DerefMut, Range};
4
5use crate::crypto::cipher::RecordLayer;
6use crate::enums::{ContentType, ProtocolVersion};
7use crate::error::{Error, InvalidMessage, PeerMisbehaved};
8use crate::msgs::base::hex;
9use crate::msgs::codec::{Codec, Reader};
10use crate::msgs::fragmenter::MAX_FRAGMENT_LEN;
11use crate::msgs::message::{HEADER_SIZE, read_opaque_message_header};
12
13/// A TLS message with encoded (but not necessarily encrypted) payload.
14#[expect(clippy::exhaustive_structs)]
15#[derive(Clone, Debug)]
16pub struct EncodedMessage<P> {
17    /// The content type of this message.
18    pub typ: ContentType,
19    /// The protocol version of this message.
20    pub version: ProtocolVersion,
21    /// The payload of this message.
22    pub payload: P,
23}
24
25impl<P> EncodedMessage<P> {
26    /// Create a new `EncodedMessage` with the given fields.
27    pub fn new(typ: ContentType, version: ProtocolVersion, payload: P) -> Self {
28        Self {
29            typ,
30            version,
31            payload,
32        }
33    }
34}
35
36impl<'a> EncodedMessage<Payload<'a>> {
37    /// Construct by decoding from a [`Reader`].
38    ///
39    /// `MessageError` allows callers to distinguish between valid prefixes (might
40    /// become valid if we read more data) and invalid data.
41    pub fn read(r: &mut Reader<'a>) -> Result<Self, MessageError> {
42        let (typ, version, len) = read_opaque_message_header(r)?;
43
44        let content = r
45            .take(len as usize)
46            .ok_or(MessageError::TooShortForLength)?;
47
48        Ok(Self {
49            typ,
50            version,
51            payload: Payload::Borrowed(content),
52        })
53    }
54
55    /// Convert into an unencrypted [`EncodedMessage<OutboundOpaque>`] (without decrypting).
56    pub fn into_unencrypted_opaque(self) -> EncodedMessage<OutboundOpaque> {
57        EncodedMessage {
58            version: self.version,
59            typ: self.typ,
60            payload: OutboundOpaque::from(self.payload.bytes()),
61        }
62    }
63
64    /// Borrow as an [`EncodedMessage<OutboundPlain<'a>>`].
65    pub fn borrow_outbound(&'a self) -> EncodedMessage<OutboundPlain<'a>> {
66        EncodedMessage {
67            version: self.version,
68            typ: self.typ,
69            payload: self.payload.bytes().into(),
70        }
71    }
72
73    /// Convert into an owned `EncodedMessage<Plain<'static>>`.
74    pub fn into_owned(self) -> Self {
75        Self {
76            typ: self.typ,
77            version: self.version,
78            payload: self.payload.into_owned(),
79        }
80    }
81}
82
83impl EncodedMessage<&'_ [u8]> {
84    /// Returns true if the payload is a CCS message.
85    ///
86    /// We passthrough ChangeCipherSpec messages in the deframer without decrypting them.
87    /// Note: this is prior to the record layer, so is unencrypted. See
88    /// third paragraph of section 5 in RFC8446.
89    pub(crate) fn is_valid_ccs(&self) -> bool {
90        self.typ == ContentType::ChangeCipherSpec && self.payload == [0x01]
91    }
92}
93
94impl<'a> EncodedMessage<InboundOpaque<'a>> {
95    /// For TLS1.3 (only), checks the length msg.payload is valid and removes the padding.
96    ///
97    /// Returns an error if the message (pre-unpadding) is too long, or the padding is invalid,
98    /// or the message (post-unpadding) is too long.
99    pub fn into_tls13_unpadded_message(mut self) -> Result<EncodedMessage<&'a [u8]>, Error> {
100        let payload = &mut self.payload;
101
102        if payload.len() > MAX_FRAGMENT_LEN + 1 {
103            return Err(Error::PeerSentOversizedRecord);
104        }
105
106        self.typ = unpad_tls13_payload(payload);
107        if self.typ == ContentType::Unknown(0) {
108            return Err(PeerMisbehaved::IllegalTlsInnerPlaintext.into());
109        }
110
111        if payload.len() > MAX_FRAGMENT_LEN {
112            return Err(Error::PeerSentOversizedRecord);
113        }
114
115        self.version = ProtocolVersion::TLSv1_3;
116        Ok(self.into_plain_message())
117    }
118
119    /// Force conversion into a plaintext message.
120    ///
121    /// `range` restricts the resulting message: this function panics if it is out of range for
122    /// the underlying message payload.
123    ///
124    /// This should only be used for messages that are known to be in plaintext. Otherwise, the
125    /// [`EncodedMessage<InboundOpaque<'_>>`] should be decrypted into an
126    /// `EncodedMessage<&'_ [u8]>` using a `MessageDecrypter`.
127    pub fn into_plain_message_range(self, range: Range<usize>) -> EncodedMessage<&'a [u8]> {
128        EncodedMessage {
129            typ: self.typ,
130            version: self.version,
131            payload: &self.payload.into_inner()[range],
132        }
133    }
134
135    /// Force conversion into a plaintext message.
136    ///
137    /// This should only be used for messages that are known to be in plaintext. Otherwise, the
138    /// [`EncodedMessage<InboundOpaque<'a>>`] should be decrypted into a
139    /// `EncodedMessage<&'a [u8]>` using a `MessageDecrypter`.
140    pub fn into_plain_message(self) -> EncodedMessage<&'a [u8]> {
141        EncodedMessage {
142            typ: self.typ,
143            version: self.version,
144            payload: self.payload.into_inner(),
145        }
146    }
147}
148
149impl EncodedMessage<OutboundPlain<'_>> {
150    pub(crate) fn to_unencrypted_opaque(&self) -> EncodedMessage<OutboundOpaque> {
151        let mut payload = OutboundOpaque::with_capacity(self.payload.len());
152        payload.extend_from_chunks(&self.payload);
153        EncodedMessage {
154            version: self.version,
155            typ: self.typ,
156            payload,
157        }
158    }
159
160    pub(crate) fn encoded_len(&self, record_layer: &RecordLayer) -> usize {
161        HEADER_SIZE + record_layer.encrypted_len(self.payload.len())
162    }
163}
164
165impl EncodedMessage<OutboundOpaque> {
166    /// Encode this message to a vector of bytes.
167    pub fn encode(self) -> Vec<u8> {
168        let length = self.payload.len() as u16;
169        let mut encoded_payload = self.payload.0;
170        encoded_payload[0] = self.typ.into();
171        encoded_payload[1..3].copy_from_slice(&self.version.to_array());
172        encoded_payload[3..5].copy_from_slice(&(length).to_be_bytes());
173        encoded_payload
174    }
175}
176
177/// A collection of borrowed plaintext slices.
178///
179/// Warning: OutboundChunks does not guarantee that the simplest variant is used.
180/// Multiple can hold non fragmented or empty payloads.
181#[non_exhaustive]
182#[derive(Debug, Clone)]
183pub enum OutboundPlain<'a> {
184    /// A single byte slice.
185    ///
186    /// Contrary to `Multiple`, this uses a single pointer indirection
187    Single(&'a [u8]),
188    /// A collection of chunks (byte slices).
189    Multiple {
190        /// A collection of byte slices that hold the buffered data.
191        chunks: &'a [&'a [u8]],
192        /// The start cursor into the first chunk.
193        start: usize,
194        /// The end cursor into the last chunk.
195        end: usize,
196    },
197}
198
199impl<'a> OutboundPlain<'a> {
200    /// Create a payload from a slice of byte slices.
201    /// If fragmented the cursors are added by default: start = 0, end = length
202    pub fn new(chunks: &'a [&'a [u8]]) -> Self {
203        if chunks.len() == 1 {
204            Self::Single(chunks[0])
205        } else {
206            Self::Multiple {
207                chunks,
208                start: 0,
209                end: chunks
210                    .iter()
211                    .map(|chunk| chunk.len())
212                    .sum(),
213            }
214        }
215    }
216
217    /// Create a payload with a single empty slice
218    pub fn new_empty() -> Self {
219        Self::Single(&[])
220    }
221
222    /// Flatten the slice of byte slices to an owned vector of bytes
223    pub fn to_vec(&self) -> Vec<u8> {
224        let mut vec = Vec::with_capacity(self.len());
225        self.copy_to_vec(&mut vec);
226        vec
227    }
228
229    /// Append all bytes to a vector
230    pub fn copy_to_vec(&self, vec: &mut Vec<u8>) {
231        match *self {
232            Self::Single(chunk) => vec.extend_from_slice(chunk),
233            Self::Multiple { chunks, start, end } => {
234                let mut size = 0;
235                for chunk in chunks.iter() {
236                    let psize = size;
237                    let len = chunk.len();
238                    size += len;
239                    if size <= start || psize >= end {
240                        continue;
241                    }
242                    let start = start.saturating_sub(psize);
243                    let end = if end - psize < len { end - psize } else { len };
244                    vec.extend_from_slice(&chunk[start..end]);
245                }
246            }
247        }
248    }
249
250    /// Split self in two, around an index
251    /// Works similarly to `split_at` in the core library, except it doesn't panic if out of bound
252    pub(crate) fn split_at(&self, mid: usize) -> (Self, Self) {
253        match *self {
254            Self::Single(chunk) => {
255                let mid = Ord::min(mid, chunk.len());
256                (Self::Single(&chunk[..mid]), Self::Single(&chunk[mid..]))
257            }
258            Self::Multiple { chunks, start, end } => {
259                let mid = Ord::min(start + mid, end);
260                (
261                    Self::Multiple {
262                        chunks,
263                        start,
264                        end: mid,
265                    },
266                    Self::Multiple {
267                        chunks,
268                        start: mid,
269                        end,
270                    },
271                )
272            }
273        }
274    }
275
276    /// Returns true if the payload is empty
277    pub(crate) fn is_empty(&self) -> bool {
278        self.len() == 0
279    }
280
281    /// Returns the cumulative length of all chunks
282    #[expect(clippy::len_without_is_empty)]
283    pub fn len(&self) -> usize {
284        match self {
285            Self::Single(chunk) => chunk.len(),
286            Self::Multiple { start, end, .. } => end - start,
287        }
288    }
289}
290
291impl<'a> From<&'a [u8]> for OutboundPlain<'a> {
292    fn from(payload: &'a [u8]) -> Self {
293        Self::Single(payload)
294    }
295}
296
297/// A payload buffer with space reserved at the front for a TLS message header.
298///
299/// `EncodedMessage<OutboundOpaque>` is named `TLSPlaintext` in the standard.
300///
301/// This outbound type owns all memory for its interior parts.
302/// It results from encryption and is used for io write.
303#[derive(Clone, Debug)]
304pub struct OutboundOpaque(Vec<u8>);
305
306impl OutboundOpaque {
307    /// Create a new value with the given payload capacity.
308    ///
309    /// (The actual capacity of the returned value will be at least `HEADER_SIZE + capacity`.)
310    pub fn with_capacity(capacity: usize) -> Self {
311        let mut prefixed_payload = Vec::with_capacity(HEADER_SIZE + capacity);
312        prefixed_payload.resize(HEADER_SIZE, 0);
313        Self(prefixed_payload)
314    }
315
316    /// Append bytes from a slice.
317    pub fn extend_from_slice(&mut self, slice: &[u8]) {
318        self.0.extend_from_slice(slice)
319    }
320
321    /// Append bytes from an `OutboundChunks`.
322    pub fn extend_from_chunks(&mut self, chunks: &OutboundPlain<'_>) {
323        chunks.copy_to_vec(&mut self.0)
324    }
325
326    /// Truncate the payload to the given length (plus header).
327    pub fn truncate(&mut self, len: usize) {
328        self.0.truncate(len + HEADER_SIZE)
329    }
330
331    fn len(&self) -> usize {
332        self.0.len() - HEADER_SIZE
333    }
334}
335
336impl AsRef<[u8]> for OutboundOpaque {
337    fn as_ref(&self) -> &[u8] {
338        &self.0[HEADER_SIZE..]
339    }
340}
341
342impl AsMut<[u8]> for OutboundOpaque {
343    fn as_mut(&mut self) -> &mut [u8] {
344        &mut self.0[HEADER_SIZE..]
345    }
346}
347
348impl<'a> Extend<&'a u8> for OutboundOpaque {
349    fn extend<T: IntoIterator<Item = &'a u8>>(&mut self, iter: T) {
350        self.0.extend(iter)
351    }
352}
353
354impl From<&[u8]> for OutboundOpaque {
355    fn from(content: &[u8]) -> Self {
356        let mut payload = Vec::with_capacity(HEADER_SIZE + content.len());
357        payload.extend(&[0u8; HEADER_SIZE]);
358        payload.extend(content);
359        Self(payload)
360    }
361}
362
363impl<const N: usize> From<&[u8; N]> for OutboundOpaque {
364    fn from(content: &[u8; N]) -> Self {
365        Self::from(&content[..])
366    }
367}
368
369/// An externally length'd payload
370///
371/// When encountered in an [`EncodedMessage`], it represents a plaintext payload. It can be
372/// decrypted from an [`InboundOpaque`] or encrypted into an [`OutboundOpaque`],
373/// and it is also used for joining and fragmenting.
374#[non_exhaustive]
375#[derive(Clone, Eq, PartialEq)]
376pub enum Payload<'a> {
377    /// Borrowed payload
378    Borrowed(&'a [u8]),
379    /// Owned payload
380    Owned(Vec<u8>),
381}
382
383impl<'a> Payload<'a> {
384    /// A reference to the payload's bytes
385    pub fn bytes(&'a self) -> &'a [u8] {
386        match self {
387            Self::Borrowed(bytes) => bytes,
388            Self::Owned(bytes) => bytes,
389        }
390    }
391
392    pub(crate) fn into_owned(self) -> Payload<'static> {
393        Payload::Owned(self.into_vec())
394    }
395
396    pub(crate) fn into_vec(self) -> Vec<u8> {
397        match self {
398            Self::Borrowed(bytes) => bytes.to_vec(),
399            Self::Owned(bytes) => bytes,
400        }
401    }
402
403    pub(crate) fn read(r: &mut Reader<'a>) -> Self {
404        Self::Borrowed(r.rest())
405    }
406}
407
408impl Payload<'static> {
409    /// Create a new owned payload from the given `bytes`.
410    pub fn new(bytes: impl Into<Vec<u8>>) -> Self {
411        Self::Owned(bytes.into())
412    }
413}
414
415impl<'a> Codec<'a> for Payload<'a> {
416    fn encode(&self, bytes: &mut Vec<u8>) {
417        bytes.extend_from_slice(self.bytes());
418    }
419
420    fn read(r: &mut Reader<'a>) -> Result<Self, InvalidMessage> {
421        Ok(Self::read(r))
422    }
423}
424
425impl fmt::Debug for Payload<'_> {
426    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
427        hex(f, self.bytes())
428    }
429}
430
431/// A borrowed payload buffer.
432#[expect(clippy::exhaustive_structs)]
433pub struct InboundOpaque<'a>(pub &'a mut [u8]);
434
435impl<'a> InboundOpaque<'a> {
436    /// Truncate the payload to `len` bytes.
437    pub fn truncate(&mut self, len: usize) {
438        if len >= self.len() {
439            return;
440        }
441
442        self.0 = core::mem::take(&mut self.0)
443            .split_at_mut(len)
444            .0;
445    }
446
447    pub(crate) fn into_inner(self) -> &'a mut [u8] {
448        self.0
449    }
450
451    pub(crate) fn pop(&mut self) -> Option<u8> {
452        if self.is_empty() {
453            return None;
454        }
455
456        let len = self.len();
457        let last = self[len - 1];
458        self.truncate(len - 1);
459        Some(last)
460    }
461}
462
463impl Deref for InboundOpaque<'_> {
464    type Target = [u8];
465
466    fn deref(&self) -> &Self::Target {
467        self.0
468    }
469}
470
471impl DerefMut for InboundOpaque<'_> {
472    fn deref_mut(&mut self) -> &mut Self::Target {
473        self.0
474    }
475}
476
477/// Decode a TLS1.3 `TLSInnerPlaintext` encoding.
478///
479/// `p` is a message payload, immediately post-decryption.  This function
480/// removes zero padding bytes, until a non-zero byte is encountered which is
481/// the content type, which is returned.  See RFC8446 s5.2.
482///
483/// ContentType(0) is returned if the message payload is empty or all zeroes.
484fn unpad_tls13_payload(p: &mut InboundOpaque<'_>) -> ContentType {
485    loop {
486        match p.pop() {
487            Some(0) => {}
488            Some(content_type) => return ContentType::from(content_type),
489            None => return ContentType::Unknown(0),
490        }
491    }
492}
493
494/// Errors from trying to parse a TLS message.
495#[expect(missing_docs)]
496#[non_exhaustive]
497#[derive(Debug)]
498pub enum MessageError {
499    TooShortForHeader,
500    TooShortForLength,
501    InvalidEmptyPayload,
502    MessageTooLarge,
503    InvalidContentType,
504    UnknownProtocolVersion,
505}
506
507#[cfg(test)]
508mod tests {
509    use std::{println, vec};
510
511    use super::*;
512
513    #[test]
514    fn split_at_with_single_slice() {
515        let owner: &[u8] = &[0, 1, 2, 3, 4, 5, 6, 7];
516        let borrowed_payload = OutboundPlain::Single(owner);
517
518        let (before, after) = borrowed_payload.split_at(6);
519        println!("before:{before:?}\nafter:{after:?}");
520        assert_eq!(before.to_vec(), &[0, 1, 2, 3, 4, 5]);
521        assert_eq!(after.to_vec(), &[6, 7]);
522    }
523
524    #[test]
525    fn split_at_with_multiple_slices() {
526        let owner: Vec<&[u8]> = vec![&[0, 1, 2, 3], &[4, 5], &[6, 7, 8], &[9, 10, 11, 12]];
527        let borrowed_payload = OutboundPlain::new(&owner);
528
529        let (before, after) = borrowed_payload.split_at(3);
530        println!("before:{before:?}\nafter:{after:?}");
531        assert_eq!(before.to_vec(), &[0, 1, 2]);
532        assert_eq!(after.to_vec(), &[3, 4, 5, 6, 7, 8, 9, 10, 11, 12]);
533
534        let (before, after) = borrowed_payload.split_at(8);
535        println!("before:{before:?}\nafter:{after:?}");
536        assert_eq!(before.to_vec(), &[0, 1, 2, 3, 4, 5, 6, 7]);
537        assert_eq!(after.to_vec(), &[8, 9, 10, 11, 12]);
538
539        let (before, after) = borrowed_payload.split_at(11);
540        println!("before:{before:?}\nafter:{after:?}");
541        assert_eq!(before.to_vec(), &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
542        assert_eq!(after.to_vec(), &[11, 12]);
543    }
544
545    #[test]
546    fn split_out_of_bounds() {
547        let owner: Vec<&[u8]> = vec![&[0, 1, 2, 3], &[4, 5], &[6, 7, 8], &[9, 10, 11, 12]];
548
549        let single_payload = OutboundPlain::Single(owner[0]);
550        let (before, after) = single_payload.split_at(17);
551        println!("before:{before:?}\nafter:{after:?}");
552        assert_eq!(before.to_vec(), &[0, 1, 2, 3]);
553        assert!(after.is_empty());
554
555        let multiple_payload = OutboundPlain::new(&owner);
556        let (before, after) = multiple_payload.split_at(17);
557        println!("before:{before:?}\nafter:{after:?}");
558        assert_eq!(before.to_vec(), &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]);
559        assert!(after.is_empty());
560
561        let empty_payload = OutboundPlain::new_empty();
562        let (before, after) = empty_payload.split_at(17);
563        println!("before:{before:?}\nafter:{after:?}");
564        assert!(before.is_empty());
565        assert!(after.is_empty());
566    }
567
568    #[test]
569    fn empty_slices_mixed() {
570        let owner: Vec<&[u8]> = vec![&[], &[], &[0], &[], &[1, 2], &[], &[3], &[4], &[], &[]];
571        let mut borrowed_payload = OutboundPlain::new(&owner);
572        let mut fragment_count = 0;
573        let mut fragment;
574        let expected_fragments: &[&[u8]] = &[&[0, 1], &[2, 3], &[4]];
575
576        while !borrowed_payload.is_empty() {
577            (fragment, borrowed_payload) = borrowed_payload.split_at(2);
578            println!("{fragment:?}");
579            assert_eq!(&expected_fragments[fragment_count], &fragment.to_vec());
580            fragment_count += 1;
581        }
582        assert_eq!(fragment_count, expected_fragments.len());
583    }
584
585    #[test]
586    fn exhaustive_splitting() {
587        let owner: Vec<u8> = (0..127).collect();
588        let slices = (0..7)
589            .map(|i| &owner[((1 << i) - 1)..((1 << (i + 1)) - 1)])
590            .collect::<Vec<_>>();
591        let payload = OutboundPlain::new(&slices);
592
593        assert_eq!(payload.to_vec(), owner);
594        println!("{payload:#?}");
595
596        for start in 0..128 {
597            for end in start..128 {
598                for mid in 0..(end - start) {
599                    let witness = owner[start..end].split_at(mid);
600                    let split_payload = payload
601                        .split_at(end)
602                        .0
603                        .split_at(start)
604                        .1
605                        .split_at(mid);
606                    assert_eq!(
607                        witness.0,
608                        split_payload.0.to_vec(),
609                        "start: {start}, mid:{mid}, end:{end}"
610                    );
611                    assert_eq!(
612                        witness.1,
613                        split_payload.1.to_vec(),
614                        "start: {start}, mid:{mid}, end:{end}"
615                    );
616                }
617            }
618        }
619    }
620}