Skip to main content

tss_esapi/
traits.rs

1// Copyright 2021 Contributors to the Parsec project.
2// SPDX-License-Identifier: Apache-2.0
3use crate::{tss2_esys::UINT32, Result};
4use std::convert::TryFrom;
5
6/// Trait for types that can be converted into
7/// TPM marshalled data.
8pub trait Marshall: Sized {
9    const BUFFER_SIZE: usize;
10    /// Returns the type in the form of marshalled data
11    fn marshall(&self) -> Result<Vec<u8>> {
12        let mut buffer = vec![0; Self::BUFFER_SIZE];
13        let mut offset = 0;
14
15        self.marshall_offset(&mut buffer, &mut offset)?;
16
17        buffer.truncate(offset);
18
19        Ok(buffer)
20    }
21
22    /// Writes the type in the form of marshalled data to `marshalled_data`,
23    /// and modifies the `offset` to point to the first byte in the buffer
24    /// which was not written in the conversion.
25    fn marshall_offset(&self, _marshalled_data: &mut [u8], _offset: &mut usize) -> Result<()> {
26        unimplemented!();
27    }
28}
29
30/// Trait for types that can be created from
31/// TPM marshalled data.
32pub trait UnMarshall: Sized {
33    /// Creates the type from marshalled data.
34    fn unmarshall(marshalled_data: &[u8]) -> Result<Self> {
35        Self::unmarshall_offset(marshalled_data, &mut 0)
36    }
37
38    /// Creates the type from the marshalled data, and modifies
39    /// the `offset` to point to the first byte in the `marshalled_data`
40    /// buffer which was not used in the conversion.
41    fn unmarshall_offset(_marshalled_data: &[u8], _offset: &mut usize) -> Result<Self> {
42        unimplemented!();
43    }
44}
45
46/// A macro for implementing the Marshall trait
47/// for a specific TSS type.
48macro_rules! impl_marshall_trait {
49    ($native_type:ident, $tss_type:ident, $tss_mu_type:ident, $convert_expression:stmt, $( $ref_sign:tt )?) => {
50        paste::item! {
51            impl $crate::traits::Marshall for $native_type {
52                const BUFFER_SIZE: usize = ::std::mem::size_of::<$tss_type>();
53
54                fn marshall_offset(
55                    &self,
56                    marshalled_data: &mut [u8],
57                    offset: &mut usize,
58                ) -> $crate::Result<()> {
59                    let ffi_object = self.clone().$convert_expression;
60                    let ffi_buffer_size = $crate::ffi::FfiSizeType::try_from(marshalled_data.len())?;
61                    let mut ffi_offset = $crate::ffi::FfiSizeType::try_from(*offset)?;
62                    $crate::ReturnCode::ensure_success(
63                        unsafe {
64                            $crate::tss2_esys::[< Tss2_MU_ $tss_mu_type _Marshal >](
65                                $( $ref_sign )?ffi_object,
66                                marshalled_data.as_mut_ptr(),
67                                ffi_buffer_size.into(),
68                                ffi_offset.as_mut_ptr(),
69                            )
70                        },
71                        |ret| {
72                            log::error!(
73                                "Failed to marshall {}: {}",
74                                std::stringify!($native_type),
75                                ret
76                            );
77                        },
78                    )?;
79                    *offset = usize::try_from(ffi_offset)?;
80                    Ok(())
81                }
82            }
83        }
84    };
85}
86
87/// A macro for implementing the Unmarshall trait
88/// for a specific TSS type.
89macro_rules! impl_unmarshall_trait {
90    ($native_type:ident, $tss_type:ident, $tss_mu_type:ident, $convert_expression:expr) => {
91        paste::item! {
92            impl $crate::traits::UnMarshall for $native_type {
93                fn unmarshall_offset(marshalled_data: &[u8], offset: &mut usize) -> Result<Self> {
94                    let mut dest = $tss_type::default();
95                    let ffi_buffer_size = $crate::ffi::FfiSizeType::try_from(marshalled_data.len())?;
96                    let mut ffi_offset = $crate::ffi::FfiSizeType::try_from(*offset)?;
97                    crate::ReturnCode::ensure_success(
98                        unsafe {
99                            crate::tss2_esys::[ < Tss2_MU_ $tss_mu_type _Unmarshal >](
100                                marshalled_data.as_ptr(),
101                                ffi_buffer_size.into(),
102                                ffi_offset.as_mut_ptr(),
103                                &mut dest,
104                            )
105                        },
106                        |ret| log::error!("Failed to unmarshal {}: {}", std::stringify!($native_type), ret),
107                    )?;
108                    *offset = usize::try_from(ffi_offset)?;
109                    $convert_expression(dest)
110                }
111            }
112        }
113    };
114}
115
116/// Macro used to implement Marshall and Unmarshall for types
117/// that are just a type aliases of native types and are passed
118/// to MUAPI by value.
119macro_rules! impl_mu_aliases {
120    ($tss_type:ident) => {
121        $crate::traits::impl_marshall_trait!($tss_type, $tss_type, $tss_type, into(),);
122        $crate::traits::impl_unmarshall_trait!($tss_type, $tss_type, $tss_type, Ok);
123    };
124}
125
126/// Macro used to implement Marshall and Unmarshall for types that
127/// can be converted from native to TSS i.e. it cannot fail and are
128/// passed to MUAPI by value.
129macro_rules! impl_mu_simple {
130    ($native_type:ident, $tss_type:ident, $tss_mu_type:ident) => {
131        $crate::traits::impl_marshall_trait!($native_type, $tss_type, $tss_mu_type, into(),);
132        $crate::traits::impl_unmarshall_trait!(
133            $native_type,
134            $tss_type,
135            $tss_mu_type,
136            $native_type::try_from
137        );
138    };
139    ($native_type:ident, $tss_type:ident) => {
140        $crate::traits::impl_mu_simple!($native_type, $tss_type, $tss_type);
141    };
142}
143
144/// Macro used to implement Marshall and Unmarshall for types that
145/// can be converted from native to TSS without failing and are
146/// passed to MUAPI by reference(i.e. pointer).
147macro_rules! impl_mu_standard {
148    ($native_type:ident, $tss_type:ident, $tss_mu_type:ident) => {
149        $crate::traits::impl_marshall_trait!($native_type, $tss_type, $tss_mu_type, into(), &);
150        $crate::traits::impl_unmarshall_trait!(
151            $native_type,
152            $tss_type,
153            $tss_mu_type,
154            $native_type::try_from
155        );
156    };
157    ($native_type:ident, $tss_type:ident) => {
158        $crate::traits::impl_mu_standard!($native_type, $tss_type, $tss_type);
159    };
160}
161
162/// Macro used to implement Marshall and Unmarshall for types that
163/// can be converted from native to TSS with the possibility of failing
164/// and are passed to MUAPI by reference(i.e. pointer).
165macro_rules! impl_mu_complex {
166    ($native_type:ident, $tss_type:ident, $tss_mu_type:ident) => {
167        $crate::traits::impl_marshall_trait!($native_type, $tss_type, $tss_mu_type, try_into()?, &);
168        $crate::traits::impl_unmarshall_trait!(
169            $native_type,
170            $tss_type,
171            $tss_mu_type,
172            $native_type::try_from
173        );
174    };
175    ($native_type:ident, $tss_type:ident) => {
176        $crate::traits::impl_mu_complex!($native_type, $tss_type, $tss_type);
177    };
178}
179
180// Make the macros usable outside of the module.
181pub(crate) use impl_marshall_trait;
182pub(crate) use impl_mu_complex;
183pub(crate) use impl_mu_simple;
184pub(crate) use impl_mu_standard;
185pub(crate) use impl_unmarshall_trait;
186// Implementation of Marshall and UnMarshall macro for base TSS types.
187impl_mu_aliases!(UINT32);