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