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