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            $(pub $handle_field:ident: $handle_type:ty),*
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: $handle_type,)*
24            $(pub $param_field: $param_type,)*
25        }
26
27        impl $crate::TpmSized for $name {
28            const SIZE: usize = 0 $(+ <$handle_type>::SIZE)* $(+ <$param_type>::SIZE)*;
29            fn len(&self) -> usize {
30                0 $(+ $crate::TpmSized::len(&self.$handle_field))* $(+ $crate::TpmSized::len(&self.$param_field))*
31            }
32        }
33
34        impl $crate::TpmBuild for $name {
35            #[allow(unused_variables)]
36            fn build(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
37                <Self as $crate::message::TpmBodyBuild>::build_handles(self, writer)?;
38                <Self as $crate::message::TpmBodyBuild>::build_parameters(self, writer)
39            }
40        }
41
42        impl $crate::message::TpmBodyBuild for $name {
43            #[allow(unused_variables)]
44            fn build_handles(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
45                $($crate::TpmBuild::build(&self.$handle_field, writer)?;)*
46                Ok(())
47            }
48
49            #[allow(unused_variables)]
50            fn build_parameters(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
51                $($crate::TpmBuild::build(&self.$param_field, writer)?;)*
52                Ok(())
53            }
54        }
55
56        impl $crate::message::TpmCommandBodyParse for $name {
57            #[allow(unused_mut)]
58            fn parse_body<'a>(
59                handles: &'a [u8],
60                params: &'a [u8],
61            ) -> $crate::TpmResult<(Self, &'a [u8])> {
62                let mut cursor = handles;
63                $(
64                    let ($handle_field, tail) = <$handle_type as $crate::TpmParse>::parse(cursor)?;
65                    cursor = tail;
66                )*
67
68                if !cursor.is_empty() {
69                    return Err($crate::TpmErrorKind::TrailingData);
70                }
71
72                let mut cursor = params;
73                $(
74                    let ($param_field, tail) = <$param_type as $crate::TpmParse>::parse(cursor)?;
75                    cursor = tail;
76                )*
77
78                Ok((
79                    Self {
80                        $($handle_field,)*
81                        $($param_field,)*
82                    },
83                    cursor,
84                ))
85            }
86        }
87
88        impl $crate::message::TpmHeader for $name {
89            const CC: $crate::data::TpmCc = $cc;
90            const HANDLES: usize = 0 $(+ {let _ = stringify!($handle_field); 1})*;
91        }
92    };
93
94    (
95        $(#[$meta:meta])*
96        kind: Response,
97        name: $name:ident,
98        cc: $cc:expr,
99        handles: {
100            $(pub $handle_field:ident: $handle_type:ty),*
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: $handle_type,)*
111            $(pub $param_field: $param_type,)*
112        }
113
114        impl $crate::message::TpmBodyBuild for $name {
115            #[allow(unused_variables)]
116            fn build_handles(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
117                $($crate::TpmBuild::build(&self.$handle_field, writer)?;)*
118                Ok(())
119            }
120            #[allow(unused_variables)]
121            fn build_parameters(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
122                $($crate::TpmBuild::build(&self.$param_field, writer)?;)*
123                Ok(())
124            }
125        }
126
127        impl $crate::TpmSized for $name {
128            const SIZE: usize = 0 $(+ <$handle_type>::SIZE)* $(+ <$param_type>::SIZE)*;
129            fn len(&self) -> usize {
130                0 $(+ $crate::TpmSized::len(&self.$handle_field))* $(+ $crate::TpmSized::len(&self.$param_field))*
131            }
132        }
133
134        impl $crate::TpmBuild for $name {
135            fn build(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
136                <Self as $crate::message::TpmBodyBuild>::build_handles(self, writer)?;
137                <Self as $crate::message::TpmBodyBuild>::build_parameters(self, writer)
138            }
139        }
140
141        impl $crate::message::TpmResponseBodyParse for $name {
142            #[allow(unused_mut)]
143            fn parse_body(
144                tag: $crate::data::TpmSt,
145                buf: &[u8],
146            ) -> $crate::TpmResult<(Self, &[u8])> {
147                let mut cursor = buf;
148                $(
149                    let ($handle_field, tail) = <$handle_type as $crate::TpmParse>::parse(cursor)?;
150                    cursor = tail;
151                )*
152
153                if tag == $crate::data::TpmSt::Sessions {
154                    let (size, buf_after_size) = <u32 as $crate::TpmParse>::parse(cursor)?;
155                    let size = size as usize;
156                    if buf_after_size.len() < size {
157                        return Err($crate::TpmErrorKind::Underflow);
158                    }
159                    let (mut params_cursor, final_tail) = buf_after_size.split_at(size);
160
161                    $(
162                        let ($param_field, tail) = <$param_type as $crate::TpmParse>::parse(params_cursor)?;
163                        params_cursor = tail;
164                    )*
165
166                    if !params_cursor.is_empty() {
167                        return Err($crate::TpmErrorKind::TrailingData);
168                    }
169
170                    Ok((
171                        Self {
172                            $($handle_field,)*
173                            $($param_field,)*
174                        },
175                        final_tail,
176                    ))
177                } else {
178                    let mut params_cursor = cursor;
179                    $(
180                        let ($param_field, tail) = <$param_type as $crate::TpmParse>::parse(params_cursor)?;
181                        params_cursor = tail;
182                    )*
183
184                    Ok((
185                        Self {
186                            $($handle_field,)*
187                            $($param_field,)*
188                        },
189                        params_cursor,
190                    ))
191                }
192            }
193        }
194
195        impl $crate::message::TpmHeader for $name {
196            const CC: $crate::data::TpmCc = $cc;
197            const HANDLES: usize = 0 $(+ {let _ = stringify!($handle_field); 1})*;
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}