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, Copy)]
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 TpmtKdfScheme {
157        pub scheme: TpmAlgId,
158    }
159}
160
161tpm_struct_tagged! {
162    #[derive(Debug, PartialEq, Eq, Clone, Copy)]
163    pub struct TpmtRsaDecrypt {
164        pub scheme: TpmAlgId,
165        pub details: crate::data::tpmu::TpmuAsymScheme,
166    }
167}
168
169impl Default for TpmtRsaDecrypt {
170    fn default() -> Self {
171        Self {
172            scheme: TpmAlgId::Null,
173            details: crate::data::tpmu::TpmuAsymScheme::default(),
174        }
175    }
176}
177
178#[derive(Debug, PartialEq, Eq, Clone, Default)]
179pub struct TpmtSensitive {
180    pub sensitive_type: TpmAlgId,
181    pub auth_value: Tpm2bAuth,
182    pub seed_value: Tpm2bDigest,
183    pub sensitive: TpmuSensitiveComposite,
184}
185
186impl TpmtSensitive {
187    /// Constructs a `TpmtSensitive` from a given key algorithm and raw private key bytes.
188    ///
189    /// # Errors
190    ///
191    /// Returns a `TpmErrorKind::InvalidValue` if the key algorithm is not supported for this operation.
192    pub fn from_private_bytes(
193        key_alg: TpmAlgId,
194        private_bytes: &[u8],
195    ) -> Result<Self, TpmErrorKind> {
196        let sensitive = match key_alg {
197            TpmAlgId::Rsa => TpmuSensitiveComposite::Rsa(
198                crate::data::Tpm2bPrivateKeyRsa::try_from(private_bytes)?,
199            ),
200            TpmAlgId::Ecc => TpmuSensitiveComposite::Ecc(crate::data::Tpm2bEccParameter::try_from(
201                private_bytes,
202            )?),
203            TpmAlgId::KeyedHash => TpmuSensitiveComposite::Bits(
204                crate::data::Tpm2bSensitiveData::try_from(private_bytes)?,
205            ),
206            TpmAlgId::SymCipher => {
207                TpmuSensitiveComposite::Sym(crate::data::Tpm2bSymKey::try_from(private_bytes)?)
208            }
209            _ => return Err(TpmErrorKind::InvalidValue),
210        };
211        Ok(Self {
212            sensitive_type: key_alg,
213            auth_value: Tpm2bAuth::default(),
214            seed_value: Tpm2bDigest::default(),
215            sensitive,
216        })
217    }
218}
219
220impl TpmSized for TpmtSensitive {
221    const SIZE: usize =
222        TpmAlgId::SIZE + Tpm2bAuth::SIZE + Tpm2bDigest::SIZE + TpmuSensitiveComposite::SIZE;
223    fn len(&self) -> usize {
224        self.sensitive_type.len()
225            + self.auth_value.len()
226            + self.seed_value.len()
227            + self.sensitive.len()
228    }
229}
230
231impl TpmBuild for TpmtSensitive {
232    fn build(&self, writer: &mut TpmWriter) -> TpmResult<()> {
233        self.sensitive_type.build(writer)?;
234        self.auth_value.build(writer)?;
235        self.seed_value.build(writer)?;
236        self.sensitive.build(writer)
237    }
238}
239
240impl TpmParse for TpmtSensitive {
241    fn parse(buf: &[u8]) -> TpmResult<(Self, &[u8])> {
242        let (sensitive_type, buf) = TpmAlgId::parse(buf)?;
243        let (auth_value, buf) = Tpm2bAuth::parse(buf)?;
244        let (seed_value, buf) = Tpm2bDigest::parse(buf)?;
245        let (sensitive, buf) = match sensitive_type {
246            TpmAlgId::Rsa => {
247                let (val, buf) = crate::data::Tpm2bPrivateKeyRsa::parse(buf)?;
248                (TpmuSensitiveComposite::Rsa(val), buf)
249            }
250            TpmAlgId::Ecc => {
251                let (val, buf) = Tpm2bEccParameter::parse(buf)?;
252                (TpmuSensitiveComposite::Ecc(val), buf)
253            }
254            TpmAlgId::KeyedHash => {
255                let (val, buf) = Tpm2bSensitiveData::parse(buf)?;
256                (TpmuSensitiveComposite::Bits(val), buf)
257            }
258            TpmAlgId::SymCipher => {
259                let (val, buf) = Tpm2bSymKey::parse(buf)?;
260                (TpmuSensitiveComposite::Sym(val), buf)
261            }
262            _ => return Err(TpmErrorKind::InvalidValue),
263        };
264        Ok((
265            Self {
266                sensitive_type,
267                auth_value,
268                seed_value,
269                sensitive,
270            },
271            buf,
272        ))
273    }
274}
275
276#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
277pub struct TpmtSymDef {
278    pub algorithm: TpmAlgId,
279    pub key_bits: TpmuSymKeyBits,
280    pub mode: TpmuSymMode,
281}
282
283impl TpmSized for TpmtSymDef {
284    const SIZE: usize = TpmAlgId::SIZE + TpmuSymKeyBits::SIZE + TpmAlgId::SIZE;
285    fn len(&self) -> usize {
286        if self.algorithm == TpmAlgId::Null {
287            self.algorithm.len()
288        } else {
289            self.algorithm.len() + self.key_bits.len() + self.mode.len()
290        }
291    }
292}
293
294impl TpmBuild for TpmtSymDef {
295    fn build(&self, writer: &mut TpmWriter) -> TpmResult<()> {
296        self.algorithm.build(writer)?;
297        if self.algorithm != TpmAlgId::Null {
298            self.key_bits.build(writer)?;
299            self.mode.build(writer)?;
300        }
301        Ok(())
302    }
303}
304
305impl TpmParse for TpmtSymDef {
306    fn parse(buf: &[u8]) -> TpmResult<(Self, &[u8])> {
307        let (algorithm, buf) = TpmAlgId::parse(buf)?;
308        if algorithm == TpmAlgId::Null {
309            return Ok((
310                Self {
311                    algorithm,
312                    key_bits: TpmuSymKeyBits::Null,
313                    mode: TpmuSymMode::Null,
314                },
315                buf,
316            ));
317        }
318        let (key_bits, buf) = match algorithm {
319            TpmAlgId::Aes => {
320                let (val, buf) = u16::parse(buf)?;
321                (TpmuSymKeyBits::Aes(val), buf)
322            }
323            TpmAlgId::Sm4 => {
324                let (val, buf) = u16::parse(buf)?;
325                (TpmuSymKeyBits::Sm4(val), buf)
326            }
327            TpmAlgId::Camellia => {
328                let (val, buf) = u16::parse(buf)?;
329                (TpmuSymKeyBits::Camellia(val), buf)
330            }
331            TpmAlgId::Xor => {
332                let (val, buf) = TpmAlgId::parse(buf)?;
333                (TpmuSymKeyBits::Xor(val), buf)
334            }
335            TpmAlgId::Null => (TpmuSymKeyBits::Null, buf),
336            _ => return Err(TpmErrorKind::InvalidValue),
337        };
338        let (mode, buf) = match algorithm {
339            TpmAlgId::Aes => {
340                let (val, buf) = TpmAlgId::parse(buf)?;
341                (TpmuSymMode::Aes(val), buf)
342            }
343            TpmAlgId::Sm4 => {
344                let (val, buf) = TpmAlgId::parse(buf)?;
345                (TpmuSymMode::Sm4(val), buf)
346            }
347            TpmAlgId::Camellia => {
348                let (val, buf) = TpmAlgId::parse(buf)?;
349                (TpmuSymMode::Camellia(val), buf)
350            }
351            TpmAlgId::Xor => {
352                let (val, buf) = TpmAlgId::parse(buf)?;
353                (TpmuSymMode::Xor(val), buf)
354            }
355            TpmAlgId::Null => (TpmuSymMode::Null, buf),
356            _ => return Err(TpmErrorKind::InvalidValue),
357        };
358        Ok((
359            Self {
360                algorithm,
361                key_bits,
362                mode,
363            },
364            buf,
365        ))
366    }
367}
368
369pub type TpmtSymDefObject = TpmtSymDef;
370
371tpm_struct_tagged! {
372    #[derive(Debug, PartialEq, Eq, Clone, Copy)]
373    pub struct TpmtNvPublic2 {
374        pub handle_type: TpmHt,
375        pub public_area: TpmuNvPublic2,
376    }
377}
378
379tpm_struct! {
380    #[derive(Debug, PartialEq, Eq, Clone, Default)]
381    pub struct TpmtTkCreation {
382        pub tag: TpmSt,
383        pub hierarchy: TpmRh,
384        pub digest: Tpm2bDigest,
385    }
386}
387
388tpm_struct! {
389    #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
390    pub struct TpmtTkVerified {
391        pub tag: TpmSt,
392        pub hierarchy: TpmRh,
393        pub digest: Tpm2bDigest,
394    }
395}
396
397tpm_struct! {
398    #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
399    pub struct TpmtTkAuth {
400        pub tag: TpmSt,
401        pub hierarchy: TpmRh,
402        pub digest: Tpm2bDigest,
403    }
404}
405
406tpm_struct! {
407    #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
408    pub struct TpmtTkHashcheck {
409        pub tag: TpmSt,
410        pub hierarchy: TpmRh,
411        pub digest: Tpm2bDigest,
412    }
413}
414
415tpm_struct_tagged! {
416    #[derive(Debug, PartialEq, Eq, Clone, Copy)]
417    pub struct TpmtHa {
418        pub hash_alg: TpmAlgId,
419        pub digest: TpmuHa,
420    }
421}
422
423impl Default for TpmtHa {
424    fn default() -> Self {
425        Self {
426            hash_alg: TpmAlgId::Null,
427            digest: TpmuHa::default(),
428        }
429    }
430}
431
432tpm_struct_tagged! {
433    #[derive(Debug, PartialEq, Eq, Clone)]
434    pub struct TpmtSignature {
435        pub sig_alg: TpmAlgId,
436        pub signature: crate::data::tpmu::TpmuSignature,
437    }
438}
439
440tpm_struct_tagged! {
441    #[derive(Debug, Default, PartialEq, Eq, Clone, Copy)]
442    pub struct TpmtKeyedhashScheme {
443        pub scheme: TpmAlgId,
444        pub details: TpmuKeyedhashScheme,
445    }
446}
447
448tpm_struct_tagged! {
449    #[derive(Debug, PartialEq, Eq, Clone, Copy)]
450    pub struct TpmtSigScheme {
451        pub scheme: TpmAlgId,
452        pub details: TpmuSigScheme,
453    }
454}
455
456impl Default for TpmtSigScheme {
457    fn default() -> Self {
458        Self {
459            scheme: TpmAlgId::Null,
460            details: TpmuSigScheme::default(),
461        }
462    }
463}
464
465tpm_struct_tagged! {
466    #[derive(Debug, PartialEq, Eq, Clone, Copy)]
467    pub struct TpmtRsaScheme {
468        pub scheme: TpmAlgId,
469        pub details: crate::data::tpmu::TpmuAsymScheme,
470    }
471}
472
473impl Default for TpmtRsaScheme {
474    fn default() -> Self {
475        Self {
476            scheme: TpmAlgId::Null,
477            details: crate::data::tpmu::TpmuAsymScheme::default(),
478        }
479    }
480}
481
482tpm_struct_tagged! {
483    #[derive(Debug, PartialEq, Eq, Clone, Copy)]
484    pub struct TpmtEccScheme {
485        pub scheme: TpmAlgId,
486        pub details: crate::data::tpmu::TpmuAsymScheme,
487    }
488}
489
490impl Default for TpmtEccScheme {
491    fn default() -> Self {
492        Self {
493            scheme: TpmAlgId::Null,
494            details: crate::data::tpmu::TpmuAsymScheme::default(),
495        }
496    }
497}