rustls/msgs/message/
mod.rs

1use crate::enums::{AlertDescription, ContentType, HandshakeType, ProtocolVersion};
2use crate::error::InvalidMessage;
3use crate::msgs::alert::AlertMessagePayload;
4use crate::msgs::base::Payload;
5use crate::msgs::ccs::ChangeCipherSpecPayload;
6use crate::msgs::codec::{Codec, Reader};
7use crate::msgs::enums::{AlertLevel, KeyUpdateRequest};
8use crate::msgs::handshake::{HandshakeMessagePayload, HandshakePayload};
9
10mod inbound;
11pub use inbound::{BorrowedPayload, InboundOpaqueMessage, InboundPlainMessage};
12
13mod outbound;
14use alloc::vec::Vec;
15
16pub(crate) use outbound::read_opaque_message_header;
17pub use outbound::{OutboundChunks, OutboundOpaqueMessage, OutboundPlainMessage, PrefixedPayload};
18
19#[non_exhaustive]
20#[derive(Debug)]
21pub enum MessagePayload<'a> {
22    Alert(AlertMessagePayload),
23    // one handshake message, parsed
24    Handshake {
25        parsed: HandshakeMessagePayload<'a>,
26        encoded: Payload<'a>,
27    },
28    // (potentially) multiple handshake messages, unparsed
29    HandshakeFlight(Payload<'a>),
30    ChangeCipherSpec(ChangeCipherSpecPayload),
31    ApplicationData(Payload<'a>),
32}
33
34impl<'a> MessagePayload<'a> {
35    pub fn encode(&self, bytes: &mut Vec<u8>) {
36        match self {
37            Self::Alert(x) => x.encode(bytes),
38            Self::Handshake { encoded, .. } => bytes.extend(encoded.bytes()),
39            Self::HandshakeFlight(x) => bytes.extend(x.bytes()),
40            Self::ChangeCipherSpec(x) => x.encode(bytes),
41            Self::ApplicationData(x) => x.encode(bytes),
42        }
43    }
44
45    pub fn handshake(parsed: HandshakeMessagePayload<'a>) -> Self {
46        Self::Handshake {
47            encoded: Payload::new(parsed.get_encoding()),
48            parsed,
49        }
50    }
51
52    pub fn new(
53        typ: ContentType,
54        vers: ProtocolVersion,
55        payload: &'a [u8],
56    ) -> Result<Self, InvalidMessage> {
57        let mut r = Reader::init(payload);
58        match typ {
59            ContentType::ApplicationData => Ok(Self::ApplicationData(Payload::Borrowed(payload))),
60            ContentType::Alert => AlertMessagePayload::read(&mut r).map(MessagePayload::Alert),
61            ContentType::Handshake => {
62                HandshakeMessagePayload::read_version(&mut r, vers).map(|parsed| Self::Handshake {
63                    parsed,
64                    encoded: Payload::Borrowed(payload),
65                })
66            }
67            ContentType::ChangeCipherSpec => {
68                ChangeCipherSpecPayload::read(&mut r).map(MessagePayload::ChangeCipherSpec)
69            }
70            _ => Err(InvalidMessage::InvalidContentType),
71        }
72    }
73
74    pub fn content_type(&self) -> ContentType {
75        match self {
76            Self::Alert(_) => ContentType::Alert,
77            Self::Handshake { .. } | Self::HandshakeFlight(_) => ContentType::Handshake,
78            Self::ChangeCipherSpec(_) => ContentType::ChangeCipherSpec,
79            Self::ApplicationData(_) => ContentType::ApplicationData,
80        }
81    }
82
83    pub(crate) fn into_owned(self) -> MessagePayload<'static> {
84        use MessagePayload::*;
85        match self {
86            Alert(x) => Alert(x),
87            Handshake { parsed, encoded } => Handshake {
88                parsed: parsed.into_owned(),
89                encoded: encoded.into_owned(),
90            },
91            HandshakeFlight(x) => HandshakeFlight(x.into_owned()),
92            ChangeCipherSpec(x) => ChangeCipherSpec(x),
93            ApplicationData(x) => ApplicationData(x.into_owned()),
94        }
95    }
96}
97
98impl From<Message<'_>> for PlainMessage {
99    fn from(msg: Message<'_>) -> Self {
100        let typ = msg.payload.content_type();
101        let payload = match msg.payload {
102            MessagePayload::ApplicationData(payload) => payload.into_owned(),
103            _ => {
104                let mut buf = Vec::new();
105                msg.payload.encode(&mut buf);
106                Payload::Owned(buf)
107            }
108        };
109
110        Self {
111            typ,
112            version: msg.version,
113            payload,
114        }
115    }
116}
117
118/// A decrypted TLS frame
119///
120/// This type owns all memory for its interior parts. It can be decrypted from an OpaqueMessage
121/// or encrypted into an OpaqueMessage, and it is also used for joining and fragmenting.
122#[allow(clippy::exhaustive_structs)]
123#[derive(Clone, Debug)]
124pub struct PlainMessage {
125    pub typ: ContentType,
126    pub version: ProtocolVersion,
127    pub payload: Payload<'static>,
128}
129
130impl PlainMessage {
131    pub fn into_unencrypted_opaque(self) -> OutboundOpaqueMessage {
132        OutboundOpaqueMessage {
133            version: self.version,
134            typ: self.typ,
135            payload: PrefixedPayload::from(self.payload.bytes()),
136        }
137    }
138
139    pub fn borrow_inbound(&self) -> InboundPlainMessage<'_> {
140        InboundPlainMessage {
141            version: self.version,
142            typ: self.typ,
143            payload: self.payload.bytes(),
144        }
145    }
146
147    pub fn borrow_outbound(&self) -> OutboundPlainMessage<'_> {
148        OutboundPlainMessage {
149            version: self.version,
150            typ: self.typ,
151            payload: self.payload.bytes().into(),
152        }
153    }
154}
155
156/// A message with decoded payload
157#[allow(clippy::exhaustive_structs)]
158#[derive(Debug)]
159pub struct Message<'a> {
160    pub version: ProtocolVersion,
161    pub payload: MessagePayload<'a>,
162}
163
164impl Message<'_> {
165    pub fn is_handshake_type(&self, hstyp: HandshakeType) -> bool {
166        // Bit of a layering violation, but OK.
167        if let MessagePayload::Handshake { parsed, .. } = &self.payload {
168            parsed.0.handshake_type() == hstyp
169        } else {
170            false
171        }
172    }
173
174    pub fn build_alert(level: AlertLevel, desc: AlertDescription) -> Self {
175        Self {
176            version: ProtocolVersion::TLSv1_2,
177            payload: MessagePayload::Alert(AlertMessagePayload {
178                level,
179                description: desc,
180            }),
181        }
182    }
183
184    pub fn build_key_update_notify() -> Self {
185        Self {
186            version: ProtocolVersion::TLSv1_3,
187            payload: MessagePayload::handshake(HandshakeMessagePayload(
188                HandshakePayload::KeyUpdate(KeyUpdateRequest::UpdateNotRequested),
189            )),
190        }
191    }
192
193    pub fn build_key_update_request() -> Self {
194        Self {
195            version: ProtocolVersion::TLSv1_3,
196            payload: MessagePayload::handshake(HandshakeMessagePayload(
197                HandshakePayload::KeyUpdate(KeyUpdateRequest::UpdateRequested),
198            )),
199        }
200    }
201
202    #[cfg(feature = "std")]
203    pub(crate) fn into_owned(self) -> Message<'static> {
204        let Self { version, payload } = self;
205        Message {
206            version,
207            payload: payload.into_owned(),
208        }
209    }
210
211    #[cfg(test)]
212    pub(crate) fn into_wire_bytes(self) -> Vec<u8> {
213        PlainMessage::from(self)
214            .into_unencrypted_opaque()
215            .encode()
216    }
217}
218
219impl TryFrom<PlainMessage> for Message<'static> {
220    type Error = InvalidMessage;
221
222    fn try_from(plain: PlainMessage) -> Result<Self, Self::Error> {
223        Ok(Self {
224            version: plain.version,
225            payload: MessagePayload::new(plain.typ, plain.version, plain.payload.bytes())?
226                .into_owned(),
227        })
228    }
229}
230
231/// Parses a plaintext message into a well-typed [`Message`].
232///
233/// A [`PlainMessage`] must contain plaintext content. Encrypted content should be stored in an
234/// [`InboundOpaqueMessage`] and decrypted before being stored into a [`PlainMessage`].
235impl<'a> TryFrom<InboundPlainMessage<'a>> for Message<'a> {
236    type Error = InvalidMessage;
237
238    fn try_from(plain: InboundPlainMessage<'a>) -> Result<Self, Self::Error> {
239        Ok(Self {
240            version: plain.version,
241            payload: MessagePayload::new(plain.typ, plain.version, plain.payload)?,
242        })
243    }
244}
245
246#[derive(Debug)]
247pub enum MessageError {
248    TooShortForHeader,
249    TooShortForLength,
250    InvalidEmptyPayload,
251    MessageTooLarge,
252    InvalidContentType,
253    UnknownProtocolVersion,
254}
255
256/// Content type, version and size.
257pub(crate) const HEADER_SIZE: usize = 1 + 2 + 2;
258
259/// Maximum message payload size.
260/// That's 2^14 payload bytes and a 2KB allowance for ciphertext overheads.
261const MAX_PAYLOAD: u16 = 16_384 + 2048;
262
263/// Maximum on-the-wire message size.
264#[cfg(feature = "std")]
265pub(crate) const MAX_WIRE_SIZE: usize = MAX_PAYLOAD as usize + HEADER_SIZE;