tls_codec/
lib.rs

1#![no_std]
2#![cfg_attr(docsrs, feature(doc_auto_cfg))]
3#![doc = include_str!("../README.md")]
4#![warn(
5    clippy::mod_module_files,
6    clippy::unwrap_used,
7    rust_2018_idioms,
8    unused_lifetimes
9)]
10
11//! ## Usage
12//!
13//! ```
14//! # #[cfg(feature = "std")]
15//! # {
16//! use tls_codec::{TlsVecU8, Serialize, Deserialize};
17//! let mut b = &[1u8, 4, 77, 88, 1, 99] as &[u8];
18//!
19//! let a = u8::tls_deserialize(&mut b).expect("Unable to tls_deserialize");
20//! assert_eq!(1, a);
21//! println!("b: {:?}", b);
22//! let v = TlsVecU8::<u8>::tls_deserialize(&mut b).expect("Unable to tls_deserialize");
23//! assert_eq!(&[77, 88, 1, 99], v.as_slice());
24//! # }
25//! ```
26
27#[macro_use]
28extern crate alloc;
29
30#[cfg(feature = "std")]
31extern crate std;
32
33use alloc::{string::String, vec::Vec};
34use core::fmt::{self, Display};
35#[cfg(feature = "std")]
36use std::io::{Read, Write};
37
38mod arrays;
39mod primitives;
40mod quic_vec;
41mod tls_vec;
42
43pub use tls_vec::{
44    SecretTlsVecU16, SecretTlsVecU24, SecretTlsVecU32, SecretTlsVecU8, TlsByteSliceU16,
45    TlsByteSliceU24, TlsByteSliceU32, TlsByteSliceU8, TlsByteVecU16, TlsByteVecU24, TlsByteVecU32,
46    TlsByteVecU8, TlsSliceU16, TlsSliceU24, TlsSliceU32, TlsSliceU8, TlsVecU16, TlsVecU24,
47    TlsVecU32, TlsVecU8,
48};
49
50#[cfg(feature = "std")]
51pub use quic_vec::{rw as vlen, SecretVLBytes};
52pub use quic_vec::{VLByteSlice, VLBytes};
53
54#[cfg(feature = "derive")]
55pub use tls_codec_derive::{
56    TlsDeserialize, TlsDeserializeBytes, TlsSerialize, TlsSerializeBytes, TlsSize,
57};
58
59#[cfg(feature = "conditional_deserialization")]
60pub use tls_codec_derive::conditionally_deserializable;
61
62/// Errors that are thrown by this crate.
63#[derive(Debug, Eq, PartialEq, Clone)]
64pub enum Error {
65    /// An error occurred during encoding.
66    EncodingError(String),
67
68    /// The length of a vector is invalid.
69    InvalidVectorLength,
70
71    /// Error writing everything out.
72    InvalidWriteLength(String),
73
74    /// Invalid input when trying to decode a primitive integer.
75    InvalidInput,
76
77    /// An error occurred during decoding.
78    DecodingError(String),
79
80    /// Reached the end of a byte stream.
81    EndOfStream,
82
83    /// Found unexpected data after deserializing.
84    TrailingData,
85
86    /// An unknown value in an enum.
87    /// The application might not want to treat this as an error because it is
88    /// only an unknown value, not an invalid value.
89    UnknownValue(u64),
90
91    /// An internal library error that indicates a bug.
92    LibraryError,
93}
94
95#[cfg(feature = "std")]
96impl std::error::Error for Error {}
97
98impl Display for Error {
99    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
100        f.write_fmt(format_args!("{self:?}"))
101    }
102}
103
104#[cfg(feature = "std")]
105impl From<std::io::Error> for Error {
106    fn from(e: std::io::Error) -> Self {
107        match e.kind() {
108            std::io::ErrorKind::UnexpectedEof => Self::EndOfStream,
109            _ => Self::DecodingError(format!("io error: {e:?}")),
110        }
111    }
112}
113
114/// The `Size` trait needs to be implemented by any struct that should be
115/// efficiently serialized.
116/// This allows to collect the length of a serialized structure before allocating
117/// memory.
118pub trait Size {
119    fn tls_serialized_len(&self) -> usize;
120}
121
122/// The `Serialize` trait provides functions to serialize a struct or enum.
123///
124/// The trait provides two functions:
125/// * `tls_serialize` that takes a buffer to write the serialization to
126/// * `tls_serialize_detached` that returns a byte vector
127pub trait Serialize: Size {
128    /// Serialize `self` and write it to the `writer`.
129    /// The function returns the number of bytes written to `writer`.
130    #[cfg(feature = "std")]
131    fn tls_serialize<W: Write>(&self, writer: &mut W) -> Result<usize, Error>;
132
133    /// Serialize `self` and return it as a byte vector.
134    #[cfg(feature = "std")]
135    fn tls_serialize_detached(&self) -> Result<Vec<u8>, Error> {
136        let mut buffer = Vec::with_capacity(self.tls_serialized_len());
137        let written = self.tls_serialize(&mut buffer)?;
138        debug_assert_eq!(
139            written,
140            buffer.len(),
141            "Expected that {} bytes were written but the output holds {} bytes",
142            written,
143            buffer.len()
144        );
145        if written != buffer.len() {
146            Err(Error::EncodingError(format!(
147                "Expected that {} bytes were written but the output holds {} bytes",
148                written,
149                buffer.len()
150            )))
151        } else {
152            Ok(buffer)
153        }
154    }
155}
156
157/// The `SerializeBytes` trait provides a function to serialize a struct or enum.
158///
159/// The trait provides one function:
160/// * `tls_serialize` that returns a byte vector
161pub trait SerializeBytes: Size {
162    /// Serialize `self` and return it as a byte vector.
163    fn tls_serialize(&self) -> Result<Vec<u8>, Error>;
164}
165
166/// The `Deserialize` trait defines functions to deserialize a byte slice to a
167/// struct or enum.
168pub trait Deserialize: Size {
169    /// This function deserializes the `bytes` from the provided a [`std::io::Read`]
170    /// and returns the populated struct.
171    ///
172    /// In order to get the amount of bytes read, use [`Size::tls_serialized_len`].
173    ///
174    /// Returns an error if one occurs during deserialization.
175    #[cfg(feature = "std")]
176    fn tls_deserialize<R: Read>(bytes: &mut R) -> Result<Self, Error>
177    where
178        Self: Sized;
179
180    /// This function deserializes the provided `bytes` and returns the populated
181    /// struct. All bytes must be consumed.
182    ///
183    /// Returns an error if not all bytes are read from the input, or if an error
184    /// occurs during deserialization.
185    #[cfg(feature = "std")]
186    fn tls_deserialize_exact(bytes: impl AsRef<[u8]>) -> Result<Self, Error>
187    where
188        Self: Sized,
189    {
190        let mut bytes = bytes.as_ref();
191        let out = Self::tls_deserialize(&mut bytes)?;
192
193        if !bytes.is_empty() {
194            return Err(Error::TrailingData);
195        }
196
197        Ok(out)
198    }
199}
200
201/// The `DeserializeBytes` trait defines functions to deserialize a byte slice
202/// to a struct or enum. In contrast to [`Deserialize`], this trait operates
203/// directly on byte slices and can return any remaining bytes.
204pub trait DeserializeBytes: Size {
205    /// This function deserializes the `bytes` from the provided a `&[u8]`
206    /// and returns the populated struct, as well as the remaining slice.
207    ///
208    /// In order to get the amount of bytes read, use [`Size::tls_serialized_len`].
209    ///
210    /// Returns an error if one occurs during deserialization.
211    fn tls_deserialize_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), Error>
212    where
213        Self: Sized;
214
215    /// This function deserializes the provided `bytes` and returns the populated
216    /// struct. All bytes must be consumed.
217    ///
218    /// Returns an error if not all bytes are read from the input, or if an error
219    /// occurs during deserialization.
220    fn tls_deserialize_exact_bytes(bytes: &[u8]) -> Result<Self, Error>
221    where
222        Self: Sized,
223    {
224        let (out, remainder) = Self::tls_deserialize_bytes(bytes)?;
225
226        if !remainder.is_empty() {
227            return Err(Error::TrailingData);
228        }
229
230        Ok(out)
231    }
232}
233
234/// A 3 byte wide unsigned integer type as defined in [RFC 5246].
235///
236/// [RFC 5246]: https://datatracker.ietf.org/doc/html/rfc5246#section-4.4
237#[derive(Copy, Clone, Debug, Default, PartialEq)]
238pub struct U24([u8; 3]);
239
240impl U24 {
241    pub const MAX: Self = Self([255u8; 3]);
242    pub const MIN: Self = Self([0u8; 3]);
243
244    pub fn from_be_bytes(bytes: [u8; 3]) -> Self {
245        U24(bytes)
246    }
247
248    pub fn to_be_bytes(self) -> [u8; 3] {
249        self.0
250    }
251}
252
253impl From<U24> for usize {
254    fn from(value: U24) -> usize {
255        const LEN: usize = core::mem::size_of::<usize>();
256        let mut usize_bytes = [0u8; LEN];
257        usize_bytes[LEN - 3..].copy_from_slice(&value.0);
258        usize::from_be_bytes(usize_bytes)
259    }
260}
261
262impl TryFrom<usize> for U24 {
263    type Error = Error;
264
265    fn try_from(value: usize) -> Result<Self, Self::Error> {
266        const LEN: usize = core::mem::size_of::<usize>();
267        // In practice, our usages of this conversion should never be invalid, as the values
268        // have to come from `TryFrom<U24> for usize`.
269        if value > (1 << 24) - 1 {
270            Err(Error::LibraryError)
271        } else {
272            Ok(U24(value.to_be_bytes()[LEN - 3..].try_into()?))
273        }
274    }
275}