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