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