cli/
print.rs

1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright (c) 2025 Opinsys Oy
3// Copyright (c) 2024-2025 Jarkko Sakkinen
4
5use std::{io::Write, vec::Vec};
6use tpm2_protocol::{
7    self,
8    data::{
9        self, Tpm2bNvPublic, Tpm2bPublic, Tpm2bSensitiveCreate, TpmAlgId, TpmCap, TpmCc,
10        TpmEccCurve, TpmPt, TpmRh, TpmSe, TpmSt, TpmaAlgorithm, TpmaCc, TpmaLocality, TpmaNv,
11        TpmaObject, TpmaSession, TpmiYesNo, TpmsAlgProperty, TpmsAuthCommand, TpmsCapabilityData,
12        TpmsContext, TpmsCreationData, TpmsEccPoint, TpmsKeyedhashParms, TpmsNvPublic,
13        TpmsPcrSelection, TpmsSchemeHash, TpmsSchemeXor, TpmsSensitiveCreate, TpmsSymcipherParms,
14        TpmsTaggedProperty, TpmtEccScheme, TpmtHa, TpmtKdfScheme, TpmtKeyedhashScheme, TpmtPublic,
15        TpmtPublicParms, TpmtRsaScheme, TpmtSymDefObject, TpmtTkAuth, TpmtTkCreation,
16        TpmtTkHashcheck, TpmuAsymScheme, TpmuCapabilities, TpmuHa, TpmuKeyedhashScheme,
17        TpmuPublicId, TpmuPublicParms, TpmuSensitiveComposite, TpmuSymKeyBits, TpmuSymMode,
18    },
19    message::{
20        TpmCommandBody, TpmContextLoadCommand, TpmContextLoadResponse, TpmContextSaveCommand,
21        TpmContextSaveResponse, TpmCreateCommand, TpmCreatePrimaryCommand,
22        TpmCreatePrimaryResponse, TpmCreateResponse, TpmDictionaryAttackLockResetCommand,
23        TpmDictionaryAttackLockResetResponse, TpmEccParametersCommand, TpmEvictControlCommand,
24        TpmEvictControlResponse, TpmFlushContextCommand, TpmFlushContextResponse,
25        TpmGetCapabilityCommand, TpmGetCapabilityResponse, TpmImportCommand, TpmImportResponse,
26        TpmLoadCommand, TpmLoadResponse, TpmNvReadCommand, TpmNvReadPublicCommand,
27        TpmNvReadPublicResponse, TpmNvReadResponse, TpmPcrEventCommand, TpmPcrEventResponse,
28        TpmPcrReadCommand, TpmPcrReadResponse, TpmPolicyGetDigestCommand,
29        TpmPolicyGetDigestResponse, TpmPolicyOrCommand, TpmPolicyPcrCommand, TpmPolicyPcrResponse,
30        TpmPolicySecretCommand, TpmPolicySecretResponse, TpmReadPublicCommand,
31        TpmReadPublicResponse, TpmResponseBody, TpmStartAuthSessionCommand,
32        TpmStartAuthSessionResponse, TpmTestParmsCommand, TpmUnsealCommand, TpmUnsealResponse,
33    },
34    TpmBuffer, TpmHandle, TpmList,
35};
36
37pub const INDENT: usize = 2;
38
39pub trait TpmPrint {
40    /// # Errors
41    ///
42    /// Returns `std::io::Error` on I/O failure.
43    fn print(
44        &self,
45        writer: &mut dyn Write,
46        name: &str,
47        indent: usize,
48    ) -> Result<(), std::io::Error>;
49}
50
51macro_rules! tpm_print_simple {
52    ($type:ty, $format:literal) => {
53        impl TpmPrint for $type {
54            fn print(
55                &self,
56                writer: &mut dyn Write,
57                name: &str,
58                indent: usize,
59            ) -> Result<(), std::io::Error> {
60                let prefix = " ".repeat(indent * INDENT);
61                writeln!(
62                    writer,
63                    "{prefix}{name}: {value}",
64                    prefix = prefix,
65                    name = name,
66                    value = format_args!($format, self)
67                )
68            }
69        }
70    };
71}
72
73macro_rules! tpm_print_bitflags {
74    ($type:ty) => {
75        impl TpmPrint for $type {
76            fn print(
77                &self,
78                writer: &mut dyn Write,
79                name: &str,
80                indent: usize,
81            ) -> Result<(), std::io::Error> {
82                let prefix = " ".repeat(indent * INDENT);
83                let flags: Vec<&str> = self.flag_names().collect();
84                let flags_str = if flags.is_empty() {
85                    "NONE".to_string()
86                } else {
87                    flags.join(" | ")
88                };
89                writeln!(
90                    writer,
91                    "{prefix}{name}: {flags_str} ({value:#x})",
92                    name = name,
93                    prefix = prefix,
94                    flags_str = flags_str,
95                    value = self.bits()
96                )
97            }
98        }
99    };
100}
101
102tpm_print_simple!(u8, "{:02x}");
103tpm_print_simple!(u16, "{:04x}");
104tpm_print_simple!(u32, "{:08x}");
105tpm_print_simple!(u64, "{:16x}");
106tpm_print_simple!(i32, "{}");
107tpm_print_simple!(TpmHandle, "{:08x}");
108tpm_print_simple!(TpmAlgId, "{}");
109tpm_print_simple!(TpmCc, "{}");
110tpm_print_simple!(TpmPt, "{}");
111tpm_print_simple!(TpmRh, "{}");
112tpm_print_simple!(TpmCap, "{}");
113tpm_print_simple!(TpmSe, "{:?}");
114tpm_print_simple!(TpmSt, "{:?}");
115tpm_print_simple!(TpmEccCurve, "{:?}");
116tpm_print_simple!(TpmiYesNo, "{:?}");
117
118tpm_print_bitflags!(TpmaObject);
119tpm_print_bitflags!(TpmaAlgorithm);
120tpm_print_bitflags!(TpmaSession);
121tpm_print_bitflags!(TpmaLocality);
122tpm_print_bitflags!(TpmaNv);
123tpm_print_bitflags!(TpmaCc);
124
125impl<const CAPACITY: usize> TpmPrint for TpmBuffer<CAPACITY> {
126    fn print(
127        &self,
128        writer: &mut dyn Write,
129        name: &str,
130        indent: usize,
131    ) -> Result<(), std::io::Error> {
132        let prefix = " ".repeat(indent * INDENT);
133        writeln!(
134            writer,
135            "{}{}: (size={}) {}",
136            prefix,
137            name,
138            self.len(),
139            hex::encode(self)
140        )
141    }
142}
143
144impl<T, const CAPACITY: usize> TpmPrint for TpmList<T, CAPACITY>
145where
146    T: TpmPrint + Copy,
147{
148    fn print(
149        &self,
150        writer: &mut dyn Write,
151        name: &str,
152        indent: usize,
153    ) -> Result<(), std::io::Error> {
154        let prefix = " ".repeat(indent * INDENT);
155        writeln!(writer, "{}{}: (count={})", prefix, name, self.len())?;
156        for item in self.iter() {
157            item.print(writer, "", indent + 1)?;
158        }
159        Ok(())
160    }
161}
162
163macro_rules! tpm_print_struct {
164    ($type:ty, $($field:ident => $name:literal),* $(,)?) => {
165        impl TpmPrint for $type {
166            fn print(
167                &self,
168                writer: &mut dyn Write,
169                name: &str,
170                indent: usize,
171            ) -> Result<(), std::io::Error> {
172                let prefix = " ".repeat(indent * INDENT);
173                if !name.is_empty() {
174                    writeln!(writer, "{}{}:", prefix, name)?;
175                } else if stringify!($($field),*).is_empty() {
176                    return Ok(());
177                }
178
179                #[allow(unused_variables)]
180                let field_indent = if name.is_empty() { indent } else { indent + 1 };
181                $(
182                    self.$field.print(writer, $name, field_indent)?;
183                )*
184                Ok(())
185            }
186        }
187    };
188}
189
190tpm_print_struct!(TpmsAlgProperty, alg => "alg", alg_properties => "algProperties");
191tpm_print_struct!(TpmsTaggedProperty, property => "property", value => "value");
192tpm_print_struct!(TpmsPcrSelection, hash => "hash", pcr_select => "pcrSelect");
193tpm_print_struct!(TpmsKeyedhashParms, scheme => "scheme");
194tpm_print_struct!(TpmsSymcipherParms, sym => "sym");
195tpm_print_struct!(TpmtKdfScheme, scheme => "scheme");
196tpm_print_struct!(TpmsEccPoint, x => "x", y => "y");
197tpm_print_struct!(TpmsContext, sequence => "sequence", saved_handle => "savedHandle", hierarchy => "hierarchy", context_blob => "contextBlob");
198tpm_print_struct!(TpmsAuthCommand, session_handle => "sessionHandle", nonce => "nonce", session_attributes => "sessionAttributes", hmac => "hmac");
199tpm_print_struct!(TpmsSensitiveCreate, user_auth => "userAuth", data => "data");
200tpm_print_struct!(TpmtTkCreation, tag => "tag", hierarchy => "hierarchy", digest => "digest");
201tpm_print_struct!(TpmtTkAuth, tag => "tag", hierarchy => "hierarchy", digest => "digest");
202tpm_print_struct!(TpmtTkHashcheck, tag => "tag", hierarchy => "hierarchy", digest => "digest");
203tpm_print_struct!(TpmsSchemeHash, hash_alg => "hashAlg");
204tpm_print_struct!(TpmsSchemeXor, hash_alg => "hashAlg", kdf => "kdf");
205tpm_print_struct!(TpmtRsaScheme, scheme => "scheme", details => "details");
206tpm_print_struct!(TpmtEccScheme, scheme => "scheme", details => "details");
207tpm_print_struct!(
208    TpmsCreationData,
209    pcr_select => "pcrSelect",
210    pcr_digest => "pcrDigest",
211    locality => "locality",
212    parent_name_alg => "parentNameAlg",
213    parent_name => "parentName",
214    parent_qualified_name => "parentQualifiedName",
215    outside_info => "outsideInfo",
216);
217tpm_print_struct!(Tpm2bPublic, inner => "inner");
218tpm_print_struct!(Tpm2bSensitiveCreate, inner => "inner");
219tpm_print_struct!(data::Tpm2bCreationData, inner => "inner");
220tpm_print_struct!(TpmsNvPublic, nv_index => "nvIndex", name_alg => "nameAlg", attributes => "attributes", auth_policy => "authPolicy", data_size => "dataSize");
221tpm_print_struct!(Tpm2bNvPublic, inner => "inner");
222
223tpm_print_struct!(TpmCreatePrimaryCommand, primary_handle => "primaryHandle", in_sensitive => "inSensitive", in_public => "inPublic", outside_info => "outsideInfo", creation_pcr => "creationPcr");
224tpm_print_struct!(TpmContextSaveCommand, save_handle => "saveHandle");
225tpm_print_struct!(TpmEvictControlCommand, auth => "auth", object_handle => "objectHandle", persistent_handle => "persistentHandle");
226tpm_print_struct!(TpmFlushContextCommand, flush_handle => "flushHandle");
227tpm_print_struct!(TpmReadPublicCommand, object_handle => "objectHandle");
228tpm_print_struct!(TpmImportCommand, parent_handle => "parentHandle", encryption_key => "encryptionKey", object_public => "objectPublic", duplicate => "duplicate", in_sym_seed => "inSymSeed", symmetric_alg => "symmetricAlg");
229tpm_print_struct!(TpmLoadCommand, parent_handle => "parentHandle", in_private => "inPrivate", in_public => "inPublic");
230tpm_print_struct!(TpmNvReadPublicCommand, nv_index => "nvIndex");
231tpm_print_struct!(TpmNvReadCommand, auth_handle => "authHandle", nv_index => "nvIndex", size => "size", offset => "offset");
232tpm_print_struct!(TpmPcrEventCommand, pcr_handle => "pcrHandle", event_data => "eventData");
233tpm_print_struct!(TpmPcrReadCommand, pcr_selection_in => "pcrSelectionIn");
234tpm_print_struct!(TpmPolicyPcrCommand, policy_session => "policySession", pcr_digest => "pcrDigest", pcrs => "pcrs");
235tpm_print_struct!(TpmPolicySecretCommand, auth_handle => "authHandle", policy_session => "policySession", nonce_tpm => "nonceTpm", cp_hash_a => "cpHashA", policy_ref => "policyRef", expiration => "expiration");
236tpm_print_struct!(TpmPolicyOrCommand, policy_session => "policySession", p_hash_list => "pHashList");
237tpm_print_struct!(TpmPolicyGetDigestCommand, policy_session => "policySession");
238tpm_print_struct!(TpmDictionaryAttackLockResetCommand, lock_handle => "lockHandle");
239tpm_print_struct!(TpmCreateCommand, parent_handle => "parentHandle", in_sensitive => "inSensitive", in_public => "inPublic", outside_info => "outsideInfo", creation_pcr => "creationPcr");
240tpm_print_struct!(TpmUnsealCommand, item_handle => "itemHandle");
241tpm_print_struct!(TpmGetCapabilityCommand, cap => "cap", property => "property", property_count => "propertyCount");
242tpm_print_struct!(TpmStartAuthSessionCommand, tpm_key => "tpmKey", bind => "bind", nonce_caller => "nonceCaller", encrypted_salt => "encryptedSalt", session_type => "sessionType", symmetric => "symmetric", auth_hash => "authHash");
243tpm_print_struct!(TpmContextLoadCommand, context => "context");
244tpm_print_struct!(TpmTestParmsCommand, parameters => "parameters");
245tpm_print_struct!(TpmEccParametersCommand, curve_id => "curveId");
246
247tpm_print_struct!(TpmCreatePrimaryResponse, object_handle => "objectHandle", out_public => "outPublic", creation_data => "creationData", creation_hash => "creationHash", creation_ticket => "creationTicket", name => "name");
248tpm_print_struct!(TpmContextSaveResponse, context => "context");
249tpm_print_struct!(TpmEvictControlResponse,);
250tpm_print_struct!(TpmFlushContextResponse,);
251tpm_print_struct!(TpmReadPublicResponse, out_public => "outPublic", name => "name", qualified_name => "qualifiedName");
252tpm_print_struct!(TpmImportResponse, out_private => "outPrivate");
253tpm_print_struct!(TpmLoadResponse, object_handle => "objectHandle", name => "name");
254tpm_print_struct!(TpmNvReadPublicResponse, nv_public => "nvPublic", nv_name => "nvName");
255tpm_print_struct!(TpmNvReadResponse, data => "data");
256tpm_print_struct!(TpmPcrEventResponse, digests => "digests");
257tpm_print_struct!(TpmPolicyPcrResponse,);
258tpm_print_struct!(TpmPolicySecretResponse, timeout => "timeout", policy_ticket => "policyTicket");
259tpm_print_struct!(TpmPolicyGetDigestResponse, policy_digest => "policyDigest");
260tpm_print_struct!(TpmDictionaryAttackLockResetResponse,);
261tpm_print_struct!(TpmCreateResponse, out_private => "outPrivate", out_public => "outPublic", creation_data => "creationData", creation_hash => "creationHash", creation_ticket => "creationTicket");
262tpm_print_struct!(TpmUnsealResponse, out_data => "outData");
263tpm_print_struct!(TpmGetCapabilityResponse, more_data => "moreData", capability_data => "capabilityData");
264tpm_print_struct!(TpmPcrReadResponse, pcr_update_counter => "pcrUpdateCounter", pcr_selection_out => "pcrSelectionOut", pcr_values => "pcrValues");
265tpm_print_struct!(TpmStartAuthSessionResponse, session_handle => "sessionHandle", nonce_tpm => "nonceTpm");
266tpm_print_struct!(TpmContextLoadResponse, loaded_handle => "loadedHandle");
267
268impl TpmPrint for TpmuHa {
269    fn print(
270        &self,
271        writer: &mut dyn Write,
272        name: &str,
273        indent: usize,
274    ) -> Result<(), std::io::Error> {
275        let prefix = " ".repeat(indent * INDENT);
276        let (variant, bytes): (&str, &[u8]) = match self {
277            Self::Null => ("Null", &[]),
278            Self::Digest(d) => ("Digest", d),
279        };
280        writeln!(
281            writer,
282            "{}{}: (size={}) {} ({})",
283            prefix,
284            name,
285            bytes.len(),
286            hex::encode(bytes),
287            variant,
288        )
289    }
290}
291
292impl TpmPrint for TpmtHa {
293    fn print(
294        &self,
295        writer: &mut dyn Write,
296        name: &str,
297        indent: usize,
298    ) -> Result<(), std::io::Error> {
299        let prefix = " ".repeat(indent * INDENT);
300        writeln!(writer, "{prefix}{name}:")?;
301        self.hash_alg.print(writer, "hashAlg", indent + 1)?;
302        self.digest.print(writer, "digest", indent + 1)?;
303        Ok(())
304    }
305}
306
307impl TpmPrint for TpmsCapabilityData {
308    fn print(
309        &self,
310        writer: &mut dyn Write,
311        name: &str,
312        indent: usize,
313    ) -> Result<(), std::io::Error> {
314        let prefix = " ".repeat(indent * INDENT);
315        writeln!(writer, "{prefix}{name}:")?;
316        self.capability.print(writer, "capability", indent + 1)?;
317        self.data.print(writer, "data", indent + 1)?;
318        Ok(())
319    }
320}
321
322impl TpmPrint for TpmuCapabilities {
323    fn print(
324        &self,
325        writer: &mut dyn Write,
326        name: &str,
327        indent: usize,
328    ) -> Result<(), std::io::Error> {
329        match self {
330            Self::Algs(algs) => algs.print(writer, name, indent),
331            Self::Handles(handles) => handles.print(writer, name, indent),
332            Self::Commands(commands) => commands.print(writer, name, indent),
333            Self::Pcrs(pcrs) => pcrs.print(writer, name, indent),
334            Self::EccCurves(curves) => curves.print(writer, name, indent),
335            Self::TpmProperties(props) => props.print(writer, name, indent),
336        }
337    }
338}
339
340impl TpmPrint for TpmtPublic {
341    fn print(
342        &self,
343        writer: &mut dyn Write,
344        name: &str,
345        indent: usize,
346    ) -> Result<(), std::io::Error> {
347        let prefix = " ".repeat(indent * INDENT);
348        writeln!(writer, "{prefix}{name}:")?;
349        self.object_type.print(writer, "type", indent + 1)?;
350        self.name_alg.print(writer, "nameAlg", indent + 1)?;
351        self.object_attributes
352            .print(writer, "objectAttributes", indent + 1)?;
353        self.auth_policy.print(writer, "authPolicy", indent + 1)?;
354        self.parameters.print(writer, "parameters", indent + 1)?;
355        self.unique.print(writer, "unique", indent + 1)?;
356        Ok(())
357    }
358}
359
360impl TpmPrint for TpmuPublicId {
361    fn print(
362        &self,
363        writer: &mut dyn Write,
364        name: &str,
365        indent: usize,
366    ) -> Result<(), std::io::Error> {
367        let prefix = " ".repeat(indent * INDENT);
368        match self {
369            Self::KeyedHash(b) => b.print(writer, &format!("{name} (keyedHash)"), indent),
370            Self::SymCipher(b) => b.print(writer, &format!("{name} (sym)"), indent),
371            Self::Rsa(b) => b.print(writer, &format!("{name} (rsa)"), indent),
372            Self::Ecc(p) => p.print(writer, &format!("{name} (ecc)"), indent),
373            Self::Null => writeln!(writer, "{prefix}{name}: null"),
374        }
375    }
376}
377
378impl TpmPrint for TpmtPublicParms {
379    fn print(
380        &self,
381        writer: &mut dyn Write,
382        name: &str,
383        indent: usize,
384    ) -> Result<(), std::io::Error> {
385        let prefix = " ".repeat(indent * INDENT);
386        writeln!(writer, "{prefix}{name}:")?;
387        self.object_type.print(writer, "type", indent + 1)?;
388        self.parameters.print(writer, "parameters", indent + 1)?;
389        Ok(())
390    }
391}
392
393impl TpmPrint for TpmuPublicParms {
394    fn print(
395        &self,
396        writer: &mut dyn Write,
397        name: &str,
398        indent: usize,
399    ) -> Result<(), std::io::Error> {
400        let prefix = " ".repeat(indent * INDENT);
401        match self {
402            Self::KeyedHash(details) => {
403                details.print(writer, &format!("{name} (keyedHash)"), indent)?;
404            }
405            Self::SymCipher(details) => details.print(writer, &format!("{name} (sym)"), indent)?,
406            Self::Rsa(params) => {
407                writeln!(writer, "{prefix}{name}: (rsa)")?;
408                params.symmetric.print(writer, "symmetric", indent + 1)?;
409                params.scheme.print(writer, "scheme", indent + 1)?;
410                params.key_bits.print(writer, "keyBits", indent + 1)?;
411                params.exponent.print(writer, "exponent", indent + 1)?;
412            }
413            Self::Ecc(params) => {
414                writeln!(writer, "{prefix}{name}: (ecc)")?;
415                params.symmetric.print(writer, "symmetric", indent + 1)?;
416                params.scheme.print(writer, "scheme", indent + 1)?;
417                params.curve_id.print(writer, "curveId", indent + 1)?;
418                params.kdf.print(writer, "kdf", indent + 1)?;
419            }
420            Self::Null => writeln!(writer, "{prefix}{name}: null")?,
421        }
422        Ok(())
423    }
424}
425
426impl TpmPrint for TpmtSymDefObject {
427    fn print(
428        &self,
429        writer: &mut dyn Write,
430        name: &str,
431        indent: usize,
432    ) -> Result<(), std::io::Error> {
433        if self.algorithm == TpmAlgId::Null {
434            self.algorithm.print(writer, name, indent)
435        } else {
436            let prefix = " ".repeat(indent * INDENT);
437            writeln!(writer, "{prefix}{name}:")?;
438            self.algorithm.print(writer, "algorithm", indent + 1)?;
439            self.key_bits.print(writer, "keyBits", indent + 1)?;
440            self.mode.print(writer, "mode", indent + 1)?;
441            Ok(())
442        }
443    }
444}
445
446impl TpmPrint for TpmuSymKeyBits {
447    fn print(
448        &self,
449        writer: &mut dyn Write,
450        name: &str,
451        indent: usize,
452    ) -> Result<(), std::io::Error> {
453        let prefix = " ".repeat(indent * INDENT);
454        match self {
455            Self::Aes(v) => v.print(writer, &format!("{name} (aes)"), indent),
456            Self::Sm4(v) => v.print(writer, &format!("{name} (sm4)"), indent),
457            Self::Camellia(v) => v.print(writer, &format!("{name} (camellia)"), indent),
458            Self::Xor(v) => v.print(writer, &format!("{name} (xor)"), indent),
459            Self::Null => writeln!(writer, "{prefix}{name}: null"),
460        }
461    }
462}
463
464impl TpmPrint for TpmuSymMode {
465    fn print(
466        &self,
467        writer: &mut dyn Write,
468        name: &str,
469        indent: usize,
470    ) -> Result<(), std::io::Error> {
471        let prefix = " ".repeat(indent * INDENT);
472        match self {
473            Self::Aes(v) => v.print(writer, &format!("{name} (aes)"), indent),
474            Self::Sm4(v) => v.print(writer, &format!("{name} (sm4)"), indent),
475            Self::Camellia(v) => v.print(writer, &format!("{name} (camellia)"), indent),
476            Self::Xor(v) => v.print(writer, &format!("{name} (xor)"), indent),
477            Self::Null => writeln!(writer, "{prefix}{name}: null"),
478        }
479    }
480}
481
482impl TpmPrint for TpmuAsymScheme {
483    fn print(
484        &self,
485        writer: &mut dyn Write,
486        name: &str,
487        indent: usize,
488    ) -> Result<(), std::io::Error> {
489        let prefix = " ".repeat(indent * INDENT);
490        match self {
491            Self::Any(s) => s.print(writer, &format!("{name} (any)"), indent),
492            Self::Null => writeln!(writer, "{prefix}{name}: null"),
493        }
494    }
495}
496
497impl TpmPrint for TpmuSensitiveComposite {
498    fn print(
499        &self,
500        writer: &mut dyn Write,
501        name: &str,
502        indent: usize,
503    ) -> Result<(), std::io::Error> {
504        match self {
505            Self::Rsa(b) => b.print(writer, &format!("{name} (rsa)"), indent),
506            Self::Ecc(b) => b.print(writer, &format!("{name} (ecc)"), indent),
507            Self::Bits(b) => b.print(writer, &format!("{name} (bits)"), indent),
508            Self::Sym(b) => b.print(writer, &format!("{name} (sym)"), indent),
509        }
510    }
511}
512
513impl TpmPrint for TpmtKeyedhashScheme {
514    fn print(
515        &self,
516        writer: &mut dyn Write,
517        name: &str,
518        indent: usize,
519    ) -> Result<(), std::io::Error> {
520        let prefix = " ".repeat(indent * INDENT);
521        writeln!(writer, "{prefix}{name}:")?;
522        self.scheme.print(writer, "scheme", indent + 1)?;
523        self.details.print(writer, "details", indent + 1)?;
524        Ok(())
525    }
526}
527
528impl TpmPrint for TpmuKeyedhashScheme {
529    fn print(
530        &self,
531        writer: &mut dyn Write,
532        name: &str,
533        indent: usize,
534    ) -> Result<(), std::io::Error> {
535        let prefix = " ".repeat(indent * INDENT);
536        match self {
537            Self::Hmac(s) => s.print(writer, &format!("{name} (hmac)"), indent),
538            Self::Xor(s) => s.print(writer, &format!("{name} (xor)"), indent),
539            Self::Null => writeln!(writer, "{prefix}{name}: null"),
540        }
541    }
542}
543
544impl TpmPrint for TpmCommandBody {
545    fn print(
546        &self,
547        writer: &mut dyn Write,
548        name: &str,
549        indent: usize,
550    ) -> Result<(), std::io::Error> {
551        match self {
552            Self::CreatePrimary(cmd) => cmd.print(writer, name, indent),
553            Self::ContextSave(cmd) => cmd.print(writer, name, indent),
554            Self::EvictControl(cmd) => cmd.print(writer, name, indent),
555            Self::FlushContext(cmd) => cmd.print(writer, name, indent),
556            Self::ReadPublic(cmd) => cmd.print(writer, name, indent),
557            Self::Import(cmd) => cmd.print(writer, name, indent),
558            Self::Load(cmd) => cmd.print(writer, name, indent),
559            Self::NvRead(cmd) => cmd.print(writer, name, indent),
560            Self::NvReadPublic(cmd) => cmd.print(writer, name, indent),
561            Self::PcrEvent(cmd) => cmd.print(writer, name, indent),
562            Self::PcrRead(cmd) => cmd.print(writer, name, indent),
563            Self::PolicyPcr(cmd) => cmd.print(writer, name, indent),
564            Self::PolicySecret(cmd) => cmd.print(writer, name, indent),
565            Self::PolicyOr(cmd) => cmd.print(writer, name, indent),
566            Self::PolicyGetDigest(cmd) => cmd.print(writer, name, indent),
567            Self::DictionaryAttackLockReset(cmd) => cmd.print(writer, name, indent),
568            Self::Create(cmd) => cmd.print(writer, name, indent),
569            Self::Unseal(cmd) => cmd.print(writer, name, indent),
570            Self::GetCapability(cmd) => cmd.print(writer, name, indent),
571            Self::StartAuthSession(cmd) => cmd.print(writer, name, indent),
572            Self::ContextLoad(cmd) => cmd.print(writer, name, indent),
573            Self::TestParms(cmd) => cmd.print(writer, name, indent),
574            Self::EccParameters(cmd) => cmd.print(writer, name, indent),
575            _ => {
576                let prefix = " ".repeat(indent * INDENT);
577                writeln!(
578                    writer,
579                    "{prefix}{name}: {self:?} (unimplemented pretty trace)"
580                )
581            }
582        }
583    }
584}
585
586impl TpmPrint for TpmResponseBody {
587    fn print(
588        &self,
589        writer: &mut dyn Write,
590        name: &str,
591        indent: usize,
592    ) -> Result<(), std::io::Error> {
593        match self {
594            Self::GetCapability(resp) => resp.print(writer, name, indent),
595            Self::PcrRead(resp) => resp.print(writer, name, indent),
596            Self::StartAuthSession(resp) => resp.print(writer, name, indent),
597            Self::CreatePrimary(resp) => resp.print(writer, name, indent),
598            Self::ContextSave(resp) => resp.print(writer, name, indent),
599            Self::EvictControl(resp) => resp.print(writer, name, indent),
600            Self::FlushContext(resp) => resp.print(writer, name, indent),
601            Self::ReadPublic(resp) => resp.print(writer, name, indent),
602            Self::Import(resp) => resp.print(writer, name, indent),
603            Self::Load(resp) => resp.print(writer, name, indent),
604            Self::NvRead(resp) => resp.print(writer, name, indent),
605            Self::NvReadPublic(resp) => resp.print(writer, name, indent),
606            Self::PcrEvent(resp) => resp.print(writer, name, indent),
607            Self::PolicyPcr(resp) => resp.print(writer, name, indent),
608            Self::PolicySecret(resp) => resp.print(writer, name, indent),
609            Self::PolicyGetDigest(resp) => resp.print(writer, name, indent),
610            Self::DictionaryAttackLockReset(resp) => resp.print(writer, name, indent),
611            Self::Create(resp) => resp.print(writer, name, indent),
612            Self::Unseal(resp) => resp.print(writer, name, indent),
613            Self::ContextLoad(resp) => resp.print(writer, name, indent),
614            _ => {
615                let prefix = " ".repeat(indent * INDENT);
616                writeln!(
617                    writer,
618                    "{prefix}{name}: {self:?} (unimplemented pretty trace)"
619                )
620            }
621        }
622    }
623}