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