| use crate::enums::ProtocolVersion; |
| use crate::enums::{AlertDescription, ContentType, HandshakeType}; |
| use crate::error::{Error, InvalidMessage}; |
| use crate::msgs::alert::AlertMessagePayload; |
| use crate::msgs::base::Payload; |
| use crate::msgs::ccs::ChangeCipherSpecPayload; |
| use crate::msgs::codec::{Codec, Reader}; |
| use crate::msgs::enums::AlertLevel; |
| use crate::msgs::handshake::HandshakeMessagePayload; |
| |
| #[derive(Debug)] |
| pub enum MessagePayload { |
| Alert(AlertMessagePayload), |
| Handshake { |
| parsed: HandshakeMessagePayload, |
| encoded: Payload, |
| }, |
| ChangeCipherSpec(ChangeCipherSpecPayload), |
| ApplicationData(Payload), |
| } |
| |
| impl MessagePayload { |
| pub fn encode(&self, bytes: &mut Vec<u8>) { |
| match self { |
| Self::Alert(x) => x.encode(bytes), |
| Self::Handshake { encoded, .. } => bytes.extend(&encoded.0), |
| Self::ChangeCipherSpec(x) => x.encode(bytes), |
| Self::ApplicationData(x) => x.encode(bytes), |
| } |
| } |
| |
| pub fn handshake(parsed: HandshakeMessagePayload) -> Self { |
| Self::Handshake { |
| encoded: Payload::new(parsed.get_encoding()), |
| parsed, |
| } |
| } |
| |
| pub fn new( |
| typ: ContentType, |
| vers: ProtocolVersion, |
| payload: Payload, |
| ) -> Result<Self, InvalidMessage> { |
| let mut r = Reader::init(&payload.0); |
| match typ { |
| ContentType::ApplicationData => Ok(Self::ApplicationData(payload)), |
| ContentType::Alert => AlertMessagePayload::read(&mut r).map(MessagePayload::Alert), |
| ContentType::Handshake => { |
| HandshakeMessagePayload::read_version(&mut r, vers).map(|parsed| Self::Handshake { |
| parsed, |
| encoded: payload, |
| }) |
| } |
| ContentType::ChangeCipherSpec => { |
| ChangeCipherSpecPayload::read(&mut r).map(MessagePayload::ChangeCipherSpec) |
| } |
| _ => Err(InvalidMessage::InvalidContentType), |
| } |
| } |
| |
| pub fn content_type(&self) -> ContentType { |
| match self { |
| Self::Alert(_) => ContentType::Alert, |
| Self::Handshake { .. } => ContentType::Handshake, |
| Self::ChangeCipherSpec(_) => ContentType::ChangeCipherSpec, |
| Self::ApplicationData(_) => ContentType::ApplicationData, |
| } |
| } |
| } |
| |
| /// A TLS frame, named TLSPlaintext in the standard. |
| /// |
| /// This type owns all memory for its interior parts. It is used to read/write from/to I/O |
| /// buffers as well as for fragmenting, joining and encryption/decryption. It can be converted |
| /// into a `Message` by decoding the payload. |
| #[derive(Clone, Debug)] |
| pub struct OpaqueMessage { |
| pub typ: ContentType, |
| pub version: ProtocolVersion, |
| pub payload: Payload, |
| } |
| |
| impl OpaqueMessage { |
| /// `MessageError` allows callers to distinguish between valid prefixes (might |
| /// become valid if we read more data) and invalid data. |
| pub fn read(r: &mut Reader) -> Result<Self, MessageError> { |
| let typ = ContentType::read(r).map_err(|_| MessageError::TooShortForHeader)?; |
| // Don't accept any new content-types. |
| if let ContentType::Unknown(_) = typ { |
| return Err(MessageError::InvalidContentType); |
| } |
| |
| let version = ProtocolVersion::read(r).map_err(|_| MessageError::TooShortForHeader)?; |
| // Accept only versions 0x03XX for any XX. |
| match version { |
| ProtocolVersion::Unknown(ref v) if (v & 0xff00) != 0x0300 => { |
| return Err(MessageError::UnknownProtocolVersion); |
| } |
| _ => {} |
| }; |
| |
| let len = u16::read(r).map_err(|_| MessageError::TooShortForHeader)?; |
| |
| // Reject undersize messages |
| // implemented per section 5.1 of RFC8446 (TLSv1.3) |
| // per section 6.2.1 of RFC5246 (TLSv1.2) |
| if typ != ContentType::ApplicationData && len == 0 { |
| return Err(MessageError::InvalidEmptyPayload); |
| } |
| |
| // Reject oversize messages |
| if len >= Self::MAX_PAYLOAD { |
| return Err(MessageError::MessageTooLarge); |
| } |
| |
| let mut sub = r |
| .sub(len as usize) |
| .map_err(|_| MessageError::TooShortForLength)?; |
| let payload = Payload::read(&mut sub); |
| |
| Ok(Self { |
| typ, |
| version, |
| payload, |
| }) |
| } |
| |
| pub fn encode(self) -> Vec<u8> { |
| let mut buf = Vec::new(); |
| self.typ.encode(&mut buf); |
| self.version.encode(&mut buf); |
| (self.payload.0.len() as u16).encode(&mut buf); |
| self.payload.encode(&mut buf); |
| buf |
| } |
| |
| /// Force conversion into a plaintext message. |
| /// |
| /// This should only be used for messages that are known to be in plaintext. Otherwise, the |
| /// `OpaqueMessage` should be decrypted into a `PlainMessage` using a `MessageDecrypter`. |
| pub fn into_plain_message(self) -> PlainMessage { |
| PlainMessage { |
| version: self.version, |
| typ: self.typ, |
| payload: self.payload, |
| } |
| } |
| |
| /// This is the maximum on-the-wire size of a TLSCiphertext. |
| /// That's 2^14 payload bytes, a header, and a 2KB allowance |
| /// for ciphertext overheads. |
| const MAX_PAYLOAD: u16 = 16384 + 2048; |
| |
| /// Content type, version and size. |
| const HEADER_SIZE: u16 = 1 + 2 + 2; |
| |
| /// Maximum on-wire message size. |
| pub const MAX_WIRE_SIZE: usize = (Self::MAX_PAYLOAD + Self::HEADER_SIZE) as usize; |
| } |
| |
| impl From<Message> for PlainMessage { |
| fn from(msg: Message) -> Self { |
| let typ = msg.payload.content_type(); |
| let payload = match msg.payload { |
| MessagePayload::ApplicationData(payload) => payload, |
| _ => { |
| let mut buf = Vec::new(); |
| msg.payload.encode(&mut buf); |
| Payload(buf) |
| } |
| }; |
| |
| Self { |
| typ, |
| version: msg.version, |
| payload, |
| } |
| } |
| } |
| |
| /// A decrypted TLS frame |
| /// |
| /// This type owns all memory for its interior parts. It can be decrypted from an OpaqueMessage |
| /// or encrypted into an OpaqueMessage, and it is also used for joining and fragmenting. |
| #[derive(Clone, Debug)] |
| pub struct PlainMessage { |
| pub typ: ContentType, |
| pub version: ProtocolVersion, |
| pub payload: Payload, |
| } |
| |
| impl PlainMessage { |
| pub fn into_unencrypted_opaque(self) -> OpaqueMessage { |
| OpaqueMessage { |
| version: self.version, |
| typ: self.typ, |
| payload: self.payload, |
| } |
| } |
| |
| pub fn borrow(&self) -> BorrowedPlainMessage<'_> { |
| BorrowedPlainMessage { |
| version: self.version, |
| typ: self.typ, |
| payload: &self.payload.0, |
| } |
| } |
| } |
| |
| /// A message with decoded payload |
| #[derive(Debug)] |
| pub struct Message { |
| pub version: ProtocolVersion, |
| pub payload: MessagePayload, |
| } |
| |
| impl Message { |
| pub fn is_handshake_type(&self, hstyp: HandshakeType) -> bool { |
| // Bit of a layering violation, but OK. |
| if let MessagePayload::Handshake { parsed, .. } = &self.payload { |
| parsed.typ == hstyp |
| } else { |
| false |
| } |
| } |
| |
| pub fn build_alert(level: AlertLevel, desc: AlertDescription) -> Self { |
| Self { |
| version: ProtocolVersion::TLSv1_2, |
| payload: MessagePayload::Alert(AlertMessagePayload { |
| level, |
| description: desc, |
| }), |
| } |
| } |
| |
| pub fn build_key_update_notify() -> Self { |
| Self { |
| version: ProtocolVersion::TLSv1_3, |
| payload: MessagePayload::handshake(HandshakeMessagePayload::build_key_update_notify()), |
| } |
| } |
| } |
| |
| /// Parses a plaintext message into a well-typed [`Message`]. |
| /// |
| /// A [`PlainMessage`] must contain plaintext content. Encrypted content should be stored in an |
| /// [`OpaqueMessage`] and decrypted before being stored into a [`PlainMessage`]. |
| impl TryFrom<PlainMessage> for Message { |
| type Error = Error; |
| |
| fn try_from(plain: PlainMessage) -> Result<Self, Self::Error> { |
| Ok(Self { |
| version: plain.version, |
| payload: MessagePayload::new(plain.typ, plain.version, plain.payload)?, |
| }) |
| } |
| } |
| |
| /// A TLS frame, named TLSPlaintext in the standard. |
| /// |
| /// This type differs from `OpaqueMessage` because it borrows |
| /// its payload. You can make a `OpaqueMessage` from an |
| /// `BorrowMessage`, but this involves a copy. |
| /// |
| /// This type also cannot decode its internals and |
| /// cannot be read/encoded; only `OpaqueMessage` can do that. |
| pub struct BorrowedPlainMessage<'a> { |
| pub typ: ContentType, |
| pub version: ProtocolVersion, |
| pub payload: &'a [u8], |
| } |
| |
| impl<'a> BorrowedPlainMessage<'a> { |
| pub fn to_unencrypted_opaque(&self) -> OpaqueMessage { |
| OpaqueMessage { |
| version: self.version, |
| typ: self.typ, |
| payload: Payload(self.payload.to_vec()), |
| } |
| } |
| } |
| |
| #[derive(Debug)] |
| pub enum MessageError { |
| TooShortForHeader, |
| TooShortForLength, |
| InvalidEmptyPayload, |
| MessageTooLarge, |
| InvalidContentType, |
| UnknownProtocolVersion, |
| } |