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