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