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