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                let raw = u8::from(val);
165                match raw {
166                    0 => Ok((Self(false), buf)),
167                    1 => Ok((Self(true), buf)),
168                    _ => Err($crate::TpmError::InvalidBoolean(
169                        $crate::TpmErrorValue::new(0).value(u64::from(raw)),
170                    )),
171                }
172            }
173        }
174
175        impl $crate::TpmSized for $name {
176            const SIZE: usize = core::mem::size_of::<$crate::basic::TpmUint8>();
177            fn len(&self) -> usize {
178                Self::SIZE
179            }
180        }
181    };
182}
183
184#[macro_export]
185macro_rules! tpm_dispatch {
186    (@const_check_sorted) => {};
187    (@const_check_sorted $prev_cmd:ident, $( $rest_cmd:ident, )*) => {
188        $crate::tpm_dispatch!(@const_check_sorted_impl $prev_cmd, $( $rest_cmd, )*);
189    };
190    (@const_check_sorted_impl $prev_cmd:ident,) => {};
191    (@const_check_sorted_impl $prev_cmd:ident, $current_cmd:ident, $( $rest_cmd:ident, )* ) => {
192        const _: () = assert!(
193            <$crate::frame::data::$prev_cmd as $crate::frame::TpmHeader>::CC as u32 <= <$crate::frame::data::$current_cmd as $crate::frame::TpmHeader>::CC as u32,
194            "TPM_DISPATCH_TABLE must be sorted by TpmCc."
195        );
196        $crate::tpm_dispatch!(@const_check_sorted_impl $current_cmd, $( $rest_cmd, )*);
197    };
198
199    ( $( ($cmd:ident, $resp:ident, $variant:ident) ),* $(,)? ) => {
200        /// An owned TPM command body value.
201        #[allow(clippy::large_enum_variant)]
202        #[derive(Debug, PartialEq, Eq, Clone)]
203        pub enum TpmCommandValue {
204            $( $variant($crate::frame::data::$cmd), )*
205        }
206
207        impl $crate::TpmSized for TpmCommandValue {
208            const SIZE: usize = $crate::constant::TPM_MAX_COMMAND_SIZE;
209            fn len(&self) -> usize {
210                match self {
211                    $( Self::$variant(c) => $crate::TpmSized::len(c), )*
212                }
213            }
214        }
215
216        impl $crate::frame::TpmMarshalBody for TpmCommandValue {
217             fn marshal_handles(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
218                 match self {
219                     $( Self::$variant(c) => $crate::frame::TpmMarshalBody::marshal_handles(c, writer), )*
220                 }
221             }
222             fn marshal_parameters(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
223                 match self {
224                     $( Self::$variant(c) => $crate::frame::TpmMarshalBody::marshal_parameters(c, writer), )*
225                 }
226             }
227        }
228
229        impl $crate::TpmMarshal for TpmCommandValue {
230             fn marshal(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
231                 match self {
232                     $( Self::$variant(c) => $crate::TpmMarshal::marshal(c, writer), )*
233                 }
234             }
235        }
236
237        impl $crate::frame::TpmFrame for TpmCommandValue {
238            fn cc(&self) -> $crate::data::TpmCc {
239                match self {
240                    $( Self::$variant(c) => $crate::frame::TpmFrame::cc(c), )*
241                }
242            }
243            fn handles(&self) -> usize {
244                match self {
245                    $( Self::$variant(c) => $crate::frame::TpmFrame::handles(c), )*
246                }
247            }
248        }
249
250        impl TpmCommandValue {
251            /// Marshals a command body into a writer.
252            ///
253            /// # Errors
254            ///
255            /// Returns `Err(TpmError)` on a marshal failure.
256            pub fn marshal_frame(
257                &self,
258                tag: $crate::data::TpmSt,
259                sessions: &$crate::frame::TpmAuthCommands,
260                writer: &mut $crate::TpmWriter,
261            ) -> $crate::TpmResult<()> {
262                match self {
263                    $( Self::$variant(c) => $crate::frame::tpm_marshal_command(c, tag, sessions, writer), )*
264                }
265            }
266        }
267
268        /// An owned TPM response body value.
269        #[allow(clippy::large_enum_variant)]
270        #[derive(Debug, PartialEq, Eq, Clone)]
271        pub enum TpmResponseValue {
272            $( $variant($crate::frame::data::$resp), )*
273        }
274
275        impl $crate::TpmSized for TpmResponseValue {
276            const SIZE: usize = $crate::constant::TPM_MAX_COMMAND_SIZE;
277            fn len(&self) -> usize {
278                match self {
279                    $( Self::$variant(r) => $crate::TpmSized::len(r), )*
280                }
281            }
282        }
283
284        impl $crate::frame::TpmMarshalBody for TpmResponseValue {
285             fn marshal_handles(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
286                 match self {
287                     $( Self::$variant(r) => $crate::frame::TpmMarshalBody::marshal_handles(r, writer), )*
288                 }
289             }
290             fn marshal_parameters(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
291                 match self {
292                     $( Self::$variant(r) => $crate::frame::TpmMarshalBody::marshal_parameters(r, writer), )*
293                 }
294             }
295        }
296
297        impl $crate::TpmMarshal for TpmResponseValue {
298             fn marshal(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
299                 match self {
300                     $( Self::$variant(r) => $crate::TpmMarshal::marshal(r, writer), )*
301                 }
302             }
303        }
304
305        impl $crate::frame::TpmFrame for TpmResponseValue {
306            fn cc(&self) -> $crate::data::TpmCc {
307                match self {
308                    $( Self::$variant(r) => $crate::frame::TpmFrame::cc(r), )*
309                }
310            }
311            fn handles(&self) -> usize {
312                match self {
313                    $( Self::$variant(r) => $crate::frame::TpmFrame::handles(r), )*
314                }
315            }
316        }
317
318        impl TpmResponseValue {
319            $(
320                /// Attempts to convert the `TpmResponseValue` into a specific response type.
321                ///
322                /// # Errors
323                ///
324                /// Returns the original `TpmResponseValue` as an error if the enum variant does not match.
325                #[allow(non_snake_case, clippy::result_large_err)]
326                pub fn $variant(self) -> Result<$crate::frame::data::$resp, Self> {
327                    if let Self::$variant(r) = self {
328                        Ok(r)
329                    } else {
330                        Err(self)
331                    }
332                }
333            )*
334
335            /// Marshals a response body into a writer.
336            ///
337            /// # Errors
338            ///
339            /// Returns `Err(TpmError)` on a marshal failure.
340            pub fn marshal_frame(
341                &self,
342                rc: $crate::data::TpmRc,
343                sessions: &$crate::frame::TpmAuthResponses,
344                writer: &mut $crate::TpmWriter,
345            ) -> $crate::TpmResult<()> {
346                match self {
347                    $( Self::$variant(r) => $crate::frame::tpm_marshal_response(r, sessions, rc, writer), )*
348                }
349            }
350        }
351
352        pub(crate) static TPM_DISPATCH_TABLE: &[$crate::frame::TpmDispatch] = &[
353            $(
354                $crate::frame::TpmDispatch {
355                    cc: <$crate::frame::data::$cmd as $crate::frame::TpmHeader>::CC,
356                    handles: <$crate::frame::data::$cmd as $crate::frame::TpmHeader>::HANDLES,
357                    response_handles: <$crate::frame::data::$resp as $crate::frame::TpmHeader>::HANDLES,
358                    command_unmarshaler: |handles, params| {
359                        <$crate::frame::data::$cmd as $crate::frame::TpmUnmarshalCommand>::unmarshal_body(handles, params)
360                            .map(|(c, r)| (TpmCommandValue::$variant(c), r))
361                    },
362                    response_unmarshaler: |tag, buf| {
363                        <$crate::frame::data::$resp as $crate::frame::TpmUnmarshalResponse>::unmarshal_body(tag, buf)
364                            .map(|(r, rest)| (TpmResponseValue::$variant(r), rest))
365                    },
366                },
367            )*
368        ];
369
370        $crate::tpm_dispatch!(@const_check_sorted $( $cmd, )*);
371    };
372}