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, TpmlPcrSelection, TpmtEccScheme, TpmtKdfScheme, TpmtKeyedhashScheme,
13        TpmtRsaScheme, TpmtSymDefObject, TpmuAttest, TpmuCapabilities,
14    },
15    tpm_struct, TpmHandle, TpmMarshal, TpmProtocolError, TpmResult, TpmSized, TpmUnmarshal,
16    TpmUnmarshalTagged, 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 = TpmProtocolError;
59
60    fn try_from(slice: &[u8]) -> Result<Self, Self::Error> {
61        if slice.len() > TPM_PCR_SELECT_MAX as usize {
62            return Err(TpmProtocolError::TooManyItems);
63        }
64        let mut pcr_select = Self::new();
65        let len_u8 = u8::try_from(slice.len()).map_err(|_| TpmProtocolError::OperationFailed)?;
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(TpmProtocolError::TooManyItems);
103        }
104        if remainder.len() < size as usize {
105            return Err(TpmProtocolError::UnexpectedEnd);
106        }
107
108        let (pcr_bytes, final_remainder) = remainder.split_at(size as usize);
109        let pcr_select =
110            Self::try_from(pcr_bytes).map_err(|_| TpmProtocolError::CapacityExceeded)?;
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 TpmMarshal for TpmsCapabilityData {
164    fn marshal(&self, writer: &mut TpmWriter) -> TpmResult<()> {
165        self.capability.marshal(writer)?;
166        self.data.marshal(writer)
167    }
168}
169
170impl TpmUnmarshal for TpmsCapabilityData {
171    fn unmarshal(buf: &[u8]) -> TpmResult<(Self, &[u8])> {
172        let (capability, buf) = TpmCap::unmarshal(buf)?;
173        let (data, buf) = TpmuCapabilities::unmarshal_tagged(capability, buf)?;
174        Ok((Self { capability, data }, buf))
175    }
176}
177
178tpm_struct! {
179    #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
180    pub struct TpmsClockInfo {
181        pub clock: u64,
182        pub reset_count: u32,
183        pub restart_count: u32,
184        pub safe: TpmiYesNo,
185    }
186}
187
188tpm_struct! {
189    #[derive(Debug, PartialEq, Eq, Clone)]
190    pub struct TpmsContext {
191        pub sequence: u64,
192        pub saved_handle: TpmHandle,
193        pub hierarchy: TpmRh,
194        pub context_blob: Tpm2b,
195    }
196}
197
198tpm_struct! {
199    #[derive(Debug, PartialEq, Eq, Clone, Default)]
200    pub struct TpmsCreationData {
201        pub pcr_select: TpmlPcrSelection,
202        pub pcr_digest: Tpm2bDigest,
203        pub locality: TpmaLocality,
204        pub parent_name_alg: TpmAlgId,
205        pub parent_name: Tpm2bName,
206        pub parent_qualified_name: Tpm2bName,
207        pub outside_info: Tpm2bData,
208    }
209}
210
211tpm_struct! {
212    #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
213    pub struct TpmsEccPoint {
214        pub x: Tpm2bEccParameter,
215        pub y: Tpm2bEccParameter,
216    }
217}
218
219tpm_struct! {
220    #[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
221    pub struct TpmsEmpty {}
222}
223
224tpm_struct! {
225    #[derive(Debug, PartialEq, Eq, Clone, Default, Copy)]
226    pub struct TpmsKeyedhashParms {
227        pub scheme: TpmtKeyedhashScheme,
228    }
229}
230
231tpm_struct! {
232    #[derive(Debug, PartialEq, Eq, Clone, Default, Copy)]
233    pub struct TpmsNvPublic {
234        pub nv_index: TpmHandle,
235        pub name_alg: TpmAlgId,
236        pub attributes: TpmaNv,
237        pub auth_policy: Tpm2bDigest,
238        pub data_size: u16,
239    }
240}
241
242tpm_struct! {
243    #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
244    pub struct TpmsNvPublicExpAttr {
245        pub nv_index: TpmiRhNvExpIndex,
246        pub name_alg: TpmAlgId,
247        pub attributes: TpmaNvExp,
248        pub auth_policy: Tpm2bDigest,
249        pub data_size: u16,
250    }
251}
252
253#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
254pub struct TpmsPcrSelection {
255    pub hash: TpmAlgId,
256    pub pcr_select: TpmsPcrSelect,
257}
258
259impl TpmSized for TpmsPcrSelection {
260    const SIZE: usize = TpmAlgId::SIZE + 1 + TPM_PCR_SELECT_MAX as usize;
261
262    fn len(&self) -> usize {
263        self.hash.len() + self.pcr_select.len()
264    }
265}
266
267impl TpmMarshal for TpmsPcrSelection {
268    fn marshal(&self, writer: &mut TpmWriter) -> TpmResult<()> {
269        self.hash.marshal(writer)?;
270        self.pcr_select.marshal(writer)
271    }
272}
273
274impl TpmUnmarshal for TpmsPcrSelection {
275    fn unmarshal(buf: &[u8]) -> TpmResult<(Self, &[u8])> {
276        let (hash, buf) = TpmAlgId::unmarshal(buf)?;
277        let (pcr_select, buf) = TpmsPcrSelect::unmarshal(buf)?;
278        Ok((Self { hash, pcr_select }, buf))
279    }
280}
281
282tpm_struct! {
283    #[derive(Debug, Default, PartialEq, Eq, Clone)]
284    pub struct TpmsSensitiveCreate {
285        pub user_auth: Tpm2bAuth,
286        pub data: Tpm2bSensitiveData,
287    }
288}
289
290tpm_struct! {
291    #[derive(Debug, PartialEq, Eq, Clone, Default, Copy)]
292    pub struct TpmsIdObject {
293        pub integrity_hmac: Tpm2bDigest,
294        pub enc_identity: Tpm2bDigest,
295    }
296}
297
298tpm_struct! {
299    #[derive(Debug, PartialEq, Eq, Clone, Default, Copy)]
300    pub struct TpmsSymcipherParms {
301        pub sym: TpmtSymDefObject,
302    }
303}
304
305tpm_struct! {
306    #[derive(Debug, PartialEq, Eq, Clone, Copy)]
307    pub struct TpmsTaggedProperty {
308        pub property: TpmPt,
309        pub value: u32,
310    }
311}
312
313tpm_struct! {
314    #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
315    pub struct TpmsTimeInfo {
316        pub time: u64,
317        pub clock_info: TpmsClockInfo,
318    }
319}
320
321tpm_struct! {
322    #[derive(Debug, PartialEq, Eq, Clone, Default, Copy)]
323    pub struct TpmsSignatureRsa {
324        pub hash: TpmAlgId,
325        pub sig: crate::data::Tpm2bPublicKeyRsa,
326    }
327}
328
329tpm_struct! {
330    #[derive(Debug, PartialEq, Eq, Clone, Default, Copy)]
331    pub struct TpmsSignatureEcc {
332        pub hash: TpmAlgId,
333        pub signature_r: Tpm2bEccParameter,
334        pub signature_s: Tpm2bEccParameter,
335    }
336}
337
338tpm_struct! {
339    #[derive(Debug, PartialEq, Eq, Clone, Default)]
340    pub struct TpmsTimeAttestInfo {
341        pub time: TpmsTimeInfo,
342        pub firmware_version: u64,
343    }
344}
345
346tpm_struct! {
347    #[derive(Debug, PartialEq, Eq, Clone, Default)]
348    pub struct TpmsCertifyInfo {
349        pub name: Tpm2bName,
350        pub qualified_name: Tpm2bName,
351    }
352}
353
354tpm_struct! {
355    #[derive(Debug, PartialEq, Eq, Clone, Default)]
356    pub struct TpmsQuoteInfo {
357        pub pcr_select: TpmlPcrSelection,
358        pub pcr_digest: Tpm2bDigest,
359    }
360}
361
362tpm_struct! {
363    #[derive(Debug, PartialEq, Eq, Clone, Default)]
364    pub struct TpmsCommandAuditInfo {
365        pub audit_counter: u64,
366        pub digest_alg: TpmAlgId,
367        pub audit_digest: Tpm2bDigest,
368        pub command_digest: Tpm2bDigest,
369    }
370}
371
372tpm_struct! {
373    #[derive(Debug, PartialEq, Eq, Clone, Default, Copy)]
374    pub struct TpmsSessionAuditInfo {
375        pub exclusive_session: TpmiYesNo,
376        pub session_digest: Tpm2bDigest,
377    }
378}
379
380tpm_struct! {
381    #[derive(Debug, PartialEq, Eq, Clone, Default)]
382    pub struct TpmsCreationInfo {
383        pub object_name: Tpm2bName,
384        pub creation_hash: Tpm2bDigest,
385    }
386}
387
388tpm_struct! {
389    #[derive(Debug, PartialEq, Eq, Clone, Default)]
390    pub struct TpmsNvCertifyInfo {
391        pub index_name: Tpm2bName,
392        pub offset: u16,
393        pub nv_contents: Tpm2bMaxNvBuffer,
394    }
395}
396
397tpm_struct! {
398    #[derive(Debug, PartialEq, Eq, Clone, Default)]
399    pub struct TpmsNvDigestCertifyInfo {
400        pub index_name: Tpm2bName,
401        pub nv_digest: Tpm2bDigest,
402    }
403}
404
405tpm_struct! {
406    #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
407    pub struct TpmsAlgorithmDetailEcc {
408        pub curve_id: TpmEccCurve,
409        pub key_size: u16,
410        pub kdf: TpmtKdfScheme,
411        pub sign: TpmtEccScheme,
412        pub p: Tpm2bEccParameter,
413        pub a: Tpm2bEccParameter,
414        pub b: Tpm2bEccParameter,
415        pub gx: Tpm2bEccParameter,
416        pub gy: Tpm2bEccParameter,
417        pub n: Tpm2bEccParameter,
418        pub h: Tpm2bEccParameter,
419    }
420}
421
422#[derive(Debug, PartialEq, Eq, Clone)]
423pub struct TpmsAttest {
424    pub magic: u32,
425    pub attest_type: TpmSt,
426    pub qualified_signer: Tpm2bName,
427    pub extra_data: Tpm2bData,
428    pub clock_info: TpmsClockInfo,
429    pub firmware_version: u64,
430    pub attested: TpmuAttest,
431}
432
433impl TpmSized for TpmsAttest {
434    const SIZE: usize = size_of::<u32>()
435        + TpmSt::SIZE
436        + Tpm2bName::SIZE
437        + Tpm2bData::SIZE
438        + TpmsClockInfo::SIZE
439        + size_of::<u64>()
440        + TpmuAttest::SIZE;
441    fn len(&self) -> usize {
442        size_of::<u32>()
443            + self.attest_type.len()
444            + self.qualified_signer.len()
445            + self.extra_data.len()
446            + self.clock_info.len()
447            + size_of::<u64>()
448            + self.attested.len()
449    }
450}
451
452impl TpmMarshal for TpmsAttest {
453    fn marshal(&self, writer: &mut TpmWriter) -> TpmResult<()> {
454        0xff54_4347_u32.marshal(writer)?;
455        self.attest_type.marshal(writer)?;
456        self.qualified_signer.marshal(writer)?;
457        self.extra_data.marshal(writer)?;
458        self.clock_info.marshal(writer)?;
459        self.firmware_version.marshal(writer)?;
460        self.attested.marshal(writer)
461    }
462}
463
464impl TpmUnmarshal for TpmsAttest {
465    fn unmarshal(buf: &[u8]) -> TpmResult<(Self, &[u8])> {
466        let (magic, buf) = u32::unmarshal(buf)?;
467        if magic != TPM_GENERATED_VALUE {
468            return Err(TpmProtocolError::InvalidAttestMagic);
469        }
470        let (attest_type, buf) = TpmSt::unmarshal(buf)?;
471        let (qualified_signer, buf) = Tpm2bName::unmarshal(buf)?;
472        let (extra_data, buf) = Tpm2bData::unmarshal(buf)?;
473        let (clock_info, buf) = TpmsClockInfo::unmarshal(buf)?;
474        let (firmware_version, buf) = u64::unmarshal(buf)?;
475        let (attested, buf) = TpmuAttest::unmarshal_tagged(attest_type, buf)?;
476
477        Ok((
478            Self {
479                magic,
480                attest_type,
481                qualified_signer,
482                extra_data,
483                clock_info,
484                firmware_version,
485                attested,
486            },
487            buf,
488        ))
489    }
490}
491
492tpm_struct! {
493    #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
494    pub struct TpmsSchemeHash {
495        pub hash_alg: TpmiAlgHash,
496    }
497}
498
499pub type TpmsSchemeHmac = TpmsSchemeHash;
500
501tpm_struct! {
502    #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
503    pub struct TpmsSchemeXor {
504        pub hash_alg: TpmiAlgHash,
505        pub kdf: TpmtKdfScheme,
506    }
507}
508
509tpm_struct! {
510    #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
511    pub struct TpmsRsaParms {
512        pub symmetric: TpmtSymDefObject,
513        pub scheme: TpmtRsaScheme,
514        pub key_bits: u16,
515        pub exponent: u32,
516    }
517}
518
519tpm_struct! {
520    #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
521    pub struct TpmsEccParms {
522        pub symmetric: TpmtSymDefObject,
523        pub scheme: TpmtEccScheme,
524        pub curve_id: TpmEccCurve,
525        pub kdf: TpmtKdfScheme,
526    }
527}