1#![cfg_attr(not(test), no_std)]
22#![deny(unsafe_code)]
23#![deny(clippy::all)]
24#![deny(clippy::pedantic)]
25#![recursion_limit = "256"]
26
27pub mod basic;
28pub mod constant;
29pub mod data;
30#[macro_use]
31pub mod r#macro;
32pub mod message;
33
34#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
36#[repr(transparent)]
37pub struct TpmHandle(pub u32);
38
39impl core::convert::From<u32> for TpmHandle {
40    fn from(val: u32) -> Self {
41        Self(val)
42    }
43}
44
45impl core::convert::From<TpmHandle> for u32 {
46    fn from(val: TpmHandle) -> Self {
47        val.0
48    }
49}
50
51impl TpmBuild for TpmHandle {
52    fn build(&self, writer: &mut TpmWriter) -> TpmResult<()> {
53        TpmBuild::build(&self.0, writer)
54    }
55}
56
57impl TpmParse for TpmHandle {
58    fn parse(buf: &[u8]) -> TpmResult<(Self, &[u8])> {
59        let (val, buf) = u32::parse(buf)?;
60        Ok((Self(val), buf))
61    }
62}
63
64impl TpmSized for TpmHandle {
65    const SIZE: usize = size_of::<u32>();
66    fn len(&self) -> usize {
67        Self::SIZE
68    }
69}
70
71impl core::fmt::Display for TpmHandle {
72    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
73        core::fmt::Display::fmt(&self.0, f)
74    }
75}
76
77impl core::fmt::LowerHex for TpmHandle {
78    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
79        core::fmt::LowerHex::fmt(&self.0, f)
80    }
81}
82
83impl core::fmt::UpperHex for TpmHandle {
84    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
85        core::fmt::UpperHex::fmt(&self.0, f)
86    }
87}
88
89#[derive(Debug, PartialEq, Eq)]
90pub enum TpmDiscriminant {
91    Signed(i64),
92    Unsigned(u64),
93}
94
95impl core::fmt::LowerHex for TpmDiscriminant {
96    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
97        match self {
98            TpmDiscriminant::Signed(v) => write!(f, "{v:x}"),
99            TpmDiscriminant::Unsigned(v) => write!(f, "{v:x}"),
100        }
101    }
102}
103
104#[derive(Debug, PartialEq, Eq)]
105pub enum TpmError {
107    CapacityExceeded,
109    Malformed,
111    TrailingData,
113    Truncated,
115    UnknownDiscriminant(&'static str, TpmDiscriminant),
117}
118
119impl core::fmt::Display for TpmError {
120    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
121        match self {
122            Self::CapacityExceeded => write!(f, "capacity exceeded"),
123            Self::Malformed => write!(f, "malformed data"),
124            Self::TrailingData => write!(f, "trailing data"),
125            Self::Truncated => write!(f, "truncated data"),
126            Self::UnknownDiscriminant(type_name, value) => {
127                write!(f, "unknown discriminant: {type_name}:  0x{value:x}")
128            }
129        }
130    }
131}
132
133impl From<core::num::TryFromIntError> for TpmError {
134    fn from(_: core::num::TryFromIntError) -> Self {
135        Self::CapacityExceeded
136    }
137}
138
139pub type TpmResult<T> = Result<T, TpmError>;
140
141pub struct TpmWriter<'a> {
143    buffer: &'a mut [u8],
144    cursor: usize,
145}
146
147impl<'a> TpmWriter<'a> {
148    #[must_use]
150    pub fn new(buffer: &'a mut [u8]) -> Self {
151        Self { buffer, cursor: 0 }
152    }
153
154    #[must_use]
156    pub fn len(&self) -> usize {
157        self.cursor
158    }
159
160    #[must_use]
162    pub fn is_empty(&self) -> bool {
163        self.cursor == 0
164    }
165
166    pub fn write_bytes(&mut self, bytes: &[u8]) -> TpmResult<()> {
173        let end = self.cursor + bytes.len();
174        if end > self.buffer.len() {
175            return Err(TpmError::CapacityExceeded);
176        }
177        self.buffer[self.cursor..end].copy_from_slice(bytes);
178        self.cursor = end;
179        Ok(())
180    }
181}
182
183pub trait TpmSized {
186    const SIZE: usize;
189
190    fn len(&self) -> usize;
192
193    fn is_empty(&self) -> bool {
195        self.len() == 0
196    }
197}
198
199pub trait TpmBuild: TpmSized {
200    fn build(&self, writer: &mut TpmWriter) -> TpmResult<()>;
206}
207
208pub trait TpmParse: Sized + TpmSized {
209    fn parse(buf: &[u8]) -> TpmResult<(Self, &[u8])>;
217}
218
219pub trait TpmTagged {
221    type Tag: TpmParse + TpmBuild + Copy;
223    type Value;
225}
226
227pub trait TpmParseTagged: Sized {
229    fn parse_tagged(tag: <Self as TpmTagged>::Tag, buf: &[u8]) -> TpmResult<(Self, &[u8])>
237    where
238        Self: TpmTagged,
239        <Self as TpmTagged>::Tag: TpmParse + TpmBuild;
240}
241
242tpm_integer!(u8, Unsigned);
243tpm_integer!(i8, Signed);
244tpm_integer!(i32, Signed);
245tpm_integer!(u16, Unsigned);
246tpm_integer!(u32, Unsigned);
247tpm_integer!(u64, Unsigned);