Skip to main content

net_wire/tls/
record.rs

1//! TLS record views and caller-buffer construction.
2use super::{
3    error::{TlsBuildError, TlsParseError},
4    types::{TlsContentType, TlsProtocolVersion},
5};
6/// A single structurally bounded TLS record.
7#[derive(Clone, Copy, Debug, Eq, PartialEq)]
8pub struct TlsRecord<'a> {
9    bytes: &'a [u8],
10}
11impl<'a> TlsRecord<'a> {
12    /// Parses the first complete record and excludes any coalesced suffix.
13    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    /// Returns the content type.
20    pub fn content_type(&self) -> TlsContentType {
21        TlsContentType::new(self.bytes[0])
22    }
23    /// Returns the legacy record version.
24    pub fn version(&self) -> TlsProtocolVersion {
25        TlsProtocolVersion::new(u16::from_be_bytes([self.bytes[1], self.bytes[2]]))
26    }
27    /// Returns the fragment.
28    pub fn fragment(&self) -> &'a [u8] {
29        &self.bytes[5..]
30    }
31    /// Returns the represented record bytes.
32    pub fn as_bytes(&self) -> &'a [u8] {
33        self.bytes
34    }
35}
36/// A mutable structurally bounded TLS record.
37#[derive(Debug, Eq, PartialEq)]
38pub struct TlsRecordMut<'a> {
39    bytes: &'a mut [u8],
40}
41impl<'a> TlsRecordMut<'a> {
42    /// Parses the first complete record and excludes any coalesced suffix.
43    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    /// Returns the content type.
53    pub fn content_type(&self) -> TlsContentType {
54        TlsContentType::new(self.bytes[0])
55    }
56    /// Replaces the content type.
57    pub fn set_content_type(&mut self, value: TlsContentType) {
58        self.bytes[0] = value.raw();
59    }
60    /// Returns the legacy record version.
61    pub fn version(&self) -> TlsProtocolVersion {
62        TlsProtocolVersion::new(u16::from_be_bytes([self.bytes[1], self.bytes[2]]))
63    }
64    /// Replaces the legacy record version.
65    pub fn set_version(&mut self, value: TlsProtocolVersion) {
66        self.bytes[1..3].copy_from_slice(&value.raw().to_be_bytes());
67    }
68    /// Returns the fragment.
69    pub fn fragment(&self) -> &[u8] {
70        &self.bytes[5..]
71    }
72    /// Returns the fragment mutably without changing its encoded length.
73    pub fn fragment_mut(&mut self) -> &mut [u8] {
74        &mut self.bytes[5..]
75    }
76    /// Returns represented record bytes.
77    pub fn as_bytes(&self) -> &[u8] {
78        self.bytes
79    }
80}
81/// Builds a TLS record in caller-owned storage.
82pub 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    /// Starts a record builder with a copied fragment input.
90    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    /// Validates all inputs before writing the record.
104    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}