tpm2_protocol/data/
tpmu.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::{MAX_DIGEST_SIZE, TPM_MAX_COMMAND_SIZE},
7    data::{
8        Tpm2bDigest, Tpm2bEccParameter, Tpm2bPublicKeyRsa, Tpm2bSensitiveData, Tpm2bSymKey,
9        TpmAlgId, TpmHt, TpmlAlgProperty, TpmlCca, TpmlEccCurve, TpmlHandle, TpmlPcrSelection,
10        TpmlTaggedTpmProperty, TpmsCertifyInfo, TpmsCommandAuditInfo, TpmsCreationInfo,
11        TpmsEccParms, TpmsEccPoint, TpmsKeyedhashParms, TpmsNvCertifyInfo, TpmsNvDigestCertifyInfo,
12        TpmsNvPublic, TpmsNvPublicExpAttr, TpmsQuoteInfo, TpmsRsaParms, TpmsSchemeHash,
13        TpmsSchemeHmac, TpmsSchemeXor, TpmsSessionAuditInfo, TpmsSignatureEcc, TpmsSignatureRsa,
14        TpmsSymcipherParms, TpmsTimeAttestInfo, TpmtHa,
15    },
16    tpm_hash_size, TpmBuffer, TpmBuild, TpmErrorKind, TpmParse, TpmParseTagged, TpmResult,
17    TpmSized, TpmTagged, TpmWriter,
18};
19use core::ops::Deref;
20
21#[derive(Debug, PartialEq, Eq, Clone, Copy)]
22pub enum TpmuAsymScheme {
23    Any(TpmsSchemeHash),
24    Null,
25}
26
27impl Default for TpmuAsymScheme {
28    fn default() -> Self {
29        Self::Null
30    }
31}
32
33impl TpmTagged for TpmuAsymScheme {
34    type Tag = TpmAlgId;
35    type Value = ();
36}
37
38impl TpmSized for TpmuAsymScheme {
39    const SIZE: usize = TPM_MAX_COMMAND_SIZE;
40    fn len(&self) -> usize {
41        match self {
42            Self::Any(s) => s.len(),
43            Self::Null => 0,
44        }
45    }
46}
47
48impl TpmBuild for TpmuAsymScheme {
49    fn build(&self, writer: &mut TpmWriter) -> TpmResult<()> {
50        match self {
51            Self::Any(s) => s.build(writer),
52            Self::Null => Ok(()),
53        }
54    }
55}
56
57impl TpmParseTagged for TpmuAsymScheme {
58    fn parse_tagged(tag: TpmAlgId, buf: &[u8]) -> TpmResult<(Self, &[u8])> {
59        if tag == TpmAlgId::Null {
60            Ok((Self::Null, buf))
61        } else {
62            let (val, buf) = TpmsSchemeHash::parse(buf)?;
63            Ok((Self::Any(val), buf))
64        }
65    }
66}
67
68#[derive(Debug, PartialEq, Eq, Clone)]
69#[allow(clippy::large_enum_variant)]
70pub enum TpmuCapabilities {
71    Algs(TpmlAlgProperty),
72    Handles(TpmlHandle),
73    Pcrs(TpmlPcrSelection),
74    Commands(TpmlCca),
75    TpmProperties(TpmlTaggedTpmProperty),
76    EccCurves(TpmlEccCurve),
77}
78
79impl TpmSized for TpmuCapabilities {
80    const SIZE: usize = TPM_MAX_COMMAND_SIZE;
81    fn len(&self) -> usize {
82        match self {
83            Self::Algs(algs) => algs.len(),
84            Self::Handles(handles) => handles.len(),
85            Self::Pcrs(pcrs) => pcrs.len(),
86            Self::Commands(cmds) => cmds.len(),
87            Self::TpmProperties(props) => props.len(),
88            Self::EccCurves(curves) => curves.len(),
89        }
90    }
91}
92
93impl TpmBuild for TpmuCapabilities {
94    fn build(&self, writer: &mut TpmWriter) -> TpmResult<()> {
95        match self {
96            Self::Algs(algs) => algs.build(writer),
97            Self::Handles(handles) => handles.build(writer),
98            Self::Pcrs(pcrs) => pcrs.build(writer),
99            Self::Commands(cmds) => cmds.build(writer),
100            Self::TpmProperties(props) => props.build(writer),
101            Self::EccCurves(curves) => curves.build(writer),
102        }
103    }
104}
105
106#[derive(Debug, PartialEq, Eq, Clone, Copy)]
107pub enum TpmuHa {
108    Null,
109    Digest(TpmBuffer<MAX_DIGEST_SIZE>),
110}
111
112impl TpmTagged for TpmuHa {
113    type Tag = TpmAlgId;
114    type Value = ();
115}
116
117impl TpmBuild for TpmuHa {
118    fn build(&self, writer: &mut TpmWriter) -> TpmResult<()> {
119        match self {
120            Self::Null => Ok(()),
121            Self::Digest(d) => writer.write_bytes(d),
122        }
123    }
124}
125
126impl TpmParseTagged for TpmuHa {
127    fn parse_tagged(tag: TpmAlgId, buf: &[u8]) -> TpmResult<(Self, &[u8])> {
128        if tag == TpmAlgId::Null {
129            return Ok((Self::Null, buf));
130        }
131
132        let digest_size = tpm_hash_size(&tag).ok_or(TpmErrorKind::InvalidValue)?;
133        if buf.len() < digest_size {
134            return Err(TpmErrorKind::Underflow);
135        }
136
137        let (digest_bytes, buf) = buf.split_at(digest_size);
138
139        let digest = Self::Digest(TpmBuffer::try_from(digest_bytes)?);
140
141        Ok((digest, buf))
142    }
143}
144
145impl Default for TpmuHa {
146    fn default() -> Self {
147        Self::Null
148    }
149}
150
151impl TpmSized for TpmuHa {
152    const SIZE: usize = MAX_DIGEST_SIZE;
153    fn len(&self) -> usize {
154        match self {
155            Self::Null => 0,
156            Self::Digest(d) => d.deref().len(),
157        }
158    }
159}
160
161impl Deref for TpmuHa {
162    type Target = [u8];
163
164    fn deref(&self) -> &Self::Target {
165        match self {
166            Self::Null => &[],
167            Self::Digest(d) => d,
168        }
169    }
170}
171
172#[allow(clippy::large_enum_variant)]
173#[derive(Debug, PartialEq, Eq, Clone)]
174pub enum TpmuPublicId {
175    KeyedHash(Tpm2bDigest),
176    SymCipher(Tpm2bSymKey),
177    Rsa(Tpm2bPublicKeyRsa),
178    Ecc(TpmsEccPoint),
179    Null,
180}
181
182impl TpmSized for TpmuPublicId {
183    const SIZE: usize = TPM_MAX_COMMAND_SIZE;
184    fn len(&self) -> usize {
185        match self {
186            Self::KeyedHash(data) => data.len(),
187            Self::SymCipher(data) => data.len(),
188            Self::Rsa(data) => data.len(),
189            Self::Ecc(point) => point.len(),
190            Self::Null => 0,
191        }
192    }
193}
194
195impl TpmBuild for TpmuPublicId {
196    fn build(&self, writer: &mut TpmWriter) -> TpmResult<()> {
197        match self {
198            Self::KeyedHash(data) => data.build(writer),
199            Self::SymCipher(data) => data.build(writer),
200            Self::Rsa(data) => data.build(writer),
201            Self::Ecc(point) => point.build(writer),
202            Self::Null => Ok(()),
203        }
204    }
205}
206
207impl Default for TpmuPublicId {
208    fn default() -> Self {
209        Self::Null
210    }
211}
212
213#[derive(Debug, PartialEq, Eq, Clone, Copy)]
214pub enum TpmuPublicParms {
215    KeyedHash(TpmsKeyedhashParms),
216    SymCipher(TpmsSymcipherParms),
217    Rsa(TpmsRsaParms),
218    Ecc(TpmsEccParms),
219    Null,
220}
221
222impl TpmTagged for TpmuPublicParms {
223    type Tag = TpmAlgId;
224    type Value = ();
225}
226
227impl TpmSized for TpmuPublicParms {
228    const SIZE: usize = TPM_MAX_COMMAND_SIZE;
229    fn len(&self) -> usize {
230        match self {
231            Self::KeyedHash(d) => d.len(),
232            Self::SymCipher(d) => d.len(),
233            Self::Rsa(d) => d.len(),
234            Self::Ecc(d) => d.len(),
235            Self::Null => 0,
236        }
237    }
238}
239
240impl TpmBuild for TpmuPublicParms {
241    fn build(&self, writer: &mut TpmWriter) -> TpmResult<()> {
242        match self {
243            Self::KeyedHash(d) => d.build(writer),
244            Self::SymCipher(d) => d.build(writer),
245            Self::Rsa(d) => d.build(writer),
246            Self::Ecc(d) => d.build(writer),
247            Self::Null => Ok(()),
248        }
249    }
250}
251
252impl TpmParseTagged for TpmuPublicParms {
253    fn parse_tagged(tag: TpmAlgId, buf: &[u8]) -> TpmResult<(Self, &[u8])> {
254        match tag {
255            TpmAlgId::KeyedHash => {
256                let (details, buf) = TpmsKeyedhashParms::parse(buf)?;
257                Ok((Self::KeyedHash(details), buf))
258            }
259            TpmAlgId::SymCipher => {
260                let (details, buf) = TpmsSymcipherParms::parse(buf)?;
261                Ok((Self::SymCipher(details), buf))
262            }
263            TpmAlgId::Rsa => {
264                let (details, buf) = TpmsRsaParms::parse(buf)?;
265                Ok((Self::Rsa(details), buf))
266            }
267            TpmAlgId::Ecc => {
268                let (details, buf) = TpmsEccParms::parse(buf)?;
269                Ok((Self::Ecc(details), buf))
270            }
271            TpmAlgId::Null => Ok((Self::Null, buf)),
272            _ => Err(TpmErrorKind::InvalidValue),
273        }
274    }
275}
276
277#[allow(clippy::large_enum_variant)]
278#[derive(Debug, PartialEq, Eq, Clone)]
279pub enum TpmuSensitiveComposite {
280    Rsa(crate::data::Tpm2bPrivateKeyRsa),
281    Ecc(Tpm2bEccParameter),
282    Bits(Tpm2bSensitiveData),
283    Sym(Tpm2bSymKey),
284}
285
286impl Default for TpmuSensitiveComposite {
287    fn default() -> Self {
288        Self::Rsa(crate::data::Tpm2bPrivateKeyRsa::default())
289    }
290}
291
292impl TpmSized for TpmuSensitiveComposite {
293    const SIZE: usize = TPM_MAX_COMMAND_SIZE;
294    fn len(&self) -> usize {
295        match self {
296            Self::Ecc(val) => val.len(),
297            Self::Sym(val) => val.len(),
298            Self::Rsa(val) | Self::Bits(val) => val.len(),
299        }
300    }
301}
302
303impl TpmBuild for TpmuSensitiveComposite {
304    fn build(&self, writer: &mut TpmWriter) -> TpmResult<()> {
305        match self {
306            Self::Ecc(val) => val.build(writer),
307            Self::Sym(val) => val.build(writer),
308            Self::Rsa(val) | Self::Bits(val) => val.build(writer),
309        }
310    }
311}
312
313#[derive(Debug, PartialEq, Eq, Clone, Copy)]
314pub enum TpmuSymKeyBits {
315    Aes(u16),
316    Sm4(u16),
317    Camellia(u16),
318    Xor(TpmAlgId),
319    Null,
320}
321
322impl Default for TpmuSymKeyBits {
323    fn default() -> Self {
324        Self::Null
325    }
326}
327
328impl TpmSized for TpmuSymKeyBits {
329    const SIZE: usize = core::mem::size_of::<u16>();
330    fn len(&self) -> usize {
331        match self {
332            Self::Aes(val) | Self::Sm4(val) | Self::Camellia(val) => val.len(),
333            Self::Xor(val) => val.len(),
334            Self::Null => 0,
335        }
336    }
337}
338
339impl TpmBuild for TpmuSymKeyBits {
340    fn build(&self, writer: &mut TpmWriter) -> TpmResult<()> {
341        match self {
342            Self::Aes(val) | Self::Sm4(val) | Self::Camellia(val) => val.build(writer),
343            Self::Xor(val) => val.build(writer),
344            Self::Null => Ok(()),
345        }
346    }
347}
348
349#[derive(Debug, PartialEq, Eq, Clone, Copy)]
350pub enum TpmuSymMode {
351    Aes(TpmAlgId),
352    Sm4(TpmAlgId),
353    Camellia(TpmAlgId),
354    Xor(TpmAlgId),
355    Null,
356}
357
358impl Default for TpmuSymMode {
359    fn default() -> Self {
360        Self::Null
361    }
362}
363
364impl TpmSized for TpmuSymMode {
365    const SIZE: usize = core::mem::size_of::<u16>();
366    fn len(&self) -> usize {
367        match self {
368            Self::Aes(val) | Self::Sm4(val) | Self::Camellia(val) | Self::Xor(val) => val.len(),
369            Self::Null => 0,
370        }
371    }
372}
373
374impl TpmBuild for TpmuSymMode {
375    fn build(&self, writer: &mut TpmWriter) -> TpmResult<()> {
376        match self {
377            Self::Aes(val) | Self::Sm4(val) | Self::Camellia(val) | Self::Xor(val) => {
378                val.build(writer)
379            }
380            Self::Null => Ok(()),
381        }
382    }
383}
384
385#[derive(Debug, PartialEq, Eq, Clone)]
386pub enum TpmuSignature {
387    Rsassa(TpmsSignatureRsa),
388    Rsapss(TpmsSignatureRsa),
389    Ecdsa(TpmsSignatureEcc),
390    Ecdaa(TpmsSignatureEcc),
391    Sm2(TpmsSignatureEcc),
392    Ecschnorr(TpmsSignatureEcc),
393    Hmac(TpmtHa),
394    Null,
395}
396
397impl TpmTagged for TpmuSignature {
398    type Tag = TpmAlgId;
399    type Value = ();
400}
401
402impl TpmSized for TpmuSignature {
403    const SIZE: usize = TPM_MAX_COMMAND_SIZE;
404    fn len(&self) -> usize {
405        match self {
406            Self::Rsassa(s) | Self::Rsapss(s) => s.len(),
407            Self::Ecdsa(s) | Self::Ecdaa(s) | Self::Sm2(s) | Self::Ecschnorr(s) => s.len(),
408            Self::Hmac(s) => s.len(),
409            Self::Null => 0,
410        }
411    }
412}
413
414impl TpmBuild for TpmuSignature {
415    fn build(&self, writer: &mut TpmWriter) -> TpmResult<()> {
416        match self {
417            Self::Rsassa(s) | Self::Rsapss(s) => s.build(writer),
418            Self::Ecdsa(s) | Self::Ecdaa(s) | Self::Sm2(s) | Self::Ecschnorr(s) => s.build(writer),
419            Self::Hmac(s) => s.build(writer),
420            Self::Null => Ok(()),
421        }
422    }
423}
424
425impl TpmParseTagged for TpmuSignature {
426    fn parse_tagged(tag: TpmAlgId, buf: &[u8]) -> TpmResult<(Self, &[u8])> {
427        match tag {
428            TpmAlgId::Rsassa => {
429                let (val, buf) = TpmsSignatureRsa::parse(buf)?;
430                Ok((Self::Rsassa(val), buf))
431            }
432            TpmAlgId::Rsapss => {
433                let (val, buf) = TpmsSignatureRsa::parse(buf)?;
434                Ok((Self::Rsapss(val), buf))
435            }
436            TpmAlgId::Ecdsa => {
437                let (val, buf) = TpmsSignatureEcc::parse(buf)?;
438                Ok((Self::Ecdsa(val), buf))
439            }
440            TpmAlgId::Ecdaa => {
441                let (val, buf) = TpmsSignatureEcc::parse(buf)?;
442                Ok((Self::Ecdaa(val), buf))
443            }
444            TpmAlgId::Sm2 => {
445                let (val, buf) = TpmsSignatureEcc::parse(buf)?;
446                Ok((Self::Sm2(val), buf))
447            }
448            TpmAlgId::Ecschnorr => {
449                let (val, buf) = TpmsSignatureEcc::parse(buf)?;
450                Ok((Self::Ecschnorr(val), buf))
451            }
452            TpmAlgId::Hmac => {
453                let (val, buf) = TpmtHa::parse(buf)?;
454                Ok((Self::Hmac(val), buf))
455            }
456            TpmAlgId::Null => Ok((Self::Null, buf)),
457            _ => Err(TpmErrorKind::InvalidValue),
458        }
459    }
460}
461
462#[allow(clippy::large_enum_variant)]
463#[derive(Debug, PartialEq, Eq, Clone)]
464pub enum TpmuAttest {
465    Certify(TpmsCertifyInfo),
466    Creation(TpmsCreationInfo),
467    Quote(TpmsQuoteInfo),
468    CommandAudit(TpmsCommandAuditInfo),
469    SessionAudit(TpmsSessionAuditInfo),
470    Time(TpmsTimeAttestInfo),
471    Nv(TpmsNvCertifyInfo),
472    NvDigest(TpmsNvDigestCertifyInfo),
473}
474
475impl TpmSized for TpmuAttest {
476    const SIZE: usize = TPM_MAX_COMMAND_SIZE;
477    fn len(&self) -> usize {
478        match self {
479            Self::Certify(i) => i.len(),
480            Self::Creation(i) => i.len(),
481            Self::Quote(i) => i.len(),
482            Self::CommandAudit(i) => i.len(),
483            Self::SessionAudit(i) => i.len(),
484            Self::Time(i) => i.len(),
485            Self::Nv(i) => i.len(),
486            Self::NvDigest(i) => i.len(),
487        }
488    }
489}
490
491impl TpmBuild for TpmuAttest {
492    fn build(&self, writer: &mut TpmWriter) -> TpmResult<()> {
493        match self {
494            Self::Certify(i) => i.build(writer),
495            Self::Creation(i) => i.build(writer),
496            Self::Quote(i) => i.build(writer),
497            Self::CommandAudit(i) => i.build(writer),
498            Self::SessionAudit(i) => i.build(writer),
499            Self::Time(i) => i.build(writer),
500            Self::Nv(i) => i.build(writer),
501            Self::NvDigest(i) => i.build(writer),
502        }
503    }
504}
505
506#[derive(Debug, Default, PartialEq, Eq, Clone, Copy)]
507pub enum TpmuKeyedhashScheme {
508    Hmac(TpmsSchemeHash),
509    Xor(TpmsSchemeXor),
510    #[default]
511    Null,
512}
513
514impl TpmTagged for TpmuKeyedhashScheme {
515    type Tag = TpmAlgId;
516    type Value = ();
517}
518
519impl TpmSized for TpmuKeyedhashScheme {
520    const SIZE: usize = TPM_MAX_COMMAND_SIZE;
521    fn len(&self) -> usize {
522        match self {
523            Self::Hmac(s) => s.len(),
524            Self::Xor(s) => s.len(),
525            Self::Null => 0,
526        }
527    }
528}
529
530impl TpmBuild for TpmuKeyedhashScheme {
531    fn build(&self, writer: &mut TpmWriter) -> TpmResult<()> {
532        match self {
533            Self::Hmac(s) => s.build(writer),
534            Self::Xor(s) => s.build(writer),
535            Self::Null => Ok(()),
536        }
537    }
538}
539
540impl TpmParseTagged for TpmuKeyedhashScheme {
541    fn parse_tagged(tag: TpmAlgId, buf: &[u8]) -> TpmResult<(Self, &[u8])> {
542        match tag {
543            TpmAlgId::Hmac => {
544                let (val, buf) = TpmsSchemeHash::parse(buf)?;
545                Ok((Self::Hmac(val), buf))
546            }
547            TpmAlgId::Xor => {
548                let (val, buf) = TpmsSchemeXor::parse(buf)?;
549                Ok((Self::Xor(val), buf))
550            }
551            TpmAlgId::Null => Ok((Self::Null, buf)),
552            _ => Err(TpmErrorKind::InvalidValue),
553        }
554    }
555}
556
557#[derive(Debug, PartialEq, Eq, Clone, Copy)]
558pub enum TpmuSigScheme {
559    Any(TpmsSchemeHash),
560    Hmac(TpmsSchemeHmac),
561    Null,
562}
563
564impl Default for TpmuSigScheme {
565    fn default() -> Self {
566        Self::Null
567    }
568}
569
570impl TpmTagged for TpmuSigScheme {
571    type Tag = TpmAlgId;
572    type Value = ();
573}
574
575impl TpmSized for TpmuSigScheme {
576    const SIZE: usize = TPM_MAX_COMMAND_SIZE;
577    fn len(&self) -> usize {
578        match self {
579            Self::Any(s) | Self::Hmac(s) => s.len(),
580            Self::Null => 0,
581        }
582    }
583}
584
585impl TpmBuild for TpmuSigScheme {
586    fn build(&self, writer: &mut TpmWriter) -> TpmResult<()> {
587        match self {
588            Self::Any(s) | Self::Hmac(s) => s.build(writer),
589            Self::Null => Ok(()),
590        }
591    }
592}
593
594impl TpmParseTagged for TpmuSigScheme {
595    fn parse_tagged(tag: TpmAlgId, buf: &[u8]) -> TpmResult<(Self, &[u8])> {
596        if tag == TpmAlgId::Null {
597            Ok((Self::Null, buf))
598        } else {
599            let (val, buf) = TpmsSchemeHash::parse(buf)?;
600            Ok((Self::Any(val), buf))
601        }
602    }
603}
604
605#[derive(Debug, PartialEq, Eq, Clone, Copy)]
606pub enum TpmuNvPublic2 {
607    NvIndex(TpmsNvPublic),
608    ExternalNv(TpmsNvPublicExpAttr),
609    PermanentNv(TpmsNvPublic),
610}
611
612impl TpmTagged for TpmuNvPublic2 {
613    type Tag = TpmHt;
614    type Value = ();
615}
616
617#[allow(clippy::match_same_arms)]
618impl TpmSized for TpmuNvPublic2 {
619    const SIZE: usize = TPM_MAX_COMMAND_SIZE;
620    fn len(&self) -> usize {
621        match self {
622            Self::NvIndex(s) => s.len(),
623            Self::ExternalNv(s) => s.len(),
624            Self::PermanentNv(s) => s.len(),
625        }
626    }
627}
628
629impl TpmBuild for TpmuNvPublic2 {
630    fn build(&self, writer: &mut TpmWriter) -> TpmResult<()> {
631        match self {
632            Self::ExternalNv(s) => s.build(writer),
633            Self::NvIndex(s) | Self::PermanentNv(s) => s.build(writer),
634        }
635    }
636}
637
638impl TpmParseTagged for TpmuNvPublic2 {
639    fn parse_tagged(tag: TpmHt, buf: &[u8]) -> TpmResult<(Self, &[u8])> {
640        match tag {
641            TpmHt::NvIndex => {
642                let (val, buf) = TpmsNvPublic::parse(buf)?;
643                Ok((Self::NvIndex(val), buf))
644            }
645            TpmHt::ExternalNv => {
646                let (val, buf) = TpmsNvPublicExpAttr::parse(buf)?;
647                Ok((Self::ExternalNv(val), buf))
648            }
649            TpmHt::PermanentNv => {
650                let (val, buf) = TpmsNvPublic::parse(buf)?;
651                Ok((Self::PermanentNv(val), buf))
652            }
653            _ => Err(TpmErrorKind::InvalidValue),
654        }
655    }
656}