| 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 | |