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    (@impl $(#[$outer:meta])* $vis:vis struct $name:ident($wrapper:ty, $repr:ty) {
12        $(
13            $(#[$inner:meta])*
14            const $field:ident = $value:expr, $string_name:literal;
15        )*
16    }) => {
17        $(#[$outer])*
18        $vis struct $name($repr);
19
20        impl $name {
21            $(
22                $(#[$inner])*
23                pub const $field: Self = Self($value);
24            )*
25
26            #[must_use]
27            pub const fn bits(&self) -> $repr {
28                self.0
29            }
30
31            #[must_use]
32            pub const fn from_bits_truncate(bits: $repr) -> Self {
33                Self(bits)
34            }
35
36            #[must_use]
37            pub const fn empty() -> Self {
38                Self(0)
39            }
40
41            #[must_use]
42            pub const fn contains(&self, other: Self) -> bool {
43                (self.0 & other.0) == other.0
44            }
45        }
46
47        impl core::ops::BitOr for $name {
48            type Output = Self;
49            fn bitor(self, rhs: Self) -> Self::Output {
50                Self(self.0 | rhs.0)
51            }
52        }
53
54        impl core::ops::BitOrAssign for $name {
55            fn bitor_assign(&mut self, rhs: Self) {
56                self.0 |= rhs.0;
57            }
58        }
59
60        impl core::ops::BitAnd for $name {
61            type Output = Self;
62            fn bitand(self, rhs: Self) -> Self::Output {
63                Self(self.0 & rhs.0)
64            }
65        }
66
67        impl core::ops::BitAndAssign for $name {
68            fn bitand_assign(&mut self, rhs: Self) {
69                self.0 &= rhs.0;
70            }
71        }
72
73        impl core::ops::BitXor for $name {
74            type Output = Self;
75            fn bitxor(self, rhs: Self) -> Self::Output {
76                Self(self.0 ^ rhs.0)
77            }
78        }
79
80        impl core::ops::BitXorAssign for $name {
81            fn bitxor_assign(&mut self, rhs: Self) {
82                self.0 ^= rhs.0;
83            }
84        }
85
86        impl core::ops::Not for $name {
87            type Output = Self;
88            fn not(self) -> Self::Output {
89                Self(!self.0)
90            }
91        }
92
93        impl $crate::TpmMarshal for $name {
94            fn marshal(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
95                let value = <$wrapper>::from(self.0);
96                $crate::TpmMarshal::marshal(&value, writer)
97            }
98        }
99
100        impl $crate::TpmUnmarshal for $name {
101            fn unmarshal(buf: &[u8]) -> $crate::TpmResult<(Self, &[u8])> {
102                let (val, buf) = <$wrapper as $crate::TpmUnmarshal>::unmarshal(buf)?;
103                Ok((Self(val.into()), buf))
104            }
105        }
106
107        impl $crate::TpmSized for $name {
108            const SIZE: usize = core::mem::size_of::<$repr>();
109            fn len(&self) -> usize {
110                Self::SIZE
111            }
112        }
113    };
114
115    ($(#[$meta:meta])* $vis:vis struct $name:ident(TpmUint8) { $($rest:tt)* }) => {
116        tpm_bitflags!(@impl $(#[$meta])* $vis struct $name($crate::basic::TpmUint8, u8) { $($rest)* });
117    };
118    ($(#[$meta:meta])* $vis:vis struct $name:ident(TpmUint16) { $($rest:tt)* }) => {
119        tpm_bitflags!(@impl $(#[$meta])* $vis struct $name($crate::basic::TpmUint16, u16) { $($rest)* });
120    };
121    ($(#[$meta:meta])* $vis:vis struct $name:ident(TpmUint32) { $($rest:tt)* }) => {
122        tpm_bitflags!(@impl $(#[$meta])* $vis struct $name($crate::basic::TpmUint32, u32) { $($rest)* });
123    };
124    ($(#[$meta:meta])* $vis:vis struct $name:ident(TpmUint64) { $($rest:tt)* }) => {
125        tpm_bitflags!(@impl $(#[$meta])* $vis struct $name($crate::basic::TpmUint64, u64) { $($rest)* });
126    };
127}
128
129#[macro_export]
130macro_rules! tpm_bool {
131    (
132        $(#[$outer:meta])*
133        $vis:vis struct $name:ident(bool);
134    ) => {
135        $(#[$outer])*
136        $vis struct $name(pub bool);
137
138        impl From<bool> for $name {
139            fn from(val: bool) -> Self {
140                Self(val)
141            }
142        }
143
144        impl From<$name> for bool {
145            fn from(val: $name) -> Self {
146                val.0
147            }
148        }
149
150        impl $crate::TpmMarshal for $name {
151            fn marshal(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
152                let value = if self.0 { 1 } else { 0 };
153                $crate::basic::TpmUint8::from(value).marshal(writer)
154            }
155        }
156
157        impl $crate::TpmUnmarshal for $name {
158            fn unmarshal(buf: &[u8]) -> $crate::TpmResult<(Self, &[u8])> {
159                let (val, buf) = $crate::basic::TpmUint8::unmarshal(buf)?;
160                match u8::from(val) {
161                    0 => Ok((Self(false), buf)),
162                    1 => Ok((Self(true), buf)),
163                    _ => Err($crate::TpmProtocolError::InvalidBoolean),
164                }
165            }
166        }
167
168        impl $crate::TpmSized for $name {
169            const SIZE: usize = core::mem::size_of::<$crate::basic::TpmUint8>();
170            fn len(&self) -> usize {
171                Self::SIZE
172            }
173        }
174    };
175}
176
177#[macro_export]
178macro_rules! tpm_dispatch {
179    (@const_check_sorted) => {};
180    (@const_check_sorted $prev_cmd:ident, $( $rest_cmd:ident, )*) => {
181        $crate::tpm_dispatch!(@const_check_sorted_impl $prev_cmd, $( $rest_cmd, )*);
182    };
183    (@const_check_sorted_impl $prev_cmd:ident,) => {};
184    (@const_check_sorted_impl $prev_cmd:ident, $current_cmd:ident, $( $rest_cmd:ident, )* ) => {
185        const _: () = assert!(
186            <$crate::frame::data::$prev_cmd as $crate::frame::TpmHeader>::CC as u32 <= <$crate::frame::data::$current_cmd as $crate::frame::TpmHeader>::CC as u32,
187            "TPM_DISPATCH_TABLE must be sorted by TpmCc."
188        );
189        $crate::tpm_dispatch!(@const_check_sorted_impl $current_cmd, $( $rest_cmd, )*);
190    };
191
192    ( $( ($cmd:ident, $resp:ident, $variant:ident) ),* $(,)? ) => {
193        /// A TPM command
194        #[allow(clippy::large_enum_variant)]
195        #[derive(Debug, PartialEq, Eq, Clone)]
196        pub enum TpmCommand {
197            $( $variant($crate::frame::data::$cmd), )*
198        }
199
200        impl $crate::TpmSized for TpmCommand {
201            const SIZE: usize = $crate::constant::TPM_MAX_COMMAND_SIZE;
202            fn len(&self) -> usize {
203                match self {
204                    $( Self::$variant(c) => $crate::TpmSized::len(c), )*
205                }
206            }
207        }
208
209        impl $crate::frame::TpmMarshalBody for TpmCommand {
210             fn marshal_handles(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
211                 match self {
212                     $( Self::$variant(c) => $crate::frame::TpmMarshalBody::marshal_handles(c, writer), )*
213                 }
214             }
215             fn marshal_parameters(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
216                 match self {
217                     $( Self::$variant(c) => $crate::frame::TpmMarshalBody::marshal_parameters(c, writer), )*
218                 }
219             }
220        }
221
222        impl $crate::TpmMarshal for TpmCommand {
223             fn marshal(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
224                 match self {
225                     $( Self::$variant(c) => $crate::TpmMarshal::marshal(c, writer), )*
226                 }
227             }
228        }
229
230        impl $crate::frame::TpmFrame for TpmCommand {
231            fn cc(&self) -> $crate::data::TpmCc {
232                match self {
233                    $( Self::$variant(c) => $crate::frame::TpmFrame::cc(c), )*
234                }
235            }
236            fn handles(&self) -> usize {
237                match self {
238                    $( Self::$variant(c) => $crate::frame::TpmFrame::handles(c), )*
239                }
240            }
241        }
242
243        impl TpmCommand {
244            /// Marshals a command body into a writer.
245            ///
246            /// # Errors
247            ///
248            /// Returns `Err(TpmProtocolError)` on a marshal failure.
249            pub fn marshal_frame(
250                &self,
251                tag: $crate::data::TpmSt,
252                sessions: &$crate::frame::TpmAuthCommands,
253                writer: &mut $crate::TpmWriter,
254            ) -> $crate::TpmResult<()> {
255                match self {
256                    $( Self::$variant(c) => $crate::frame::tpm_marshal_command(c, tag, sessions, writer), )*
257                }
258            }
259        }
260
261        /// A TPM response body
262        #[allow(clippy::large_enum_variant)]
263        #[derive(Debug, PartialEq, Eq, Clone)]
264        pub enum TpmResponse {
265            $( $variant($crate::frame::data::$resp), )*
266        }
267
268        impl $crate::TpmSized for TpmResponse {
269            const SIZE: usize = $crate::constant::TPM_MAX_COMMAND_SIZE;
270            fn len(&self) -> usize {
271                match self {
272                    $( Self::$variant(r) => $crate::TpmSized::len(r), )*
273                }
274            }
275        }
276
277        impl $crate::frame::TpmMarshalBody for TpmResponse {
278             fn marshal_handles(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
279                 match self {
280                     $( Self::$variant(r) => $crate::frame::TpmMarshalBody::marshal_handles(r, writer), )*
281                 }
282             }
283             fn marshal_parameters(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
284                 match self {
285                     $( Self::$variant(r) => $crate::frame::TpmMarshalBody::marshal_parameters(r, writer), )*
286                 }
287             }
288        }
289
290        impl $crate::TpmMarshal for TpmResponse {
291             fn marshal(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
292                 match self {
293                     $( Self::$variant(r) => $crate::TpmMarshal::marshal(r, writer), )*
294                 }
295             }
296        }
297
298        impl $crate::frame::TpmFrame for TpmResponse {
299            fn cc(&self) -> $crate::data::TpmCc {
300                match self {
301                    $( Self::$variant(r) => $crate::frame::TpmFrame::cc(r), )*
302                }
303            }
304            fn handles(&self) -> usize {
305                match self {
306                    $( Self::$variant(r) => $crate::frame::TpmFrame::handles(r), )*
307                }
308            }
309        }
310
311        impl TpmResponse {
312            $(
313                /// Attempts to convert the `TpmResponse` into a specific response type.
314                ///
315                /// # Errors
316                ///
317                /// Returns the original `TpmResponse` as an error if the enum variant does not match.
318                #[allow(non_snake_case, clippy::result_large_err)]
319                pub fn $variant(self) -> Result<$crate::frame::data::$resp, Self> {
320                    if let Self::$variant(r) = self {
321                        Ok(r)
322                    } else {
323                        Err(self)
324                    }
325                }
326            )*
327
328            /// Marshals a response body into a writer.
329            ///
330            /// # Errors
331            ///
332            /// Returns `Err(TpmProtocolError)` on a marshal failure.
333            pub fn marshal_frame(
334                &self,
335                rc: $crate::data::TpmRc,
336                sessions: &$crate::frame::TpmAuthResponses,
337                writer: &mut $crate::TpmWriter,
338            ) -> $crate::TpmResult<()> {
339                match self {
340                    $( Self::$variant(r) => $crate::frame::tpm_marshal_response(r, sessions, rc, writer), )*
341                }
342            }
343        }
344
345        pub(crate) static TPM_DISPATCH_TABLE: &[$crate::frame::TpmDispatch] = &[
346            $(
347                $crate::frame::TpmDispatch {
348                    cc: <$crate::frame::data::$cmd as $crate::frame::TpmHeader>::CC,
349                    handles: <$crate::frame::data::$cmd as $crate::frame::TpmHeader>::HANDLES,
350                    command_unmarshaler: |handles, params| {
351                        <$crate::frame::data::$cmd as $crate::frame::TpmUnmarshalCommand>::unmarshal_body(handles, params)
352                            .map(|(c, r)| (TpmCommand::$variant(c), r))
353                    },
354                    response_unmarshaler: |tag, buf| {
355                        <$crate::frame::data::$resp as $crate::frame::TpmUnmarshalResponse>::unmarshal_body(tag, buf)
356                            .map(|(r, rest)| (TpmResponse::$variant(r), rest))
357                    },
358                },
359            )*
360        ];
361
362        $crate::tpm_dispatch!(@const_check_sorted $( $cmd, )*);
363    };
364}