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    basic::{TpmHandle, TpmUint16, TpmUint32, TpmUint64, TpmUint8},
7    constant::{TPM_GENERATED_VALUE, 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, 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: 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 = 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::IntegerTooLarge)?;
66        pcr_select.size = TpmUint8::from(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::<TpmUint8>() + TPM_PCR_SELECT_MAX as usize;
84
85    fn len(&self) -> usize {
86        size_of::<TpmUint8>() + u8::from(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) = TpmUint8::unmarshal(buf)?;
100        let raw = u8::from(size);
101
102        if raw > TPM_PCR_SELECT_MAX {
103            return Err(TpmProtocolError::TooManyItems);
104        }
105        if remainder.len() < raw as usize {
106            return Err(TpmProtocolError::UnexpectedEnd);
107        }
108
109        let (pcr_bytes, final_remainder) = remainder.split_at(raw as usize);
110        let pcr_select = Self::try_from(pcr_bytes)?;
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: TpmUint32,
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::<TpmUint32>() + 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: TpmUint64,
182        pub reset_count: TpmUint32,
183        pub restart_count: TpmUint32,
184        pub safe: TpmiYesNo,
185    }
186}
187
188tpm_struct! {
189    #[derive(Debug, PartialEq, Eq, Clone)]
190    pub struct TpmsContext {
191        pub sequence: TpmUint64,
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: TpmUint16,
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: TpmUint16,
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: TpmUint32,
310    }
311}
312
313tpm_struct! {
314    #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
315    pub struct TpmsTimeInfo {
316        pub time: TpmUint64,
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: TpmUint64,
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: TpmUint64,
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: TpmUint16,
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: TpmUint16,
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 attest_type: TpmSt,
425    pub qualified_signer: Tpm2bName,
426    pub extra_data: Tpm2bData,
427    pub clock_info: TpmsClockInfo,
428    pub firmware_version: TpmUint64,
429    pub attested: TpmuAttest,
430}
431
432impl TpmSized for TpmsAttest {
433    const SIZE: usize = size_of::<TpmUint32>()
434        + TpmSt::SIZE
435        + Tpm2bName::SIZE
436        + Tpm2bData::SIZE
437        + TpmsClockInfo::SIZE
438        + size_of::<TpmUint64>()
439        + TpmuAttest::SIZE;
440    fn len(&self) -> usize {
441        size_of::<TpmUint32>()
442            + self.attest_type.len()
443            + self.qualified_signer.len()
444            + self.extra_data.len()
445            + self.clock_info.len()
446            + size_of::<TpmUint64>()
447            + self.attested.len()
448    }
449}
450
451impl TpmMarshal for TpmsAttest {
452    fn marshal(&self, writer: &mut TpmWriter) -> TpmResult<()> {
453        crate::basic::TpmUint32::from(TPM_GENERATED_VALUE).marshal(writer)?;
454        self.attest_type.marshal(writer)?;
455        self.qualified_signer.marshal(writer)?;
456        self.extra_data.marshal(writer)?;
457        self.clock_info.marshal(writer)?;
458        self.firmware_version.marshal(writer)?;
459        self.attested.marshal(writer)
460    }
461}
462
463impl TpmUnmarshal for TpmsAttest {
464    fn unmarshal(buf: &[u8]) -> TpmResult<(Self, &[u8])> {
465        let (magic, buf) = crate::basic::TpmUint32::unmarshal(buf)?;
466        if u32::from(magic) != TPM_GENERATED_VALUE {
467            return Err(TpmProtocolError::InvalidMagicNumber);
468        }
469        let (attest_type, buf) = TpmSt::unmarshal(buf)?;
470        let (qualified_signer, buf) = Tpm2bName::unmarshal(buf)?;
471        let (extra_data, buf) = Tpm2bData::unmarshal(buf)?;
472        let (clock_info, buf) = TpmsClockInfo::unmarshal(buf)?;
473        let (firmware_version, buf) = TpmUint64::unmarshal(buf)?;
474        let (attested, buf) = TpmuAttest::unmarshal_tagged(attest_type, buf)?;
475
476        Ok((
477            Self {
478                attest_type,
479                qualified_signer,
480                extra_data,
481                clock_info,
482                firmware_version,
483                attested,
484            },
485            buf,
486        ))
487    }
488}
489
490tpm_struct! {
491    #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
492    pub struct TpmsSchemeHash {
493        pub hash_alg: TpmiAlgHash,
494    }
495}
496
497pub type TpmsSchemeHmac = TpmsSchemeHash;
498
499tpm_struct! {
500    #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
501    pub struct TpmsSchemeXor {
502        pub hash_alg: TpmiAlgHash,
503        pub kdf: TpmtKdfScheme,
504    }
505}
506
507tpm_struct! {
508    #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
509    pub struct TpmsRsaParms {
510        pub symmetric: TpmtSymDefObject,
511        pub scheme: TpmtRsaScheme,
512        pub key_bits: TpmUint16,
513        pub exponent: TpmUint32,
514    }
515}
516
517tpm_struct! {
518    #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
519    pub struct TpmsEccParms {
520        pub symmetric: TpmtSymDefObject,
521        pub scheme: TpmtEccScheme,
522        pub curve_id: TpmEccCurve,
523        pub kdf: TpmtKdfScheme,
524    }
525}