Skip to main content

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