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