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