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 event {
290    use std::mem::size_of;
291    const TPM2B_EVENT_BUFFER_SIZE: usize = size_of::<TPM2B_EVENT>() - size_of::<u16>();
292    buffer_type!(Event, TPM2B_EVENT_BUFFER_SIZE, TPM2B_EVENT);
293}
294
295pub mod id_object {
296    use crate::tss2_esys::TPMS_ID_OBJECT;
297    use std::mem::size_of;
298    const TPM2B_ID_OBJECT_BUFFER_SIZE: usize = size_of::<TPMS_ID_OBJECT>();
299    named_field_buffer_type!(
300        IdObject,
301        TPM2B_ID_OBJECT_BUFFER_SIZE,
302        TPM2B_ID_OBJECT,
303        credential
304    );
305}
306
307pub mod initial_value {
308    use crate::tss2_esys::TPM2_MAX_SYM_BLOCK_SIZE;
309    const TPM2B_IV_BUFFER_SIZE: usize = TPM2_MAX_SYM_BLOCK_SIZE as usize;
310    buffer_type!(InitialValue, TPM2B_IV_BUFFER_SIZE, TPM2B_IV);
311}
312
313pub mod max_buffer {
314    use crate::tss2_esys::TPM2_MAX_DIGEST_BUFFER;
315    const TPM2B_MAX_BUFFER_BUFFER_SIZE: usize = TPM2_MAX_DIGEST_BUFFER as usize;
316    buffer_type!(MaxBuffer, TPM2B_MAX_BUFFER_BUFFER_SIZE, TPM2B_MAX_BUFFER);
317}
318
319pub mod max_nv_buffer {
320    use crate::tss2_esys::TPM2_MAX_NV_BUFFER_SIZE;
321    const TPM2B_MAX_NV_BUFFER_BUFFER_SIZE: usize = TPM2_MAX_NV_BUFFER_SIZE as usize;
322    buffer_type!(
323        MaxNvBuffer,
324        TPM2B_MAX_NV_BUFFER_BUFFER_SIZE,
325        TPM2B_MAX_NV_BUFFER
326    );
327}
328
329pub mod nonce {
330    // Same size as TPM2B_DIGEST according to the specification.
331    use crate::tss2_esys::TPMU_HA;
332    use std::mem::size_of;
333    const TPM2B_NONCE_BUFFER_SIZE: usize = size_of::<TPMU_HA>();
334
335    buffer_type!(Nonce, TPM2B_NONCE_BUFFER_SIZE, TPM2B_NONCE);
336}
337
338pub mod private_key_rsa {
339    use crate::tss2_esys::TPM2_MAX_RSA_KEY_BYTES;
340    const TPM2B_PRIVATE_KEY_RSA_BUFFER_SIZE: usize = (TPM2_MAX_RSA_KEY_BYTES as usize) * 5 / 2;
341
342    buffer_type!(
343        PrivateKeyRsa,
344        TPM2B_PRIVATE_KEY_RSA_BUFFER_SIZE,
345        TPM2B_PRIVATE_KEY_RSA
346    );
347}
348
349pub mod private_vendor_specific {
350    use crate::tss2_esys::TPM2_PRIVATE_VENDOR_SPECIFIC_BYTES;
351    const TPM2B_PRIVATE_VENDOR_SPECIFIC_BUFFER_SIZE: usize =
352        TPM2_PRIVATE_VENDOR_SPECIFIC_BYTES as usize;
353    // The spec states the maximum size as:
354    // "The value for PRIVATE_VENDOR_SPECIFIC_BYTES is determined by the vendor."
355    // Not very helpful, but the TSS exposes a generic value that we can use.
356    buffer_type!(
357        PrivateVendorSpecific,
358        TPM2B_PRIVATE_VENDOR_SPECIFIC_BUFFER_SIZE,
359        TPM2B_PRIVATE_VENDOR_SPECIFIC
360    );
361}
362
363pub mod public_key_rsa {
364    use crate::{interface_types::key_bits::RsaKeyBits, tss2_esys::TPM2_MAX_RSA_KEY_BYTES};
365    const TPM2B_PUBLIC_KEY_RSA_BUFFER_SIZE: usize = TPM2_MAX_RSA_KEY_BYTES as usize;
366    buffer_type!(
367        PublicKeyRsa,
368        TPM2B_PUBLIC_KEY_RSA_BUFFER_SIZE,
369        TPM2B_PUBLIC_KEY_RSA
370    );
371
372    impl PublicKeyRsa {
373        pub fn new_empty_with_size(rsa_key_bits: RsaKeyBits) -> Self {
374            match rsa_key_bits {
375                RsaKeyBits::Rsa1024 => PublicKeyRsa(vec![0u8; 128].into()),
376                RsaKeyBits::Rsa2048 => PublicKeyRsa(vec![0u8; 256].into()),
377                RsaKeyBits::Rsa3072 => PublicKeyRsa(vec![0u8; 384].into()),
378                RsaKeyBits::Rsa4096 => PublicKeyRsa(vec![0u8; 512].into()),
379            }
380        }
381
382        pub fn new_empty() -> Self {
383            PublicKeyRsa(vec![0u8; 0].into())
384        }
385    }
386
387    impl TryFrom<PublicKeyRsa> for [u8; 128] {
388        type Error = Error;
389
390        fn try_from(public_key_rsa: PublicKeyRsa) -> Result<Self> {
391            if public_key_rsa.len() > 128 {
392                return Err(Error::local_error(WrapperErrorKind::WrongParamSize));
393            }
394
395            let mut value = [0u8; 128];
396            value.copy_from_slice(public_key_rsa.as_bytes());
397            Ok(value)
398        }
399    }
400
401    impl TryFrom<PublicKeyRsa> for [u8; 256] {
402        type Error = Error;
403
404        fn try_from(public_key_rsa: PublicKeyRsa) -> Result<Self> {
405            if public_key_rsa.len() > 256 {
406                return Err(Error::local_error(WrapperErrorKind::WrongParamSize));
407            }
408
409            let mut value = [0u8; 256];
410            value.copy_from_slice(public_key_rsa.as_bytes());
411            Ok(value)
412        }
413    }
414
415    impl TryFrom<PublicKeyRsa> for [u8; 384] {
416        type Error = Error;
417
418        fn try_from(public_key_rsa: PublicKeyRsa) -> Result<Self> {
419            if public_key_rsa.len() > 384 {
420                return Err(Error::local_error(WrapperErrorKind::WrongParamSize));
421            }
422
423            let mut value = [0u8; 384];
424            value.copy_from_slice(public_key_rsa.as_bytes());
425            Ok(value)
426        }
427    }
428
429    impl TryFrom<PublicKeyRsa> for [u8; 512] {
430        type Error = Error;
431
432        fn try_from(public_key_rsa: PublicKeyRsa) -> Result<Self> {
433            if public_key_rsa.len() > 512 {
434                return Err(Error::local_error(WrapperErrorKind::WrongParamSize));
435            }
436
437            let mut value = [0u8; 512];
438            value.copy_from_slice(public_key_rsa.as_bytes());
439            Ok(value)
440        }
441    }
442}
443
444pub mod sensitive_data {
445    // The specification says that the size of the buffer should be the size
446    // TPMU_SENSITIVE_CREATE structure. This does not exist in all the
447    // versions of tpm2-tss supported by the crate so the fall back is to
448    // calculate the max size by removing the size of the size parameter(UINT16)
449    // from the total size of the buffer type.
450    use std::mem::size_of;
451    cfg_if::cfg_if! {
452        if #[cfg(has_tpmu_sensitive_create)] {
453            use crate::tss2_esys::TPMU_SENSITIVE_CREATE;
454            const TPM2B_SENSITIVE_DATA_BUFFER_SIZE: usize = size_of::<TPMU_SENSITIVE_CREATE>();
455        } else {
456            use crate::tss2_esys::UINT16;
457            const TPM2B_SENSITIVE_DATA_BUFFER_SIZE: usize = size_of::<TPM2B_SENSITIVE_DATA>() - size_of::<UINT16>();
458        }
459    }
460    buffer_type!(
461        SensitiveData,
462        TPM2B_SENSITIVE_DATA_BUFFER_SIZE,
463        TPM2B_SENSITIVE_DATA
464    );
465}
466
467pub mod symmetric_key {
468    use crate::tss2_esys::TPM2_MAX_SYM_KEY_BYTES;
469    const TPM2B_SYM_KEY_BUFFER_SIZE: usize = TPM2_MAX_SYM_KEY_BYTES as usize;
470    // The spec states the maximum size as:
471    // "MAX_SYM_KEY_BYTES will be the larger of the largest symmetric key supported by the TPM and the
472    // largest digest produced by any hashing algorithm implemented on the TPM"
473    buffer_type!(SymmetricKey, TPM2B_SYM_KEY_BUFFER_SIZE, TPM2B_SYM_KEY);
474}
475
476pub mod timeout {
477    use crate::tss2_esys::UINT64;
478    use std::mem::size_of;
479    const TPM2B_TIMEOUT_BUFFER_SIZE: usize = size_of::<UINT64>();
480    buffer_type!(Timeout, TPM2B_TIMEOUT_BUFFER_SIZE, TPM2B_TIMEOUT);
481}
482
483pub mod tpm_context_data {
484    use crate::tss2_esys::TPMS_CONTEXT_DATA;
485    use std::mem::size_of;
486
487    const TPM2B_CONTEXT_DATA_BUFFER_SIZE: usize = size_of::<TPMS_CONTEXT_DATA>();
488    buffer_type!(
489        TpmContextData,
490        TPM2B_CONTEXT_DATA_BUFFER_SIZE,
491        TPM2B_CONTEXT_DATA
492    );
493}