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::{TpmBuild, TpmError, TpmParse, TpmResult, TpmSized, TpmWriter};
6use core::{convert::TryFrom, fmt::Debug, mem::size_of, ops::Deref};
7
8/// A buffer in the native TPM2B wire format.
9#[repr(C)]
10#[derive(Clone, Copy, PartialEq, Eq)]
11pub struct TpmBuffer<const CAPACITY: usize> {
12    size: u16,
13    data: [u8; CAPACITY],
14}
15
16impl<const CAPACITY: usize> TpmBuffer<CAPACITY> {
17    /// Creates a new, empty `TpmBuffer`.
18    #[must_use]
19    pub const fn new() -> Self {
20        Self {
21            size: 0,
22            data: [0; CAPACITY],
23        }
24    }
25
26    /// Reads the size field from the buffer's header.
27    fn size(&self) -> u16 {
28        u16::from_be(self.size)
29    }
30
31    /// Writes the size field to the buffer's header.
32    fn set_size(&mut self, size: u16) {
33        self.size = size.to_be();
34    }
35}
36
37impl<const CAPACITY: usize> Deref for TpmBuffer<CAPACITY> {
38    type Target = [u8];
39
40    fn deref(&self) -> &Self::Target {
41        let size = self.size() as usize;
42        &self.data[..size]
43    }
44}
45
46impl<const CAPACITY: usize> Default for TpmBuffer<CAPACITY> {
47    fn default() -> Self {
48        Self::new()
49    }
50}
51
52impl<const CAPACITY: usize> TpmSized for TpmBuffer<CAPACITY> {
53    const SIZE: usize = size_of::<u16>() + CAPACITY;
54    fn len(&self) -> usize {
55        size_of::<u16>() + self.size() as usize
56    }
57}
58
59impl<const CAPACITY: usize> TpmBuild for TpmBuffer<CAPACITY> {
60    fn build(&self, writer: &mut TpmWriter) -> TpmResult<()> {
61        let native_size = self.size();
62        native_size.build(writer)?;
63        writer.write_bytes(&self.data[..native_size as usize])
64    }
65}
66
67impl<const CAPACITY: usize> TpmParse for TpmBuffer<CAPACITY> {
68    fn parse(buf: &[u8]) -> TpmResult<(Self, &[u8])> {
69        let (native_size, remainder) = u16::parse(buf)?;
70        let size_usize = native_size as usize;
71
72        if size_usize > CAPACITY {
73            return Err(TpmError::CapacityExceeded);
74        }
75
76        if remainder.len() < size_usize {
77            return Err(TpmError::DataTruncated);
78        }
79
80        let mut buffer = Self::new();
81        buffer.set_size(native_size);
82        buffer.data[..size_usize].copy_from_slice(&remainder[..size_usize]);
83        Ok((buffer, &remainder[size_usize..]))
84    }
85}
86
87impl<const CAPACITY: usize> TryFrom<&[u8]> for TpmBuffer<CAPACITY> {
88    type Error = TpmError;
89
90    fn try_from(slice: &[u8]) -> Result<Self, Self::Error> {
91        if slice.len() > CAPACITY {
92            return Err(TpmError::CapacityExceeded);
93        }
94        let mut buffer = Self::new();
95        let len_u16 = u16::try_from(slice.len())?;
96        buffer.set_size(len_u16);
97        buffer.data[..slice.len()].copy_from_slice(slice);
98        Ok(buffer)
99    }
100}
101
102impl<const CAPACITY: usize> AsRef<[u8]> for TpmBuffer<CAPACITY> {
103    fn as_ref(&self) -> &[u8] {
104        self
105    }
106}
107
108impl<const CAPACITY: usize> Debug for TpmBuffer<CAPACITY> {
109    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
110        write!(f, "TpmBuffer(")?;
111        for byte in self.iter() {
112            write!(f, "{byte:02X}")?;
113        }
114        write!(f, ")")
115    }
116}