tpm2_protocol/macro/
struct.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2// Copyright (c) 2025 Opinsys Oy
3// Copyright (c) 2024-2025 Jarkko Sakkinen
4
5#[macro_export]
6macro_rules! tpm_struct {
7    (
8        $(#[$meta:meta])*
9        kind: Command,
10        name: $name:ident,
11        cc: $cc:expr,
12        no_sessions: $no_sessions:expr,
13        with_sessions: $with_sessions:expr,
14        handles: {
15            $(pub $handle_field:ident: $handle_type:ty),*
16            $(,)?
17        },
18        parameters: {
19            $(pub $param_field:ident: $param_type:ty),*
20            $(,)?
21        }
22    ) => {
23        $(#[$meta])*
24        pub struct $name {
25            $(pub $handle_field: $handle_type,)*
26            $(pub $param_field: $param_type,)*
27        }
28
29        impl $crate::TpmSized for $name {
30            const SIZE: usize = 0 $(+ <$handle_type>::SIZE)* $(+ <$param_type>::SIZE)*;
31            fn len(&self) -> usize {
32                0 $(+ $crate::TpmSized::len(&self.$handle_field))* $(+ $crate::TpmSized::len(&self.$param_field))*
33            }
34        }
35
36        impl $crate::TpmBuild for $name {
37            #[allow(unused_variables)]
38            fn build(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
39                <Self as $crate::message::TpmCommandBuild>::build_handles(self, writer)?;
40                <Self as $crate::message::TpmCommandBuild>::build_parameters(self, writer)
41            }
42        }
43
44        impl $crate::message::TpmCommandBuild for $name {
45            #[allow(unused_variables)]
46            fn build_handles(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
47                $($crate::TpmBuild::build(&self.$handle_field, writer)?;)*
48                Ok(())
49            }
50
51            #[allow(unused_variables)]
52            fn build_parameters(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
53                $($crate::TpmBuild::build(&self.$param_field, writer)?;)*
54                Ok(())
55            }
56        }
57
58        impl $crate::message::TpmCommandBodyParse for $name {
59            #[allow(unused_mut)]
60            fn parse_body<'a>(
61                handles: &'a [u8],
62                params: &'a [u8],
63            ) -> $crate::TpmResult<(Self, &'a [u8])> {
64                let mut cursor = handles;
65                $(
66                    let ($handle_field, tail) = <$handle_type as $crate::TpmParse>::parse(cursor)?;
67                    cursor = tail;
68                )*
69
70                if !cursor.is_empty() {
71                    return Err($crate::TpmErrorKind::TrailingData);
72                }
73
74                let mut cursor = params;
75                $(
76                    let ($param_field, tail) = <$param_type as $crate::TpmParse>::parse(cursor)?;
77                    cursor = tail;
78                )*
79
80                Ok((
81                    Self {
82                        $($handle_field,)*
83                        $($param_field,)*
84                    },
85                    cursor,
86                ))
87            }
88        }
89
90        impl $crate::message::TpmHeader for $name {
91            const COMMAND: $crate::data::TpmCc = $cc;
92            const NO_SESSIONS: bool = $no_sessions;
93            const WITH_SESSIONS: bool = $with_sessions;
94            const HANDLES: usize = 0 $(+ {let _ = stringify!($handle_field); 1})*;
95        }
96    };
97
98    (
99        $(#[$meta:meta])*
100        kind: Response,
101        name: $name:ident,
102        cc: $cc:expr,
103        no_sessions: $no_sessions:expr,
104        with_sessions: $with_sessions:expr,
105        handles: {
106            $(pub $handle_field:ident: $handle_type:ty),*
107            $(,)?
108        },
109        parameters: {
110            $(pub $param_field:ident: $param_type:ty),*
111            $(,)?
112        }
113    ) => {
114        $(#[$meta])*
115        pub struct $name {
116            $(pub $handle_field: $handle_type,)*
117            $(pub $param_field: $param_type,)*
118        }
119
120        impl $crate::message::TpmResponseBuild for $name {
121            #[allow(unused_variables)]
122            fn build_handles(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
123                $($crate::TpmBuild::build(&self.$handle_field, writer)?;)*
124                Ok(())
125            }
126            #[allow(unused_variables)]
127            fn build_parameters(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
128                $($crate::TpmBuild::build(&self.$param_field, writer)?;)*
129                Ok(())
130            }
131        }
132
133        impl $crate::TpmSized for $name {
134            const SIZE: usize = 0 $(+ <$handle_type>::SIZE)* $(+ <$param_type>::SIZE)*;
135            fn len(&self) -> usize {
136                0 $(+ $crate::TpmSized::len(&self.$handle_field))* $(+ $crate::TpmSized::len(&self.$param_field))*
137            }
138        }
139
140        impl $crate::TpmBuild for $name {
141            fn build(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
142                <Self as $crate::message::TpmResponseBuild>::build_handles(self, writer)?;
143                <Self as $crate::message::TpmResponseBuild>::build_parameters(self, writer)
144            }
145        }
146
147        impl $crate::message::TpmResponseBodyParse for $name {
148            #[allow(unused_mut)]
149            fn parse_body(
150                tag: $crate::data::TpmSt,
151                buf: &[u8],
152            ) -> $crate::TpmResult<(Self, &[u8])> {
153                let mut cursor = buf;
154                $(
155                    let ($handle_field, tail) = <$handle_type as $crate::TpmParse>::parse(cursor)?;
156                    cursor = tail;
157                )*
158
159                if $with_sessions && tag == $crate::data::TpmSt::Sessions {
160                    let (size, buf_after_size) = <u32 as $crate::TpmParse>::parse(cursor)?;
161                    let size = size as usize;
162                    if buf_after_size.len() < size {
163                        return Err($crate::TpmErrorKind::ParseUnderflow);
164                    }
165                    let (mut params_cursor, final_tail) = buf_after_size.split_at(size);
166
167                    $(
168                        let ($param_field, tail) = <$param_type as $crate::TpmParse>::parse(params_cursor)?;
169                        params_cursor = tail;
170                    )*
171
172                    if !params_cursor.is_empty() {
173                        return Err($crate::TpmErrorKind::TrailingData);
174                    }
175
176                    Ok((
177                        Self {
178                            $($handle_field,)*
179                            $($param_field,)*
180                        },
181                        final_tail,
182                    ))
183                } else {
184                    let mut params_cursor = cursor;
185                    $(
186                        let ($param_field, tail) = <$param_type as $crate::TpmParse>::parse(params_cursor)?;
187                        params_cursor = tail;
188                    )*
189
190                    Ok((
191                        Self {
192                            $($handle_field,)*
193                            $($param_field,)*
194                        },
195                        params_cursor,
196                    ))
197                }
198            }
199        }
200
201        impl $crate::message::TpmHeader for $name {
202            const COMMAND: $crate::data::TpmCc = $cc;
203            const NO_SESSIONS: bool = $no_sessions;
204            const WITH_SESSIONS: bool = $with_sessions;
205            const HANDLES: usize = 0 $(+ {let _ = stringify!($handle_field); 1})*;
206        }
207    };
208
209    (
210        $(#[$meta:meta])*
211        $vis:vis struct $name:ident {
212            $(pub $field_name:ident: $field_type:ty),*
213            $(,)?
214        }
215    ) => {
216        $(#[$meta])*
217        $vis struct $name {
218            $(pub $field_name: $field_type,)*
219        }
220
221        impl $crate::TpmSized for $name {
222            const SIZE: usize = 0 $(+ <$field_type>::SIZE)*;
223            fn len(&self) -> usize {
224                0 $(+ $crate::TpmSized::len(&self.$field_name))*
225            }
226        }
227
228        impl $crate::TpmBuild for $name {
229            #[allow(unused_variables)]
230            fn build(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
231                $( $crate::TpmBuild::build(&self.$field_name, writer)?; )*
232                Ok(())
233            }
234        }
235
236        impl $crate::TpmParse for $name {
237            fn parse(buf: &[u8]) -> $crate::TpmResult<(Self, &[u8])> {
238                $(let ($field_name, buf) = <$field_type>::parse(buf)?;)*
239                Ok((
240                    Self {
241                        $($field_name,)*
242                    },
243                    buf,
244                ))
245            }
246        }
247    };
248}
249
250#[macro_export]
251macro_rules! tpm_tagged_struct {
252    (
253        $(#[$outer:meta])*
254        $vis:vis struct $name:ident {
255            pub $tag_field:ident: $tag_ty:ty,
256            pub $value_field:ident: $value_ty:ty,
257        }
258    ) => {
259        $(#[$outer])*
260        $vis struct $name {
261            pub $tag_field: $tag_ty,
262            pub $value_field: $value_ty,
263        }
264
265        impl $crate::TpmTagged for $name {
266            type Tag = $tag_ty;
267            type Value = $value_ty;
268        }
269
270        impl $crate::TpmSized for $name {
271            const SIZE: usize = <$tag_ty>::SIZE + <$value_ty>::SIZE;
272            fn len(&self) -> usize {
273                $crate::TpmSized::len(&self.$tag_field) + $crate::TpmSized::len(&self.$value_field)
274            }
275        }
276
277        impl $crate::TpmBuild for $name {
278            fn build(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
279                $crate::TpmBuild::build(&self.$tag_field, writer)?;
280                $crate::TpmBuild::build(&self.$value_field, writer)
281            }
282        }
283
284        impl $crate::TpmParse for $name {
285            fn parse(buf: &[u8]) -> $crate::TpmResult<(Self, &[u8])> {
286                let ($tag_field, buf) = <$tag_ty>::parse(buf)?;
287                let ($value_field, buf) =
288                    <$value_ty as $crate::TpmParseTagged>::parse_tagged($tag_field, buf)?;
289                Ok((
290                    Self {
291                        $tag_field,
292                        $value_field,
293                    },
294                    buf,
295                ))
296            }
297        }
298    };
299}