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    data::{
7        Tpm2b, Tpm2bAuth, Tpm2bData, Tpm2bDigest, Tpm2bEccParameter, Tpm2bMaxNvBuffer, Tpm2bName,
8        Tpm2bNonce, Tpm2bSensitiveData, TpmAlgId, TpmCap, TpmEccCurve, TpmRh, TpmSt, TpmaAlgorithm,
9        TpmaLocality, TpmaNv, TpmaSession, TpmiYesNo, TpmlPcrSelection, TpmtKdfScheme, TpmtScheme,
10        TpmtSymDefObject, TpmuCapabilities,
11    },
12    tpm_struct, TpmBuffer, TpmBuild, TpmErrorKind, TpmParse, TpmParseTagged, TpmResult, TpmSized,
13    TpmTagged, TpmWriter,
14};
15use core::{convert::TryFrom, mem::size_of, ops::Deref};
16
17pub const TPM_PCR_SELECT_MAX: usize = 3;
18pub type TpmsPcrSelect = TpmBuffer<TPM_PCR_SELECT_MAX>;
19
20tpm_struct! {
21    #[derive(Debug, PartialEq, Eq, Clone, Default, Copy)]
22    pub struct TpmsAlgProperty {
23        pub alg: TpmAlgId,
24        pub alg_properties: TpmaAlgorithm,
25    }
26}
27
28tpm_struct! {
29    #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
30    pub struct TpmsAuthCommand {
31        pub session_handle: crate::TpmSession,
32        pub nonce: Tpm2bNonce,
33        pub session_attributes: TpmaSession,
34        pub hmac: Tpm2bAuth,
35    }
36}
37
38tpm_struct! {
39    #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
40    pub struct TpmsAuthResponse {
41        pub nonce: Tpm2bNonce,
42        pub session_attributes: TpmaSession,
43        pub hmac: Tpm2bAuth,
44    }
45}
46
47#[derive(Debug, PartialEq, Eq, Clone)]
48pub struct TpmsCapabilityData {
49    pub capability: TpmCap,
50    pub data: TpmuCapabilities,
51}
52
53impl TpmTagged for TpmsCapabilityData {
54    type Tag = TpmCap;
55    type Value = ();
56}
57
58impl TpmSized for TpmsCapabilityData {
59    const SIZE: usize = size_of::<u32>() + TpmuCapabilities::SIZE;
60    fn len(&self) -> usize {
61        self.capability.len() + self.data.len()
62    }
63}
64
65impl TpmBuild for TpmsCapabilityData {
66    fn build(&self, writer: &mut TpmWriter) -> TpmResult<()> {
67        self.capability.build(writer)?;
68        self.data.build(writer)
69    }
70}
71
72impl TpmParse for TpmsCapabilityData {
73    fn parse(buf: &[u8]) -> TpmResult<(Self, &[u8])> {
74        let (capability, buf) = TpmCap::parse(buf)?;
75        let (data, buf) = TpmuCapabilities::parse_tagged(capability, buf)?;
76        Ok((Self { capability, data }, buf))
77    }
78}
79
80tpm_struct! {
81    #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
82    pub struct TpmsClockInfo {
83        pub clock: u64,
84        pub reset_count: u32,
85        pub restart_count: u32,
86        pub safe: TpmiYesNo,
87    }
88}
89
90tpm_struct! {
91    #[derive(Debug, PartialEq, Eq, Clone)]
92    pub struct TpmsContext {
93        pub sequence: u64,
94        pub saved_handle: crate::TpmTransient,
95        pub hierarchy: TpmRh,
96        pub context_blob: Tpm2b,
97    }
98}
99
100tpm_struct! {
101    #[derive(Debug, PartialEq, Eq, Clone, Default)]
102    pub struct TpmsCreationData {
103        pub pcr_select: TpmlPcrSelection,
104        pub pcr_digest: Tpm2bDigest,
105        pub locality: TpmaLocality,
106        pub parent_name_alg: TpmAlgId,
107        pub parent_name: Tpm2bName,
108        pub parent_qualified_name: Tpm2bName,
109        pub outside_info: Tpm2bData,
110    }
111}
112
113tpm_struct! {
114    #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
115    pub struct TpmsEccPoint {
116        pub x: Tpm2bEccParameter,
117        pub y: Tpm2bEccParameter,
118    }
119}
120
121tpm_struct! {
122    #[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
123    pub struct TpmsEmpty {}
124}
125
126tpm_struct! {
127    #[derive(Debug, PartialEq, Eq, Clone, Default, Copy)]
128    pub struct TpmsKeyedhashParms {
129        pub scheme: TpmtScheme,
130    }
131}
132
133tpm_struct! {
134    #[derive(Debug, PartialEq, Eq, Clone, Default, Copy)]
135    pub struct TpmsNvPublic {
136        pub nv_index: u32,
137        pub name_alg: TpmAlgId,
138        pub attributes: TpmaNv,
139        pub auth_policy: Tpm2bDigest,
140        pub data_size: u16,
141    }
142}
143
144#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
145pub struct TpmsPcrSelection {
146    pub hash: TpmAlgId,
147    pub pcr_select: TpmsPcrSelect,
148}
149
150impl TpmSized for TpmsPcrSelection {
151    const SIZE: usize = TpmAlgId::SIZE + 1 + TPM_PCR_SELECT_MAX;
152
153    fn len(&self) -> usize {
154        self.hash.len() + 1 + self.pcr_select.deref().len()
155    }
156}
157
158impl TpmBuild for TpmsPcrSelection {
159    fn build(&self, writer: &mut TpmWriter) -> TpmResult<()> {
160        self.hash.build(writer)?;
161        let size =
162            u8::try_from(self.pcr_select.deref().len()).map_err(|_| TpmErrorKind::ValueTooLarge)?;
163        size.build(writer)?;
164        writer.write_bytes(&self.pcr_select)
165    }
166}
167
168impl TpmParse for TpmsPcrSelection {
169    fn parse(buf: &[u8]) -> TpmResult<(Self, &[u8])> {
170        let (hash, buf) = TpmAlgId::parse(buf)?;
171        let (size, buf) = u8::parse(buf)?;
172        let size = size as usize;
173
174        if size > TPM_PCR_SELECT_MAX {
175            return Err(TpmErrorKind::ValueTooLarge);
176        }
177        if buf.len() < size {
178            return Err(TpmErrorKind::Boundary);
179        }
180
181        let (pcr_bytes, buf) = buf.split_at(size);
182        let pcr_select = TpmBuffer::try_from(pcr_bytes)?;
183
184        Ok((Self { hash, pcr_select }, buf))
185    }
186}
187
188tpm_struct! {
189    #[derive(Debug, PartialEq, Eq, Clone, Default)]
190    pub struct TpmsSensitiveCreate {
191        pub user_auth: Tpm2bAuth,
192        pub data: Tpm2bSensitiveData,
193    }
194}
195
196tpm_struct! {
197    #[derive(Debug, PartialEq, Eq, Clone, Default, Copy)]
198    pub struct TpmsIdObject {
199        pub integrity_hmac: Tpm2bDigest,
200        pub enc_identity: Tpm2bDigest,
201    }
202}
203
204tpm_struct! {
205    #[derive(Debug, PartialEq, Eq, Clone, Default, Copy)]
206    pub struct TpmsSymcipherParms {
207        pub sym: TpmtSymDefObject,
208    }
209}
210
211tpm_struct! {
212    #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
213    pub struct TpmsTimeInfo {
214        pub time: u64,
215        pub clock_info: TpmsClockInfo,
216    }
217}
218
219tpm_struct! {
220    #[derive(Debug, PartialEq, Eq, Clone, Default, Copy)]
221    pub struct TpmsSignatureRsa {
222        pub hash: TpmAlgId,
223        pub sig: crate::data::Tpm2bPublicKeyRsa,
224    }
225}
226
227tpm_struct! {
228    #[derive(Debug, PartialEq, Eq, Clone, Default, Copy)]
229    pub struct TpmsSignatureEcc {
230        pub hash: TpmAlgId,
231        pub signature_r: Tpm2bEccParameter,
232        pub signature_s: Tpm2bEccParameter,
233    }
234}
235
236tpm_struct! {
237    #[derive(Debug, PartialEq, Eq, Clone, Default)]
238    pub struct TpmsTimeAttestInfo {
239        pub time: TpmsTimeInfo,
240        pub firmware_version: u64,
241    }
242}
243
244tpm_struct! {
245    #[derive(Debug, PartialEq, Eq, Clone, Default)]
246    pub struct TpmsCertifyInfo {
247        pub name: Tpm2bName,
248        pub qualified_name: Tpm2bName,
249    }
250}
251
252tpm_struct! {
253    #[derive(Debug, PartialEq, Eq, Clone, Default)]
254    pub struct TpmsQuoteInfo {
255        pub pcr_select: TpmlPcrSelection,
256        pub pcr_digest: Tpm2bDigest,
257    }
258}
259
260tpm_struct! {
261    #[derive(Debug, PartialEq, Eq, Clone, Default)]
262    pub struct TpmsCommandAuditInfo {
263        pub audit_counter: u64,
264        pub digest_alg: TpmAlgId,
265        pub audit_digest: Tpm2bDigest,
266        pub command_digest: Tpm2bDigest,
267    }
268}
269
270tpm_struct! {
271    #[derive(Debug, PartialEq, Eq, Clone, Default, Copy)]
272    pub struct TpmsSessionAuditInfo {
273        pub exclusive_session: TpmiYesNo,
274        pub session_digest: Tpm2bDigest,
275    }
276}
277
278tpm_struct! {
279    #[derive(Debug, PartialEq, Eq, Clone, Default)]
280    pub struct TpmsCreationInfo {
281        pub object_name: Tpm2bName,
282        pub creation_hash: Tpm2bDigest,
283    }
284}
285
286tpm_struct! {
287    #[derive(Debug, PartialEq, Eq, Clone, Default)]
288    pub struct TpmsNvCertifyInfo {
289        pub index_name: Tpm2bName,
290        pub offset: u16,
291        pub nv_contents: Tpm2bMaxNvBuffer,
292    }
293}
294
295tpm_struct! {
296    #[derive(Debug, PartialEq, Eq, Clone, Default)]
297    pub struct TpmsNvDigestCertifyInfo {
298        pub index_name: Tpm2bName,
299        pub nv_digest: Tpm2bDigest,
300    }
301}
302
303tpm_struct! {
304    #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
305    pub struct TpmsAlgorithmDetailEcc {
306        pub curve_id: TpmEccCurve,
307        pub key_size: u16,
308        pub kdf: TpmtKdfScheme,
309        pub sign: TpmtScheme,
310        pub p: Tpm2bEccParameter,
311        pub a: Tpm2bEccParameter,
312        pub b: Tpm2bEccParameter,
313        pub gx: Tpm2bEccParameter,
314        pub gy: Tpm2bEccParameter,
315        pub n: Tpm2bEccParameter,
316        pub h: Tpm2bEccParameter,
317    }
318}
319
320#[derive(Debug, PartialEq, Eq, Clone)]
321pub struct TpmsAttest {
322    pub magic: u32,
323    pub attest_type: TpmSt,
324    pub qualified_signer: Tpm2bName,
325    pub extra_data: Tpm2bData,
326    pub clock_info: TpmsClockInfo,
327    pub firmware_version: u64,
328    pub attested: crate::data::TpmuAttest,
329}
330
331impl TpmTagged for TpmsAttest {
332    type Tag = TpmSt;
333    type Value = crate::data::TpmuAttest;
334}
335
336impl TpmSized for TpmsAttest {
337    const SIZE: usize = size_of::<u32>()
338        + TpmSt::SIZE
339        + Tpm2bName::SIZE
340        + Tpm2bData::SIZE
341        + TpmsClockInfo::SIZE
342        + size_of::<u64>()
343        + crate::data::TpmuAttest::SIZE;
344    fn len(&self) -> usize {
345        size_of::<u32>()
346            + self.attest_type.len()
347            + self.qualified_signer.len()
348            + self.extra_data.len()
349            + self.clock_info.len()
350            + size_of::<u64>()
351            + self.attested.len()
352    }
353}
354
355impl TpmBuild for TpmsAttest {
356    fn build(&self, writer: &mut TpmWriter) -> TpmResult<()> {
357        0xff54_4347_u32.build(writer)?;
358        self.attest_type.build(writer)?;
359        self.qualified_signer.build(writer)?;
360        self.extra_data.build(writer)?;
361        self.clock_info.build(writer)?;
362        self.firmware_version.build(writer)?;
363        self.attested.build(writer)
364    }
365}
366
367impl TpmParse for TpmsAttest {
368    fn parse(buf: &[u8]) -> TpmResult<(Self, &[u8])> {
369        let (magic, buf) = u32::parse(buf)?;
370        if magic != 0xff54_4347 {
371            return Err(TpmErrorKind::InvalidMagic {
372                expected: 0xff54_4347,
373                got: magic,
374            });
375        }
376        let (attest_type, buf) = TpmSt::parse(buf)?;
377        let (qualified_signer, buf) = Tpm2bName::parse(buf)?;
378        let (extra_data, buf) = Tpm2bData::parse(buf)?;
379        let (clock_info, buf) = TpmsClockInfo::parse(buf)?;
380        let (firmware_version, buf) = u64::parse(buf)?;
381        let (attested, buf) = crate::data::TpmuAttest::parse_tagged(attest_type, buf)?;
382
383        Ok((
384            Self {
385                magic,
386                attest_type,
387                qualified_signer,
388                extra_data,
389                clock_info,
390                firmware_version,
391                attested,
392            },
393            buf,
394        ))
395    }
396}