Skip to main content

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, TpmAlgId, TpmHt, TpmRh, TpmSt, TpmaObject, TpmuHa, TpmuKdfScheme,
7    TpmuKeyedhashScheme, TpmuNvPublic2, TpmuPublicId, TpmuPublicParms, TpmuSensitiveComposite,
8    TpmuSigScheme, TpmuSymKeyBits, TpmuSymMode,
9};
10use crate::{
11    TpmError, TpmMarshal, TpmResult, TpmSized, TpmUnmarshal, TpmUnmarshalTagged, TpmWriter,
12    constant::TPM_MAX_COMMAND_SIZE, tpm_struct,
13};
14
15macro_rules! tpm_struct_tagged {
16    (
17        $(#[$outer:meta])*
18        $vis:vis struct $name:ident {
19            pub $tag_field:ident: $tag_ty:ty,
20            pub $value_field:ident: $value_ty:ty,
21        }
22    ) => {
23        $(#[$outer])*
24        $vis struct $name {
25            pub $tag_field: $tag_ty,
26            pub $value_field: $value_ty,
27        }
28
29        impl $crate::TpmSized for $name {
30            const SIZE: usize = <$tag_ty>::SIZE + <$value_ty>::SIZE;
31            fn len(&self) -> usize {
32                $crate::TpmSized::len(&self.$tag_field) + $crate::TpmSized::len(&self.$value_field)
33            }
34        }
35
36        impl $crate::TpmMarshal for $name {
37            fn marshal(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
38                if !self.$value_field.matches_tag(self.$tag_field) {
39                    return Err($crate::TpmError::VariantNotAvailable {
40                        offset: writer.len(),
41                        value: u64::from(self.$tag_field.value()),
42                    });
43                }
44
45                $crate::TpmMarshal::marshal(&self.$tag_field, writer)?;
46                $crate::TpmMarshal::marshal(&self.$value_field, writer)
47            }
48        }
49
50        impl<'a> $crate::TpmField<'a> for $name
51        where
52            $tag_ty: $crate::TpmField<'a, View = $tag_ty>,
53            $value_ty: $crate::TpmTaggedField<'a, $tag_ty>,
54        {
55            type View = (
56                $tag_ty,
57                <$value_ty as $crate::TpmTaggedField<'a, $tag_ty>>::View,
58            );
59
60            fn cast_prefix_field(buf: &'a [u8]) -> $crate::TpmResult<(Self::View, &'a [u8])> {
61                let ($tag_field, buf) = <$tag_ty as $crate::TpmField>::cast_prefix_field(buf)?;
62                let ($value_field, buf) =
63                    <$value_ty as $crate::TpmTaggedField<'a, $tag_ty>>::cast_tagged_prefix_field(
64                        $tag_field,
65                        buf,
66                    )?;
67
68                Ok((($tag_field, $value_field), buf))
69            }
70        }
71
72        impl $crate::TpmUnmarshal for $name
73        where
74            $tag_ty: $crate::TpmUnmarshal,
75            $value_ty: $crate::TpmUnmarshalTagged<$tag_ty>,
76        {
77            fn unmarshal(buffer: &[u8]) -> $crate::TpmResult<(Self, &[u8])> {
78                let ($tag_field, rest) = <$tag_ty as $crate::TpmUnmarshal>::unmarshal(buffer)?;
79                let offset = buffer.len() - rest.len();
80                let ($value_field, buffer) =
81                    <$value_ty as $crate::TpmUnmarshalTagged<$tag_ty>>::unmarshal_tagged(
82                        $tag_field,
83                        rest,
84                    )
85                    .map_err(|e| e.rebase(offset))?;
86
87                Ok((Self { $tag_field, $value_field }, buffer))
88            }
89        }
90    };
91}
92
93#[derive(Debug, PartialEq, Eq, Clone, Default)]
94pub struct TpmtPublic {
95    pub object_type: TpmAlgId,
96    pub name_alg: TpmAlgId,
97    pub object_attributes: TpmaObject,
98    pub auth_policy: Tpm2bDigest,
99    pub parameters: TpmuPublicParms,
100    pub unique: TpmuPublicId,
101}
102
103impl TpmSized for TpmtPublic {
104    const SIZE: usize = TPM_MAX_COMMAND_SIZE;
105    fn len(&self) -> usize {
106        self.object_type.len()
107            + self.name_alg.len()
108            + self.object_attributes.len()
109            + self.auth_policy.len()
110            + self.parameters.len()
111            + self.unique.len()
112    }
113}
114
115impl TpmMarshal for TpmtPublic {
116    fn marshal(&self, writer: &mut TpmWriter) -> TpmResult<()> {
117        if !self.parameters.matches_tag(self.object_type)
118            || !self.unique.matches_tag(self.object_type)
119        {
120            return Err(TpmError::VariantNotAvailable {
121                offset: writer.len(),
122                value: u64::from(self.object_type.value()),
123            });
124        }
125
126        self.object_type.marshal(writer)?;
127        self.name_alg.marshal(writer)?;
128        self.object_attributes.marshal(writer)?;
129        self.auth_policy.marshal(writer)?;
130        self.parameters.marshal(writer)?;
131        self.unique.marshal(writer)
132    }
133}
134
135impl TpmUnmarshal for TpmtPublic {
136    fn unmarshal(buffer: &[u8]) -> TpmResult<(Self, &[u8])> {
137        let (object_type, buffer) = TpmAlgId::unmarshal(buffer)?;
138        let (name_alg, buffer) = TpmAlgId::unmarshal(buffer)?;
139        let (object_attributes, buffer) = TpmaObject::unmarshal(buffer)?;
140        let (auth_policy, buffer) = Tpm2bDigest::unmarshal(buffer)?;
141        let (parameters, buffer) = TpmuPublicParms::unmarshal_tagged(object_type, buffer)?;
142        let (unique, buffer) = TpmuPublicId::unmarshal_tagged(object_type, buffer)?;
143
144        Ok((
145            Self {
146                object_type,
147                name_alg,
148                object_attributes,
149                auth_policy,
150                parameters,
151                unique,
152            },
153            buffer,
154        ))
155    }
156}
157
158/// Borrowed view of a [`TpmtPublic`] wire structure.
159pub struct TpmtPublicView<'a> {
160    pub object_type: TpmAlgId,
161    pub name_alg: TpmAlgId,
162    pub object_attributes: TpmaObject,
163    pub auth_policy: <Tpm2bDigest as crate::TpmField<'a>>::View,
164    pub parameters: <TpmuPublicParms as crate::TpmTaggedField<'a, TpmAlgId>>::View,
165    pub unique: <TpmuPublicId as crate::TpmTaggedField<'a, TpmAlgId>>::View,
166}
167
168impl<'a> crate::TpmField<'a> for TpmtPublic {
169    type View = TpmtPublicView<'a>;
170
171    fn cast_prefix_field(buf: &'a [u8]) -> TpmResult<(Self::View, &'a [u8])> {
172        let (object_type, buf) = <TpmAlgId as crate::TpmField>::cast_prefix_field(buf)?;
173        let (name_alg, buf) = <TpmAlgId as crate::TpmField>::cast_prefix_field(buf)?;
174        let (object_attributes, buf) = <TpmaObject as crate::TpmField>::cast_prefix_field(buf)?;
175        let (auth_policy, buf) = <Tpm2bDigest as crate::TpmField>::cast_prefix_field(buf)?;
176        let (parameters, buf) =
177            <TpmuPublicParms as crate::TpmTaggedField<'a, TpmAlgId>>::cast_tagged_prefix_field(
178                object_type,
179                buf,
180            )?;
181        let (unique, buf) =
182            <TpmuPublicId as crate::TpmTaggedField<'a, TpmAlgId>>::cast_tagged_prefix_field(
183                object_type,
184                buf,
185            )?;
186
187        Ok((
188            TpmtPublicView {
189                object_type,
190                name_alg,
191                object_attributes,
192                auth_policy,
193                parameters,
194                unique,
195            },
196            buf,
197        ))
198    }
199}
200
201tpm_struct_tagged! {
202    #[derive(Debug, PartialEq, Eq, Clone, Copy)]
203    pub struct TpmtPublicParms {
204        pub object_type: TpmAlgId,
205        pub parameters: TpmuPublicParms,
206    }
207}
208
209tpm_struct_tagged! {
210    #[derive(Debug, PartialEq, Eq, Clone, Copy)]
211    pub struct TpmtKdfScheme {
212        pub scheme: TpmAlgId,
213        pub details: TpmuKdfScheme,
214    }
215}
216
217impl Default for TpmtKdfScheme {
218    fn default() -> Self {
219        Self {
220            scheme: TpmAlgId::Null,
221            details: TpmuKdfScheme::Null,
222        }
223    }
224}
225
226tpm_struct_tagged! {
227    #[derive(Debug, PartialEq, Eq, Clone, Copy)]
228    pub struct TpmtRsaDecrypt {
229        pub scheme: TpmAlgId,
230        pub details: crate::data::tpmu::TpmuAsymScheme,
231    }
232}
233
234impl Default for TpmtRsaDecrypt {
235    fn default() -> Self {
236        Self {
237            scheme: TpmAlgId::Null,
238            details: crate::data::tpmu::TpmuAsymScheme::default(),
239        }
240    }
241}
242
243#[derive(Debug, PartialEq, Eq, Clone, Default)]
244pub struct TpmtSensitive {
245    pub sensitive_type: TpmAlgId,
246    pub auth_value: Tpm2bAuth,
247    pub seed_value: Tpm2bDigest,
248    pub sensitive: TpmuSensitiveComposite,
249}
250
251impl TpmSized for TpmtSensitive {
252    const SIZE: usize =
253        TpmAlgId::SIZE + Tpm2bAuth::SIZE + Tpm2bDigest::SIZE + TpmuSensitiveComposite::SIZE;
254    fn len(&self) -> usize {
255        self.sensitive_type.len()
256            + self.auth_value.len()
257            + self.seed_value.len()
258            + self.sensitive.len()
259    }
260}
261
262impl TpmMarshal for TpmtSensitive {
263    fn marshal(&self, writer: &mut TpmWriter) -> TpmResult<()> {
264        if !self.sensitive.matches_tag(self.sensitive_type) {
265            return Err(TpmError::VariantNotAvailable {
266                offset: writer.len(),
267                value: u64::from(self.sensitive_type.value()),
268            });
269        }
270
271        self.sensitive_type.marshal(writer)?;
272        self.auth_value.marshal(writer)?;
273        self.seed_value.marshal(writer)?;
274        self.sensitive.marshal(writer)
275    }
276}
277
278impl TpmUnmarshal for TpmtSensitive {
279    fn unmarshal(buffer: &[u8]) -> TpmResult<(Self, &[u8])> {
280        let (sensitive_type, buffer) = TpmAlgId::unmarshal(buffer)?;
281        let (auth_value, buffer) = Tpm2bAuth::unmarshal(buffer)?;
282        let (seed_value, buffer) = Tpm2bDigest::unmarshal(buffer)?;
283        let (sensitive, buffer) = TpmuSensitiveComposite::unmarshal_tagged(sensitive_type, buffer)?;
284
285        Ok((
286            Self {
287                sensitive_type,
288                auth_value,
289                seed_value,
290                sensitive,
291            },
292            buffer,
293        ))
294    }
295}
296
297#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
298pub struct TpmtSymDef {
299    pub algorithm: TpmAlgId,
300    pub key_bits: TpmuSymKeyBits,
301    pub mode: TpmuSymMode,
302}
303
304impl TpmSized for TpmtSymDef {
305    const SIZE: usize = TpmAlgId::SIZE + TpmuSymKeyBits::SIZE + TpmAlgId::SIZE;
306    fn len(&self) -> usize {
307        if self.algorithm == TpmAlgId::Null {
308            self.algorithm.len()
309        } else {
310            self.algorithm.len() + self.key_bits.len() + self.mode.len()
311        }
312    }
313}
314
315impl TpmMarshal for TpmtSymDef {
316    fn marshal(&self, writer: &mut TpmWriter) -> TpmResult<()> {
317        if self.algorithm != TpmAlgId::Null
318            && (!self.key_bits.matches_tag(self.algorithm)
319                || !self.mode.matches_tag(self.algorithm))
320        {
321            return Err(TpmError::VariantNotAvailable {
322                offset: writer.len(),
323                value: u64::from(self.algorithm.value()),
324            });
325        }
326
327        self.algorithm.marshal(writer)?;
328        if self.algorithm != TpmAlgId::Null {
329            self.key_bits.marshal(writer)?;
330            self.mode.marshal(writer)?;
331        }
332        Ok(())
333    }
334}
335
336impl TpmUnmarshal for TpmtSymDef {
337    fn unmarshal(buffer: &[u8]) -> TpmResult<(Self, &[u8])> {
338        let (algorithm, buffer) = TpmAlgId::unmarshal(buffer)?;
339        if algorithm == TpmAlgId::Null {
340            return Ok((
341                Self {
342                    algorithm,
343                    key_bits: TpmuSymKeyBits::Null,
344                    mode: TpmuSymMode::Null,
345                },
346                buffer,
347            ));
348        }
349
350        let (key_bits, buffer) = TpmuSymKeyBits::unmarshal_tagged(algorithm, buffer)?;
351        let (mode, buffer) = TpmuSymMode::unmarshal_tagged(algorithm, buffer)?;
352        Ok((
353            Self {
354                algorithm,
355                key_bits,
356                mode,
357            },
358            buffer,
359        ))
360    }
361}
362
363pub enum TpmtSymDefView<'a> {
364    Null,
365    Value {
366        algorithm: TpmAlgId,
367        key_bits: <TpmuSymKeyBits as crate::TpmTaggedField<'a, TpmAlgId>>::View,
368        mode: <TpmuSymMode as crate::TpmTaggedField<'a, TpmAlgId>>::View,
369    },
370}
371
372impl<'a> crate::TpmField<'a> for TpmtSymDef {
373    type View = TpmtSymDefView<'a>;
374
375    fn cast_prefix_field(buf: &'a [u8]) -> TpmResult<(Self::View, &'a [u8])> {
376        let (algorithm, buf) = <TpmAlgId as crate::TpmField>::cast_prefix_field(buf)?;
377
378        if algorithm == TpmAlgId::Null {
379            return Ok((TpmtSymDefView::Null, buf));
380        }
381
382        let (key_bits, buf) =
383            <TpmuSymKeyBits as crate::TpmTaggedField<'a, TpmAlgId>>::cast_tagged_prefix_field(
384                algorithm, buf,
385            )?;
386        let (mode, buf) =
387            <TpmuSymMode as crate::TpmTaggedField<'a, TpmAlgId>>::cast_tagged_prefix_field(
388                algorithm, buf,
389            )?;
390
391        Ok((
392            TpmtSymDefView::Value {
393                algorithm,
394                key_bits,
395                mode,
396            },
397            buf,
398        ))
399    }
400}
401
402pub type TpmtSymDefObject = TpmtSymDef;
403
404tpm_struct_tagged! {
405    #[derive(Debug, PartialEq, Eq, Clone, Copy)]
406    pub struct TpmtNvPublic2 {
407        pub handle_type: TpmHt,
408        pub public_area: TpmuNvPublic2,
409    }
410}
411
412tpm_struct! {
413    #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
414    wire: TpmtTkCreationWire,
415    pub struct TpmtTkCreation {
416        pub tag: TpmSt,
417        pub hierarchy: TpmRh,
418        pub digest: Tpm2bDigest,
419    }
420}
421
422tpm_struct! {
423    #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
424    wire: TpmtTkVerifiedWire,
425    pub struct TpmtTkVerified {
426        pub tag: TpmSt,
427        pub hierarchy: TpmRh,
428        pub digest: Tpm2bDigest,
429    }
430}
431
432tpm_struct! {
433    #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
434    wire: TpmtTkAuthWire,
435    pub struct TpmtTkAuth {
436        pub tag: TpmSt,
437        pub hierarchy: TpmRh,
438        pub digest: Tpm2bDigest,
439    }
440}
441
442tpm_struct! {
443    #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
444    wire: TpmtTkHashcheckWire,
445    pub struct TpmtTkHashcheck {
446        pub tag: TpmSt,
447        pub hierarchy: TpmRh,
448        pub digest: Tpm2bDigest,
449    }
450}
451
452tpm_struct_tagged! {
453    #[derive(Debug, PartialEq, Eq, Clone, Copy)]
454    pub struct TpmtHa {
455        pub hash_alg: TpmAlgId,
456        pub digest: TpmuHa,
457    }
458}
459
460impl Default for TpmtHa {
461    fn default() -> Self {
462        Self {
463            hash_alg: TpmAlgId::Null,
464            digest: TpmuHa::default(),
465        }
466    }
467}
468
469tpm_struct_tagged! {
470    #[derive(Debug, PartialEq, Eq, Clone)]
471    pub struct TpmtSignature {
472        pub sig_alg: TpmAlgId,
473        pub signature: crate::data::tpmu::TpmuSignature,
474    }
475}
476
477tpm_struct_tagged! {
478    #[derive(Debug, Default, PartialEq, Eq, Clone, Copy)]
479    pub struct TpmtKeyedhashScheme {
480        pub scheme: TpmAlgId,
481        pub details: TpmuKeyedhashScheme,
482    }
483}
484
485tpm_struct_tagged! {
486    #[derive(Debug, PartialEq, Eq, Clone, Copy)]
487    pub struct TpmtSigScheme {
488        pub scheme: TpmAlgId,
489        pub details: TpmuSigScheme,
490    }
491}
492
493impl Default for TpmtSigScheme {
494    fn default() -> Self {
495        Self {
496            scheme: TpmAlgId::Null,
497            details: TpmuSigScheme::default(),
498        }
499    }
500}
501
502tpm_struct_tagged! {
503    #[derive(Debug, PartialEq, Eq, Clone, Copy)]
504    pub struct TpmtRsaScheme {
505        pub scheme: TpmAlgId,
506        pub details: crate::data::tpmu::TpmuAsymScheme,
507    }
508}
509
510impl Default for TpmtRsaScheme {
511    fn default() -> Self {
512        Self {
513            scheme: TpmAlgId::Null,
514            details: crate::data::tpmu::TpmuAsymScheme::default(),
515        }
516    }
517}
518
519tpm_struct_tagged! {
520    #[derive(Debug, PartialEq, Eq, Clone, Copy)]
521    pub struct TpmtEccScheme {
522        pub scheme: TpmAlgId,
523        pub details: crate::data::tpmu::TpmuAsymScheme,
524    }
525}
526
527impl Default for TpmtEccScheme {
528    fn default() -> Self {
529        Self {
530            scheme: TpmAlgId::Null,
531            details: crate::data::tpmu::TpmuAsymScheme::default(),
532        }
533    }
534}