Skip to main content

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::basic::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 $name {
30            /// Casts a command frame into a typed wire view for this command.
31            ///
32            /// # Errors
33            ///
34            /// Returns `Err(TpmProtocolError)` when the frame is malformed or
35            /// has a different command code.
36            pub fn cast_frame(buf: &[u8]) -> $crate::TpmResult<&$crate::frame::TpmCommand> {
37                let command = <$crate::frame::TpmCommand>::cast(buf)?;
38
39                if command.cc()? != Self::CC {
40                    return Err($crate::TpmProtocolError::InvalidCc);
41                }
42
43                Ok(command)
44            }
45
46            /// Casts a mutable command frame into a typed mutable wire view for this command.
47            ///
48            /// # Errors
49            ///
50            /// Returns `Err(TpmProtocolError)` when the frame is malformed or
51            /// has a different command code.
52            pub fn cast_frame_mut(
53                buf: &mut [u8],
54            ) -> $crate::TpmResult<&mut $crate::frame::TpmCommand> {
55                let command = <$crate::frame::TpmCommand>::cast_mut(buf)?;
56
57                if command.cc()? != Self::CC {
58                    return Err($crate::TpmProtocolError::InvalidCc);
59                }
60
61                Ok(command)
62            }
63        }
64
65        impl $crate::frame::TpmFrame for $name {
66            fn cc(&self) -> $crate::data::TpmCc {
67                Self::CC
68            }
69            fn handles(&self) -> usize {
70                Self::HANDLES
71            }
72        }
73
74        impl $crate::TpmSized for $name {
75            const SIZE: usize = (Self::HANDLES * <$crate::basic::TpmHandle>::SIZE) $(+ <$param_type>::SIZE)*;
76            fn len(&self) -> usize {
77                (self.handles.len() * <$crate::basic::TpmHandle>::SIZE) $(+ $crate::TpmSized::len(&self.$param_field))*
78            }
79        }
80
81        impl $crate::TpmMarshal for $name {
82            #[allow(unused_variables)]
83            fn marshal(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
84                <Self as $crate::frame::TpmMarshalBody>::marshal_handles(self, writer)?;
85                <Self as $crate::frame::TpmMarshalBody>::marshal_parameters(self, writer)
86            }
87        }
88
89        impl $crate::frame::TpmMarshalBody for $name {
90            #[allow(unused_variables)]
91            fn marshal_handles(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
92                for handle in &self.handles {
93                    $crate::TpmMarshal::marshal(handle, writer)?;
94                }
95                Ok(())
96            }
97
98            #[allow(unused_variables)]
99            fn marshal_parameters(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
100                $($crate::TpmMarshal::marshal(&self.$param_field, writer)?;)*
101                Ok(())
102            }
103        }
104
105        impl $crate::frame::TpmUnmarshalCommand for $name {
106            #[allow(unused_mut, unused_variables)]
107            fn unmarshal_body<'a>(
108                handles_buf: &'a [u8],
109                params_buf: &'a [u8],
110            ) -> $crate::TpmResult<(Self, &'a [u8])> {
111                let mut cursor = handles_buf;
112                let mut handles: [$crate::basic::TpmHandle; $count] = ::core::default::Default::default();
113                for handle in &mut handles {
114                    let (val, tail) = <$crate::basic::TpmHandle as $crate::TpmUnmarshal>::unmarshal(cursor)?;
115                    *handle = val;
116                    cursor = tail;
117                }
118
119                if !cursor.is_empty() {
120                    return Err($crate::TpmProtocolError::TrailingData);
121                }
122
123                let mut cursor = params_buf;
124                $(
125                    let ($param_field, tail) = <$param_type as $crate::TpmUnmarshal>::unmarshal(cursor)?;
126                    cursor = tail;
127                )*
128
129                Ok((
130                    Self {
131                        handles,
132                        $($param_field,)*
133                    },
134                    cursor,
135                ))
136            }
137        }
138    };
139
140    (
141        $(#[$meta:meta])*
142        kind: Response,
143        name: $name:ident,
144        cc: $cc:expr,
145        handles: $count:literal,
146        parameters: {
147            $(pub $param_field:ident: $param_type:ty),*
148            $(,)?
149        }
150    ) => {
151        $(#[$meta])*
152        pub struct $name {
153            pub handles: [$crate::basic::TpmHandle; $count],
154            $(pub $param_field: $param_type,)*
155        }
156
157        impl $crate::frame::TpmHeader for $name {
158            const CC: $crate::data::TpmCc = $cc;
159            const HANDLES: usize = $count;
160        }
161
162        impl $name {
163            /// Casts a response frame into a typed wire view for this response.
164            ///
165            /// # Errors
166            ///
167            /// Returns `Err(TpmProtocolError)` when the frame envelope is malformed.
168            pub fn cast_frame(buf: &[u8]) -> $crate::TpmResult<&$crate::frame::TpmResponse> {
169                <$crate::frame::TpmResponse>::cast(buf)
170            }
171
172            /// Casts a mutable response frame into a typed mutable wire view for this response.
173            ///
174            /// # Errors
175            ///
176            /// Returns `Err(TpmProtocolError)` when the frame envelope is malformed.
177            pub fn cast_frame_mut(
178                buf: &mut [u8],
179            ) -> $crate::TpmResult<&mut $crate::frame::TpmResponse> {
180                <$crate::frame::TpmResponse>::cast_mut(buf)
181            }
182        }
183
184        impl $crate::frame::TpmFrame for $name {
185            fn cc(&self) -> $crate::data::TpmCc {
186                Self::CC
187            }
188            fn handles(&self) -> usize {
189                Self::HANDLES
190            }
191        }
192
193        impl $crate::frame::TpmMarshalBody for $name {
194            #[allow(unused_variables)]
195            fn marshal_handles(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
196                for handle in &self.handles {
197                    $crate::TpmMarshal::marshal(handle, writer)?;
198                }
199                Ok(())
200            }
201            #[allow(unused_variables)]
202            fn marshal_parameters(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
203                $($crate::TpmMarshal::marshal(&self.$param_field, writer)?;)*
204                Ok(())
205            }
206        }
207
208        impl $crate::TpmSized for $name {
209            const SIZE: usize = (Self::HANDLES * <$crate::basic::TpmHandle>::SIZE) $(+ <$param_type>::SIZE)*;
210            fn len(&self) -> usize {
211                (self.handles.len() * <$crate::basic::TpmHandle>::SIZE) $(+ $crate::TpmSized::len(&self.$param_field))*
212            }
213        }
214
215        impl $crate::TpmMarshal for $name {
216            fn marshal(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
217                <Self as $crate::frame::TpmMarshalBody>::marshal_handles(self, writer)?;
218                <Self as $crate::frame::TpmMarshalBody>::marshal_parameters(self, writer)
219            }
220        }
221
222        impl $crate::frame::TpmUnmarshalResponse for $name {
223            #[allow(unused_mut, unused_variables)]
224            fn unmarshal_body(
225                tag: $crate::data::TpmSt,
226                buf: &[u8],
227            ) -> $crate::TpmResult<(Self, &[u8])> {
228                let mut cursor = buf;
229                let mut handles: [$crate::basic::TpmHandle; $count] = ::core::default::Default::default();
230                for handle in &mut handles {
231                    let (val, tail) = <$crate::basic::TpmHandle as $crate::TpmUnmarshal>::unmarshal(cursor)?;
232                    *handle = val;
233                    cursor = tail;
234                }
235
236                if tag == $crate::data::TpmSt::Sessions {
237                    let (size, buf_after_size) =
238                        <$crate::basic::TpmUint32 as $crate::TpmUnmarshal>::unmarshal(cursor)?;
239                    let size = u32::from(size) as usize;
240                    if buf_after_size.len() < size {
241                        return Err($crate::TpmProtocolError::UnexpectedEnd);
242                    }
243                    let (mut params_cursor, final_tail) = buf_after_size.split_at(size);
244
245                    $(
246                        let ($param_field, tail) = <$param_type as $crate::TpmUnmarshal>::unmarshal(params_cursor)?;
247                        params_cursor = tail;
248                    )*
249
250                    if !params_cursor.is_empty() {
251                        return Err($crate::TpmProtocolError::TrailingData);
252                    }
253
254                    Ok((
255                        Self {
256                            handles,
257                            $($param_field,)*
258                        },
259                        final_tail,
260                    ))
261                } else {
262                    let mut params_cursor = cursor;
263                    $(
264                        let ($param_field, tail) = <$param_type as $crate::TpmUnmarshal>::unmarshal(params_cursor)?;
265                        params_cursor = tail;
266                    )*
267
268                    Ok((
269                        Self {
270                            handles,
271                            $($param_field,)*
272                        },
273                        params_cursor,
274                    ))
275                }
276            }
277        }
278    };
279
280    (
281        $(#[$meta:meta])*
282        $vis:vis struct $name:ident {
283            $(pub $field_name:ident: $field_type:ty),*
284            $(,)?
285        }
286    ) => {
287        $(#[$meta])*
288        $vis struct $name {
289            $(pub $field_name: $field_type,)*
290        }
291
292        impl $crate::TpmSized for $name {
293            const SIZE: usize = 0 $(+ <$field_type>::SIZE)*;
294            fn len(&self) -> usize {
295                0 $(+ $crate::TpmSized::len(&self.$field_name))*
296            }
297        }
298
299        impl $crate::TpmMarshal for $name {
300            #[allow(unused_variables)]
301            fn marshal(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
302                $( $crate::TpmMarshal::marshal(&self.$field_name, writer)?; )*
303                Ok(())
304            }
305        }
306
307        impl $crate::TpmUnmarshal for $name {
308            fn unmarshal(buf: &[u8]) -> $crate::TpmResult<(Self, &[u8])> {
309                $(let ($field_name, buf) = <$field_type>::unmarshal(buf)?;)*
310                Ok((
311                    Self {
312                        $($field_name,)*
313                    },
314                    buf,
315                ))
316            }
317        }
318    };
319}
320
321#[macro_export]
322macro_rules! tpm2b {
323    ($name:ident, $capacity:expr) => {
324        pub type $name = $crate::basic::TpmBuffer<$capacity>;
325    };
326}
327
328#[macro_export]
329macro_rules! tpm2b_struct {
330    (
331        $(#[$meta:meta])*
332        $wrapper_ty:ident, $inner_ty:ty) => {
333        $(#[$meta])*
334        pub struct $wrapper_ty {
335            pub inner: $inner_ty,
336        }
337
338        impl $crate::TpmSized for $wrapper_ty {
339            const SIZE: usize = $crate::basic::TpmUint16::SIZE + <$inner_ty>::SIZE;
340            fn len(&self) -> usize {
341                $crate::basic::TpmUint16::SIZE + $crate::TpmSized::len(&self.inner)
342            }
343        }
344
345        impl $crate::TpmMarshal for $wrapper_ty
346        where
347            $inner_ty: $crate::TpmSized,
348        {
349            fn marshal(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
350                let inner_len = $crate::TpmSized::len(&self.inner);
351                let len_field = <$crate::basic::TpmUint16>::try_from(inner_len)
352                    .map_err(|_| $crate::TpmProtocolError::IntegerTooLarge)?;
353                len_field.marshal(writer)?;
354                $crate::TpmMarshal::marshal(&self.inner, writer)
355            }
356        }
357
358        impl $crate::TpmUnmarshal for $wrapper_ty {
359            fn unmarshal(buf: &[u8]) -> $crate::TpmResult<(Self, &[u8])> {
360                let (size, buf_after_size) = <$crate::basic::TpmUint16 as $crate::TpmUnmarshal>::unmarshal(buf)?;
361                let size = u16::from(size) as usize;
362
363                if buf_after_size.len() < size {
364                    return Err($crate::TpmProtocolError::UnexpectedEnd);
365                }
366                let (inner_bytes, rest) = buf_after_size.split_at(size);
367
368                let (inner_val, tail) = <$inner_ty>::unmarshal(inner_bytes)?;
369
370                if !tail.is_empty() {
371                    return Err($crate::TpmProtocolError::TrailingData);
372                }
373
374                Ok((Self { inner: inner_val }, rest))
375            }
376        }
377
378        impl From<$inner_ty> for $wrapper_ty {
379            fn from(inner: $inner_ty) -> Self {
380                Self { inner }
381            }
382        }
383
384        impl core::ops::Deref for $wrapper_ty {
385            type Target = $inner_ty;
386            fn deref(&self) -> &Self::Target {
387                &self.inner
388            }
389        }
390
391        impl core::ops::DerefMut for $wrapper_ty {
392            fn deref_mut(&mut self) -> &mut Self::Target {
393                &mut self.inner
394            }
395        }
396    };
397}
398
399#[macro_export]
400macro_rules! tpml {
401    ($name:ident, $inner_ty:ty, $capacity:expr) => {
402        pub type $name = $crate::basic::TpmList<$inner_ty, $capacity>;
403    };
404}