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        handles: {
13            $($handle_field:ident),*
14            $(,)?
15        },
16        parameters: {
17            $(pub $param_field:ident: $param_type:ty),*
18            $(,)?
19        }
20    ) => {
21        $(#[$meta])*
22        pub struct $name {
23            $(pub $handle_field: $crate::TpmHandle,)*
24            $(pub $param_field: $param_type,)*
25        }
26
27        impl $crate::message::TpmHeader for $name {
28            const CC: $crate::data::TpmCc = $cc;
29            const HANDLES: usize = 0 $(+ {let _ = stringify!($handle_field); 1})*;
30        }
31
32        impl $crate::TpmSized for $name {
33            const SIZE: usize = (Self::HANDLES * <$crate::TpmHandle>::SIZE) $(+ <$param_type>::SIZE)*;
34            fn len(&self) -> usize {
35                0 $(+ $crate::TpmSized::len(&self.$handle_field))* $(+ $crate::TpmSized::len(&self.$param_field))*
36            }
37        }
38
39        impl $crate::TpmBuild for $name {
40            #[allow(unused_variables)]
41            fn build(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
42                <Self as $crate::message::TpmBodyBuild>::build_handles(self, writer)?;
43                <Self as $crate::message::TpmBodyBuild>::build_parameters(self, writer)
44            }
45        }
46
47        impl $crate::message::TpmBodyBuild for $name {
48            #[allow(unused_variables)]
49            fn build_handles(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
50                $($crate::TpmBuild::build(&self.$handle_field, writer)?;)*
51                Ok(())
52            }
53
54            #[allow(unused_variables)]
55            fn build_parameters(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
56                $($crate::TpmBuild::build(&self.$param_field, writer)?;)*
57                Ok(())
58            }
59        }
60
61        impl $crate::message::TpmCommandBodyParse for $name {
62            #[allow(unused_mut, unused_variables)]
63            fn parse_body<'a>(
64                handles: &'a [u8],
65                params: &'a [u8],
66            ) -> $crate::TpmResult<(Self, &'a [u8])> {
67                let mut cursor = handles;
68                $(
69                    let ($handle_field, tail) = <$crate::TpmHandle as $crate::TpmParse>::parse(cursor)?;
70                    cursor = tail;
71                )*
72
73                if !cursor.is_empty() {
74                    return Err($crate::TpmError::TrailingData);
75                }
76
77                let mut cursor = params;
78                $(
79                    let ($param_field, tail) = <$param_type as $crate::TpmParse>::parse(cursor)?;
80                    cursor = tail;
81                )*
82
83                Ok((
84                    Self {
85                        $($handle_field,)*
86                        $($param_field,)*
87                    },
88                    cursor,
89                ))
90            }
91        }
92    };
93
94    (
95        $(#[$meta:meta])*
96        kind: Response,
97        name: $name:ident,
98        cc: $cc:expr,
99        handles: {
100            $($handle_field:ident),*
101            $(,)?
102        },
103        parameters: {
104            $(pub $param_field:ident: $param_type:ty),*
105            $(,)?
106        }
107    ) => {
108        $(#[$meta])*
109        pub struct $name {
110            $(pub $handle_field: $crate::TpmHandle,)*
111            $(pub $param_field: $param_type,)*
112        }
113
114        impl $crate::message::TpmHeader for $name {
115            const CC: $crate::data::TpmCc = $cc;
116            const HANDLES: usize = 0 $(+ {let _ = stringify!($handle_field); 1})*;
117        }
118
119        impl $crate::message::TpmBodyBuild for $name {
120            #[allow(unused_variables)]
121            fn build_handles(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
122                $($crate::TpmBuild::build(&self.$handle_field, writer)?;)*
123                Ok(())
124            }
125            #[allow(unused_variables)]
126            fn build_parameters(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
127                $($crate::TpmBuild::build(&self.$param_field, writer)?;)*
128                Ok(())
129            }
130        }
131
132        impl $crate::TpmSized for $name {
133            const SIZE: usize = (Self::HANDLES * <$crate::TpmHandle>::SIZE) $(+ <$param_type>::SIZE)*;
134            fn len(&self) -> usize {
135                0 $(+ $crate::TpmSized::len(&self.$handle_field))* $(+ $crate::TpmSized::len(&self.$param_field))*
136            }
137        }
138
139        impl $crate::TpmBuild for $name {
140            fn build(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
141                <Self as $crate::message::TpmBodyBuild>::build_handles(self, writer)?;
142                <Self as $crate::message::TpmBodyBuild>::build_parameters(self, writer)
143            }
144        }
145
146        impl $crate::message::TpmResponseBodyParse for $name {
147            #[allow(unused_mut, unused_variables)]
148            fn parse_body(
149                tag: $crate::data::TpmSt,
150                buf: &[u8],
151            ) -> $crate::TpmResult<(Self, &[u8])> {
152                let mut cursor = buf;
153                $(
154                    let ($handle_field, tail) = <$crate::TpmHandle as $crate::TpmParse>::parse(cursor)?;
155                    cursor = tail;
156                )*
157
158                if tag == $crate::data::TpmSt::Sessions {
159                    let (size, buf_after_size) = <u32 as $crate::TpmParse>::parse(cursor)?;
160                    let size = size as usize;
161                    if buf_after_size.len() < size {
162                        return Err($crate::TpmError::Truncated);
163                    }
164                    let (mut params_cursor, final_tail) = buf_after_size.split_at(size);
165
166                    $(
167                        let ($param_field, tail) = <$param_type as $crate::TpmParse>::parse(params_cursor)?;
168                        params_cursor = tail;
169                    )*
170
171                    if !params_cursor.is_empty() {
172                        return Err($crate::TpmError::TrailingData);
173                    }
174
175                    Ok((
176                        Self {
177                            $($handle_field,)*
178                            $($param_field,)*
179                        },
180                        final_tail,
181                    ))
182                } else {
183                    let mut params_cursor = cursor;
184                    $(
185                        let ($param_field, tail) = <$param_type as $crate::TpmParse>::parse(params_cursor)?;
186                        params_cursor = tail;
187                    )*
188
189                    Ok((
190                        Self {
191                            $($handle_field,)*
192                            $($param_field,)*
193                        },
194                        params_cursor,
195                    ))
196                }
197            }
198        }
199    };
200
201    (
202        $(#[$meta:meta])*
203        $vis:vis struct $name:ident {
204            $(pub $field_name:ident: $field_type:ty),*
205            $(,)?
206        }
207    ) => {
208        $(#[$meta])*
209        $vis struct $name {
210            $(pub $field_name: $field_type,)*
211        }
212
213        impl $crate::TpmSized for $name {
214            const SIZE: usize = 0 $(+ <$field_type>::SIZE)*;
215            fn len(&self) -> usize {
216                0 $(+ $crate::TpmSized::len(&self.$field_name))*
217            }
218        }
219
220        impl $crate::TpmBuild for $name {
221            #[allow(unused_variables)]
222            fn build(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
223                $( $crate::TpmBuild::build(&self.$field_name, writer)?; )*
224                Ok(())
225            }
226        }
227
228        impl $crate::TpmParse for $name {
229            fn parse(buf: &[u8]) -> $crate::TpmResult<(Self, &[u8])> {
230                $(let ($field_name, buf) = <$field_type>::parse(buf)?;)*
231                Ok((
232                    Self {
233                        $($field_name,)*
234                    },
235                    buf,
236                ))
237            }
238        }
239    };
240}