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