Skip to main content

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