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