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) = <u32 as $crate::TpmUnmarshal>::unmarshal(cursor)?;
180                    let size = size as usize;
181                    if buf_after_size.len() < size {
182                        return Err($crate::TpmProtocolError::UnexpectedEnd);
183                    }
184                    let (mut params_cursor, final_tail) = buf_after_size.split_at(size);
185
186                    $(
187                        let ($param_field, tail) = <$param_type as $crate::TpmUnmarshal>::unmarshal(params_cursor)?;
188                        params_cursor = tail;
189                    )*
190
191                    if !params_cursor.is_empty() {
192                        return Err($crate::TpmProtocolError::TrailingData);
193                    }
194
195                    Ok((
196                        Self {
197                            handles,
198                            $($param_field,)*
199                        },
200                        final_tail,
201                    ))
202                } else {
203                    let mut params_cursor = cursor;
204                    $(
205                        let ($param_field, tail) = <$param_type as $crate::TpmUnmarshal>::unmarshal(params_cursor)?;
206                        params_cursor = tail;
207                    )*
208
209                    Ok((
210                        Self {
211                            handles,
212                            $($param_field,)*
213                        },
214                        params_cursor,
215                    ))
216                }
217            }
218        }
219    };
220
221    (
222        $(#[$meta:meta])*
223        $vis:vis struct $name:ident {
224            $(pub $field_name:ident: $field_type:ty),*
225            $(,)?
226        }
227    ) => {
228        $(#[$meta])*
229        $vis struct $name {
230            $(pub $field_name: $field_type,)*
231        }
232
233        impl $crate::TpmSized for $name {
234            const SIZE: usize = 0 $(+ <$field_type>::SIZE)*;
235            fn len(&self) -> usize {
236                0 $(+ $crate::TpmSized::len(&self.$field_name))*
237            }
238        }
239
240        impl $crate::TpmMarshal for $name {
241            #[allow(unused_variables)]
242            fn marshal(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
243                $( $crate::TpmMarshal::marshal(&self.$field_name, writer)?; )*
244                Ok(())
245            }
246        }
247
248        impl $crate::TpmUnmarshal for $name {
249            fn unmarshal(buf: &[u8]) -> $crate::TpmResult<(Self, &[u8])> {
250                $(let ($field_name, buf) = <$field_type>::unmarshal(buf)?;)*
251                Ok((
252                    Self {
253                        $($field_name,)*
254                    },
255                    buf,
256                ))
257            }
258        }
259    };
260}