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