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