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::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::TpmSized for $name {
121            const SIZE: usize = 0 $(+ <$handle_type>::SIZE)* $(+ <$param_type>::SIZE)*;
122            fn len(&self) -> usize {
123                let params_len: usize = 0 $(+ $crate::TpmSized::len(&self.$param_field))*;
124                let handles_len: usize = 0 $(+ $crate::TpmSized::len(&self.$handle_field))*;
125                let parameter_area_size_field_len: usize = if $with_sessions {
126                    core::mem::size_of::<u32>()
127                } else {
128                    0
129                };
130                handles_len + parameter_area_size_field_len + params_len
131            }
132        }
133
134        impl $crate::TpmBuild for $name {
135            fn build(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
136                let params_len: usize = 0 $(+ $crate::TpmSized::len(&self.$param_field))*;
137                $($crate::TpmBuild::build(&self.$handle_field, writer)?;)*
138                if $with_sessions {
139                    let params_len_u32 = u32::try_from(params_len)
140                        .map_err(|_| $crate::TpmErrorKind::BuildCapacity)?;
141                    $crate::TpmBuild::build(&params_len_u32, writer)?;
142                }
143                $($crate::TpmBuild::build(&self.$param_field, writer)?;)*
144                Ok(())
145            }
146        }
147
148        impl $crate::TpmParse for $name {
149            #[allow(unused_mut)]
150            fn parse(buf: &[u8]) -> $crate::TpmResult<(Self, &[u8])> {
151                let mut cursor = buf;
152                $(
153                    let ($handle_field, tail) = <$handle_type>::parse(cursor)?;
154                    cursor = tail;
155                )*
156
157                if $with_sessions {
158                    let (size, buf_after_size) = u32::parse(cursor)?;
159                    let size = size as usize;
160                    if buf_after_size.len() < size {
161                        return Err($crate::TpmErrorKind::ParseUnderflow);
162                    }
163                    let (mut params_cursor, final_tail) = buf_after_size.split_at(size);
164
165                    $(
166                        let ($param_field, tail) = <$param_type>::parse(params_cursor)?;
167                        params_cursor = tail;
168                    )*
169
170                    if !params_cursor.is_empty() {
171                        return Err($crate::TpmErrorKind::TrailingData);
172                    }
173
174                    Ok((
175                        Self {
176                            $($handle_field,)*
177                            $($param_field,)*
178                        },
179                        final_tail,
180                    ))
181                } else {
182                    let mut params_cursor = cursor;
183                    $(
184                        let ($param_field, tail) = <$param_type>::parse(params_cursor)?;
185                        params_cursor = tail;
186                    )*
187
188                    Ok((
189                        Self {
190                            $($handle_field,)*
191                            $($param_field,)*
192                        },
193                        params_cursor,
194                    ))
195                }
196            }
197        }
198
199        impl $crate::message::TpmHeader for $name {
200            const COMMAND: $crate::data::TpmCc = $cc;
201            const NO_SESSIONS: bool = $no_sessions;
202            const WITH_SESSIONS: bool = $with_sessions;
203            const HANDLES: usize = 0 $(+ {let _ = stringify!($handle_field); 1})*;
204        }
205    };
206
207    (
208        $(#[$meta:meta])*
209        $vis:vis struct $name:ident {
210            $(pub $field_name:ident: $field_type:ty),*
211            $(,)?
212        }
213    ) => {
214        $(#[$meta])*
215        $vis struct $name {
216            $(pub $field_name: $field_type,)*
217        }
218
219        impl $crate::TpmSized for $name {
220            const SIZE: usize = 0 $(+ <$field_type>::SIZE)*;
221            fn len(&self) -> usize {
222                0 $(+ $crate::TpmSized::len(&self.$field_name))*
223            }
224        }
225
226        impl $crate::TpmBuild for $name {
227            #[allow(unused_variables)]
228            fn build(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
229                $( $crate::TpmBuild::build(&self.$field_name, writer)?; )*
230                Ok(())
231            }
232        }
233
234        impl $crate::TpmParse for $name {
235            fn parse(buf: &[u8]) -> $crate::TpmResult<(Self, &[u8])> {
236                $(let ($field_name, buf) = <$field_type>::parse(buf)?;)*
237                Ok((
238                    Self {
239                        $($field_name,)*
240                    },
241                    buf,
242                ))
243            }
244        }
245    };
246}
247
248#[macro_export]
249macro_rules! tpm_tagged_struct {
250    (
251        $(#[$outer:meta])*
252        $vis:vis struct $name:ident {
253            pub $tag_field:ident: $tag_ty:ty,
254            pub $value_field:ident: $value_ty:ty,
255        }
256    ) => {
257        $(#[$outer])*
258        $vis struct $name {
259            pub $tag_field: $tag_ty,
260            pub $value_field: $value_ty,
261        }
262
263        impl $crate::TpmTagged for $name {
264            type Tag = $tag_ty;
265            type Value = $value_ty;
266        }
267
268        impl $crate::TpmSized for $name {
269            const SIZE: usize = <$tag_ty>::SIZE + <$value_ty>::SIZE;
270            fn len(&self) -> usize {
271                $crate::TpmSized::len(&self.$tag_field) + $crate::TpmSized::len(&self.$value_field)
272            }
273        }
274
275        impl $crate::TpmBuild for $name {
276            fn build(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
277                $crate::TpmBuild::build(&self.$tag_field, writer)?;
278                $crate::TpmBuild::build(&self.$value_field, writer)
279            }
280        }
281
282        impl $crate::TpmParse for $name {
283            fn parse(buf: &[u8]) -> $crate::TpmResult<(Self, &[u8])> {
284                let ($tag_field, buf) = <$tag_ty>::parse(buf)?;
285                let ($value_field, buf) =
286                    <$value_ty as $crate::TpmParseTagged>::parse_tagged($tag_field, buf)?;
287                Ok((
288                    Self {
289                        $tag_field,
290                        $value_field,
291                    },
292                    buf,
293                ))
294            }
295        }
296    };
297}