Skip to main content

tss_esapi/structures/
buffers.rs

1// Copyright 2020 Contributors to the Parsec project.
2// SPDX-License-Identifier: Apache-2.0
3
4#[allow(unused_macros)]
5macro_rules! named_field_buffer_type {
6    ($native_type:ident,$MAX:expr,$tss_type:ident,$buffer_field_name:ident) => {
7        use crate::tss2_esys::$tss_type;
8        use crate::{Error, Result, WrapperErrorKind};
9        use log::error;
10        use std::convert::TryFrom;
11        use std::ops::Deref;
12        use zeroize::{Zeroize, Zeroizing};
13
14        #[derive(Debug, Clone, PartialEq, Eq, Zeroize)]
15        pub struct $native_type(Zeroizing<Vec<u8>>);
16
17        impl Default for $native_type {
18            fn default() -> Self {
19                $native_type(Vec::new().into())
20            }
21        }
22
23        impl $native_type {
24            pub const MAX_SIZE: usize = $MAX;
25
26            pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
27                Self::ensure_valid_buffer_size(bytes.len(), "bytes(&[u8])")?;
28                Ok($native_type(bytes.to_vec().into()))
29            }
30
31            /// Returns the content of the buffer type as
32            /// a slice of bytes.
33            pub fn as_bytes(&self) -> &[u8] {
34                self.0.as_slice()
35            }
36
37            /// Private function for ensuring that a buffer size is valid.
38            fn ensure_valid_buffer_size(buffer_size: usize, container_name: &str) -> Result<()> {
39                if buffer_size > Self::MAX_SIZE {
40                    error!("Invalid {} size(> {})", container_name, Self::MAX_SIZE);
41                    return Err(Error::local_error(WrapperErrorKind::WrongParamSize));
42                }
43                Ok(())
44            }
45        }
46
47        impl AsRef<[u8]> for $native_type {
48            fn as_ref(&self) -> &[u8] {
49                self.as_bytes()
50            }
51        }
52
53        impl Deref for $native_type {
54            type Target = Vec<u8>;
55            fn deref(&self) -> &Self::Target {
56                &self.0
57            }
58        }
59
60        impl TryFrom<Vec<u8>> for $native_type {
61            type Error = Error;
62
63            fn try_from(bytes: Vec<u8>) -> Result<Self> {
64                Self::ensure_valid_buffer_size(bytes.len(), "Vec<u8>")?;
65                Ok($native_type(bytes.into()))
66            }
67        }
68
69        impl TryFrom<$tss_type> for $native_type {
70            type Error = Error;
71
72            fn try_from(tss: $tss_type) -> Result<Self> {
73                let size = tss.size as usize;
74                Self::ensure_valid_buffer_size(size, "buffer")?;
75                Ok($native_type(tss.$buffer_field_name[..size].to_vec().into()))
76            }
77        }
78
79        impl From<$native_type> for $tss_type {
80            fn from(native: $native_type) -> Self {
81                let mut buffer = $tss_type {
82                    size: native.0.len() as u16,
83                    ..Default::default()
84                };
85                buffer.$buffer_field_name[..native.0.len()].copy_from_slice(&native.0);
86                buffer
87            }
88        }
89    };
90}
91
92#[allow(unused_macros)]
93macro_rules! buffer_type {
94    ($native_type:ident,$MAX:expr,$tss_type:ident) => {
95        named_field_buffer_type!($native_type, $MAX, $tss_type, buffer);
96    };
97}
98
99pub mod attest;
100pub mod private;
101pub mod public;
102pub mod sensitive;
103pub mod sensitive_create;
104
105pub mod auth {
106    // Same size as TPM2B_DIGEST according to the specification.
107    use crate::tss2_esys::TPMU_HA;
108    use std::mem::size_of;
109    const TPM2B_AUTH_BUFFER_SIZE: usize = size_of::<TPMU_HA>();
110    buffer_type!(Auth, TPM2B_AUTH_BUFFER_SIZE, TPM2B_AUTH);
111}
112
113pub mod data {
114    // This should, according to the specification, be
115    // size_of::<TPMT_HA>() but due to a bug in tpm2-tss
116    // (https://github.com/tpm2-software/tpm2-tss/issues/2888)
117    // it is the size of TPMU_HA
118    use crate::tss2_esys::TPMU_HA;
119    use std::mem::size_of;
120    const TPM2B_DATA_BUFFER_SIZE: usize = size_of::<TPMU_HA>();
121    buffer_type!(Data, TPM2B_DATA_BUFFER_SIZE, TPM2B_DATA);
122}
123
124pub mod digest {
125    use crate::tss2_esys::TPMU_HA;
126    use std::mem::size_of;
127
128    const TPM2B_DIGEST_BUFFER_SIZE: usize = size_of::<TPMU_HA>();
129
130    buffer_type!(Digest, TPM2B_DIGEST_BUFFER_SIZE, TPM2B_DIGEST);
131
132    // Some implementations to get from Digest to [u8; N] for common values of N (sha* primarily)
133    // This is used to work around the fact that Rust does not allow custom functions for general values of N in [T; N],
134    //  and the standard try_from for Slice to Array is only for LengthAtMost32.
135    use std::convert::TryInto;
136
137    // For the arrays that are LengthAtMost32, we use the built-in try_from
138    impl TryFrom<Digest> for [u8; 20] {
139        type Error = Error;
140
141        fn try_from(value: Digest) -> Result<Self> {
142            value
143                .as_bytes()
144                .try_into()
145                .map_err(|_| Error::local_error(WrapperErrorKind::WrongParamSize))
146        }
147    }
148
149    impl TryFrom<Digest> for [u8; 32] {
150        type Error = Error;
151
152        fn try_from(value: Digest) -> Result<Self> {
153            value
154                .as_bytes()
155                .try_into()
156                .map_err(|_| Error::local_error(WrapperErrorKind::WrongParamSize))
157        }
158    }
159
160    // For the others, we build our own
161    impl TryFrom<Digest> for [u8; 48] {
162        type Error = Error;
163
164        fn try_from(value: Digest) -> Result<Self> {
165            if value.len() != 48 {
166                return Err(Error::local_error(WrapperErrorKind::WrongParamSize));
167            }
168
169            let mut result = [0; 48];
170
171            result.copy_from_slice(value.as_bytes());
172
173            Ok(result)
174        }
175    }
176
177    impl TryFrom<Digest> for [u8; 64] {
178        type Error = Error;
179
180        fn try_from(value: Digest) -> Result<Self> {
181            if value.len() != 64 {
182                return Err(Error::local_error(WrapperErrorKind::WrongParamSize));
183            }
184
185            let mut result = [0; 64];
186
187            result.copy_from_slice(value.as_bytes());
188
189            Ok(result)
190        }
191    }
192
193    impl From<[u8; 20]> for Digest {
194        fn from(mut value: [u8; 20]) -> Self {
195            let value_as_vec = value.to_vec();
196            value.zeroize();
197            Digest(value_as_vec.into())
198        }
199    }
200
201    impl From<[u8; 32]> for Digest {
202        fn from(mut value: [u8; 32]) -> Self {
203            let value_as_vec = value.to_vec();
204            value.zeroize();
205            Digest(value_as_vec.into())
206        }
207    }
208
209    impl From<[u8; 48]> for Digest {
210        fn from(mut value: [u8; 48]) -> Self {
211            let value_as_vec = value.to_vec();
212            value.zeroize();
213            Digest(value_as_vec.into())
214        }
215    }
216
217    impl From<[u8; 64]> for Digest {
218        fn from(mut value: [u8; 64]) -> Self {
219            let value_as_vec = value.to_vec();
220            value.zeroize();
221            Digest(value_as_vec.into())
222        }
223    }
224
225    #[cfg(feature = "rustcrypto")]
226    mod rustcrypto {
227        use digest::{
228            consts::{U20, U32, U48, U64},
229            generic_array::GenericArray,
230            typenum::Unsigned,
231        };
232
233        use super::*;
234
235        macro_rules! impl_from_digest {
236            ($($size:ty),+) => {
237                $(impl From<GenericArray<u8, $size>> for Digest {
238                    fn from(mut value: GenericArray<u8, $size>) -> Self {
239                        let value_as_vec = value.as_slice().to_vec();
240                        value.zeroize();
241                        Digest(value_as_vec.into())
242                    }
243                }
244
245                impl TryFrom<Digest> for GenericArray<u8, $size> {
246                    type Error = Error;
247
248                    fn try_from(value: Digest) -> Result<Self> {
249                        if value.len() != <$size>::USIZE {
250                            return Err(Error::local_error(WrapperErrorKind::WrongParamSize));
251                        }
252
253                        let mut result = [0; <$size>::USIZE];
254
255                        result.copy_from_slice(value.as_bytes());
256
257                        Ok(result.into())
258                    }
259                })+
260            }
261        }
262
263        impl_from_digest!(U20, U32, U48, U64);
264    }
265}
266
267pub mod ecc_parameter {
268    use crate::tss2_esys::TPM2_MAX_ECC_KEY_BYTES;
269    const TPM2B_ECC_PARAMETER_BUFFER_SIZE: usize = TPM2_MAX_ECC_KEY_BYTES as usize;
270    buffer_type!(
271        EccParameter,
272        TPM2B_ECC_PARAMETER_BUFFER_SIZE,
273        TPM2B_ECC_PARAMETER
274    );
275}
276
277pub mod encrypted_secret {
278    use crate::tss2_esys::TPMU_ENCRYPTED_SECRET;
279    use std::mem::size_of;
280    const TPM2B_ENCRYPTED_SECRET_BUFFER_SIZE: usize = size_of::<TPMU_ENCRYPTED_SECRET>();
281    named_field_buffer_type!(
282        EncryptedSecret,
283        TPM2B_ENCRYPTED_SECRET_BUFFER_SIZE,
284        TPM2B_ENCRYPTED_SECRET,
285        secret
286    );
287}
288
289pub mod id_object {
290    use crate::tss2_esys::TPMS_ID_OBJECT;
291    use std::mem::size_of;
292    const TPM2B_ID_OBJECT_BUFFER_SIZE: usize = size_of::<TPMS_ID_OBJECT>();
293    named_field_buffer_type!(
294        IdObject,
295        TPM2B_ID_OBJECT_BUFFER_SIZE,
296        TPM2B_ID_OBJECT,
297        credential
298    );
299}
300
301pub mod initial_value {
302    use crate::tss2_esys::TPM2_MAX_SYM_BLOCK_SIZE;
303    const TPM2B_IV_BUFFER_SIZE: usize = TPM2_MAX_SYM_BLOCK_SIZE as usize;
304    buffer_type!(InitialValue, TPM2B_IV_BUFFER_SIZE, TPM2B_IV);
305}
306
307pub mod max_buffer {
308    use crate::tss2_esys::TPM2_MAX_DIGEST_BUFFER;
309    const TPM2B_MAX_BUFFER_BUFFER_SIZE: usize = TPM2_MAX_DIGEST_BUFFER as usize;
310    buffer_type!(MaxBuffer, TPM2B_MAX_BUFFER_BUFFER_SIZE, TPM2B_MAX_BUFFER);
311}
312
313pub mod max_nv_buffer {
314    use crate::tss2_esys::TPM2_MAX_NV_BUFFER_SIZE;
315    const TPM2B_MAX_NV_BUFFER_BUFFER_SIZE: usize = TPM2_MAX_NV_BUFFER_SIZE as usize;
316    buffer_type!(
317        MaxNvBuffer,
318        TPM2B_MAX_NV_BUFFER_BUFFER_SIZE,
319        TPM2B_MAX_NV_BUFFER
320    );
321}
322
323pub mod nonce {
324    // Same size as TPM2B_DIGEST according to the specification.
325    use crate::tss2_esys::TPMU_HA;
326    use std::mem::size_of;
327    const TPM2B_NONCE_BUFFER_SIZE: usize = size_of::<TPMU_HA>();
328
329    buffer_type!(Nonce, TPM2B_NONCE_BUFFER_SIZE, TPM2B_NONCE);
330}
331
332pub mod private_key_rsa {
333    use crate::tss2_esys::TPM2_MAX_RSA_KEY_BYTES;
334    const TPM2B_PRIVATE_KEY_RSA_BUFFER_SIZE: usize = (TPM2_MAX_RSA_KEY_BYTES as usize) * 5 / 2;
335
336    buffer_type!(
337        PrivateKeyRsa,
338        TPM2B_PRIVATE_KEY_RSA_BUFFER_SIZE,
339        TPM2B_PRIVATE_KEY_RSA
340    );
341}
342
343pub mod private_vendor_specific {
344    use crate::tss2_esys::TPM2_PRIVATE_VENDOR_SPECIFIC_BYTES;
345    const TPM2B_PRIVATE_VENDOR_SPECIFIC_BUFFER_SIZE: usize =
346        TPM2_PRIVATE_VENDOR_SPECIFIC_BYTES as usize;
347    // The spec states the maximum size as:
348    // "The value for PRIVATE_VENDOR_SPECIFIC_BYTES is determined by the vendor."
349    // Not very helpful, but the TSS exposes a generic value that we can use.
350    buffer_type!(
351        PrivateVendorSpecific,
352        TPM2B_PRIVATE_VENDOR_SPECIFIC_BUFFER_SIZE,
353        TPM2B_PRIVATE_VENDOR_SPECIFIC
354    );
355}
356
357pub mod public_key_rsa {
358    use crate::{interface_types::key_bits::RsaKeyBits, tss2_esys::TPM2_MAX_RSA_KEY_BYTES};
359    const TPM2B_PUBLIC_KEY_RSA_BUFFER_SIZE: usize = TPM2_MAX_RSA_KEY_BYTES as usize;
360    buffer_type!(
361        PublicKeyRsa,
362        TPM2B_PUBLIC_KEY_RSA_BUFFER_SIZE,
363        TPM2B_PUBLIC_KEY_RSA
364    );
365
366    impl PublicKeyRsa {
367        pub fn new_empty_with_size(rsa_key_bits: RsaKeyBits) -> Self {
368            match rsa_key_bits {
369                RsaKeyBits::Rsa1024 => PublicKeyRsa(vec![0u8; 128].into()),
370                RsaKeyBits::Rsa2048 => PublicKeyRsa(vec![0u8; 256].into()),
371                RsaKeyBits::Rsa3072 => PublicKeyRsa(vec![0u8; 384].into()),
372                RsaKeyBits::Rsa4096 => PublicKeyRsa(vec![0u8; 512].into()),
373            }
374        }
375
376        pub fn new_empty() -> Self {
377            PublicKeyRsa(vec![0u8; 0].into())
378        }
379    }
380
381    impl TryFrom<PublicKeyRsa> for [u8; 128] {
382        type Error = Error;
383
384        fn try_from(public_key_rsa: PublicKeyRsa) -> Result<Self> {
385            if public_key_rsa.len() > 128 {
386                return Err(Error::local_error(WrapperErrorKind::WrongParamSize));
387            }
388
389            let mut value = [0u8; 128];
390            value.copy_from_slice(public_key_rsa.as_bytes());
391            Ok(value)
392        }
393    }
394
395    impl TryFrom<PublicKeyRsa> for [u8; 256] {
396        type Error = Error;
397
398        fn try_from(public_key_rsa: PublicKeyRsa) -> Result<Self> {
399            if public_key_rsa.len() > 256 {
400                return Err(Error::local_error(WrapperErrorKind::WrongParamSize));
401            }
402
403            let mut value = [0u8; 256];
404            value.copy_from_slice(public_key_rsa.as_bytes());
405            Ok(value)
406        }
407    }
408
409    impl TryFrom<PublicKeyRsa> for [u8; 384] {
410        type Error = Error;
411
412        fn try_from(public_key_rsa: PublicKeyRsa) -> Result<Self> {
413            if public_key_rsa.len() > 384 {
414                return Err(Error::local_error(WrapperErrorKind::WrongParamSize));
415            }
416
417            let mut value = [0u8; 384];
418            value.copy_from_slice(public_key_rsa.as_bytes());
419            Ok(value)
420        }
421    }
422
423    impl TryFrom<PublicKeyRsa> for [u8; 512] {
424        type Error = Error;
425
426        fn try_from(public_key_rsa: PublicKeyRsa) -> Result<Self> {
427            if public_key_rsa.len() > 512 {
428                return Err(Error::local_error(WrapperErrorKind::WrongParamSize));
429            }
430
431            let mut value = [0u8; 512];
432            value.copy_from_slice(public_key_rsa.as_bytes());
433            Ok(value)
434        }
435    }
436}
437
438pub mod sensitive_data {
439    // The specification says that the size of the buffer should be the size
440    // TPMU_SENSITIVE_CREATE structure. This does not exist in all the
441    // versions of tpm2-tss supported by the crate so the fall back is to
442    // calculate the max size by removing the size of the size parameter(UINT16)
443    // from the total size of the buffer type.
444    use std::mem::size_of;
445    cfg_if::cfg_if! {
446        if #[cfg(has_tpmu_sensitive_create)] {
447            use crate::tss2_esys::TPMU_SENSITIVE_CREATE;
448            const TPM2B_SENSITIVE_DATA_BUFFER_SIZE: usize = size_of::<TPMU_SENSITIVE_CREATE>();
449        } else {
450            use crate::tss2_esys::UINT16;
451            const TPM2B_SENSITIVE_DATA_BUFFER_SIZE: usize = size_of::<TPM2B_SENSITIVE_DATA>() - size_of::<UINT16>();
452        }
453    }
454    buffer_type!(
455        SensitiveData,
456        TPM2B_SENSITIVE_DATA_BUFFER_SIZE,
457        TPM2B_SENSITIVE_DATA
458    );
459}
460
461pub mod symmetric_key {
462    use crate::tss2_esys::TPM2_MAX_SYM_KEY_BYTES;
463    const TPM2B_SYM_KEY_BUFFER_SIZE: usize = TPM2_MAX_SYM_KEY_BYTES as usize;
464    // The spec states the maximum size as:
465    // "MAX_SYM_KEY_BYTES will be the larger of the largest symmetric key supported by the TPM and the
466    // largest digest produced by any hashing algorithm implemented on the TPM"
467    buffer_type!(SymmetricKey, TPM2B_SYM_KEY_BUFFER_SIZE, TPM2B_SYM_KEY);
468}
469
470pub mod timeout {
471    use crate::tss2_esys::UINT64;
472    use std::mem::size_of;
473    const TPM2B_TIMEOUT_BUFFER_SIZE: usize = size_of::<UINT64>();
474    buffer_type!(Timeout, TPM2B_TIMEOUT_BUFFER_SIZE, TPM2B_TIMEOUT);
475}
476
477pub mod tpm_context_data {
478    use crate::tss2_esys::TPMS_CONTEXT_DATA;
479    use std::mem::size_of;
480
481    const TPM2B_CONTEXT_DATA_BUFFER_SIZE: usize = size_of::<TPMS_CONTEXT_DATA>();
482    buffer_type!(
483        TpmContextData,
484        TPM2B_CONTEXT_DATA_BUFFER_SIZE,
485        TPM2B_CONTEXT_DATA
486    );
487}