Skip to main content

tpm2_protocol/data/
tpms.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 crate::{
6    TpmError, TpmMarshal, TpmResult, TpmSized, TpmWriter,
7    basic::{TpmHandle, TpmUint8, TpmUint16, TpmUint32, TpmUint64},
8    constant::{TPM_GENERATED_VALUE, TPM_PCR_SELECT_MAX},
9    data::{
10        Tpm2b, Tpm2bAuth, Tpm2bData, Tpm2bDigest, Tpm2bEccParameter, Tpm2bMaxNvBuffer, Tpm2bName,
11        Tpm2bNonce, Tpm2bSensitiveData, TpmAlgId, TpmAt, TpmCap, TpmEccCurve, TpmPt, TpmRh, TpmSt,
12        TpmaAct, TpmaAlgorithm, TpmaLocality, TpmaNv, TpmaNvExp, TpmaSession, TpmiAlgHash,
13        TpmiRhNvExpIndex, TpmiYesNo, TpmlPcrSelection, TpmtEccScheme, TpmtHa, TpmtKdfScheme,
14        TpmtKeyedhashScheme, TpmtRsaScheme, TpmtSymDefObject, TpmuAttest, TpmuAttestView,
15        TpmuCapabilities,
16    },
17    tpm_struct,
18};
19use core::{
20    convert::TryFrom,
21    fmt::{Debug, Formatter},
22    mem::size_of,
23    ops::Deref,
24};
25
26/// A fixed-capacity list for a PCR selection bitmap.
27#[derive(Clone, Copy, PartialEq, Eq)]
28pub struct TpmsPcrSelect {
29    size: TpmUint8,
30    data: [u8; TPM_PCR_SELECT_MAX as usize],
31}
32
33impl TpmsPcrSelect {
34    /// Creates a new, empty `TpmsPcrSelect`.
35    #[must_use]
36    pub const fn new() -> Self {
37        Self {
38            size: TpmUint8::new(0),
39            data: [0; TPM_PCR_SELECT_MAX as usize],
40        }
41    }
42}
43
44impl Default for TpmsPcrSelect {
45    fn default() -> Self {
46        Self::new()
47    }
48}
49
50impl Deref for TpmsPcrSelect {
51    type Target = [u8];
52
53    fn deref(&self) -> &Self::Target {
54        &self.data[..u8::from(self.size) as usize]
55    }
56}
57
58impl TryFrom<&[u8]> for TpmsPcrSelect {
59    type Error = TpmError;
60
61    fn try_from(slice: &[u8]) -> Result<Self, Self::Error> {
62        if slice.len() > TPM_PCR_SELECT_MAX as usize {
63            return Err(TpmError::TooManyItems {
64                offset: 0,
65                limit: TPM_PCR_SELECT_MAX as usize,
66                actual: slice.len(),
67            });
68        }
69        let mut pcr_select = Self::new();
70        let len_u8 = u8::try_from(slice.len()).map_err(|_| TpmError::IntegerTooLarge {
71            offset: 0,
72            value: crate::tpm_value(slice.len()),
73        })?;
74        pcr_select.size = TpmUint8::from(len_u8);
75        pcr_select.data[..slice.len()].copy_from_slice(slice);
76        Ok(pcr_select)
77    }
78}
79
80impl Debug for TpmsPcrSelect {
81    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
82        write!(f, "TpmsPcrSelect(")?;
83        for byte in self.iter() {
84            write!(f, "{byte:02X}")?;
85        }
86        write!(f, ")")
87    }
88}
89
90impl TpmSized for TpmsPcrSelect {
91    const SIZE: usize = size_of::<TpmUint8>() + TPM_PCR_SELECT_MAX as usize;
92
93    fn len(&self) -> usize {
94        size_of::<TpmUint8>() + u8::from(self.size) as usize
95    }
96}
97
98impl TpmMarshal for TpmsPcrSelect {
99    fn marshal(&self, writer: &mut TpmWriter) -> TpmResult<()> {
100        self.size.marshal(writer)?;
101        writer.write_bytes(self)
102    }
103}
104
105impl<'a> crate::TpmField<'a> for TpmsPcrSelect {
106    type View = &'a [u8];
107
108    fn cast_prefix_field(buf: &'a [u8]) -> TpmResult<(Self::View, &'a [u8])> {
109        let (size, remainder) = <TpmUint8 as crate::TpmCast>::cast_prefix(buf)?;
110        let size = size.value() as usize;
111
112        if size > TPM_PCR_SELECT_MAX as usize {
113            return Err(TpmError::TooManyItems {
114                offset: 0,
115                limit: TPM_PCR_SELECT_MAX as usize,
116                actual: size,
117            });
118        }
119
120        if remainder.len() < size {
121            return Err(TpmError::UnexpectedEnd {
122                offset: size_of::<TpmUint8>(),
123                needed: size,
124                available: remainder.len(),
125            });
126        }
127
128        let (pcr_select, remainder) = remainder.split_at(size);
129        Ok((pcr_select, remainder))
130    }
131}
132
133tpm_struct! {
134    #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
135    wire: TpmsAcOutputWire,
136    pub struct TpmsAcOutput {
137        pub tag: TpmAt,
138        pub data: TpmUint32,
139    }
140}
141
142tpm_struct! {
143    #[derive(Debug, PartialEq, Eq, Clone, Copy)]
144    wire: TpmsActDataWire,
145    pub struct TpmsActData {
146        pub handle: TpmHandle,
147        pub timeout: TpmUint32,
148        pub attributes: TpmaAct,
149    }
150}
151
152tpm_struct! {
153    #[derive(Debug, PartialEq, Eq, Clone, Default, Copy)]
154    wire: TpmsAlgPropertyWire,
155    pub struct TpmsAlgProperty {
156        pub alg: TpmAlgId,
157        pub alg_properties: TpmaAlgorithm,
158    }
159}
160
161tpm_struct! {
162    #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
163    wire: TpmsAuthCommandWire,
164    pub struct TpmsAuthCommand {
165        pub session_handle: TpmHandle,
166        pub nonce: Tpm2bNonce,
167        pub session_attributes: TpmaSession,
168        pub hmac: Tpm2bAuth,
169    }
170}
171
172tpm_struct! {
173    #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
174    wire: TpmsAuthResponseWire,
175    pub struct TpmsAuthResponse {
176        pub nonce: Tpm2bNonce,
177        pub session_attributes: TpmaSession,
178        pub hmac: Tpm2bAuth,
179    }
180}
181
182#[derive(Debug, PartialEq, Eq, Clone)]
183pub struct TpmsCapabilityData {
184    pub capability: TpmCap,
185    pub data: TpmuCapabilities,
186}
187
188impl TpmSized for TpmsCapabilityData {
189    const SIZE: usize = size_of::<TpmUint32>() + TpmuCapabilities::SIZE;
190    fn len(&self) -> usize {
191        self.capability.len() + self.data.len()
192    }
193}
194
195impl TpmMarshal for TpmsCapabilityData {
196    fn marshal(&self, writer: &mut TpmWriter) -> TpmResult<()> {
197        self.capability.marshal(writer)?;
198        self.data.marshal(writer)
199    }
200}
201
202tpm_struct! {
203    #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
204    wire: TpmsClockInfoWire,
205    pub struct TpmsClockInfo {
206        pub clock: TpmUint64,
207        pub reset_count: TpmUint32,
208        pub restart_count: TpmUint32,
209        pub safe: TpmiYesNo,
210    }
211}
212
213tpm_struct! {
214    #[derive(Debug, PartialEq, Eq, Clone)]
215    wire: TpmsContextWire,
216    pub struct TpmsContext {
217        pub sequence: TpmUint64,
218        pub saved_handle: TpmHandle,
219        pub hierarchy: TpmRh,
220        pub context_blob: Tpm2b,
221    }
222}
223
224tpm_struct! {
225    #[derive(Debug, PartialEq, Eq, Clone, Default)]
226    wire: TpmsCreationDataWire,
227    pub struct TpmsCreationData {
228        pub pcr_select: TpmlPcrSelection,
229        pub pcr_digest: Tpm2bDigest,
230        pub locality: TpmaLocality,
231        pub parent_name_alg: TpmAlgId,
232        pub parent_name: Tpm2bName,
233        pub parent_qualified_name: Tpm2bName,
234        pub outside_info: Tpm2bData,
235    }
236}
237
238tpm_struct! {
239    #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
240    wire: TpmsEccPointWire,
241    pub struct TpmsEccPoint {
242        pub x: Tpm2bEccParameter,
243        pub y: Tpm2bEccParameter,
244    }
245}
246
247tpm_struct! {
248    #[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
249    wire: TpmsEmptyWire,
250    pub struct TpmsEmpty {}
251}
252
253tpm_struct! {
254    #[derive(Debug, PartialEq, Eq, Clone, Default, Copy)]
255    wire: TpmsKeyedhashParmsWire,
256    pub struct TpmsKeyedhashParms {
257        pub scheme: TpmtKeyedhashScheme,
258    }
259}
260
261tpm_struct! {
262    #[derive(Debug, PartialEq, Eq, Clone, Default, Copy)]
263    wire: TpmsNvPublicWire,
264    pub struct TpmsNvPublic {
265        pub nv_index: TpmHandle,
266        pub name_alg: TpmAlgId,
267        pub attributes: TpmaNv,
268        pub auth_policy: Tpm2bDigest,
269        pub data_size: TpmUint16,
270    }
271}
272
273tpm_struct! {
274    #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
275    wire: TpmsNvPublicExpAttrWire,
276    pub struct TpmsNvPublicExpAttr {
277        pub nv_index: TpmiRhNvExpIndex,
278        pub name_alg: TpmAlgId,
279        pub attributes: TpmaNvExp,
280        pub auth_policy: Tpm2bDigest,
281        pub data_size: TpmUint16,
282    }
283}
284
285#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
286pub struct TpmsPcrSelection {
287    pub hash: TpmAlgId,
288    pub pcr_select: TpmsPcrSelect,
289}
290
291impl TpmSized for TpmsPcrSelection {
292    const SIZE: usize = TpmAlgId::SIZE + 1 + TPM_PCR_SELECT_MAX as usize;
293
294    fn len(&self) -> usize {
295        self.hash.len() + self.pcr_select.len()
296    }
297}
298
299impl TpmMarshal for TpmsPcrSelection {
300    fn marshal(&self, writer: &mut TpmWriter) -> TpmResult<()> {
301        self.hash.marshal(writer)?;
302        self.pcr_select.marshal(writer)
303    }
304}
305
306impl<'a> crate::TpmField<'a> for TpmsPcrSelection {
307    type View = (TpmAlgId, &'a [u8]);
308
309    fn cast_prefix_field(buf: &'a [u8]) -> TpmResult<(Self::View, &'a [u8])> {
310        let (hash, buf) = <TpmAlgId as crate::TpmField>::cast_prefix_field(buf)?;
311        let (pcr_select, buf) = <TpmsPcrSelect as crate::TpmField>::cast_prefix_field(buf)?;
312
313        Ok(((hash, pcr_select), buf))
314    }
315}
316
317tpm_struct! {
318    #[derive(Debug, Default, PartialEq, Eq, Clone)]
319    wire: TpmsSensitiveCreateWire,
320    pub struct TpmsSensitiveCreate {
321        pub user_auth: Tpm2bAuth,
322        pub data: Tpm2bSensitiveData,
323    }
324}
325
326tpm_struct! {
327    #[derive(Debug, PartialEq, Eq, Clone, Default, Copy)]
328    wire: TpmsIdObjectWire,
329    pub struct TpmsIdObject {
330        pub integrity_hmac: Tpm2bDigest,
331        pub enc_identity: Tpm2bDigest,
332    }
333}
334
335tpm_struct! {
336    #[derive(Debug, PartialEq, Eq, Clone, Default, Copy)]
337    wire: TpmsSymcipherParmsWire,
338    pub struct TpmsSymcipherParms {
339        pub sym: TpmtSymDefObject,
340    }
341}
342
343tpm_struct! {
344    #[derive(Debug, PartialEq, Eq, Clone, Copy)]
345    wire: TpmsTaggedPropertyWire,
346    pub struct TpmsTaggedProperty {
347        pub property: TpmPt,
348        pub value: TpmUint32,
349    }
350}
351
352tpm_struct! {
353    #[derive(Debug, PartialEq, Eq, Clone, Copy)]
354    wire: TpmsTaggedPolicyWire,
355    pub struct TpmsTaggedPolicy {
356        pub handle: TpmHandle,
357        pub policy_hash: TpmtHa,
358    }
359}
360
361tpm_struct! {
362    #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
363    wire: TpmsTimeInfoWire,
364    pub struct TpmsTimeInfo {
365        pub time: TpmUint64,
366        pub clock_info: TpmsClockInfo,
367    }
368}
369
370tpm_struct! {
371    #[derive(Debug, PartialEq, Eq, Clone, Default, Copy)]
372    wire: TpmsSignatureRsaWire,
373    pub struct TpmsSignatureRsa {
374        pub hash: TpmAlgId,
375        pub sig: crate::data::Tpm2bPublicKeyRsa,
376    }
377}
378
379tpm_struct! {
380    #[derive(Debug, PartialEq, Eq, Clone, Default, Copy)]
381    wire: TpmsSignatureEccWire,
382    pub struct TpmsSignatureEcc {
383        pub hash: TpmAlgId,
384        pub signature_r: Tpm2bEccParameter,
385        pub signature_s: Tpm2bEccParameter,
386    }
387}
388
389tpm_struct! {
390    #[derive(Debug, PartialEq, Eq, Clone, Default)]
391    wire: TpmsTimeAttestInfoWire,
392    pub struct TpmsTimeAttestInfo {
393        pub time: TpmsTimeInfo,
394        pub firmware_version: TpmUint64,
395    }
396}
397
398tpm_struct! {
399    #[derive(Debug, PartialEq, Eq, Clone, Default)]
400    wire: TpmsCertifyInfoWire,
401    pub struct TpmsCertifyInfo {
402        pub name: Tpm2bName,
403        pub qualified_name: Tpm2bName,
404    }
405}
406
407tpm_struct! {
408    #[derive(Debug, PartialEq, Eq, Clone, Default)]
409    wire: TpmsQuoteInfoWire,
410    pub struct TpmsQuoteInfo {
411        pub pcr_select: TpmlPcrSelection,
412        pub pcr_digest: Tpm2bDigest,
413    }
414}
415
416tpm_struct! {
417    #[derive(Debug, PartialEq, Eq, Clone, Default)]
418    wire: TpmsCommandAuditInfoWire,
419    pub struct TpmsCommandAuditInfo {
420        pub audit_counter: TpmUint64,
421        pub digest_alg: TpmAlgId,
422        pub audit_digest: Tpm2bDigest,
423        pub command_digest: Tpm2bDigest,
424    }
425}
426
427tpm_struct! {
428    #[derive(Debug, PartialEq, Eq, Clone, Default, Copy)]
429    wire: TpmsSessionAuditInfoWire,
430    pub struct TpmsSessionAuditInfo {
431        pub exclusive_session: TpmiYesNo,
432        pub session_digest: Tpm2bDigest,
433    }
434}
435
436tpm_struct! {
437    #[derive(Debug, PartialEq, Eq, Clone, Default)]
438    wire: TpmsCreationInfoWire,
439    pub struct TpmsCreationInfo {
440        pub object_name: Tpm2bName,
441        pub creation_hash: Tpm2bDigest,
442    }
443}
444
445tpm_struct! {
446    #[derive(Debug, PartialEq, Eq, Clone, Default)]
447    wire: TpmsNvCertifyInfoWire,
448    pub struct TpmsNvCertifyInfo {
449        pub index_name: Tpm2bName,
450        pub offset: TpmUint16,
451        pub nv_contents: Tpm2bMaxNvBuffer,
452    }
453}
454
455tpm_struct! {
456    #[derive(Debug, PartialEq, Eq, Clone, Default)]
457    wire: TpmsNvDigestCertifyInfoWire,
458    pub struct TpmsNvDigestCertifyInfo {
459        pub index_name: Tpm2bName,
460        pub nv_digest: Tpm2bDigest,
461    }
462}
463
464tpm_struct! {
465    #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
466    wire: TpmsAlgorithmDetailEccWire,
467    pub struct TpmsAlgorithmDetailEcc {
468        pub curve_id: TpmEccCurve,
469        pub key_size: TpmUint16,
470        pub kdf: TpmtKdfScheme,
471        pub sign: TpmtEccScheme,
472        pub p: Tpm2bEccParameter,
473        pub a: Tpm2bEccParameter,
474        pub b: Tpm2bEccParameter,
475        pub gx: Tpm2bEccParameter,
476        pub gy: Tpm2bEccParameter,
477        pub n: Tpm2bEccParameter,
478        pub h: Tpm2bEccParameter,
479    }
480}
481
482#[derive(Debug, PartialEq, Eq, Clone)]
483pub struct TpmsAttest {
484    pub attest_type: TpmSt,
485    pub qualified_signer: Tpm2bName,
486    pub extra_data: Tpm2bData,
487    pub clock_info: TpmsClockInfo,
488    pub firmware_version: TpmUint64,
489    pub attested: TpmuAttest,
490}
491
492impl TpmSized for TpmsAttest {
493    const SIZE: usize = size_of::<TpmUint32>()
494        + TpmSt::SIZE
495        + Tpm2bName::SIZE
496        + Tpm2bData::SIZE
497        + TpmsClockInfo::SIZE
498        + size_of::<TpmUint64>()
499        + TpmuAttest::SIZE;
500    fn len(&self) -> usize {
501        size_of::<TpmUint32>()
502            + self.attest_type.len()
503            + self.qualified_signer.len()
504            + self.extra_data.len()
505            + self.clock_info.len()
506            + size_of::<TpmUint64>()
507            + self.attested.len()
508    }
509}
510
511impl TpmMarshal for TpmsAttest {
512    fn marshal(&self, writer: &mut TpmWriter) -> TpmResult<()> {
513        crate::basic::TpmUint32::from(TPM_GENERATED_VALUE).marshal(writer)?;
514        self.attest_type.marshal(writer)?;
515        self.qualified_signer.marshal(writer)?;
516        self.extra_data.marshal(writer)?;
517        self.clock_info.marshal(writer)?;
518        self.firmware_version.marshal(writer)?;
519        self.attested.marshal(writer)
520    }
521}
522
523/// Borrowed view over a marshaled [`TpmsAttest`].
524///
525/// The leading magic word is validated against
526/// [`TPM_GENERATED_VALUE`](crate::constant::TPM_GENERATED_VALUE) during the
527/// cast and is therefore not exposed as a field.
528pub struct TpmsAttestView<'a> {
529    /// The attestation structure tag selecting the [`attested`](Self::attested) body.
530    pub attest_type: TpmSt,
531    /// Borrowed qualified name of the signing key.
532    pub qualified_signer: <Tpm2bName as crate::TpmField<'a>>::View,
533    /// Borrowed caller-provided qualifying data.
534    pub extra_data: <Tpm2bData as crate::TpmField<'a>>::View,
535    /// Borrowed TPM clock information.
536    pub clock_info: <TpmsClockInfo as crate::TpmField<'a>>::View,
537    /// TPM firmware version.
538    pub firmware_version: u64,
539    /// Borrowed attestation body selected by [`attest_type`](Self::attest_type).
540    pub attested: TpmuAttestView<'a>,
541}
542
543impl<'a> crate::TpmField<'a> for TpmsAttest {
544    type View = TpmsAttestView<'a>;
545
546    fn cast_prefix_field(buf: &'a [u8]) -> TpmResult<(Self::View, &'a [u8])> {
547        let (magic, buf) = <TpmUint32 as crate::TpmField>::cast_prefix_field(buf)?;
548        if magic.value() != TPM_GENERATED_VALUE {
549            return Err(TpmError::InvalidMagicNumber {
550                offset: 0,
551                value: u64::from(magic.value()),
552            });
553        }
554
555        let (attest_type, buf) = <TpmSt as crate::TpmField>::cast_prefix_field(buf)?;
556        let (qualified_signer, buf) = <Tpm2bName as crate::TpmField>::cast_prefix_field(buf)?;
557        let (extra_data, buf) = <Tpm2bData as crate::TpmField>::cast_prefix_field(buf)?;
558        let (clock_info, buf) = <TpmsClockInfo as crate::TpmField>::cast_prefix_field(buf)?;
559        let (firmware_version, buf) = <TpmUint64 as crate::TpmField>::cast_prefix_field(buf)?;
560        let (attested, buf) = TpmuAttest::cast_tagged(attest_type, buf)?;
561
562        Ok((
563            TpmsAttestView {
564                attest_type,
565                qualified_signer,
566                extra_data,
567                clock_info,
568                firmware_version: firmware_version.value(),
569                attested,
570            },
571            buf,
572        ))
573    }
574}
575
576tpm_struct! {
577    #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
578    wire: TpmsSchemeHashWire,
579    pub struct TpmsSchemeHash {
580        pub hash_alg: TpmiAlgHash,
581    }
582}
583
584pub type TpmsSchemeHmac = TpmsSchemeHash;
585
586tpm_struct! {
587    #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
588    wire: TpmsSchemeXorWire,
589    pub struct TpmsSchemeXor {
590        pub hash_alg: TpmiAlgHash,
591        pub kdf: TpmtKdfScheme,
592    }
593}
594
595tpm_struct! {
596    #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
597    wire: TpmsRsaParmsWire,
598    pub struct TpmsRsaParms {
599        pub symmetric: TpmtSymDefObject,
600        pub scheme: TpmtRsaScheme,
601        pub key_bits: TpmUint16,
602        pub exponent: TpmUint32,
603    }
604}
605
606tpm_struct! {
607    #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
608    wire: TpmsEccParmsWire,
609    pub struct TpmsEccParms {
610        pub symmetric: TpmtSymDefObject,
611        pub scheme: TpmtEccScheme,
612        pub curve_id: TpmEccCurve,
613        pub kdf: TpmtKdfScheme,
614    }
615}