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