clia_rustls_mod/msgs/message/
inbound.rs

1use core::ops::{Deref, DerefMut};
2
3use super::outbound::read_opaque_message_header;
4use super::MessageError;
5use crate::enums::{ContentType, ProtocolVersion};
6use crate::error::{Error, PeerMisbehaved};
7use crate::msgs::codec::ReaderMut;
8use crate::msgs::fragmenter::MAX_FRAGMENT_LEN;
9
10/// A TLS frame, named TLSPlaintext in the standard.
11///
12/// This inbound type borrows its encrypted payload from a `[MessageDeframer]`.
13/// It is used for joining and is consumed by decryption.
14pub struct InboundOpaqueMessage<'a> {
15    pub typ: ContentType,
16    pub version: ProtocolVersion,
17    pub payload: BorrowedPayload<'a>,
18}
19
20impl<'a> InboundOpaqueMessage<'a> {
21    /// Construct a new `InboundOpaqueMessage` from constituent fields.
22    ///
23    /// `payload` is borrowed.
24    pub fn new(typ: ContentType, version: ProtocolVersion, payload: &'a mut [u8]) -> Self {
25        Self {
26            typ,
27            version,
28            payload: BorrowedPayload(payload),
29        }
30    }
31
32    /// Force conversion into a plaintext message.
33    ///
34    /// This should only be used for messages that are known to be in plaintext. Otherwise, the
35    /// `InboundOpaqueMessage` should be decrypted into a `PlainMessage` using a `MessageDecrypter`.
36    pub fn into_plain_message(self) -> InboundPlainMessage<'a> {
37        InboundPlainMessage {
38            typ: self.typ,
39            version: self.version,
40            payload: self.payload.into_inner(),
41        }
42    }
43
44    /// For TLS1.3 (only), checks the length msg.payload is valid and removes the padding.
45    ///
46    /// Returns an error if the message (pre-unpadding) is too long, or the padding is invalid,
47    /// or the message (post-unpadding) is too long.
48    pub fn into_tls13_unpadded_message(mut self) -> Result<InboundPlainMessage<'a>, Error> {
49        let payload = &mut self.payload;
50
51        if payload.len() > MAX_FRAGMENT_LEN + 1 {
52            return Err(Error::PeerSentOversizedRecord);
53        }
54
55        self.typ = unpad_tls13_payload(payload);
56        if self.typ == ContentType::Unknown(0) {
57            return Err(PeerMisbehaved::IllegalTlsInnerPlaintext.into());
58        }
59
60        if payload.len() > MAX_FRAGMENT_LEN {
61            return Err(Error::PeerSentOversizedRecord);
62        }
63
64        self.version = ProtocolVersion::TLSv1_3;
65        Ok(self.into_plain_message())
66    }
67
68    pub(crate) fn read(r: &mut ReaderMut<'a>) -> Result<Self, MessageError> {
69        let (typ, version, len) = r.as_reader(read_opaque_message_header)?;
70
71        let mut sub = r
72            .sub(len as usize)
73            .map_err(|_| MessageError::TooShortForLength)?;
74        let payload = BorrowedPayload::read(&mut sub);
75
76        Ok(Self {
77            typ,
78            version,
79            payload,
80        })
81    }
82}
83
84pub struct BorrowedPayload<'a>(&'a mut [u8]);
85
86impl Deref for BorrowedPayload<'_> {
87    type Target = [u8];
88
89    fn deref(&self) -> &Self::Target {
90        self.0
91    }
92}
93
94impl<'a> DerefMut for BorrowedPayload<'a> {
95    fn deref_mut(&mut self) -> &mut Self::Target {
96        self.0
97    }
98}
99
100impl<'a> BorrowedPayload<'a> {
101    pub fn truncate(&mut self, len: usize) {
102        if len >= self.len() {
103            return;
104        }
105
106        self.0 = core::mem::take(&mut self.0)
107            .split_at_mut(len)
108            .0;
109    }
110
111    pub(crate) fn read(r: &mut ReaderMut<'a>) -> Self {
112        Self(r.rest())
113    }
114
115    pub(crate) fn into_inner(self) -> &'a mut [u8] {
116        self.0
117    }
118
119    pub(crate) fn pop(&mut self) -> Option<u8> {
120        if self.is_empty() {
121            return None;
122        }
123
124        let len = self.len();
125        let last = self[len - 1];
126        self.truncate(len - 1);
127        Some(last)
128    }
129}
130
131/// A TLS frame, named `TLSPlaintext` in the standard.
132///
133/// This inbound type borrows its decrypted payload from a [`MessageDeframer`].
134/// It results from decryption.
135///
136/// [`MessageDeframer`]: crate::msgs::deframer::MessageDeframer
137#[derive(Debug)]
138pub struct InboundPlainMessage<'a> {
139    pub typ: ContentType,
140    pub version: ProtocolVersion,
141    pub payload: &'a [u8],
142}
143
144impl InboundPlainMessage<'_> {
145    /// Returns true if the payload is a CCS message.
146    ///
147    /// We passthrough ChangeCipherSpec messages in the deframer without decrypting them.
148    /// Note: this is prior to the record layer, so is unencrypted. See
149    /// third paragraph of section 5 in RFC8446.
150    pub(crate) fn is_valid_ccs(&self) -> bool {
151        self.typ == ContentType::ChangeCipherSpec && self.payload == [0x01]
152    }
153
154    #[cfg(all(test, feature = "std"))]
155    pub(crate) fn into_owned(self) -> super::PlainMessage {
156        super::PlainMessage {
157            version: self.version,
158            typ: self.typ,
159            payload: crate::msgs::base::Payload::Owned(self.payload.to_vec()),
160        }
161    }
162}
163
164/// Decode a TLS1.3 `TLSInnerPlaintext` encoding.
165///
166/// `p` is a message payload, immediately post-decryption.  This function
167/// removes zero padding bytes, until a non-zero byte is encountered which is
168/// the content type, which is returned.  See RFC8446 s5.2.
169///
170/// ContentType(0) is returned if the message payload is empty or all zeroes.
171fn unpad_tls13_payload(p: &mut BorrowedPayload) -> ContentType {
172    loop {
173        match p.pop() {
174            Some(0) => {}
175            Some(content_type) => return ContentType::from(content_type),
176            None => return ContentType::Unknown(0),
177        }
178    }
179}