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