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