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