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 Handshake {
25 parsed: HandshakeMessagePayload<'a>,
26 encoded: Payload<'a>,
27 },
28 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#[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#[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 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
231impl<'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
256pub(crate) const HEADER_SIZE: usize = 1 + 2 + 2;
258
259const MAX_PAYLOAD: u16 = 16_384 + 2048;
262
263#[cfg(feature = "std")]
265pub(crate) const MAX_WIRE_SIZE: usize = MAX_PAYLOAD as usize + HEADER_SIZE;