tpm2_protocol/basic/
buffer.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2// Copyright (c) 2025 Opinsys Oy
3// Copyright (c) 2024-2025 Jarkko Sakkinen
4
5use crate::{TpmMarshal, TpmProtocolError, TpmResult, TpmSized, TpmUnmarshal, TpmWriter};
6use core::{
7    convert::TryFrom,
8    fmt::Debug,
9    hash::{Hash, Hasher},
10    mem::size_of,
11    ops::Deref,
12};
13
14/// A buffer in the TPM2B wire format.
15///
16/// The `size` field is stored in native endian and converted to big-endian
17/// only during marshaling.
18#[derive(Clone, Copy)]
19pub struct TpmBuffer<const CAPACITY: usize> {
20    size: u16,
21    data: [u8; CAPACITY],
22}
23
24impl<const CAPACITY: usize> TpmBuffer<CAPACITY> {
25    /// Creates a new, empty `TpmBuffer`.
26    #[must_use]
27    pub const fn new() -> Self {
28        Self {
29            size: 0,
30            data: [0; CAPACITY],
31        }
32    }
33
34    /// Appends a byte to the buffer.
35    ///
36    /// # Errors
37    ///
38    /// Returns [`OutOfMemory`](crate::TpmProtocolError::OutOfMemory) when the
39    /// buffer is full or the size exceeds `u16::MAX`.
40    pub fn try_push(&mut self, byte: u8) -> TpmResult<()> {
41        if (self.size as usize) >= CAPACITY || self.size == u16::MAX {
42            return Err(TpmProtocolError::OutOfMemory);
43        }
44        self.data[self.size as usize] = byte;
45        self.size += 1;
46        Ok(())
47    }
48
49    /// Appends a slice of bytes to the buffer.
50    ///
51    /// # Errors
52    ///
53    /// Returns [`OutOfMemory`](crate::TpmProtocolError::OutOfMemory) when the
54    /// resulting size exceeds the buffer capacity or `u16::MAX`.
55    pub fn try_extend_from_slice(&mut self, slice: &[u8]) -> TpmResult<()> {
56        let current_len = self.size as usize;
57        let new_len = current_len
58            .checked_add(slice.len())
59            .ok_or(TpmProtocolError::OutOfMemory)?;
60
61        if new_len > CAPACITY {
62            return Err(TpmProtocolError::OutOfMemory);
63        }
64
65        self.size = u16::try_from(new_len).map_err(|_| TpmProtocolError::OutOfMemory)?;
66        self.data[current_len..new_len].copy_from_slice(slice);
67        Ok(())
68    }
69}
70
71impl<const CAPACITY: usize> Deref for TpmBuffer<CAPACITY> {
72    type Target = [u8];
73
74    fn deref(&self) -> &Self::Target {
75        let size = self.size as usize;
76        &self.data[..size]
77    }
78}
79
80impl<const CAPACITY: usize> Default for TpmBuffer<CAPACITY> {
81    fn default() -> Self {
82        Self::new()
83    }
84}
85
86impl<const CAPACITY: usize> PartialEq for TpmBuffer<CAPACITY> {
87    fn eq(&self, other: &Self) -> bool {
88        **self == **other
89    }
90}
91
92impl<const CAPACITY: usize> Eq for TpmBuffer<CAPACITY> {}
93
94impl<const CAPACITY: usize> Hash for TpmBuffer<CAPACITY> {
95    fn hash<H: Hasher>(&self, state: &mut H) {
96        (**self).hash(state);
97    }
98}
99
100impl<const CAPACITY: usize> TpmSized for TpmBuffer<CAPACITY> {
101    const SIZE: usize = size_of::<u16>() + CAPACITY;
102    fn len(&self) -> usize {
103        size_of::<u16>() + self.size as usize
104    }
105}
106
107impl<const CAPACITY: usize> TpmMarshal for TpmBuffer<CAPACITY> {
108    fn marshal(&self, writer: &mut TpmWriter) -> TpmResult<()> {
109        self.size.marshal(writer)?;
110        writer.write_bytes(&self.data[..self.size as usize])
111    }
112}
113
114impl<const CAPACITY: usize> TpmUnmarshal for TpmBuffer<CAPACITY> {
115    fn unmarshal(buf: &[u8]) -> TpmResult<(Self, &[u8])> {
116        let (native_size, remainder) = u16::unmarshal(buf)?;
117        let size_usize = native_size as usize;
118
119        if size_usize > CAPACITY {
120            return Err(TpmProtocolError::TooManyBytes);
121        }
122
123        if remainder.len() < size_usize {
124            return Err(TpmProtocolError::UnexpectedEnd);
125        }
126
127        let mut buffer = Self::new();
128        buffer.size = native_size;
129        buffer.data[..size_usize].copy_from_slice(&remainder[..size_usize]);
130        Ok((buffer, &remainder[size_usize..]))
131    }
132}
133
134impl<'a, const CAPACITY: usize> TryFrom<&'a [u8]> for TpmBuffer<CAPACITY> {
135    type Error = TpmProtocolError;
136
137    fn try_from(slice: &'a [u8]) -> Result<Self, Self::Error> {
138        if slice.len() > CAPACITY {
139            return Err(TpmProtocolError::TooManyBytes);
140        }
141        let mut buffer = Self::new();
142        let len_u16 = u16::try_from(slice.len()).map_err(|_| TpmProtocolError::OperationFailed)?;
143        buffer.size = len_u16;
144        buffer.data[..slice.len()].copy_from_slice(slice);
145        Ok(buffer)
146    }
147}
148
149impl<const CAPACITY: usize> AsRef<[u8]> for TpmBuffer<CAPACITY> {
150    fn as_ref(&self) -> &[u8] {
151        self
152    }
153}
154
155impl<const CAPACITY: usize> Debug for TpmBuffer<CAPACITY> {
156    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
157        write!(f, "TpmBuffer(")?;
158        for byte in self.iter() {
159            write!(f, "{byte:02X}")?;
160        }
161        write!(f, ")")
162    }
163}