1use core::ops::{Deref, DerefMut, Range};
23use crate::enums::{ContentType, ProtocolVersion};
4use crate::error::{Error, PeerMisbehaved};
5use crate::msgs::fragmenter::MAX_FRAGMENT_LEN;
67/// A TLS frame, named TLSPlaintext in the standard.
8///
9/// This inbound type borrows its encrypted payload from a buffer elsewhere.
10/// It is used for joining and is consumed by decryption.
11pub struct InboundOpaqueMessage<'a> {
12pub typ: ContentType,
13pub version: ProtocolVersion,
14pub payload: BorrowedPayload<'a>,
15}
1617impl<'a> InboundOpaqueMessage<'a> {
18/// Construct a new `InboundOpaqueMessage` from constituent fields.
19 ///
20 /// `payload` is borrowed.
21pub fn new(typ: ContentType, version: ProtocolVersion, payload: &'a mut [u8]) -> Self {
22Self {
23 typ,
24 version,
25 payload: BorrowedPayload(payload),
26 }
27 }
2829/// Force conversion into a plaintext message.
30 ///
31 /// This should only be used for messages that are known to be in plaintext. Otherwise, the
32 /// `InboundOpaqueMessage` should be decrypted into a `PlainMessage` using a `MessageDecrypter`.
33pub fn into_plain_message(self) -> InboundPlainMessage<'a> {
34 InboundPlainMessage {
35 typ: self.typ,
36 version: self.version,
37 payload: self.payload.into_inner(),
38 }
39 }
4041/// Force conversion into a plaintext message.
42 ///
43 /// `range` restricts the resulting message: this function panics if it is out of range for
44 /// the underlying message payload.
45 ///
46 /// This should only be used for messages that are known to be in plaintext. Otherwise, the
47 /// `InboundOpaqueMessage` should be decrypted into a `PlainMessage` using a `MessageDecrypter`.
48pub fn into_plain_message_range(self, range: Range<usize>) -> InboundPlainMessage<'a> {
49 InboundPlainMessage {
50 typ: self.typ,
51 version: self.version,
52 payload: &self.payload.into_inner()[range],
53 }
54 }
5556/// For TLS1.3 (only), checks the length msg.payload is valid and removes the padding.
57 ///
58 /// Returns an error if the message (pre-unpadding) is too long, or the padding is invalid,
59 /// or the message (post-unpadding) is too long.
60pub fn into_tls13_unpadded_message(mut self) -> Result<InboundPlainMessage<'a>, Error> {
61let payload = &mut self.payload;
6263if payload.len() > MAX_FRAGMENT_LEN + 1 {
64return Err(Error::PeerSentOversizedRecord);
65 }
6667self.typ = unpad_tls13_payload(payload);
68if self.typ == ContentType::Unknown(0) {
69return Err(PeerMisbehaved::IllegalTlsInnerPlaintext.into());
70 }
7172if payload.len() > MAX_FRAGMENT_LEN {
73return Err(Error::PeerSentOversizedRecord);
74 }
7576self.version = ProtocolVersion::TLSv1_3;
77Ok(self.into_plain_message())
78 }
79}
8081pub struct BorrowedPayload<'a>(&'a mut [u8]);
8283impl Deref for BorrowedPayload<'_> {
84type Target = [u8];
8586fn deref(&self) -> &Self::Target {
87self.0
88}
89}
9091impl DerefMut for BorrowedPayload<'_> {
92fn deref_mut(&mut self) -> &mut Self::Target {
93self.0
94}
95}
9697impl<'a> BorrowedPayload<'a> {
98pub fn truncate(&mut self, len: usize) {
99if len >= self.len() {
100return;
101 }
102103self.0 = core::mem::take(&mut self.0)
104 .split_at_mut(len)
105 .0;
106 }
107108pub(crate) fn into_inner(self) -> &'a mut [u8] {
109self.0
110}
111112pub(crate) fn pop(&mut self) -> Option<u8> {
113if self.is_empty() {
114return None;
115 }
116117let len = self.len();
118let last = self[len - 1];
119self.truncate(len - 1);
120Some(last)
121 }
122}
123124/// A TLS frame, named `TLSPlaintext` in the standard.
125///
126/// This inbound type borrows its decrypted payload from the original buffer.
127/// It results from decryption.
128#[derive(Debug)]
129pub struct InboundPlainMessage<'a> {
130pub typ: ContentType,
131pub version: ProtocolVersion,
132pub payload: &'a [u8],
133}
134135impl InboundPlainMessage<'_> {
136/// Returns true if the payload is a CCS message.
137 ///
138 /// We passthrough ChangeCipherSpec messages in the deframer without decrypting them.
139 /// Note: this is prior to the record layer, so is unencrypted. See
140 /// third paragraph of section 5 in RFC8446.
141pub(crate) fn is_valid_ccs(&self) -> bool {
142self.typ == ContentType::ChangeCipherSpec && self.payload == [0x01]
143 }
144}
145146/// Decode a TLS1.3 `TLSInnerPlaintext` encoding.
147///
148/// `p` is a message payload, immediately post-decryption. This function
149/// removes zero padding bytes, until a non-zero byte is encountered which is
150/// the content type, which is returned. See RFC8446 s5.2.
151///
152/// ContentType(0) is returned if the message payload is empty or all zeroes.
153fn unpad_tls13_payload(p: &mut BorrowedPayload<'_>) -> ContentType {
154loop {
155match p.pop() {
156Some(0) => {}
157Some(content_type) => return ContentType::from(content_type),
158None => return ContentType::Unknown(0),
159 }
160 }
161}