tpm2_protocol/macro/
mod.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2// Copyright (c) 2025 Opinsys Oy
3// Copyright (c) 2024-2025 Jarkko Sakkinen
4
5pub mod r#enum;
6pub mod integer;
7pub mod r#struct;
8
9#[macro_export]
10macro_rules! tpm_bitflags {
11    (
12        $(#[$outer:meta])*
13        $vis:vis struct $name:ident($repr:ty) {
14            $(
15                $(#[$inner:meta])*
16                const $field:ident = $value:expr, $string_name:literal;
17            )*
18        }
19    ) => {
20        $(#[$outer])*
21        $vis struct $name($repr);
22
23        impl $name {
24            $(
25                $(#[$inner])*
26                pub const $field: Self = Self($value);
27            )*
28
29            #[must_use]
30            pub const fn bits(&self) -> $repr {
31                self.0
32            }
33
34            #[must_use]
35            pub const fn from_bits_truncate(bits: $repr) -> Self {
36                Self(bits)
37            }
38
39            #[must_use]
40            pub const fn empty() -> Self {
41                Self(0)
42            }
43
44            #[must_use]
45            pub const fn contains(&self, other: Self) -> bool {
46                (self.0 & other.0) == other.0
47            }
48        }
49
50        impl core::ops::BitOr for $name {
51            type Output = Self;
52            fn bitor(self, rhs: Self) -> Self::Output {
53                Self(self.0 | rhs.0)
54            }
55        }
56
57        impl core::ops::BitOrAssign for $name {
58            fn bitor_assign(&mut self, rhs: Self) {
59                self.0 |= rhs.0;
60            }
61        }
62
63        impl core::ops::BitAnd for $name {
64            type Output = Self;
65            fn bitand(self, rhs: Self) -> Self::Output {
66                Self(self.0 & rhs.0)
67            }
68        }
69
70        impl core::ops::BitAndAssign for $name {
71            fn bitand_assign(&mut self, rhs: Self) {
72                self.0 &= rhs.0;
73            }
74        }
75
76        impl core::ops::BitXor for $name {
77            type Output = Self;
78            fn bitxor(self, rhs: Self) -> Self::Output {
79                Self(self.0 ^ rhs.0)
80            }
81        }
82
83        impl core::ops::BitXorAssign for $name {
84            fn bitxor_assign(&mut self, rhs: Self) {
85                self.0 ^= rhs.0;
86            }
87        }
88
89        impl core::ops::Not for $name {
90            type Output = Self;
91            fn not(self) -> Self::Output {
92                Self(!self.0)
93            }
94        }
95
96        impl $crate::TpmMarshal for $name {
97            fn marshal(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
98                type Wrapper = <$repr as $crate::basic::IntegerRepr>::Wrapper;
99                Wrapper::from(self.0).marshal(writer)
100            }
101        }
102
103        impl $crate::TpmUnmarshal for $name {
104            fn unmarshal(buf: &[u8]) -> $crate::TpmResult<(Self, &[u8])> {
105                type Wrapper = <$repr as $crate::basic::IntegerRepr>::Wrapper;
106                let (val, buf) = Wrapper::unmarshal(buf)?;
107                Ok((Self(val.into()), buf))
108            }
109        }
110
111        impl $crate::TpmSized for $name {
112            const SIZE: usize = core::mem::size_of::<$repr>();
113            fn len(&self) -> usize {
114                Self::SIZE
115            }
116        }
117    };
118}
119
120#[macro_export]
121macro_rules! tpm_bool {
122    (
123        $(#[$outer:meta])*
124        $vis:vis struct $name:ident(bool);
125    ) => {
126        $(#[$outer])*
127        $vis struct $name(pub bool);
128
129        impl From<bool> for $name {
130            fn from(val: bool) -> Self {
131                Self(val)
132            }
133        }
134
135        impl From<$name> for bool {
136            fn from(val: $name) -> Self {
137                val.0
138            }
139        }
140
141        impl $crate::TpmMarshal for $name {
142            fn marshal(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
143                let value = if self.0 { 1 } else { 0 };
144                $crate::basic::Uint8::from(value).marshal(writer)
145            }
146        }
147
148        impl $crate::TpmUnmarshal for $name {
149            fn unmarshal(buf: &[u8]) -> $crate::TpmResult<(Self, &[u8])> {
150                let (val, buf) = $crate::basic::Uint8::unmarshal(buf)?;
151                match u8::from(val) {
152                    0 => Ok((Self(false), buf)),
153                    1 => Ok((Self(true), buf)),
154                    _ => Err($crate::TpmProtocolError::InvalidBoolean),
155                }
156            }
157        }
158
159        impl $crate::TpmSized for $name {
160            const SIZE: usize = core::mem::size_of::<$crate::basic::Uint8>();
161            fn len(&self) -> usize {
162                Self::SIZE
163            }
164        }
165    };
166}
167
168#[macro_export]
169macro_rules! tpm_dispatch {
170    (@const_check_sorted) => {};
171    (@const_check_sorted $prev_cmd:ident, $( $rest_cmd:ident, )*) => {
172        $crate::tpm_dispatch!(@const_check_sorted_impl $prev_cmd, $( $rest_cmd, )*);
173    };
174    (@const_check_sorted_impl $prev_cmd:ident,) => {};
175    (@const_check_sorted_impl $prev_cmd:ident, $current_cmd:ident, $( $rest_cmd:ident, )* ) => {
176        const _: () = assert!(
177            <$crate::frame::data::$prev_cmd as $crate::frame::TpmHeader>::CC as u32 <= <$crate::frame::data::$current_cmd as $crate::frame::TpmHeader>::CC as u32,
178            "TPM_DISPATCH_TABLE must be sorted by TpmCc."
179        );
180        $crate::tpm_dispatch!(@const_check_sorted_impl $current_cmd, $( $rest_cmd, )*);
181    };
182
183    ( $( ($cmd:ident, $resp:ident, $variant:ident) ),* $(,)? ) => {
184        /// A TPM command
185        #[allow(clippy::large_enum_variant)]
186        #[derive(Debug, PartialEq, Eq, Clone)]
187        pub enum TpmCommand {
188            $( $variant($crate::frame::data::$cmd), )*
189        }
190
191        impl $crate::TpmSized for TpmCommand {
192            const SIZE: usize = $crate::constant::TPM_MAX_COMMAND_SIZE;
193            fn len(&self) -> usize {
194                match self {
195                    $( Self::$variant(c) => $crate::TpmSized::len(c), )*
196                }
197            }
198        }
199
200        impl $crate::frame::TpmMarshalBody for TpmCommand {
201             fn marshal_handles(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
202                 match self {
203                     $( Self::$variant(c) => $crate::frame::TpmMarshalBody::marshal_handles(c, writer), )*
204                 }
205             }
206             fn marshal_parameters(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
207                 match self {
208                     $( Self::$variant(c) => $crate::frame::TpmMarshalBody::marshal_parameters(c, writer), )*
209                 }
210             }
211        }
212
213        impl $crate::TpmMarshal for TpmCommand {
214             fn marshal(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
215                 match self {
216                     $( Self::$variant(c) => $crate::TpmMarshal::marshal(c, writer), )*
217                 }
218             }
219        }
220
221        impl $crate::frame::TpmFrame for TpmCommand {
222            fn cc(&self) -> $crate::data::TpmCc {
223                match self {
224                    $( Self::$variant(c) => $crate::frame::TpmFrame::cc(c), )*
225                }
226            }
227            fn handles(&self) -> usize {
228                match self {
229                    $( Self::$variant(c) => $crate::frame::TpmFrame::handles(c), )*
230                }
231            }
232        }
233
234        impl TpmCommand {
235            /// Marshals a command body into a writer.
236            ///
237            /// # Errors
238            ///
239            /// Returns `Err(TpmProtocolError)` on a marshal failure.
240            pub fn marshal_frame(
241                &self,
242                tag: $crate::data::TpmSt,
243                sessions: &$crate::frame::TpmAuthCommands,
244                writer: &mut $crate::TpmWriter,
245            ) -> $crate::TpmResult<()> {
246                match self {
247                    $( Self::$variant(c) => $crate::frame::tpm_marshal_command(c, tag, sessions, writer), )*
248                }
249            }
250        }
251
252        /// A TPM response body
253        #[allow(clippy::large_enum_variant)]
254        #[derive(Debug, PartialEq, Eq, Clone)]
255        pub enum TpmResponse {
256            $( $variant($crate::frame::data::$resp), )*
257        }
258
259        impl $crate::TpmSized for TpmResponse {
260            const SIZE: usize = $crate::constant::TPM_MAX_COMMAND_SIZE;
261            fn len(&self) -> usize {
262                match self {
263                    $( Self::$variant(r) => $crate::TpmSized::len(r), )*
264                }
265            }
266        }
267
268        impl $crate::frame::TpmMarshalBody for TpmResponse {
269             fn marshal_handles(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
270                 match self {
271                     $( Self::$variant(r) => $crate::frame::TpmMarshalBody::marshal_handles(r, writer), )*
272                 }
273             }
274             fn marshal_parameters(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
275                 match self {
276                     $( Self::$variant(r) => $crate::frame::TpmMarshalBody::marshal_parameters(r, writer), )*
277                 }
278             }
279        }
280
281        impl $crate::TpmMarshal for TpmResponse {
282             fn marshal(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
283                 match self {
284                     $( Self::$variant(r) => $crate::TpmMarshal::marshal(r, writer), )*
285                 }
286             }
287        }
288
289        impl $crate::frame::TpmFrame for TpmResponse {
290            fn cc(&self) -> $crate::data::TpmCc {
291                match self {
292                    $( Self::$variant(r) => $crate::frame::TpmFrame::cc(r), )*
293                }
294            }
295            fn handles(&self) -> usize {
296                match self {
297                    $( Self::$variant(r) => $crate::frame::TpmFrame::handles(r), )*
298                }
299            }
300        }
301
302        impl TpmResponse {
303            $(
304                /// Attempts to convert the `TpmResponse` into a specific response type.
305                ///
306                /// # Errors
307                ///
308                /// Returns the original `TpmResponse` as an error if the enum variant does not match.
309                #[allow(non_snake_case, clippy::result_large_err)]
310                pub fn $variant(self) -> Result<$crate::frame::data::$resp, Self> {
311                    if let Self::$variant(r) = self {
312                        Ok(r)
313                    } else {
314                        Err(self)
315                    }
316                }
317            )*
318
319            /// Marshals a response body into a writer.
320            ///
321            /// # Errors
322            ///
323            /// Returns `Err(TpmProtocolError)` on a marshal failure.
324            pub fn marshal_frame(
325                &self,
326                rc: $crate::data::TpmRc,
327                sessions: &$crate::frame::TpmAuthResponses,
328                writer: &mut $crate::TpmWriter,
329            ) -> $crate::TpmResult<()> {
330                match self {
331                    $( Self::$variant(r) => $crate::frame::tpm_marshal_response(r, sessions, rc, writer), )*
332                }
333            }
334        }
335
336        pub(crate) static TPM_DISPATCH_TABLE: &[$crate::frame::TpmDispatch] = &[
337            $(
338                $crate::frame::TpmDispatch {
339                    cc: <$crate::frame::data::$cmd as $crate::frame::TpmHeader>::CC,
340                    handles: <$crate::frame::data::$cmd as $crate::frame::TpmHeader>::HANDLES,
341                    command_unmarshaler: |handles, params| {
342                        <$crate::frame::data::$cmd as $crate::frame::TpmUnmarshalCommand>::unmarshal_body(handles, params)
343                            .map(|(c, r)| (TpmCommand::$variant(c), r))
344                    },
345                    response_unmarshaler: |tag, buf| {
346                        <$crate::frame::data::$resp as $crate::frame::TpmUnmarshalResponse>::unmarshal_body(tag, buf)
347                            .map(|(r, rest)| (TpmResponse::$variant(r), rest))
348                    },
349                },
350            )*
351        ];
352
353        $crate::tpm_dispatch!(@const_check_sorted $( $cmd, )*);
354    };
355}
356
357#[macro_export]
358macro_rules! tpm2b {
359    ($name:ident, $capacity:expr) => {
360        pub type $name = $crate::basic::TpmBuffer<$capacity>;
361    };
362}
363
364#[macro_export]
365macro_rules! tpm2b_struct {
366    (
367        $(#[$meta:meta])*
368        $wrapper_ty:ident, $inner_ty:ty) => {
369        $(#[$meta])*
370        pub struct $wrapper_ty {
371            pub inner: $inner_ty,
372        }
373
374        impl $crate::TpmSized for $wrapper_ty {
375            const SIZE: usize = core::mem::size_of::<$crate::basic::Uint16>() + <$inner_ty>::SIZE;
376            fn len(&self) -> usize {
377                core::mem::size_of::<$crate::basic::Uint16>() + $crate::TpmSized::len(&self.inner)
378            }
379        }
380
381        impl $crate::TpmMarshal for $wrapper_ty
382        where
383            $inner_ty: $crate::TpmSized,
384        {
385            fn marshal(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
386                let inner_len = $crate::TpmSized::len(&self.inner);
387                let len_field = <$crate::basic::Uint16>::try_from(inner_len)
388                    .map_err(|_| $crate::TpmProtocolError::IntegerTooLarge)?;
389                len_field.marshal(writer)?;
390                $crate::TpmMarshal::marshal(&self.inner, writer)
391            }
392        }
393
394        impl $crate::TpmUnmarshal for $wrapper_ty {
395            fn unmarshal(buf: &[u8]) -> $crate::TpmResult<(Self, &[u8])> {
396                let (size, buf_after_size) = <$crate::basic::Uint16 as $crate::TpmUnmarshal>::unmarshal(buf)?;
397                let size = u16::from(size) as usize;
398
399                if buf_after_size.len() < size {
400                    return Err($crate::TpmProtocolError::UnexpectedEnd);
401                }
402                let (inner_bytes, rest) = buf_after_size.split_at(size);
403
404                let (inner_val, tail) = <$inner_ty>::unmarshal(inner_bytes)?;
405
406                if !tail.is_empty() {
407                    return Err($crate::TpmProtocolError::TrailingData);
408                }
409
410                Ok((Self { inner: inner_val }, rest))
411            }
412        }
413
414        impl From<$inner_ty> for $wrapper_ty {
415            fn from(inner: $inner_ty) -> Self {
416                Self { inner }
417            }
418        }
419
420        impl core::ops::Deref for $wrapper_ty {
421            type Target = $inner_ty;
422            fn deref(&self) -> &Self::Target {
423                &self.inner
424            }
425        }
426
427        impl core::ops::DerefMut for $wrapper_ty {
428            fn deref_mut(&mut self) -> &mut Self::Target {
429                &mut self.inner
430            }
431        }
432    };
433}
434
435#[macro_export]
436macro_rules! tpml {
437    ($name:ident, $inner_ty:ty, $capacity:expr) => {
438        pub type $name = $crate::basic::TpmList<$inner_ty, $capacity>;
439    };
440}