tpm2_protocol/data/
tpmt.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2// Copyright (c) 2025 Opinsys Oy
3// Copyright (c) 2024-2025 Jarkko Sakkinen
4
5use super::{
6    Tpm2bAuth, Tpm2bDigest, Tpm2bEccParameter, Tpm2bPublicKeyRsa, Tpm2bSensitiveData, Tpm2bSymKey,
7    TpmAlgId, TpmHt, TpmRh, TpmSt, TpmaObject, TpmsEccPoint, TpmuHa, TpmuKeyedhashScheme,
8    TpmuNvPublic2, TpmuPublicId, TpmuPublicParms, TpmuSensitiveComposite, TpmuSigScheme,
9    TpmuSymKeyBits, TpmuSymMode,
10};
11use crate::{
12    constant::TPM_MAX_COMMAND_SIZE, tpm_struct, TpmBuild, TpmErrorKind, TpmParse, TpmParseTagged,
13    TpmResult, TpmSized, TpmWriter,
14};
15
16macro_rules! tpm_struct_tagged {
17    (
18        $(#[$outer:meta])*
19        $vis:vis struct $name:ident {
20            pub $tag_field:ident: $tag_ty:ty,
21            pub $value_field:ident: $value_ty:ty,
22        }
23    ) => {
24        $(#[$outer])*
25        $vis struct $name {
26            pub $tag_field: $tag_ty,
27            pub $value_field: $value_ty,
28        }
29
30        impl $crate::TpmSized for $name {
31            const SIZE: usize = <$tag_ty>::SIZE + <$value_ty>::SIZE;
32            fn len(&self) -> usize {
33                $crate::TpmSized::len(&self.$tag_field) + $crate::TpmSized::len(&self.$value_field)
34            }
35        }
36
37        impl $crate::TpmBuild for $name {
38            fn build(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
39                $crate::TpmBuild::build(&self.$tag_field, writer)?;
40                $crate::TpmBuild::build(&self.$value_field, writer)
41            }
42        }
43
44        impl $crate::TpmParse for $name {
45            fn parse(buf: &[u8]) -> $crate::TpmResult<(Self, &[u8])> {
46                let ($tag_field, buf) = <$tag_ty>::parse(buf)?;
47                let ($value_field, buf) =
48                    <$value_ty as $crate::TpmParseTagged>::parse_tagged($tag_field, buf)?;
49                Ok((
50                    Self {
51                        $tag_field,
52                        $value_field,
53                    },
54                    buf,
55                ))
56            }
57        }
58    };
59}
60
61#[derive(Debug, PartialEq, Eq, Clone)]
62pub struct TpmtPublic {
63    pub object_type: TpmAlgId,
64    pub name_alg: TpmAlgId,
65    pub object_attributes: TpmaObject,
66    pub auth_policy: Tpm2bDigest,
67    pub parameters: TpmuPublicParms,
68    pub unique: TpmuPublicId,
69}
70
71impl TpmSized for TpmtPublic {
72    const SIZE: usize = TPM_MAX_COMMAND_SIZE;
73    fn len(&self) -> usize {
74        self.object_type.len()
75            + self.name_alg.len()
76            + self.object_attributes.len()
77            + self.auth_policy.len()
78            + self.parameters.len()
79            + self.unique.len()
80    }
81}
82
83impl TpmBuild for TpmtPublic {
84    fn build(&self, writer: &mut TpmWriter) -> TpmResult<()> {
85        self.object_type.build(writer)?;
86        self.name_alg.build(writer)?;
87        self.object_attributes.build(writer)?;
88        self.auth_policy.build(writer)?;
89        self.parameters.build(writer)?;
90        self.unique.build(writer)
91    }
92}
93
94impl TpmParse for TpmtPublic {
95    fn parse(buf: &[u8]) -> TpmResult<(Self, &[u8])> {
96        let (object_type, buf) = TpmAlgId::parse(buf)?;
97        let (name_alg, buf) = TpmAlgId::parse(buf)?;
98        let (object_attributes, buf) = TpmaObject::parse(buf)?;
99        let (auth_policy, buf) = Tpm2bDigest::parse(buf)?;
100        let (parameters, buf) = TpmuPublicParms::parse_tagged(object_type, buf)?;
101        let (unique, buf) = match object_type {
102            TpmAlgId::KeyedHash => {
103                let (val, rest) = Tpm2bDigest::parse(buf)?;
104                (TpmuPublicId::KeyedHash(val), rest)
105            }
106            TpmAlgId::SymCipher => {
107                let (val, rest) = Tpm2bSymKey::parse(buf)?;
108                (TpmuPublicId::SymCipher(val), rest)
109            }
110            TpmAlgId::Rsa => {
111                let (val, rest) = Tpm2bPublicKeyRsa::parse(buf)?;
112                (TpmuPublicId::Rsa(val), rest)
113            }
114            TpmAlgId::Ecc => {
115                let (point, rest) = TpmsEccPoint::parse(buf)?;
116                (TpmuPublicId::Ecc(point), rest)
117            }
118            TpmAlgId::Null => (TpmuPublicId::Null, buf),
119            _ => return Err(TpmErrorKind::InvalidValue),
120        };
121        let public_area = Self {
122            object_type,
123            name_alg,
124            object_attributes,
125            auth_policy,
126            parameters,
127            unique,
128        };
129        Ok((public_area, buf))
130    }
131}
132
133impl Default for TpmtPublic {
134    fn default() -> Self {
135        Self {
136            object_type: TpmAlgId::Null,
137            name_alg: TpmAlgId::Null,
138            object_attributes: TpmaObject::empty(),
139            auth_policy: Tpm2bDigest::default(),
140            parameters: TpmuPublicParms::Null,
141            unique: TpmuPublicId::Null,
142        }
143    }
144}
145
146tpm_struct_tagged! {
147    #[derive(Debug, PartialEq, Eq, Clone)]
148    pub struct TpmtPublicParms {
149        pub object_type: TpmAlgId,
150        pub parameters: TpmuPublicParms,
151    }
152}
153
154tpm_struct! {
155    #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
156    pub struct TpmtScheme {
157        pub scheme: TpmAlgId,
158    }
159}
160
161tpm_struct! {
162    #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
163    pub struct TpmtKdfScheme {
164        pub scheme: TpmAlgId,
165    }
166}
167
168tpm_struct_tagged! {
169    #[derive(Debug, PartialEq, Eq, Clone, Copy)]
170    pub struct TpmtRsaDecrypt {
171        pub scheme: TpmAlgId,
172        pub details: crate::data::tpmu::TpmuAsymScheme,
173    }
174}
175
176impl Default for TpmtRsaDecrypt {
177    fn default() -> Self {
178        Self {
179            scheme: TpmAlgId::Null,
180            details: crate::data::tpmu::TpmuAsymScheme::Null,
181        }
182    }
183}
184
185#[derive(Debug, PartialEq, Eq, Clone, Default)]
186pub struct TpmtSensitive {
187    pub sensitive_type: TpmAlgId,
188    pub auth_value: Tpm2bAuth,
189    pub seed_value: Tpm2bDigest,
190    pub sensitive: TpmuSensitiveComposite,
191}
192
193impl TpmtSensitive {
194    /// Constructs a `TpmtSensitive` from a given key algorithm and raw private key bytes.
195    ///
196    /// # Errors
197    ///
198    /// Returns a `TpmErrorKind::InvalidValue` if the key algorithm is not supported for this operation.
199    pub fn from_private_bytes(
200        key_alg: TpmAlgId,
201        private_bytes: &[u8],
202    ) -> Result<Self, TpmErrorKind> {
203        let sensitive = match key_alg {
204            TpmAlgId::Rsa => TpmuSensitiveComposite::Rsa(
205                crate::data::Tpm2bPrivateKeyRsa::try_from(private_bytes)?,
206            ),
207            TpmAlgId::Ecc => TpmuSensitiveComposite::Ecc(crate::data::Tpm2bEccParameter::try_from(
208                private_bytes,
209            )?),
210            TpmAlgId::KeyedHash => TpmuSensitiveComposite::Bits(
211                crate::data::Tpm2bSensitiveData::try_from(private_bytes)?,
212            ),
213            TpmAlgId::SymCipher => {
214                TpmuSensitiveComposite::Sym(crate::data::Tpm2bSymKey::try_from(private_bytes)?)
215            }
216            _ => return Err(TpmErrorKind::InvalidValue),
217        };
218        Ok(Self {
219            sensitive_type: key_alg,
220            auth_value: Tpm2bAuth::default(),
221            seed_value: Tpm2bDigest::default(),
222            sensitive,
223        })
224    }
225}
226
227impl TpmSized for TpmtSensitive {
228    const SIZE: usize =
229        TpmAlgId::SIZE + Tpm2bAuth::SIZE + Tpm2bDigest::SIZE + TpmuSensitiveComposite::SIZE;
230    fn len(&self) -> usize {
231        self.sensitive_type.len()
232            + self.auth_value.len()
233            + self.seed_value.len()
234            + self.sensitive.len()
235    }
236}
237
238impl TpmBuild for TpmtSensitive {
239    fn build(&self, writer: &mut TpmWriter) -> TpmResult<()> {
240        self.sensitive_type.build(writer)?;
241        self.auth_value.build(writer)?;
242        self.seed_value.build(writer)?;
243        self.sensitive.build(writer)
244    }
245}
246
247impl TpmParse for TpmtSensitive {
248    fn parse(buf: &[u8]) -> TpmResult<(Self, &[u8])> {
249        let (sensitive_type, buf) = TpmAlgId::parse(buf)?;
250        let (auth_value, buf) = Tpm2bAuth::parse(buf)?;
251        let (seed_value, buf) = Tpm2bDigest::parse(buf)?;
252        let (sensitive, buf) = match sensitive_type {
253            TpmAlgId::Rsa => {
254                let (val, buf) = crate::data::Tpm2bPrivateKeyRsa::parse(buf)?;
255                (TpmuSensitiveComposite::Rsa(val), buf)
256            }
257            TpmAlgId::Ecc => {
258                let (val, buf) = Tpm2bEccParameter::parse(buf)?;
259                (TpmuSensitiveComposite::Ecc(val), buf)
260            }
261            TpmAlgId::KeyedHash => {
262                let (val, buf) = Tpm2bSensitiveData::parse(buf)?;
263                (TpmuSensitiveComposite::Bits(val), buf)
264            }
265            TpmAlgId::SymCipher => {
266                let (val, buf) = Tpm2bSymKey::parse(buf)?;
267                (TpmuSensitiveComposite::Sym(val), buf)
268            }
269            _ => return Err(TpmErrorKind::InvalidValue),
270        };
271        Ok((
272            Self {
273                sensitive_type,
274                auth_value,
275                seed_value,
276                sensitive,
277            },
278            buf,
279        ))
280    }
281}
282
283#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
284pub struct TpmtSymDef {
285    pub algorithm: TpmAlgId,
286    pub key_bits: TpmuSymKeyBits,
287    pub mode: TpmuSymMode,
288}
289
290impl TpmSized for TpmtSymDef {
291    const SIZE: usize = TpmAlgId::SIZE + TpmuSymKeyBits::SIZE + TpmAlgId::SIZE;
292    fn len(&self) -> usize {
293        if self.algorithm == TpmAlgId::Null {
294            self.algorithm.len()
295        } else {
296            self.algorithm.len() + self.key_bits.len() + self.mode.len()
297        }
298    }
299}
300
301impl TpmBuild for TpmtSymDef {
302    fn build(&self, writer: &mut TpmWriter) -> TpmResult<()> {
303        self.algorithm.build(writer)?;
304        if self.algorithm != TpmAlgId::Null {
305            self.key_bits.build(writer)?;
306            self.mode.build(writer)?;
307        }
308        Ok(())
309    }
310}
311
312impl TpmParse for TpmtSymDef {
313    fn parse(buf: &[u8]) -> TpmResult<(Self, &[u8])> {
314        let (algorithm, buf) = TpmAlgId::parse(buf)?;
315        if algorithm == TpmAlgId::Null {
316            return Ok((
317                Self {
318                    algorithm,
319                    key_bits: TpmuSymKeyBits::Null,
320                    mode: TpmuSymMode::Null,
321                },
322                buf,
323            ));
324        }
325        let (key_bits, buf) = match algorithm {
326            TpmAlgId::Aes => {
327                let (val, buf) = u16::parse(buf)?;
328                (TpmuSymKeyBits::Aes(val), buf)
329            }
330            TpmAlgId::Sm4 => {
331                let (val, buf) = u16::parse(buf)?;
332                (TpmuSymKeyBits::Sm4(val), buf)
333            }
334            TpmAlgId::Camellia => {
335                let (val, buf) = u16::parse(buf)?;
336                (TpmuSymKeyBits::Camellia(val), buf)
337            }
338            TpmAlgId::Xor => {
339                let (val, buf) = TpmAlgId::parse(buf)?;
340                (TpmuSymKeyBits::Xor(val), buf)
341            }
342            TpmAlgId::Null => (TpmuSymKeyBits::Null, buf),
343            _ => return Err(TpmErrorKind::InvalidValue),
344        };
345        let (mode, buf) = match algorithm {
346            TpmAlgId::Aes => {
347                let (val, buf) = TpmAlgId::parse(buf)?;
348                (TpmuSymMode::Aes(val), buf)
349            }
350            TpmAlgId::Sm4 => {
351                let (val, buf) = TpmAlgId::parse(buf)?;
352                (TpmuSymMode::Sm4(val), buf)
353            }
354            TpmAlgId::Camellia => {
355                let (val, buf) = TpmAlgId::parse(buf)?;
356                (TpmuSymMode::Camellia(val), buf)
357            }
358            TpmAlgId::Xor => {
359                let (val, buf) = TpmAlgId::parse(buf)?;
360                (TpmuSymMode::Xor(val), buf)
361            }
362            TpmAlgId::Null => (TpmuSymMode::Null, buf),
363            _ => return Err(TpmErrorKind::InvalidValue),
364        };
365        Ok((
366            Self {
367                algorithm,
368                key_bits,
369                mode,
370            },
371            buf,
372        ))
373    }
374}
375
376pub type TpmtSymDefObject = TpmtSymDef;
377
378tpm_struct_tagged! {
379    #[derive(Debug, PartialEq, Eq, Clone, Copy)]
380    pub struct TpmtNvPublic2 {
381        pub handle_type: TpmHt,
382        pub public_area: TpmuNvPublic2,
383    }
384}
385
386tpm_struct! {
387    #[derive(Debug, PartialEq, Eq, Clone, Default)]
388    pub struct TpmtTkCreation {
389        pub tag: TpmSt,
390        pub hierarchy: TpmRh,
391        pub digest: Tpm2bDigest,
392    }
393}
394
395tpm_struct! {
396    #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
397    pub struct TpmtTkVerified {
398        pub tag: TpmSt,
399        pub hierarchy: TpmRh,
400        pub digest: Tpm2bDigest,
401    }
402}
403
404tpm_struct! {
405    #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
406    pub struct TpmtTkAuth {
407        pub tag: TpmSt,
408        pub hierarchy: TpmRh,
409        pub digest: Tpm2bDigest,
410    }
411}
412
413tpm_struct! {
414    #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
415    pub struct TpmtTkHashcheck {
416        pub tag: TpmSt,
417        pub hierarchy: TpmRh,
418        pub digest: Tpm2bDigest,
419    }
420}
421
422tpm_struct_tagged! {
423    #[derive(Debug, PartialEq, Eq, Clone, Copy)]
424    pub struct TpmtHa {
425        pub hash_alg: TpmAlgId,
426        pub digest: TpmuHa,
427    }
428}
429
430impl Default for TpmtHa {
431    fn default() -> Self {
432        Self {
433            hash_alg: TpmAlgId::Null,
434            digest: TpmuHa::default(),
435        }
436    }
437}
438
439tpm_struct_tagged! {
440    #[derive(Debug, PartialEq, Eq, Clone)]
441    pub struct TpmtSignature {
442        pub sig_alg: TpmAlgId,
443        pub signature: crate::data::tpmu::TpmuSignature,
444    }
445}
446
447tpm_struct_tagged! {
448    #[derive(Debug, PartialEq, Eq, Clone, Copy)]
449    pub struct TpmtKeyedhashScheme {
450        pub scheme: TpmAlgId,
451        pub details: TpmuKeyedhashScheme,
452    }
453}
454
455tpm_struct_tagged! {
456    #[derive(Debug, PartialEq, Eq, Clone, Copy)]
457    pub struct TpmtSigScheme {
458        pub scheme: TpmAlgId,
459        pub details: TpmuSigScheme,
460    }
461}