use core::ops::{Deref, DerefMut, Range};
use crate::enums::{ContentType, ProtocolVersion};
use crate::error::{Error, PeerMisbehaved};
use crate::msgs::fragmenter::MAX_FRAGMENT_LEN;
pub struct InboundOpaqueMessage<'a> {
pub typ: ContentType,
pub version: ProtocolVersion,
pub payload: BorrowedPayload<'a>,
}
impl<'a> InboundOpaqueMessage<'a> {
pub fn new(typ: ContentType, version: ProtocolVersion, payload: &'a mut [u8]) -> Self {
Self {
typ,
version,
payload: BorrowedPayload(payload),
}
}
pub fn into_plain_message(self) -> InboundPlainMessage<'a> {
InboundPlainMessage {
typ: self.typ,
version: self.version,
payload: self.payload.into_inner(),
}
}
pub fn into_plain_message_range(self, range: Range<usize>) -> InboundPlainMessage<'a> {
InboundPlainMessage {
typ: self.typ,
version: self.version,
payload: &self.payload.into_inner()[range],
}
}
pub fn into_tls13_unpadded_message(mut self) -> Result<InboundPlainMessage<'a>, Error> {
let payload = &mut self.payload;
if payload.len() > MAX_FRAGMENT_LEN + 1 {
return Err(Error::PeerSentOversizedRecord);
}
self.typ = unpad_tls13_payload(payload);
if self.typ == ContentType::Unknown(0) {
return Err(PeerMisbehaved::IllegalTlsInnerPlaintext.into());
}
if payload.len() > MAX_FRAGMENT_LEN {
return Err(Error::PeerSentOversizedRecord);
}
self.version = ProtocolVersion::TLSv1_3;
Ok(self.into_plain_message())
}
}
pub struct BorrowedPayload<'a>(&'a mut [u8]);
impl Deref for BorrowedPayload<'_> {
type Target = [u8];
fn deref(&self) -> &Self::Target {
self.0
}
}
impl DerefMut for BorrowedPayload<'_> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.0
}
}
impl<'a> BorrowedPayload<'a> {
pub fn truncate(&mut self, len: usize) {
if len >= self.len() {
return;
}
self.0 = core::mem::take(&mut self.0)
.split_at_mut(len)
.0;
}
pub(crate) fn into_inner(self) -> &'a mut [u8] {
self.0
}
pub(crate) fn pop(&mut self) -> Option<u8> {
if self.is_empty() {
return None;
}
let len = self.len();
let last = self[len - 1];
self.truncate(len - 1);
Some(last)
}
}
#[derive(Debug)]
pub struct InboundPlainMessage<'a> {
pub typ: ContentType,
pub version: ProtocolVersion,
pub payload: &'a [u8],
}
impl InboundPlainMessage<'_> {
pub(crate) fn is_valid_ccs(&self) -> bool {
self.typ == ContentType::ChangeCipherSpec && self.payload == [0x01]
}
}
fn unpad_tls13_payload(p: &mut BorrowedPayload<'_>) -> ContentType {
loop {
match p.pop() {
Some(0) => {}
Some(content_type) => return ContentType::from(content_type),
None => return ContentType::Unknown(0),
}
}
}