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