1 | use crate::enums::{AlertDescription, ContentType, HandshakeType, ProtocolVersion}; |
2 | use crate::error::{Error, InvalidMessage}; |
3 | use crate::msgs::alert::AlertMessagePayload; |
4 | use crate::msgs::base::Payload; |
5 | use crate::msgs::ccs::ChangeCipherSpecPayload; |
6 | use crate::msgs::codec::{Codec, Reader}; |
7 | use crate::msgs::enums::{AlertLevel, KeyUpdateRequest}; |
8 | use crate::msgs::handshake::{HandshakeMessagePayload, HandshakePayload}; |
9 | |
10 | mod inbound; |
11 | pub use inbound::{BorrowedPayload, InboundOpaqueMessage, InboundPlainMessage}; |
12 | |
13 | mod outbound; |
14 | use alloc::vec::Vec; |
15 | |
16 | pub(crate) use outbound::read_opaque_message_header; |
17 | pub use outbound::{OutboundChunks, OutboundOpaqueMessage, OutboundPlainMessage, PrefixedPayload}; |
18 | |
19 | #[derive (Debug)] |
20 | pub 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 | |
33 | impl<'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 | |
97 | impl From<Message<'_>> for PlainMessage { |
98 | fn from(msg: Message<'_>) -> Self { |
99 | let typ: ContentType = msg.payload.content_type(); |
100 | let payload: Payload<'_> = match msg.payload { |
101 | MessagePayload::ApplicationData(payload: Payload<'_>) => payload.into_owned(), |
102 | _ => { |
103 | let mut buf: Vec = 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)] |
122 | pub struct PlainMessage { |
123 | pub typ: ContentType, |
124 | pub version: ProtocolVersion, |
125 | pub payload: Payload<'static>, |
126 | } |
127 | |
128 | impl 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)] |
156 | pub struct Message<'a> { |
157 | pub version: ProtocolVersion, |
158 | pub payload: MessagePayload<'a>, |
159 | } |
160 | |
161 | impl 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 | |
211 | impl 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: MessagePayloadMessagePayload<'_>::new(plain.typ, vers:plain.version, payload: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`]. |
227 | impl<'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, vers:plain.version, plain.payload)?, |
234 | }) |
235 | } |
236 | } |
237 | |
238 | #[derive (Debug)] |
239 | pub enum MessageError { |
240 | TooShortForHeader, |
241 | TooShortForLength, |
242 | InvalidEmptyPayload, |
243 | MessageTooLarge, |
244 | InvalidContentType, |
245 | UnknownProtocolVersion, |
246 | } |
247 | |
248 | /// Content type, version and size. |
249 | pub(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. |
253 | const MAX_PAYLOAD: u16 = 16_384 + 2048; |
254 | |
255 | /// Maximum on-the-wire message size. |
256 | #[cfg (feature = "std" )] |
257 | pub(crate) const MAX_WIRE_SIZE: usize = MAX_PAYLOAD as usize + HEADER_SIZE; |
258 | |