1use super::{
3 error::{TlsBuildError, TlsParseError},
4 types::{TlsContentType, TlsProtocolVersion},
5};
6#[derive(Clone, Copy, Debug, Eq, PartialEq)]
8pub struct TlsRecord<'a> {
9 bytes: &'a [u8],
10}
11impl<'a> TlsRecord<'a> {
12 pub fn parse(bytes: &'a [u8]) -> Result<Self, TlsParseError> {
14 let length = declared(bytes, 5)?;
15 Ok(Self {
16 bytes: &bytes[..length],
17 })
18 }
19 pub fn content_type(&self) -> TlsContentType {
21 TlsContentType::new(self.bytes[0])
22 }
23 pub fn version(&self) -> TlsProtocolVersion {
25 TlsProtocolVersion::new(u16::from_be_bytes([self.bytes[1], self.bytes[2]]))
26 }
27 pub fn fragment(&self) -> &'a [u8] {
29 &self.bytes[5..]
30 }
31 pub fn as_bytes(&self) -> &'a [u8] {
33 self.bytes
34 }
35}
36#[derive(Debug, Eq, PartialEq)]
38pub struct TlsRecordMut<'a> {
39 bytes: &'a mut [u8],
40}
41impl<'a> TlsRecordMut<'a> {
42 pub fn parse(bytes: &'a mut [u8]) -> Result<Self, TlsParseError> {
44 let length = declared(bytes, 5)?;
45 Ok(Self {
46 bytes: &mut bytes[..length],
47 })
48 }
49 pub(crate) fn from_validated(bytes: &'a mut [u8]) -> Self {
50 Self { bytes }
51 }
52 pub fn content_type(&self) -> TlsContentType {
54 TlsContentType::new(self.bytes[0])
55 }
56 pub fn set_content_type(&mut self, value: TlsContentType) {
58 self.bytes[0] = value.raw();
59 }
60 pub fn version(&self) -> TlsProtocolVersion {
62 TlsProtocolVersion::new(u16::from_be_bytes([self.bytes[1], self.bytes[2]]))
63 }
64 pub fn set_version(&mut self, value: TlsProtocolVersion) {
66 self.bytes[1..3].copy_from_slice(&value.raw().to_be_bytes());
67 }
68 pub fn fragment(&self) -> &[u8] {
70 &self.bytes[5..]
71 }
72 pub fn fragment_mut(&mut self) -> &mut [u8] {
74 &mut self.bytes[5..]
75 }
76 pub fn as_bytes(&self) -> &[u8] {
78 self.bytes
79 }
80}
81pub struct TlsRecordBuilder<'a, 'b> {
83 buffer: &'a mut [u8],
84 content_type: TlsContentType,
85 version: TlsProtocolVersion,
86 fragment: &'b [u8],
87}
88impl<'a, 'b> TlsRecordBuilder<'a, 'b> {
89 pub fn new(
91 buffer: &'a mut [u8],
92 content_type: TlsContentType,
93 version: TlsProtocolVersion,
94 fragment: &'b [u8],
95 ) -> Self {
96 Self {
97 buffer,
98 content_type,
99 version,
100 fragment,
101 }
102 }
103 pub fn build(self) -> Result<TlsRecordMut<'a>, TlsBuildError> {
105 if self.fragment.len() > u16::MAX as usize {
106 return Err(TlsBuildError::LengthTooLarge);
107 }
108 let length = 5usize
109 .checked_add(self.fragment.len())
110 .ok_or(TlsBuildError::LengthTooLarge)?;
111 if self.buffer.len() < length {
112 return Err(TlsBuildError::BufferTooShort {
113 required: length,
114 available: self.buffer.len(),
115 });
116 }
117 let bytes = &mut self.buffer[..length];
118 bytes[0] = self.content_type.raw();
119 bytes[1..3].copy_from_slice(&self.version.raw().to_be_bytes());
120 bytes[3..5].copy_from_slice(&(self.fragment.len() as u16).to_be_bytes());
121 bytes[5..].copy_from_slice(self.fragment);
122 Ok(TlsRecordMut::from_validated(bytes))
123 }
124}
125fn declared(bytes: &[u8], header: usize) -> Result<usize, TlsParseError> {
126 if bytes.len() < header {
127 return Err(TlsParseError::Incomplete {
128 required: header,
129 available: bytes.len(),
130 });
131 }
132 let length = usize::from(u16::from_be_bytes([bytes[3], bytes[4]]));
133 let total = header + length;
134 if bytes.len() < total {
135 return Err(TlsParseError::Incomplete {
136 required: total,
137 available: bytes.len(),
138 });
139 }
140 Ok(total)
141}