rustls/msgs/message/
mod.rs

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