tpm/
tpm20proto.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! TPM 2.0 Protocol types, as defined in the spec
5
6//! NOTE: once the `tpm-rs` project matures, this hand-rolled code should be *deleted* and
7//! replaced with types from that `tpm-rs` project.
8
9use self::packed_nums::*;
10use bitfield_struct::bitfield;
11use thiserror::Error;
12use zerocopy::FromBytes;
13use zerocopy::FromZeros;
14use zerocopy::Immutable;
15use zerocopy::IntoBytes;
16use zerocopy::KnownLayout;
17
18#[allow(non_camel_case_types)]
19mod packed_nums {
20    pub type u16_be = zerocopy::U16<zerocopy::BigEndian>;
21    pub type u32_be = zerocopy::U32<zerocopy::BigEndian>;
22    pub type u64_be = zerocopy::U64<zerocopy::BigEndian>;
23}
24
25#[derive(Debug, Error)]
26pub enum InvalidInput {
27    #[error("input data size too large for buffer - input size > upper bound: {0} > {1}")]
28    BufferSizeTooLarge(usize, usize),
29    #[error("input list length too long - input length > upper bound: {0} > {1}")]
30    PcrSelectionsLengthTooLong(usize, usize),
31    #[error("input payload size too large - input size > upper bound: {0} > {1}")]
32    NvPublicPayloadTooLarge(usize, usize),
33}
34
35#[derive(Debug, Error)]
36pub enum TpmProtoError {
37    #[error("input user_auth to TpmsSensitiveCreate is invalid")]
38    TpmsSensitiveCreateUserAuth(#[source] InvalidInput),
39    #[error("input data to TpmsSensitiveCreate is invalid")]
40    TpmsSensitiveCreateData(#[source] InvalidInput),
41    #[error("input auth_policy to TpmtPublic is invalid")]
42    TpmtPublicAuthPolicy(#[source] InvalidInput),
43    #[error("input unique to TpmtPublic is invalid")]
44    TpmtPublicUnique(#[source] InvalidInput),
45    #[error("input auth_policy to TpmsNvPublic is invalid")]
46    TpmsNvPublicAuthPolicy(#[source] InvalidInput),
47    #[error("input outside_info to CreatePrimary is invalid")]
48    CreatePrimaryOutsideInfo(#[source] InvalidInput),
49    #[error("input creation_pcr to CreatePrimary is invalid")]
50    CreatePrimaryCreationPcr(#[source] InvalidInput),
51    #[error("input auth to NvDefineSpace is invalid")]
52    NvDefineSpaceAuth(#[source] InvalidInput),
53    #[error("input public_info to NvDefineSpace is invalid")]
54    NvDefineSpacePublicInfo(#[source] InvalidInput),
55    #[error("input data to NvWrite is invalid")]
56    NvWriteData(#[source] InvalidInput),
57    #[error("input pcr_allocation to PcrAllocate is invalid")]
58    PcrAllocatePcrAllocation(#[source] InvalidInput),
59    #[error("input data to Import is invalid")]
60    ImportData(#[source] InvalidInput),
61}
62
63#[derive(Debug, Error)]
64pub enum ResponseValidationError {
65    #[error("response size is too small to fit into the buffer")]
66    ResponseSizeTooSmall,
67    #[error(
68        "size {size} specified in the response header does not meet the minimal size of command type {expected_size}, command succeeded: {command_succeeded}"
69    )]
70    HeaderResponseSizeMismatch {
71        size: u32,
72        expected_size: usize,
73        command_succeeded: bool,
74    },
75    #[error(
76        "unexpected session tag {response_session_tag} specified in the response header, expected: {expected_session_tag}, command succeeded: {command_succeeded}"
77    )]
78    HeaderSessionTagMismatch {
79        response_session_tag: u16,
80        expected_session_tag: u16,
81        command_succeeded: bool,
82    },
83}
84
85#[repr(transparent)]
86#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq)]
87pub struct ReservedHandle(pub u32_be);
88
89impl PartialEq<ReservedHandle> for u32 {
90    fn eq(&self, other: &ReservedHandle) -> bool {
91        other.0.get() == *self
92    }
93}
94
95impl ReservedHandle {
96    pub const fn new(kind: u8, offset: u32) -> ReservedHandle {
97        ReservedHandle(new_u32_be((kind as u32) << 24 | offset))
98    }
99}
100
101pub const TPM20_HT_NV_INDEX: u8 = 0x01;
102pub const TPM20_HT_PERMANENT: u8 = 0x40;
103pub const TPM20_HT_PERSISTENT: u8 = 0x81;
104
105pub const TPM20_RH_OWNER: ReservedHandle = ReservedHandle::new(TPM20_HT_PERMANENT, 0x01);
106pub const TPM20_RH_PLATFORM: ReservedHandle = ReservedHandle::new(TPM20_HT_PERMANENT, 0x0c);
107pub const TPM20_RH_ENDORSEMENT: ReservedHandle = ReservedHandle::new(TPM20_HT_PERMANENT, 0x0b);
108// `TPM_RS_PW` (not `TPM_RH_PW`)
109// See Table 28, Section 7.4, "Trusted Platform Module Library Part 2: Structures", revision 1.38.
110pub const TPM20_RS_PW: ReservedHandle = ReservedHandle::new(TPM20_HT_PERMANENT, 0x09);
111
112// Based on Section 2.2, "Registry of Reserved TPM 2.0 Handles and Localities", version 1.1.
113pub const NV_INDEX_RANGE_BASE_PLATFORM_MANUFACTURER: u32 =
114    (TPM20_HT_NV_INDEX as u32) << 24 | 0x400000;
115pub const NV_INDEX_RANGE_BASE_TCG_ASSIGNED: u32 = (TPM20_HT_NV_INDEX as u32) << 24 | 0xc00000;
116
117// The suggested minimal size for the buffer in `TPM2B_MAX_BUFFER`.
118// See Table 79, Section 10.4.8, "Trusted Platform Module Library Part 2: Structures", revision 1.38.
119pub const MAX_DIGEST_BUFFER_SIZE: usize = 1024;
120
121#[repr(transparent)]
122#[derive(Debug, Copy, Clone, IntoBytes, Immutable, KnownLayout, FromBytes)]
123pub struct SessionTag(pub u16_be);
124
125impl PartialEq<SessionTag> for u16 {
126    fn eq(&self, other: &SessionTag) -> bool {
127        other.0.get() == *self
128    }
129}
130
131impl SessionTag {
132    const fn new(val: u16) -> SessionTag {
133        SessionTag(new_u16_be(val))
134    }
135}
136
137#[derive(Debug, Copy, Clone)]
138#[repr(u16)]
139pub enum SessionTagEnum {
140    // No structure type specified
141    Null = 0x8000,
142
143    // A command/response for a command defined in this specification. The
144    // command/response has no attached sessions. If a command has an
145    // error and the command tag value is either TPM_ST_NO_SESSIONS or
146    // TPM_ST_SESSIONS, then this tag value is used for the response code.
147    NoSessions = 0x8001,
148
149    // A command/response for a command defined in this specification. The
150    // command/response has one or more attached sessions and the sessionOffset
151    // field is present.
152    Sessions = 0x8002,
153    AttestClock = 0x8014,
154    AttestCommandAudit = 0x8015,
155    AttestSessionAudit = 0x8016,
156    AttestCertify = 0x8017,
157    AttestQuote = 0x8018,
158    AttestTick = 0x8019,
159    AttestTickstamp = 0x801A,
160    AttestTransport = 0x801B,
161    AttestCreation = 0x801C,
162    AttestNv = 0x801D,
163    // Tickets
164    Creation = 0x8021,
165    Verified = 0x8022,
166    Auth = 0x8023,
167    Hashcheck = 0x8024,
168
169    // Structure describing a Field Upgrade Policy
170    FuManifest = 0x8029,
171}
172
173impl From<SessionTagEnum> for SessionTag {
174    fn from(x: SessionTagEnum) -> Self {
175        SessionTag::new(x as u16)
176    }
177}
178
179impl SessionTagEnum {
180    pub fn from_u16(val: u16) -> Option<SessionTagEnum> {
181        let ret = match val {
182            0x8000 => Self::Null,
183            0x8001 => Self::NoSessions,
184            0x8002 => Self::Sessions,
185            0x8014 => Self::AttestClock,
186            0x8015 => Self::AttestCommandAudit,
187            0x8016 => Self::AttestSessionAudit,
188            0x8017 => Self::AttestCertify,
189            0x8018 => Self::AttestQuote,
190            0x8019 => Self::AttestTick,
191            0x801A => Self::AttestTickstamp,
192            0x801B => Self::AttestTransport,
193            0x801C => Self::AttestCreation,
194            0x801D => Self::AttestNv,
195            0x8021 => Self::Creation,
196            0x8022 => Self::Verified,
197            0x8023 => Self::Auth,
198            0x8024 => Self::Hashcheck,
199            0x8029 => Self::FuManifest,
200            _ => return None,
201        };
202        Some(ret)
203    }
204}
205
206#[repr(transparent)]
207#[derive(Debug, Copy, Clone, IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq)]
208pub struct CommandCode(pub u32_be);
209
210impl PartialEq<CommandCode> for u32 {
211    fn eq(&self, other: &CommandCode) -> bool {
212        other.0.get() == *self
213    }
214}
215
216impl CommandCode {
217    const fn new(val: u32) -> CommandCode {
218        CommandCode(new_u32_be(val))
219    }
220
221    pub fn into_enum(self) -> Option<CommandCodeEnum> {
222        CommandCodeEnum::from_u32(self.0.get())
223    }
224}
225
226#[allow(non_camel_case_types, clippy::upper_case_acronyms)]
227#[derive(Debug, Clone, Copy, PartialEq)]
228#[repr(u32)]
229pub enum CommandCodeEnum {
230    NV_UndefineSpaceSpecial = 0x0000011f,
231    EvictControl = 0x00000120,
232    HierarchyControl = 0x00000121,
233    NV_UndefineSpace = 0x00000122,
234    ChangeEPS = 0x00000124,
235    ChangePPS = 0x00000125,
236    Clear = 0x00000126,
237    ClearControl = 0x00000127,
238    ClockSet = 0x00000128,
239    HierarchyChangeAuth = 0x00000129,
240    NV_DefineSpace = 0x0000012a,
241    PCR_Allocate = 0x0000012b,
242    PCR_SetAuthPolicy = 0x0000012c,
243    PP_Commands = 0x0000012d,
244    SetPrimaryPolicy = 0x0000012e,
245    FieldUpgradeStart = 0x0000012f,
246    ClockRateAdjust = 0x00000130,
247    CreatePrimary = 0x00000131,
248    NV_GlobalWriteLock = 0x00000132,
249    GetCommandAuditDigest = 0x00000133,
250    NV_Increment = 0x00000134,
251    NV_SetBits = 0x00000135,
252    NV_Extend = 0x00000136,
253    NV_Write = 0x00000137,
254    NV_WriteLock = 0x00000138,
255    DictionaryAttackLockReset = 0x00000139,
256    DictionaryAttackParameters = 0x0000013a,
257    NV_ChangeAuth = 0x0000013b,
258    PCR_Event = 0x0000013c,
259    PCR_Reset = 0x0000013d,
260    SequenceComplete = 0x0000013e,
261    SetAlgorithmSet = 0x0000013f,
262    SetCommandCodeAuditStatus = 0x00000140,
263    FieldUpgradeData = 0x00000141,
264    IncrementalSelfTest = 0x00000142,
265    SelfTest = 0x00000143,
266    Startup = 0x00000144,
267    Shutdown = 0x00000145,
268    StirRandom = 0x00000146,
269    ActivateCredential = 0x00000147,
270    Certify = 0x00000148,
271    PolicyNV = 0x00000149,
272    CertifyCreation = 0x0000014a,
273    Duplicate = 0x0000014b,
274    GetTime = 0x0000014c,
275    GetSessionAuditDigest = 0x0000014d,
276    NV_Read = 0x0000014e,
277    NV_ReadLock = 0x0000014f,
278    ObjectChangeAuth = 0x00000150,
279    PolicySecret = 0x00000151,
280    Rewrap = 0x00000152,
281    Create = 0x00000153,
282    ECDH_ZGen = 0x00000154,
283    HMAC = 0x00000155,
284    Import = 0x00000156,
285    Load = 0x00000157,
286    Quote = 0x00000158,
287    RSA_Decrypt = 0x00000159,
288    HMAC_Start = 0x0000015b,
289    SequenceUpdate = 0x0000015c,
290    Sign = 0x0000015d,
291    Unseal = 0x0000015e,
292    PolicySigned = 0x00000160,
293    ContextLoad = 0x00000161,
294    ContextSave = 0x00000162,
295    ECDH_KeyGen = 0x00000163,
296    EncryptDecrypt = 0x00000164,
297    FlushContext = 0x00000165,
298    LoadExternal = 0x00000167,
299    MakeCredential = 0x00000168,
300    NV_ReadPublic = 0x00000169,
301    PolicyAuthorize = 0x0000016a,
302    PolicyAuthValue = 0x0000016b,
303    PolicyCommandCode = 0x0000016c,
304    PolicyCounterTimer = 0x0000016d,
305    PolicyCpHash = 0x0000016e,
306    PolicyLocality = 0x0000016f,
307    PolicyNameHash = 0x00000170,
308    PolicyOR = 0x00000171,
309    PolicyTicket = 0x00000172,
310    ReadPublic = 0x00000173,
311    RSA_Encrypt = 0x00000174,
312    StartAuthSession = 0x00000176,
313    VerifySignature = 0x00000177,
314    ECC_Parameters = 0x00000178,
315    FirmwareRead = 0x00000179,
316    GetCapability = 0x0000017a,
317    GetRandom = 0x0000017b,
318    GetTestResult = 0x0000017c,
319    Hash = 0x0000017d,
320    PCR_Read = 0x0000017e,
321    PolicyPCR = 0x0000017f,
322    PolicyRestart = 0x00000180,
323    ReadClock = 0x00000181,
324    PCR_Extend = 0x00000182,
325    PCR_SetAuthValue = 0x00000183,
326    NV_Certify = 0x00000184,
327    EventSequenceComplete = 0x00000185,
328    HashSequenceStart = 0x00000186,
329    PolicyPhysicalPresence = 0x00000187,
330    PolicyDuplicationSelect = 0x00000188,
331    PolicyGetDigest = 0x00000189,
332    TestParms = 0x0000018a,
333    Commit = 0x0000018b,
334    PolicyPassword = 0x0000018c,
335    ZGen_2Phase = 0x0000018d,
336    EC_Ephemeral = 0x0000018e,
337    PolicyNvWritten = 0x0000018f,
338    PolicyTemplate = 0x00000190,
339    CreateLoaded = 0x00000191,
340    PolicyAuthorizeNV = 0x00000192,
341    EncryptDecrypt2 = 0x00000193,
342    AC_GetCapability = 0x00000194,
343    AC_Send = 0x00000195,
344    Policy_AC_SendSelect = 0x00000196,
345    CertifyX509 = 0x00000197,
346    ACT_SetTimeout = 0x00000198,
347}
348
349impl From<CommandCodeEnum> for CommandCode {
350    fn from(x: CommandCodeEnum) -> Self {
351        CommandCode::new(x as u32)
352    }
353}
354
355impl CommandCodeEnum {
356    pub fn from_u32(val: u32) -> Option<CommandCodeEnum> {
357        let ret = match val {
358            0x0000011f => Self::NV_UndefineSpaceSpecial,
359            0x00000120 => Self::EvictControl,
360            0x00000121 => Self::HierarchyControl,
361            0x00000122 => Self::NV_UndefineSpace,
362            0x00000124 => Self::ChangeEPS,
363            0x00000125 => Self::ChangePPS,
364            0x00000126 => Self::Clear,
365            0x00000127 => Self::ClearControl,
366            0x00000128 => Self::ClockSet,
367            0x00000129 => Self::HierarchyChangeAuth,
368            0x0000012a => Self::NV_DefineSpace,
369            0x0000012b => Self::PCR_Allocate,
370            0x0000012c => Self::PCR_SetAuthPolicy,
371            0x0000012d => Self::PP_Commands,
372            0x0000012e => Self::SetPrimaryPolicy,
373            0x0000012f => Self::FieldUpgradeStart,
374            0x00000130 => Self::ClockRateAdjust,
375            0x00000131 => Self::CreatePrimary,
376            0x00000132 => Self::NV_GlobalWriteLock,
377            0x00000133 => Self::GetCommandAuditDigest,
378            0x00000134 => Self::NV_Increment,
379            0x00000135 => Self::NV_SetBits,
380            0x00000136 => Self::NV_Extend,
381            0x00000137 => Self::NV_Write,
382            0x00000138 => Self::NV_WriteLock,
383            0x00000139 => Self::DictionaryAttackLockReset,
384            0x0000013a => Self::DictionaryAttackParameters,
385            0x0000013b => Self::NV_ChangeAuth,
386            0x0000013c => Self::PCR_Event,
387            0x0000013d => Self::PCR_Reset,
388            0x0000013e => Self::SequenceComplete,
389            0x0000013f => Self::SetAlgorithmSet,
390            0x00000140 => Self::SetCommandCodeAuditStatus,
391            0x00000141 => Self::FieldUpgradeData,
392            0x00000142 => Self::IncrementalSelfTest,
393            0x00000143 => Self::SelfTest,
394            0x00000144 => Self::Startup,
395            0x00000145 => Self::Shutdown,
396            0x00000146 => Self::StirRandom,
397            0x00000147 => Self::ActivateCredential,
398            0x00000148 => Self::Certify,
399            0x00000149 => Self::PolicyNV,
400            0x0000014a => Self::CertifyCreation,
401            0x0000014b => Self::Duplicate,
402            0x0000014c => Self::GetTime,
403            0x0000014d => Self::GetSessionAuditDigest,
404            0x0000014e => Self::NV_Read,
405            0x0000014f => Self::NV_ReadLock,
406            0x00000150 => Self::ObjectChangeAuth,
407            0x00000151 => Self::PolicySecret,
408            0x00000152 => Self::Rewrap,
409            0x00000153 => Self::Create,
410            0x00000154 => Self::ECDH_ZGen,
411            0x00000155 => Self::HMAC,
412            0x00000156 => Self::Import,
413            0x00000157 => Self::Load,
414            0x00000158 => Self::Quote,
415            0x00000159 => Self::RSA_Decrypt,
416            0x0000015b => Self::HMAC_Start,
417            0x0000015c => Self::SequenceUpdate,
418            0x0000015d => Self::Sign,
419            0x0000015e => Self::Unseal,
420            0x00000160 => Self::PolicySigned,
421            0x00000161 => Self::ContextLoad,
422            0x00000162 => Self::ContextSave,
423            0x00000163 => Self::ECDH_KeyGen,
424            0x00000164 => Self::EncryptDecrypt,
425            0x00000165 => Self::FlushContext,
426            0x00000167 => Self::LoadExternal,
427            0x00000168 => Self::MakeCredential,
428            0x00000169 => Self::NV_ReadPublic,
429            0x0000016a => Self::PolicyAuthorize,
430            0x0000016b => Self::PolicyAuthValue,
431            0x0000016c => Self::PolicyCommandCode,
432            0x0000016d => Self::PolicyCounterTimer,
433            0x0000016e => Self::PolicyCpHash,
434            0x0000016f => Self::PolicyLocality,
435            0x00000170 => Self::PolicyNameHash,
436            0x00000171 => Self::PolicyOR,
437            0x00000172 => Self::PolicyTicket,
438            0x00000173 => Self::ReadPublic,
439            0x00000174 => Self::RSA_Encrypt,
440            0x00000176 => Self::StartAuthSession,
441            0x00000177 => Self::VerifySignature,
442            0x00000178 => Self::ECC_Parameters,
443            0x00000179 => Self::FirmwareRead,
444            0x0000017a => Self::GetCapability,
445            0x0000017b => Self::GetRandom,
446            0x0000017c => Self::GetTestResult,
447            0x0000017d => Self::Hash,
448            0x0000017e => Self::PCR_Read,
449            0x0000017f => Self::PolicyPCR,
450            0x00000180 => Self::PolicyRestart,
451            0x00000181 => Self::ReadClock,
452            0x00000182 => Self::PCR_Extend,
453            0x00000183 => Self::PCR_SetAuthValue,
454            0x00000184 => Self::NV_Certify,
455            0x00000185 => Self::EventSequenceComplete,
456            0x00000186 => Self::HashSequenceStart,
457            0x00000187 => Self::PolicyPhysicalPresence,
458            0x00000188 => Self::PolicyDuplicationSelect,
459            0x00000189 => Self::PolicyGetDigest,
460            0x0000018a => Self::TestParms,
461            0x0000018b => Self::Commit,
462            0x0000018c => Self::PolicyPassword,
463            0x0000018d => Self::ZGen_2Phase,
464            0x0000018e => Self::EC_Ephemeral,
465            0x0000018f => Self::PolicyNvWritten,
466            0x00000190 => Self::PolicyTemplate,
467            0x00000191 => Self::CreateLoaded,
468            0x00000192 => Self::PolicyAuthorizeNV,
469            0x00000193 => Self::EncryptDecrypt2,
470            0x00000194 => Self::AC_GetCapability,
471            0x00000195 => Self::AC_Send,
472            0x00000196 => Self::Policy_AC_SendSelect,
473            0x00000197 => Self::CertifyX509,
474            0x00000198 => Self::ACT_SetTimeout,
475            _ => return None,
476        };
477
478        Some(ret)
479    }
480}
481
482const FLAG_FMT1: u32 = 0x0080;
483const FLAG_VER1: u32 = 0x0100;
484const FLAG_WARN: u32 = 0x0800 + FLAG_VER1;
485
486#[repr(u32)]
487pub enum ResponseCode {
488    Success = 0x000,
489    /// The given handle value is not valid or cannot be used for this
490    /// command.
491    Value = FLAG_FMT1 + 0x004,
492    /// Hierarchy is not enabled or is not correct for the use.
493    Hierarchy = FLAG_FMT1 + 0x0005,
494    /// The handle is not correct for the use.
495    Handle = FLAG_FMT1 + 0x000B,
496    /// The authorization HMAC check failed.
497    AuthFail = FLAG_FMT1 + 0x000E,
498    /// Structure is the wrong size.
499    Size = FLAG_FMT1 + 0x0015,
500    /// The TPM was unable to unmarshal a value because there were not
501    /// enough bytes in the input buffer.
502    Insufficient = FLAG_FMT1 + 0x001A,
503    /// Integrity check fail.
504    Integrity = FLAG_FMT1 + 0x001F,
505    /// TPM is in failure mode.
506    Failure = FLAG_VER1 + 0x0001,
507    /// Use of an authorization session with a context command.
508    AuthContext = FLAG_VER1 + 0x0045,
509    /// The NV index is used before being initialized or the state saved by
510    /// TPM20_CC_Shutdown could not be restored.
511    NvUninitialized = FLAG_VER1 + 0x04A,
512    /// ...
513    Sensitive = FLAG_VER1 + 0x055,
514    /// Gap for session context ID is too large.
515    ContextGap = FLAG_WARN + 0x001,
516    /// Out of memory for object contexts.
517    ObjectMemory = FLAG_WARN + 0x002,
518    /// Out of memory for session contexts.
519    SessionMemory = FLAG_WARN + 0x003,
520    /// Out of shared object/session memory or need space for internal
521    /// operations.
522    Memory = FLAG_WARN + 0x004,
523    /// Out of session handles - a session must be flushed before a new
524    /// session may be created.
525    SessionHandles = FLAG_WARN + 0x005,
526    /// Out of object handles - the handle space for objects is depleted and
527    /// a reboot is required .
528    /// NOTE:This cannot occur on the reference implementation.
529    ObjectHandles = FLAG_WARN + 0x006,
530    /// The TPM has suspended operation on the command. Forward progress was
531    /// made and the command may be retried.
532    Yielded = FLAG_WARN + 0x008,
533    /// The command was cancelled. The command may be retried.
534    Cancelled = FLAG_WARN + 0x009,
535    /// TPM is performing self tests.
536    Testing = FLAG_WARN + 0x00A,
537    /// The TPM is rate-limiting accesses to prevent wearout of NV.
538    NvRate = FLAG_WARN + 0x020,
539    /// Commands are not being accepted because the TPM is in DA lockout
540    /// mode.
541    Lockout = FLAG_WARN + 0x021,
542    /// The TPM was not able to start the command. Retry might work.
543    Retry = FLAG_WARN + 0x022,
544    /// The command may require writing of NV and NV is not current
545    /// accessible.
546    NvUnavailable = FLAG_WARN + 0x023,
547    /// This value is reserved and shall not be returned by the TPM.
548    NotUsed = FLAG_WARN + 0x07F,
549    /// Add to a parameter-, handle-, or session-related error.
550    Rc1 = 0x100,
551}
552
553impl ResponseCode {
554    pub fn from_u32(val: u32) -> Option<ResponseCode> {
555        let ret = match val {
556            x if x == ResponseCode::Success as u32 => ResponseCode::Success,
557            x if x == ResponseCode::Value as u32 => ResponseCode::Value,
558            x if x == ResponseCode::Hierarchy as u32 => ResponseCode::Hierarchy,
559            x if x == ResponseCode::Handle as u32 => ResponseCode::Handle,
560            x if x == ResponseCode::AuthFail as u32 => ResponseCode::AuthFail,
561            x if x == ResponseCode::Size as u32 => ResponseCode::Size,
562            x if x == ResponseCode::Insufficient as u32 => ResponseCode::Insufficient,
563            x if x == ResponseCode::Integrity as u32 => ResponseCode::Integrity,
564            x if x == ResponseCode::Failure as u32 => ResponseCode::Failure,
565            x if x == ResponseCode::AuthContext as u32 => ResponseCode::AuthContext,
566            x if x == ResponseCode::NvUninitialized as u32 => ResponseCode::NvUninitialized,
567            x if x == ResponseCode::Sensitive as u32 => ResponseCode::Sensitive,
568            x if x == ResponseCode::ContextGap as u32 => ResponseCode::ContextGap,
569            x if x == ResponseCode::ObjectMemory as u32 => ResponseCode::ObjectMemory,
570            x if x == ResponseCode::SessionMemory as u32 => ResponseCode::SessionMemory,
571            x if x == ResponseCode::Memory as u32 => ResponseCode::Memory,
572            x if x == ResponseCode::SessionHandles as u32 => ResponseCode::SessionHandles,
573            x if x == ResponseCode::ObjectHandles as u32 => ResponseCode::ObjectHandles,
574            x if x == ResponseCode::Yielded as u32 => ResponseCode::Yielded,
575            x if x == ResponseCode::Cancelled as u32 => ResponseCode::Cancelled,
576            x if x == ResponseCode::Testing as u32 => ResponseCode::Testing,
577            x if x == ResponseCode::NvRate as u32 => ResponseCode::NvRate,
578            x if x == ResponseCode::Lockout as u32 => ResponseCode::Lockout,
579            x if x == ResponseCode::Retry as u32 => ResponseCode::Retry,
580            x if x == ResponseCode::NvUnavailable as u32 => ResponseCode::NvUnavailable,
581            x if x == ResponseCode::NotUsed as u32 => ResponseCode::NotUsed,
582            _ => return None,
583        };
584        Some(ret)
585    }
586}
587
588#[repr(transparent)]
589#[derive(Debug, Copy, Clone, IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq)]
590pub struct AlgId(pub u16_be);
591
592impl PartialEq<AlgId> for u16 {
593    fn eq(&self, other: &AlgId) -> bool {
594        other.0.get() == *self
595    }
596}
597
598impl AlgId {
599    const fn new(val: u16) -> AlgId {
600        AlgId(new_u16_be(val))
601    }
602}
603
604#[allow(non_camel_case_types, clippy::upper_case_acronyms)]
605#[derive(Debug)]
606#[repr(u16)]
607pub enum AlgIdEnum {
608    RSA = 0x0001,
609    SHA = 0x0004,
610    AES = 0x0006,
611    SHA256 = 0x000b,
612    SHA384 = 0x000c,
613    SHA512 = 0x000d,
614    NULL = 0x0010,
615    SM3_256 = 0x0012,
616    RSASSA = 0x0014,
617    CFB = 0x0043,
618}
619
620impl From<AlgIdEnum> for AlgId {
621    fn from(x: AlgIdEnum) -> Self {
622        AlgId::new(x as u16)
623    }
624}
625
626impl AlgIdEnum {
627    pub fn from_u16(val: u16) -> Option<AlgIdEnum> {
628        let ret = match val {
629            0x0004 => Self::SHA,
630            0x000b => Self::SHA256,
631            0x000c => Self::SHA384,
632            0x000d => Self::SHA512,
633            0x0012 => Self::SM3_256,
634            _ => return None,
635        };
636
637        Some(ret)
638    }
639}
640
641/// `TPMA_OBJECT`
642#[repr(transparent)]
643#[derive(Debug, Copy, Clone, IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq)]
644pub struct TpmaObject(pub u32_be);
645
646impl TpmaObject {
647    const fn new(val: u32) -> Self {
648        Self(new_u32_be(val))
649    }
650}
651
652impl From<TpmaObjectBits> for TpmaObject {
653    fn from(x: TpmaObjectBits) -> Self {
654        let val: u32 = x.into();
655        Self::new(val)
656    }
657}
658
659impl From<u32> for TpmaObject {
660    fn from(x: u32) -> Self {
661        Self::new(x)
662    }
663}
664
665#[bitfield(u32)]
666pub struct TpmaObjectBits {
667    _reserved0: bool,
668    pub fixed_tpm: bool,
669    pub st_clear: bool,
670    _reserved1: bool,
671    pub fixed_parent: bool,
672    pub sensitive_data_origin: bool,
673    pub user_with_auth: bool,
674    pub admin_with_policy: bool,
675    #[bits(2)]
676    _reserved2: u8,
677    pub no_da: bool,
678    pub encrypted_duplication: bool,
679    #[bits(4)]
680    _reserved3: u8,
681    pub restricted: bool,
682    pub decrypt: bool,
683    pub sign_encrypt: bool,
684    #[bits(13)]
685    _reserved4: u16,
686}
687
688/// `TPMA_NV`
689#[repr(transparent)]
690#[derive(Debug, Copy, Clone, IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq)]
691pub struct TpmaNv(pub u32_be);
692
693impl TpmaNv {
694    const fn new(val: u32) -> Self {
695        Self(new_u32_be(val))
696    }
697}
698
699impl From<TpmaNvBits> for TpmaNv {
700    fn from(x: TpmaNvBits) -> Self {
701        let val: u32 = x.into();
702        Self::new(val)
703    }
704}
705
706impl From<u32> for TpmaNv {
707    fn from(x: u32) -> Self {
708        Self::new(x)
709    }
710}
711
712#[bitfield(u32)]
713pub struct TpmaNvBits {
714    pub nv_ppwrite: bool,
715    pub nv_ownerwrite: bool,
716    pub nv_authwrite: bool,
717    pub nv_policywrite: bool,
718    // bits 7:4: `TPM_NT`
719    // 0001 - `tpm_nt_counter`
720    pub nt_counter: bool,
721    // 0010 - `tpm_nt_bits`
722    pub nt_bits: bool,
723    // 0100 - `tpm_nt_extend`
724    pub nt_extend: bool,
725    _unused0: bool,
726    // bits 9:8 are reserved
727    #[bits(2)]
728    _reserved1: u8,
729    pub nv_policy_delete: bool,
730    pub nv_writelocked: bool,
731    pub nv_writeall: bool,
732    pub nv_writedefine: bool,
733    pub nv_write_stclear: bool,
734    pub nv_globallock: bool,
735    pub nv_ppread: bool,
736    pub nv_ownerread: bool,
737    pub nv_authread: bool,
738    pub nv_policyread: bool,
739    // bits 24:20 are reserved
740    #[bits(5)]
741    _reserved2: u8,
742    pub nv_no_da: bool,
743    pub nv_orderly: bool,
744    pub nv_clear_stclear: bool,
745    pub nv_readlocked: bool,
746    pub nv_written: bool,
747    pub nv_platformcreate: bool,
748    pub nv_read_stclear: bool,
749}
750
751/// Workaround to allow constructing a zerocopy U64 in a const context.
752const fn new_u64_be(val: u64) -> u64_be {
753    u64_be::from_bytes(val.to_be_bytes())
754}
755
756/// Workaround to allow constructing a zerocopy U32 in a const context.
757const fn new_u32_be(val: u32) -> u32_be {
758    u32_be::from_bytes(val.to_be_bytes())
759}
760
761/// Workaround to allow constructing a zerocopy U16 in a const context.
762const fn new_u16_be(val: u16) -> u16_be {
763    u16_be::from_bytes(val.to_be_bytes())
764}
765
766/// TPM command / response definitions
767pub mod protocol {
768    use super::*;
769
770    /// Common structs shared between multiple command / response structs
771    pub mod common {
772        use super::*;
773
774        #[repr(C)]
775        #[derive(Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
776        pub struct CmdHeader {
777            pub session_tag: SessionTag,
778            pub size: u32_be,
779            pub command_code: CommandCode,
780        }
781
782        impl CmdHeader {
783            /// Construct a header for a fixed-size command
784            pub fn new<Cmd: Sized>(
785                session_tag: SessionTag,
786                command_code: CommandCode,
787            ) -> CmdHeader {
788                CmdHeader {
789                    session_tag,
790                    size: (size_of::<Cmd>() as u32).into(),
791                    command_code,
792                }
793            }
794        }
795
796        #[repr(C)]
797        #[derive(Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
798        pub struct ReplyHeader {
799            pub session_tag: u16_be,
800            pub size: u32_be,
801            pub response_code: u32_be,
802        }
803
804        impl ReplyHeader {
805            /// Performs a few command-agnostic validation checks:
806            /// - Ensures the size matches the size_of the provided `FullReply` type
807            /// - Compares provided session_tag
808            ///
809            /// Returns Ok(bool) if the validation passes. The bool value indicates whether
810            /// the response_code is [`ResponseCode::Success`] or not.
811            /// Returns Err(ResponseValidationError) otherwise.
812            pub fn base_validation(
813                &self,
814                session_tag: SessionTag,
815                expected_size: u32,
816            ) -> Result<bool, ResponseValidationError> {
817                // Response code other than Success indicates that the command fails
818                // See Section 6.2, "Trusted Platform Module Library Part 3: Commands", revision 1.38.
819                let command_succeeded = ResponseCode::from_u32(self.response_code.get())
820                    .map(|c| matches!(c, ResponseCode::Success))
821                    .unwrap_or(false);
822
823                let (expected_tag, expected_size) = if command_succeeded {
824                    (session_tag, expected_size as usize)
825                } else {
826                    // If the command fails, the expected tag should be NoSessions and the minimal size
827                    // of the response should be the size of the header.
828                    // See Section 6.1, "Trusted Platform Module Library Part 3: Commands", revision 1.38.
829                    //
830                    // DEVNOTE: we do not handle the special case caused by sending unsupported commands where
831                    // the session tag will be `TPM_RC_BAD_TAG` instead.
832                    (SessionTagEnum::NoSessions.into(), size_of::<Self>())
833                };
834
835                if self.session_tag.get() != expected_tag {
836                    Err(ResponseValidationError::HeaderSessionTagMismatch {
837                        response_session_tag: self.session_tag.get(),
838                        expected_session_tag: session_tag.0.get(),
839                        command_succeeded,
840                    })?
841                }
842
843                // Allow the size specified in the header to be equal to or larger than the expected size in case
844                // that the expected size does not take the authorization area into account.
845                if (self.size.get() as usize) < expected_size {
846                    Err(ResponseValidationError::HeaderResponseSizeMismatch {
847                        size: self.size.get(),
848                        expected_size,
849                        command_succeeded,
850                    })?
851                }
852
853                Ok(command_succeeded)
854            }
855        }
856
857        #[repr(C)]
858        #[derive(Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
859        pub struct CmdAuth {
860            handle: ReservedHandle,
861            nonce_2b: u16_be,
862            session: u8,
863            auth_2b: u16_be,
864        }
865
866        impl CmdAuth {
867            pub fn new(handle: ReservedHandle, nonce_2b: u16, session: u8, auth_2b: u16) -> Self {
868                CmdAuth {
869                    handle,
870                    nonce_2b: nonce_2b.into(),
871                    session,
872                    auth_2b: auth_2b.into(),
873                }
874            }
875        }
876
877        #[repr(C)]
878        #[derive(Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
879        pub struct ReplyAuth {
880            pub nonce_2b: u16_be,
881            pub session: u8,
882            pub auth_2b: u16_be,
883        }
884    }
885
886    use common::CmdHeader;
887    use common::ReplyHeader;
888
889    /// Marker trait for a struct that corresponds to a TPM Command
890    pub trait TpmCommand: IntoBytes + FromBytes + Sized + Immutable + KnownLayout {
891        type Reply: TpmReply;
892
893        fn base_validate_reply(
894            reply_buf: &[u8],
895            session_tag: impl Into<SessionTag>,
896        ) -> Result<(Self::Reply, bool), ResponseValidationError> {
897            let res = Self::Reply::deserialize(reply_buf)
898                .ok_or(ResponseValidationError::ResponseSizeTooSmall)?;
899            let succeeded = res.base_validation(session_tag.into())?;
900
901            Ok((res, succeeded))
902        }
903    }
904
905    /// Marker trait for a struct that corresponds to a TPM Reply
906    pub trait TpmReply: IntoBytes + FromBytes + Sized + Immutable + KnownLayout {
907        type Command: TpmCommand;
908
909        fn base_validation(
910            &self,
911            session_tag: SessionTag,
912        ) -> Result<bool, ResponseValidationError> {
913            // `Reply::deserialize` guarantees this should not fail
914            let header = ReplyHeader::ref_from_prefix(self.as_bytes())
915                .expect("unexpected response size")
916                .0; // TODO: zerocopy: error (https://github.com/microsoft/openvmm/issues/759)
917            header.base_validation(session_tag, self.payload_size() as u32)
918        }
919        fn deserialize(bytes: &[u8]) -> Option<Self>;
920        fn payload_size(&self) -> usize;
921    }
922
923    /// General type for TPM 2.0 sized buffers.
924    #[repr(C)]
925    #[derive(Debug, Copy, Clone, FromBytes, IntoBytes, Immutable, KnownLayout)]
926    pub struct Tpm2bBuffer {
927        pub size: u16_be,
928        // Use value that is large enough as the buffer size so that we
929        // only need to define one struct.
930        pub buffer: [u8; MAX_DIGEST_BUFFER_SIZE],
931    }
932
933    impl Tpm2bBuffer {
934        /// Create a `Tpm2bBuffer` from a slice.
935        pub fn new(data: &[u8]) -> Result<Self, InvalidInput> {
936            let size = data.len();
937            if size > MAX_DIGEST_BUFFER_SIZE {
938                Err(InvalidInput::BufferSizeTooLarge(
939                    size,
940                    MAX_DIGEST_BUFFER_SIZE,
941                ))?
942            }
943
944            let mut buffer = [0u8; MAX_DIGEST_BUFFER_SIZE];
945            buffer[..size].copy_from_slice(data);
946
947            Ok(Self {
948                size: new_u16_be(size as u16),
949                buffer,
950            })
951        }
952
953        pub fn serialize(self) -> Vec<u8> {
954            let mut buffer = Vec::new();
955
956            buffer.extend_from_slice(self.size.as_bytes());
957            buffer.extend_from_slice(&self.buffer[..self.size.get() as usize]);
958
959            buffer
960        }
961
962        pub fn deserialize(bytes: &[u8]) -> Option<Self> {
963            let mut start = 0;
964            let mut end = size_of::<u16_be>();
965            if bytes.len() < end {
966                return None;
967            }
968
969            let size: u16 = u16_be::read_from_bytes(&bytes[start..end]).ok()?.into(); // TODO: zerocopy: simplify (https://github.com/microsoft/openvmm/issues/759)
970            if size as usize > MAX_DIGEST_BUFFER_SIZE {
971                return None;
972            }
973
974            start = end;
975            end += size as usize;
976            if bytes.len() < end {
977                return None;
978            }
979            let mut buffer = [0u8; MAX_DIGEST_BUFFER_SIZE];
980            buffer[..size as usize].copy_from_slice(&bytes[start..end]);
981
982            Some(Self {
983                size: size.into(),
984                buffer,
985            })
986        }
987
988        pub fn payload_size(&self) -> usize {
989            let mut payload_size = 0;
990
991            payload_size += size_of_val(&self.size);
992            payload_size += self.size.get() as usize;
993
994            payload_size
995        }
996    }
997
998    /// `TPML_PCR_SELECTION`
999    #[repr(C)]
1000    #[derive(Debug, Copy, Clone, FromBytes, IntoBytes, Immutable, KnownLayout)]
1001    pub struct TpmlPcrSelection {
1002        pub count: u32_be,
1003        pub pcr_selections: [PcrSelection; 5],
1004    }
1005
1006    impl TpmlPcrSelection {
1007        pub fn new(pcr_selections: &[PcrSelection]) -> Result<Self, InvalidInput> {
1008            let count = pcr_selections.len();
1009            if count > 5 {
1010                Err(InvalidInput::PcrSelectionsLengthTooLong(count, 5))?
1011            }
1012
1013            let mut base = [PcrSelection::new_zeroed(); 5];
1014            base[..count].copy_from_slice(pcr_selections);
1015
1016            Ok(Self {
1017                count: new_u32_be(count as u32),
1018                pcr_selections: base,
1019            })
1020        }
1021
1022        pub fn serialize(self) -> Vec<u8> {
1023            let mut buffer = Vec::new();
1024
1025            buffer.extend_from_slice(self.count.as_bytes());
1026            for i in 0..self.count.get() {
1027                buffer.extend_from_slice(&self.pcr_selections[i as usize].serialize());
1028            }
1029
1030            buffer
1031        }
1032
1033        pub fn deserialize(bytes: &[u8]) -> Option<Self> {
1034            let mut start = 0;
1035            let mut end = size_of::<u32_be>();
1036
1037            if bytes.len() < end {
1038                return None;
1039            }
1040
1041            let count: u32 = u32_be::read_from_bytes(&bytes[start..end]).ok()?.into(); // TODO: zerocopy: simplify (https://github.com/microsoft/openvmm/issues/759)
1042            if count > 5 {
1043                return None;
1044            }
1045
1046            let mut pcr_selections = [PcrSelection::new_zeroed(); 5];
1047            for i in 0..count {
1048                start = end;
1049                pcr_selections[i as usize] = PcrSelection::deserialize(&bytes[start..])?;
1050                end += pcr_selections[i as usize].payload_size();
1051            }
1052
1053            Some(Self {
1054                count: count.into(),
1055                pcr_selections,
1056            })
1057        }
1058
1059        pub fn payload_size(&self) -> usize {
1060            let mut payload_size = 0;
1061            let count = self.count;
1062
1063            payload_size += size_of_val(&count);
1064            for i in 0..count.get() {
1065                payload_size += self.pcr_selections[i as usize].payload_size();
1066            }
1067
1068            payload_size
1069        }
1070    }
1071
1072    /// `TPMS_SENSITIVE_CREATE`
1073    #[repr(C)]
1074    #[derive(Debug, Copy, Clone, FromBytes, IntoBytes, Immutable, KnownLayout)]
1075    pub struct TpmsSensitiveCreate {
1076        user_auth: Tpm2bBuffer,
1077        data: Tpm2bBuffer,
1078    }
1079
1080    impl TpmsSensitiveCreate {
1081        pub fn new(user_auth: &[u8], data: &[u8]) -> Result<Self, TpmProtoError> {
1082            let user_auth =
1083                Tpm2bBuffer::new(user_auth).map_err(TpmProtoError::TpmsSensitiveCreateUserAuth)?;
1084            let data = Tpm2bBuffer::new(data).map_err(TpmProtoError::TpmsSensitiveCreateData)?;
1085            Ok(Self { user_auth, data })
1086        }
1087
1088        pub fn serialize(self) -> Vec<u8> {
1089            let mut buffer = Vec::new();
1090
1091            buffer.extend_from_slice(&self.user_auth.serialize());
1092            buffer.extend_from_slice(&self.data.serialize());
1093
1094            buffer
1095        }
1096
1097        pub fn payload_size(&self) -> usize {
1098            let mut payload_size = 0;
1099
1100            payload_size += self.user_auth.payload_size();
1101            payload_size += self.data.payload_size();
1102
1103            payload_size
1104        }
1105    }
1106
1107    /// `TPM2B_SENSITIVE_CREATE`
1108    #[repr(C)]
1109    #[derive(Debug, Copy, Clone, FromBytes, IntoBytes, Immutable, KnownLayout)]
1110    pub struct Tpm2bSensitiveCreate {
1111        size: u16_be,
1112        sensitive: TpmsSensitiveCreate,
1113    }
1114
1115    impl Tpm2bSensitiveCreate {
1116        pub fn new(sensitive: TpmsSensitiveCreate) -> Self {
1117            let size = sensitive.payload_size() as u16;
1118            Self {
1119                size: size.into(),
1120                sensitive,
1121            }
1122        }
1123
1124        pub fn serialize(self) -> Vec<u8> {
1125            let mut buffer = Vec::new();
1126
1127            buffer.extend_from_slice(self.size.as_bytes());
1128            buffer.extend_from_slice(&self.sensitive.serialize());
1129
1130            buffer
1131        }
1132
1133        pub fn payload_size(&self) -> usize {
1134            let mut payload_size = 0;
1135            let size = self.size;
1136
1137            payload_size += size_of_val(&size);
1138            payload_size += self.sensitive.payload_size();
1139
1140            payload_size
1141        }
1142    }
1143
1144    /// `TPMT_RSA_SCHEME`
1145    #[repr(C)]
1146    #[derive(Debug, Copy, Clone, FromBytes, IntoBytes, Immutable, KnownLayout, PartialEq)]
1147    pub struct TpmtRsaScheme {
1148        scheme: AlgId,
1149        hash_alg: AlgId,
1150    }
1151
1152    impl TpmtRsaScheme {
1153        pub fn new(scheme: AlgId, hash_alg: Option<AlgId>) -> Self {
1154            let hash_alg = hash_alg.map_or_else(|| AlgId::new(0), |v| v);
1155
1156            Self { scheme, hash_alg }
1157        }
1158
1159        pub fn serialize(&self) -> Vec<u8> {
1160            let mut buffer = Vec::new();
1161
1162            buffer.extend_from_slice(self.scheme.as_bytes());
1163
1164            // No parameters when algorithm is NULL
1165            if self.scheme != AlgIdEnum::NULL.into() {
1166                // Only support scheme with hash (e.g., RSASSA) for now
1167                buffer.extend_from_slice(self.hash_alg.as_bytes());
1168            }
1169
1170            buffer
1171        }
1172
1173        pub fn deserialize(bytes: &[u8]) -> Option<Self> {
1174            let mut start = 0;
1175            let mut end = size_of::<AlgId>();
1176
1177            if bytes.len() < end {
1178                return None;
1179            }
1180
1181            let scheme = AlgId::read_from_prefix(&bytes[start..end]).ok()?.0; // TODO: zerocopy: use-rest-of-range, option-to-error (https://github.com/microsoft/openvmm/issues/759)
1182
1183            let hash_alg = if scheme != AlgIdEnum::NULL.into() {
1184                start = end;
1185                end += size_of::<AlgId>();
1186                AlgId::read_from_prefix(&bytes[start..end]).ok()?.0 // TODO: zerocopy: use-rest-of-range, option-to-error (https://github.com/microsoft/openvmm/issues/759)
1187            } else {
1188                AlgId::new(0)
1189            };
1190
1191            Some(Self { scheme, hash_alg })
1192        }
1193
1194        pub fn payload_size(&self) -> usize {
1195            let mut payload_size = 0;
1196
1197            payload_size += size_of_val(&self.scheme);
1198
1199            if self.scheme != AlgIdEnum::NULL.into() {
1200                payload_size += size_of_val(&self.hash_alg);
1201            }
1202
1203            payload_size
1204        }
1205    }
1206
1207    /// `TPMT_SYM_DEF_OBJECT`
1208    #[repr(C)]
1209    #[derive(Debug, Copy, Clone, FromBytes, IntoBytes, Immutable, KnownLayout, PartialEq)]
1210    pub struct TpmtSymDefObject {
1211        algorithm: AlgId,
1212        key_bits: u16_be,
1213        mode: AlgId,
1214    }
1215
1216    impl TpmtSymDefObject {
1217        pub fn new(algorithm: AlgId, key_bits: Option<u16>, mode: Option<AlgId>) -> Self {
1218            let key_bits = key_bits.map_or_else(|| new_u16_be(0), |v| v.into());
1219            let mode = mode.map_or_else(|| AlgId::new(0), |v| v);
1220
1221            Self {
1222                algorithm,
1223                key_bits,
1224                mode,
1225            }
1226        }
1227
1228        pub fn serialize(&self) -> Vec<u8> {
1229            let mut buffer = Vec::new();
1230
1231            buffer.extend_from_slice(self.algorithm.as_bytes());
1232
1233            // No parameters when algorithm is NULL
1234            if self.algorithm != AlgIdEnum::NULL.into() {
1235                buffer.extend_from_slice(self.key_bits.as_bytes());
1236                buffer.extend_from_slice(self.mode.as_bytes());
1237            }
1238
1239            buffer
1240        }
1241
1242        pub fn deserialize(bytes: &[u8]) -> Option<Self> {
1243            let mut start = 0;
1244            let mut end = size_of::<AlgId>();
1245
1246            if bytes.len() < end {
1247                return None;
1248            }
1249
1250            let algorithm = AlgId::read_from_prefix(&bytes[start..end]).ok()?.0; // TODO: zerocopy: use-rest-of-range, option-to-error (https://github.com/microsoft/openvmm/issues/759)
1251
1252            let (key_bits, mode) = if algorithm != AlgIdEnum::NULL.into() {
1253                start = end;
1254                end += size_of::<u16_be>();
1255                let key_bits = u16_be::read_from_bytes(&bytes[start..end]).ok()?; // TODO: zerocopy: simplify (https://github.com/microsoft/openvmm/issues/759)
1256
1257                start = end;
1258                end += size_of::<AlgId>();
1259                let mode = AlgId::read_from_prefix(&bytes[start..end]).ok()?.0; // TODO: zerocopy: use-rest-of-range, option-to-error (https://github.com/microsoft/openvmm/issues/759)
1260
1261                (key_bits, mode)
1262            } else {
1263                (new_u16_be(0), AlgId::new(0))
1264            };
1265
1266            Some(Self {
1267                algorithm,
1268                key_bits,
1269                mode,
1270            })
1271        }
1272
1273        pub fn payload_size(&self) -> usize {
1274            let mut payload_size = 0;
1275
1276            payload_size += size_of_val(&self.algorithm);
1277
1278            if self.algorithm != AlgIdEnum::NULL.into() {
1279                payload_size += size_of_val(&self.key_bits);
1280                payload_size += size_of_val(&self.mode);
1281            }
1282
1283            payload_size
1284        }
1285    }
1286
1287    /// `TPMS_RSA_PARMS`
1288    #[repr(C)]
1289    #[derive(Debug, Copy, Clone, FromBytes, IntoBytes, Immutable, KnownLayout, PartialEq)]
1290    pub struct TpmsRsaParams {
1291        symmetric: TpmtSymDefObject,
1292        scheme: TpmtRsaScheme,
1293        key_bits: u16_be,
1294        pub exponent: u32_be,
1295    }
1296
1297    impl TpmsRsaParams {
1298        pub fn new(
1299            symmetric: TpmtSymDefObject,
1300            scheme: TpmtRsaScheme,
1301            key_bits: u16,
1302            exponent: u32,
1303        ) -> Self {
1304            Self {
1305                symmetric,
1306                scheme,
1307                key_bits: key_bits.into(),
1308                exponent: exponent.into(),
1309            }
1310        }
1311
1312        pub fn serialize(&self) -> Vec<u8> {
1313            let mut buffer = Vec::new();
1314
1315            buffer.extend_from_slice(&self.symmetric.serialize());
1316            buffer.extend_from_slice(&self.scheme.serialize());
1317            buffer.extend_from_slice(self.key_bits.as_bytes());
1318            buffer.extend_from_slice(self.exponent.as_bytes());
1319
1320            buffer
1321        }
1322
1323        pub fn deserialize(bytes: &[u8]) -> Option<Self> {
1324            let mut start = 0;
1325            let mut end = 0;
1326
1327            let symmetric = TpmtSymDefObject::deserialize(&bytes[start..])?;
1328            end += symmetric.payload_size();
1329
1330            start = end;
1331            let scheme = TpmtRsaScheme::deserialize(&bytes[start..])?;
1332            end += scheme.payload_size();
1333
1334            // TODO: zerocopy: as of zerocopy 0.8 this can be simplified with `read_from_bytes`....ok()?, to avoid (https://github.com/microsoft/openvmm/issues/759)
1335            // manual size checks. Leaving this code as-is to reduce risk of the 0.7 -> 0.8 move.
1336            start = end;
1337            end += size_of::<u16_be>();
1338            if bytes.len() < end {
1339                return None;
1340            }
1341            let key_bits = u16_be::read_from_bytes(&bytes[start..end]).ok()?;
1342
1343            // TODO: zerocopy: as of zerocopy 0.8 this can be simplified with `read_from_bytes`....ok()?, to avoid (https://github.com/microsoft/openvmm/issues/759)
1344            // manual size checks. Leaving this code as-is to reduce risk of the 0.7 -> 0.8 move.
1345            start = end;
1346            end += size_of::<u32_be>();
1347            if bytes.len() < end {
1348                return None;
1349            }
1350            let exponent = u32_be::read_from_bytes(&bytes[start..end]).ok()?;
1351
1352            Some(Self {
1353                symmetric,
1354                scheme,
1355                key_bits,
1356                exponent,
1357            })
1358        }
1359
1360        pub fn payload_size(&self) -> usize {
1361            let mut payload_size = 0;
1362
1363            payload_size += self.symmetric.payload_size();
1364            payload_size += self.scheme.payload_size();
1365            payload_size += size_of_val(&self.key_bits);
1366            payload_size += size_of_val(&self.exponent);
1367
1368            payload_size
1369        }
1370    }
1371
1372    /// `TPMT_PUBLIC`
1373    #[repr(C)]
1374    #[derive(Debug, Copy, Clone, FromBytes, IntoBytes, Immutable, KnownLayout)]
1375    pub struct TpmtPublic {
1376        my_type: AlgId,
1377        name_alg: AlgId,
1378        object_attributes: TpmaObject,
1379        auth_policy: Tpm2bBuffer,
1380        // `TPMS_RSA_PARAMS`
1381        pub parameters: TpmsRsaParams,
1382        // `TPM2B_PUBLIC_KEY_RSA`
1383        pub unique: Tpm2bBuffer,
1384    }
1385
1386    impl TpmtPublic {
1387        pub fn new(
1388            my_type: AlgId,
1389            name_alg: AlgId,
1390            object_attributes: TpmaObjectBits,
1391            auth_policy: &[u8],
1392            parameters: TpmsRsaParams,
1393            unique: &[u8],
1394        ) -> Result<Self, TpmProtoError> {
1395            let auth_policy =
1396                Tpm2bBuffer::new(auth_policy).map_err(TpmProtoError::TpmtPublicAuthPolicy)?;
1397            let unique = Tpm2bBuffer::new(unique).map_err(TpmProtoError::TpmtPublicUnique)?;
1398            Ok(Self {
1399                my_type,
1400                name_alg,
1401                object_attributes: object_attributes.into(),
1402                auth_policy,
1403                parameters,
1404                unique,
1405            })
1406        }
1407
1408        pub fn serialize(self) -> Vec<u8> {
1409            let mut buffer = Vec::new();
1410
1411            buffer.extend_from_slice(self.my_type.as_bytes());
1412            buffer.extend_from_slice(self.name_alg.as_bytes());
1413            buffer.extend_from_slice(self.object_attributes.as_bytes());
1414            buffer.extend_from_slice(&self.auth_policy.serialize());
1415            buffer.extend_from_slice(&self.parameters.serialize());
1416            buffer.extend_from_slice(&self.unique.serialize());
1417
1418            buffer
1419        }
1420
1421        pub fn deserialize(bytes: &[u8]) -> Option<Self> {
1422            let mut start = 0;
1423            let mut end = size_of::<AlgId>();
1424            if bytes.len() < end {
1425                return None;
1426            }
1427            let r#type = AlgId::read_from_prefix(&bytes[start..end]).ok()?.0; // TODO: zerocopy: use-rest-of-range, option-to-error (https://github.com/microsoft/openvmm/issues/759)
1428
1429            start = end;
1430            end += size_of::<AlgId>();
1431            if bytes.len() < end {
1432                return None;
1433            }
1434            let name_alg = AlgId::read_from_prefix(&bytes[start..end]).ok()?.0; // TODO: zerocopy: use-rest-of-range, option-to-error (https://github.com/microsoft/openvmm/issues/759)
1435
1436            start = end;
1437            end += size_of::<TpmaObject>();
1438            if bytes.len() < end {
1439                return None;
1440            }
1441            let object_attributes: u32 = u32_be::read_from_bytes(&bytes[start..end]).ok()?.into(); // TODO: zerocopy: simplify (https://github.com/microsoft/openvmm/issues/759)
1442
1443            start = end;
1444            let auth_policy = Tpm2bBuffer::deserialize(&bytes[start..])?;
1445            end += auth_policy.payload_size();
1446            if bytes.len() < end {
1447                return None;
1448            }
1449
1450            start = end;
1451            let parameters = TpmsRsaParams::deserialize(&bytes[start..])?;
1452            end += parameters.payload_size();
1453
1454            start = end;
1455            let unique = Tpm2bBuffer::deserialize(&bytes[start..])?;
1456
1457            Some(Self {
1458                my_type: r#type,
1459                name_alg,
1460                object_attributes: object_attributes.into(),
1461                auth_policy,
1462                parameters,
1463                unique,
1464            })
1465        }
1466
1467        pub fn payload_size(&self) -> usize {
1468            let mut payload_size = 0;
1469
1470            payload_size += size_of_val(&self.my_type);
1471            payload_size += size_of_val(&self.name_alg);
1472            payload_size += size_of_val(&self.object_attributes);
1473            payload_size += self.auth_policy.payload_size();
1474            payload_size += self.parameters.payload_size();
1475            payload_size += self.unique.payload_size();
1476
1477            payload_size
1478        }
1479    }
1480
1481    /// `TPM2B_PUBLIC`
1482    #[repr(C)]
1483    #[derive(Debug, Copy, Clone, FromBytes, IntoBytes, Immutable, KnownLayout)]
1484    pub struct Tpm2bPublic {
1485        pub size: u16_be,
1486        pub public_area: TpmtPublic,
1487    }
1488
1489    impl Tpm2bPublic {
1490        pub fn new(public_area: TpmtPublic) -> Self {
1491            let size = public_area.payload_size() as u16;
1492            Self {
1493                size: size.into(),
1494                public_area,
1495            }
1496        }
1497
1498        pub fn serialize(self) -> Vec<u8> {
1499            let mut buffer = Vec::new();
1500
1501            buffer.extend_from_slice(self.size.as_bytes());
1502            buffer.extend_from_slice(&self.public_area.serialize());
1503
1504            buffer
1505        }
1506
1507        pub fn deserialize(bytes: &[u8]) -> Option<Self> {
1508            let mut start = 0;
1509            let end = size_of::<u16_be>();
1510
1511            if bytes.len() < end {
1512                return None;
1513            }
1514
1515            let size = u16_be::read_from_bytes(&bytes[start..end]).ok()?; // TODO: zerocopy: simplify (https://github.com/microsoft/openvmm/issues/759)
1516
1517            start = end;
1518            let public_area = TpmtPublic::deserialize(&bytes[start..])?;
1519
1520            Some(Self { size, public_area })
1521        }
1522
1523        pub fn payload_size(&self) -> usize {
1524            let mut payload_size = 0;
1525
1526            payload_size += size_of_val(&self.size);
1527            payload_size += self.public_area.payload_size();
1528
1529            payload_size
1530        }
1531    }
1532
1533    /// `TPMS_CREATION_DATA`
1534    #[repr(C)]
1535    #[derive(Debug, FromBytes, IntoBytes, Immutable, KnownLayout)]
1536    pub struct TpmsCreationData {
1537        pcr_select: TpmlPcrSelection,
1538        pcr_digest: Tpm2bBuffer,
1539        locality: u8,
1540        parent_name_alg: AlgId,
1541        parent_name: Tpm2bBuffer,
1542        parent_qualified_name: Tpm2bBuffer,
1543        outside_info: Tpm2bBuffer,
1544    }
1545
1546    impl TpmsCreationData {
1547        pub fn deserialize(bytes: &[u8]) -> Option<Self> {
1548            let mut start = 0;
1549            let mut end = 0;
1550
1551            let pcr_select = TpmlPcrSelection::deserialize(&bytes[start..])?;
1552            end += pcr_select.payload_size();
1553
1554            start = end;
1555            let pcr_digest = Tpm2bBuffer::deserialize(&bytes[start..])?;
1556            end += pcr_digest.payload_size();
1557
1558            start = end;
1559            end += size_of::<u8>();
1560            if bytes.len() < end {
1561                return None;
1562            }
1563            let locality = bytes[start];
1564
1565            start = end;
1566            end += size_of::<AlgId>();
1567            if bytes.len() < end {
1568                return None;
1569            }
1570            let parent_name_alg = AlgId::read_from_prefix(&bytes[start..end]).ok()?.0; // TODO: zerocopy: use-rest-of-range, option-to-error (https://github.com/microsoft/openvmm/issues/759)
1571
1572            start = end;
1573            let parent_name = Tpm2bBuffer::deserialize(&bytes[start..])?;
1574            end += parent_name.payload_size();
1575
1576            start = end;
1577            let parent_qualified_name = Tpm2bBuffer::deserialize(&bytes[start..])?;
1578            end += parent_qualified_name.payload_size();
1579
1580            start = end;
1581            let outside_info = Tpm2bBuffer::deserialize(&bytes[start..])?;
1582
1583            Some(Self {
1584                pcr_select,
1585                pcr_digest,
1586                locality,
1587                parent_name_alg,
1588                parent_name,
1589                parent_qualified_name,
1590                outside_info,
1591            })
1592        }
1593
1594        pub fn payload_size(&self) -> usize {
1595            let mut payload_size = 0;
1596
1597            payload_size += self.pcr_select.payload_size();
1598            payload_size += self.pcr_digest.payload_size();
1599            payload_size += size_of_val(&self.locality);
1600            payload_size += size_of_val(&self.parent_name_alg);
1601            payload_size += self.parent_name.payload_size();
1602            payload_size += self.parent_qualified_name.payload_size();
1603            payload_size += self.outside_info.payload_size();
1604
1605            payload_size
1606        }
1607    }
1608
1609    /// `TPM2B_CREATION_DATA`
1610    #[derive(Debug, FromBytes, IntoBytes, Immutable, KnownLayout)]
1611    #[repr(C)]
1612    pub struct Tpm2bCreationData {
1613        size: u16_be,
1614        creation_data: TpmsCreationData,
1615    }
1616
1617    impl Tpm2bCreationData {
1618        pub fn deserialize(bytes: &[u8]) -> Option<Self> {
1619            let mut start = 0;
1620            let end = size_of::<u16_be>();
1621
1622            if bytes.len() < end {
1623                return None;
1624            }
1625
1626            let size = u16_be::read_from_bytes(&bytes[start..end]).ok()?; // TODO: zerocopy: simplify (https://github.com/microsoft/openvmm/issues/759)
1627
1628            start = end;
1629            let creation_data = TpmsCreationData::deserialize(&bytes[start..])?;
1630
1631            Some(Self {
1632                size,
1633                creation_data,
1634            })
1635        }
1636
1637        pub fn payload_size(&self) -> usize {
1638            let mut payload_size = 0;
1639
1640            payload_size += size_of_val(&self.size);
1641            payload_size += self.creation_data.payload_size();
1642
1643            payload_size
1644        }
1645    }
1646
1647    /// `TPMT_TK_CREATION`
1648    #[repr(C)]
1649    #[derive(Debug, FromBytes, IntoBytes, Immutable, KnownLayout)]
1650    pub struct TpmtTkCreation {
1651        tag: SessionTag,
1652        hierarchy: ReservedHandle,
1653        digest: Tpm2bBuffer,
1654    }
1655
1656    impl TpmtTkCreation {
1657        pub fn deserialize(bytes: &[u8]) -> Option<Self> {
1658            let mut start = 0;
1659            let mut end = size_of::<SessionTag>();
1660            if bytes.len() < end {
1661                return None;
1662            }
1663            let tag = SessionTag::read_from_prefix(&bytes[start..end]).ok()?.0; // TODO: zerocopy: use-rest-of-range, option-to-error (https://github.com/microsoft/openvmm/issues/759)
1664
1665            start = end;
1666            end += size_of::<ReservedHandle>();
1667            if bytes.len() < end {
1668                return None;
1669            }
1670            let hierarchy = ReservedHandle::read_from_prefix(&bytes[start..end]).ok()?.0; // TODO: zerocopy: use-rest-of-range, option-to-error (https://github.com/microsoft/openvmm/issues/759)
1671
1672            start = end;
1673            let digest = Tpm2bBuffer::deserialize(&bytes[start..])?;
1674
1675            Some(Self {
1676                tag,
1677                hierarchy,
1678                digest,
1679            })
1680        }
1681
1682        pub fn payload_size(&self) -> usize {
1683            let mut payload_size = 0;
1684
1685            payload_size += size_of_val(&self.tag);
1686            payload_size += size_of_val(&self.hierarchy);
1687            payload_size += self.digest.payload_size();
1688
1689            payload_size
1690        }
1691    }
1692
1693    /// `TPMS_NV_PUBLIC`
1694    #[repr(C)]
1695    #[derive(Debug, Copy, Clone, FromBytes, IntoBytes, Immutable, KnownLayout)]
1696    pub struct TpmsNvPublic {
1697        nv_index: u32_be,
1698        name_alg: AlgId,
1699        pub attributes: TpmaNv,
1700        auth_policy: Tpm2bBuffer,
1701        pub data_size: u16_be,
1702    }
1703
1704    impl TpmsNvPublic {
1705        pub fn new(
1706            nv_index: u32,
1707            name_alg: AlgId,
1708            attributes: TpmaNvBits,
1709            auth_policy: &[u8],
1710            data_size: u16,
1711        ) -> Result<Self, TpmProtoError> {
1712            let auth_policy =
1713                Tpm2bBuffer::new(auth_policy).map_err(TpmProtoError::TpmsNvPublicAuthPolicy)?;
1714
1715            Ok(Self {
1716                nv_index: nv_index.into(),
1717                name_alg,
1718                attributes: attributes.into(),
1719                auth_policy,
1720                data_size: data_size.into(),
1721            })
1722        }
1723
1724        pub fn serialize(self) -> Vec<u8> {
1725            let mut buffer = Vec::new();
1726
1727            buffer.extend_from_slice(self.nv_index.as_bytes());
1728            buffer.extend_from_slice(self.name_alg.as_bytes());
1729            buffer.extend_from_slice(self.attributes.as_bytes());
1730            buffer.extend_from_slice(&self.auth_policy.serialize());
1731            buffer.extend_from_slice(self.data_size.as_bytes());
1732
1733            buffer
1734        }
1735
1736        pub fn deserialize(bytes: &[u8]) -> Option<Self> {
1737            let mut start = 0;
1738            let mut end = size_of::<u32_be>();
1739            if bytes.len() < end {
1740                return None;
1741            }
1742            let nv_index: u32 = u32_be::read_from_bytes(&bytes[start..end]).ok()?.into(); // TODO: zerocopy: simplify (https://github.com/microsoft/openvmm/issues/759)
1743
1744            start = end;
1745            end += size_of::<AlgId>();
1746            if bytes.len() < end {
1747                return None;
1748            }
1749            let name_alg = AlgId::read_from_prefix(&bytes[start..end]).ok()?.0; // TODO: zerocopy: use-rest-of-range, option-to-error (https://github.com/microsoft/openvmm/issues/759)
1750
1751            start = end;
1752            end += size_of::<TpmaNv>();
1753            if bytes.len() < end {
1754                return None;
1755            }
1756            let attributes: u32 = u32_be::read_from_bytes(&bytes[start..end]).ok()?.into(); // TODO: zerocopy: simplify (https://github.com/microsoft/openvmm/issues/759)
1757
1758            start = end;
1759            let auth_policy = Tpm2bBuffer::deserialize(&bytes[start..])?;
1760            end += auth_policy.payload_size();
1761
1762            start = end;
1763            end += size_of::<u16_be>();
1764            if bytes.len() < end {
1765                return None;
1766            }
1767            let data_size = u16_be::read_from_bytes(&bytes[start..end]).ok()?; // TODO: zerocopy: simplify (https://github.com/microsoft/openvmm/issues/759)
1768
1769            Some(Self {
1770                nv_index: nv_index.into(),
1771                name_alg,
1772                attributes: attributes.into(),
1773                auth_policy,
1774                data_size,
1775            })
1776        }
1777
1778        pub fn payload_size(&self) -> usize {
1779            let mut payload_size = 0;
1780
1781            payload_size += size_of_val(&self.nv_index);
1782            payload_size += size_of_val(&self.name_alg);
1783            payload_size += size_of_val(&self.attributes);
1784            payload_size += self.auth_policy.payload_size();
1785            payload_size += size_of_val(&self.data_size);
1786
1787            payload_size
1788        }
1789    }
1790
1791    /// `TPM2B_NV_PUBLIC`
1792    #[repr(C)]
1793    #[derive(Debug, Copy, Clone, FromBytes, IntoBytes, Immutable, KnownLayout)]
1794    pub struct Tpm2bNvPublic {
1795        size: u16_be,
1796        pub nv_public: TpmsNvPublic,
1797    }
1798
1799    impl Tpm2bNvPublic {
1800        pub fn new(nv_public: TpmsNvPublic) -> Result<Self, InvalidInput> {
1801            let size = nv_public.payload_size();
1802            if size > u16::MAX.into() {
1803                Err(InvalidInput::NvPublicPayloadTooLarge(size, u16::MAX.into()))?
1804            }
1805
1806            Ok(Self {
1807                size: (size as u16).into(),
1808                nv_public,
1809            })
1810        }
1811
1812        pub fn serialize(self) -> Vec<u8> {
1813            let mut buffer = Vec::new();
1814
1815            buffer.extend_from_slice(self.size.as_bytes());
1816            buffer.extend_from_slice(&self.nv_public.serialize());
1817
1818            buffer
1819        }
1820
1821        pub fn deserialize(bytes: &[u8]) -> Option<Self> {
1822            let mut start = 0;
1823            let end = size_of::<u16_be>();
1824
1825            if bytes.len() < end {
1826                return None;
1827            }
1828
1829            let size = u16_be::read_from_bytes(&bytes[start..end]).ok()?; // TODO: zerocopy: simplify (https://github.com/microsoft/openvmm/issues/759)
1830
1831            start = end;
1832            let nv_public = TpmsNvPublic::deserialize(&bytes[start..])?;
1833
1834            Some(Self { size, nv_public })
1835        }
1836
1837        pub fn payload_size(&self) -> usize {
1838            let mut payload_size = 0;
1839
1840            payload_size += size_of_val(&self.size);
1841            payload_size += self.nv_public.payload_size();
1842
1843            payload_size
1844        }
1845    }
1846
1847    // === ClearControl === //
1848
1849    #[repr(C)]
1850    #[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
1851    pub struct ClearControlCmd {
1852        header: CmdHeader,
1853        auth_handle: ReservedHandle,
1854        auth_size: u32_be,
1855        auth: common::CmdAuth,
1856        disable: u8,
1857    }
1858
1859    impl ClearControlCmd {
1860        pub fn new(
1861            session: SessionTag,
1862            auth_handle: ReservedHandle,
1863            auth: common::CmdAuth,
1864            disable: bool,
1865        ) -> Self {
1866            Self {
1867                header: CmdHeader::new::<Self>(session, CommandCodeEnum::ClearControl.into()),
1868                auth_handle,
1869                auth_size: (size_of::<common::CmdAuth>() as u32).into(),
1870                auth,
1871                disable: disable as u8,
1872            }
1873        }
1874    }
1875
1876    #[repr(C)]
1877    #[derive(Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
1878    pub struct ClearControlReply {
1879        pub header: ReplyHeader,
1880        pub param_size: u32_be,
1881        pub auth: common::ReplyAuth,
1882    }
1883
1884    impl TpmCommand for ClearControlCmd {
1885        type Reply = ClearControlReply;
1886    }
1887
1888    impl TpmReply for ClearControlReply {
1889        type Command = ClearControlCmd;
1890
1891        fn deserialize(bytes: &[u8]) -> Option<Self> {
1892            Some(Self::read_from_prefix(bytes).ok()?.0) // TODO: zerocopy: tpm better error? (https://github.com/microsoft/openvmm/issues/759)
1893        }
1894
1895        fn payload_size(&self) -> usize {
1896            size_of::<Self>()
1897        }
1898    }
1899
1900    // === Clear === //
1901
1902    #[repr(C)]
1903    #[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
1904    pub struct ClearCmd {
1905        header: CmdHeader,
1906
1907        auth_handle: ReservedHandle,
1908        auth_size: u32_be,
1909        auth: common::CmdAuth,
1910    }
1911
1912    impl ClearCmd {
1913        pub fn new(
1914            session: SessionTag,
1915            auth_handle: ReservedHandle,
1916            auth: common::CmdAuth,
1917        ) -> Self {
1918            Self {
1919                header: CmdHeader::new::<Self>(session, CommandCodeEnum::Clear.into()),
1920                auth_handle,
1921                auth_size: (size_of::<common::CmdAuth>() as u32).into(),
1922                auth,
1923            }
1924        }
1925    }
1926
1927    #[repr(C)]
1928    #[derive(Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
1929    pub struct ClearReply {
1930        pub header: ReplyHeader,
1931        pub param_size: u32_be,
1932        pub auth: common::ReplyAuth,
1933    }
1934
1935    impl TpmCommand for ClearCmd {
1936        type Reply = ClearReply;
1937    }
1938
1939    impl TpmReply for ClearReply {
1940        type Command = ClearCmd;
1941
1942        fn deserialize(bytes: &[u8]) -> Option<Self> {
1943            Some(Self::read_from_prefix(bytes).ok()?.0) // TODO: zerocopy: tpm better error? (https://github.com/microsoft/openvmm/issues/759)
1944        }
1945
1946        fn payload_size(&self) -> usize {
1947            size_of::<Self>()
1948        }
1949    }
1950
1951    // === Startup === //
1952
1953    #[expect(dead_code)]
1954    pub enum StartupType {
1955        Clear,
1956        State,
1957    }
1958
1959    #[repr(C)]
1960    #[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
1961    pub struct StartupCmd {
1962        header: CmdHeader,
1963        startup_type: u16_be,
1964    }
1965
1966    impl StartupCmd {
1967        pub fn new(session_tag: SessionTag, startup_type: StartupType) -> StartupCmd {
1968            StartupCmd {
1969                header: CmdHeader::new::<Self>(session_tag, CommandCodeEnum::Startup.into()),
1970                startup_type: match startup_type {
1971                    StartupType::Clear => 0,
1972                    StartupType::State => 1,
1973                }
1974                .into(),
1975            }
1976        }
1977    }
1978
1979    #[repr(C)]
1980    #[derive(Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
1981    pub struct StartupReply {
1982        pub header: ReplyHeader,
1983    }
1984
1985    impl TpmCommand for StartupCmd {
1986        type Reply = StartupReply;
1987    }
1988
1989    impl TpmReply for StartupReply {
1990        type Command = StartupCmd;
1991
1992        fn deserialize(bytes: &[u8]) -> Option<Self> {
1993            Some(Self::read_from_prefix(bytes).ok()?.0) // TODO: zerocopy: tpm better error? (https://github.com/microsoft/openvmm/issues/759)
1994        }
1995
1996        fn payload_size(&self) -> usize {
1997            size_of::<Self>()
1998        }
1999    }
2000
2001    // === Self Test === //
2002
2003    #[repr(C)]
2004    #[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
2005    pub struct SelfTestCmd {
2006        header: CmdHeader,
2007        full_test: u8,
2008    }
2009
2010    impl SelfTestCmd {
2011        pub fn new(session_tag: SessionTag, full_test: bool) -> SelfTestCmd {
2012            SelfTestCmd {
2013                header: CmdHeader::new::<Self>(session_tag, CommandCodeEnum::SelfTest.into()),
2014                full_test: full_test as u8,
2015            }
2016        }
2017    }
2018
2019    #[repr(C)]
2020    #[derive(Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
2021    pub struct SelfTestReply {
2022        pub header: ReplyHeader,
2023    }
2024
2025    impl TpmCommand for SelfTestCmd {
2026        type Reply = SelfTestReply;
2027    }
2028
2029    impl TpmReply for SelfTestReply {
2030        type Command = SelfTestCmd;
2031
2032        fn deserialize(bytes: &[u8]) -> Option<Self> {
2033            Some(Self::read_from_prefix(bytes).ok()?.0) // TODO: zerocopy: tpm better error? (https://github.com/microsoft/openvmm/issues/759)
2034        }
2035
2036        fn payload_size(&self) -> usize {
2037            size_of::<Self>()
2038        }
2039    }
2040
2041    // === Hierarchy Control === //
2042
2043    #[repr(C)]
2044    #[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
2045    pub struct HierarchyControlCmd {
2046        header: CmdHeader,
2047
2048        auth_handle: ReservedHandle,
2049        auth_size: u32_be,
2050        auth: common::CmdAuth,
2051
2052        hierarchy: ReservedHandle,
2053        state: u8,
2054    }
2055
2056    impl HierarchyControlCmd {
2057        pub fn new(
2058            session: SessionTag,
2059            auth_handle: ReservedHandle,
2060            auth: common::CmdAuth,
2061            hierarchy: ReservedHandle,
2062            state: bool,
2063        ) -> Self {
2064            Self {
2065                header: CmdHeader::new::<Self>(session, CommandCodeEnum::HierarchyControl.into()),
2066                auth_handle,
2067                auth_size: (size_of::<common::CmdAuth>() as u32).into(),
2068                auth,
2069                hierarchy,
2070                state: state as u8,
2071            }
2072        }
2073    }
2074
2075    #[repr(C)]
2076    #[derive(Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
2077    pub struct HierarchyControlReply {
2078        pub header: ReplyHeader,
2079        pub param_size: u32_be,
2080        pub auth: common::ReplyAuth,
2081    }
2082
2083    impl TpmCommand for HierarchyControlCmd {
2084        type Reply = HierarchyControlReply;
2085    }
2086
2087    impl TpmReply for HierarchyControlReply {
2088        type Command = HierarchyControlCmd;
2089
2090        fn deserialize(bytes: &[u8]) -> Option<Self> {
2091            Some(Self::read_from_prefix(bytes).ok()?.0) // TODO: zerocopy: tpm better error? (https://github.com/microsoft/openvmm/issues/759)
2092        }
2093
2094        fn payload_size(&self) -> usize {
2095            size_of::<Self>()
2096        }
2097    }
2098
2099    // === Pcr Allocate === //
2100
2101    #[repr(C)]
2102    #[derive(Debug, Copy, Clone, IntoBytes, Immutable, KnownLayout, FromBytes)]
2103    pub struct PcrSelection {
2104        pub hash: AlgId,
2105        pub size_of_select: u8,
2106        pub bitmap: [u8; 3],
2107    }
2108
2109    impl PcrSelection {
2110        pub fn serialize(self) -> Vec<u8> {
2111            let mut buffer = Vec::new();
2112
2113            buffer.extend_from_slice(self.hash.as_bytes());
2114            buffer.extend_from_slice(self.size_of_select.as_bytes());
2115            buffer.extend_from_slice(&self.bitmap[..self.size_of_select as usize]);
2116
2117            buffer
2118        }
2119
2120        pub fn deserialize(bytes: &[u8]) -> Option<Self> {
2121            let mut start = 0;
2122            let mut end = size_of::<AlgId>();
2123            if bytes.len() < end {
2124                return None;
2125            }
2126            let hash = AlgId::read_from_prefix(&bytes[start..end]).ok()?.0; // TODO: zerocopy: use-rest-of-range, option-to-error (https://github.com/microsoft/openvmm/issues/759)
2127
2128            start = end;
2129            end += size_of::<u8>();
2130            if bytes.len() < end {
2131                return None;
2132            }
2133            let size_of_select = bytes[start];
2134            if size_of_select > 3 {
2135                return None;
2136            }
2137
2138            start = end;
2139            end += size_of_select as usize;
2140            if bytes.len() < end {
2141                return None;
2142            }
2143            let mut bitmap = [0u8; 3];
2144            bitmap[..size_of_select as usize].copy_from_slice(&bytes[start..end]);
2145
2146            Some(Self {
2147                hash,
2148                size_of_select,
2149                bitmap,
2150            })
2151        }
2152
2153        pub fn payload_size(&self) -> usize {
2154            let mut payload_size = 0;
2155
2156            payload_size += size_of_val(&self.hash);
2157            payload_size += size_of_val(&self.size_of_select);
2158            payload_size += self.size_of_select as usize;
2159
2160            payload_size
2161        }
2162    }
2163
2164    #[repr(C)]
2165    #[derive(Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
2166    pub struct PcrAllocateCmd {
2167        header: CmdHeader,
2168        auth_handle: ReservedHandle,
2169        // Authorization area
2170        auth_size: u32_be,
2171        auth: common::CmdAuth,
2172        // Parameters
2173        pcr_allocation: TpmlPcrSelection,
2174    }
2175
2176    impl PcrAllocateCmd {
2177        pub const HASH_ALG_TO_ID: [(u32, AlgId); 5] = [
2178            (1 << 0, AlgId::new(AlgIdEnum::SHA as u16)),
2179            (1 << 1, AlgId::new(AlgIdEnum::SHA256 as u16)),
2180            (1 << 2, AlgId::new(AlgIdEnum::SHA384 as u16)),
2181            (1 << 3, AlgId::new(AlgIdEnum::SHA512 as u16)),
2182            (1 << 4, AlgId::new(AlgIdEnum::SM3_256 as u16)),
2183        ];
2184
2185        /// # Panics
2186        ///
2187        /// `pcr_selections` must be have a len less than `TCG_BOOT_HASH_COUNT`
2188        pub fn new(
2189            session: SessionTag,
2190            auth_handle: ReservedHandle,
2191            auth: common::CmdAuth,
2192            pcr_selections: &[PcrSelection],
2193        ) -> Result<Self, TpmProtoError> {
2194            let pcr_allocation = TpmlPcrSelection::new(pcr_selections)
2195                .map_err(TpmProtoError::PcrAllocatePcrAllocation)?;
2196
2197            let mut cmd = Self {
2198                header: CmdHeader::new::<Self>(session, CommandCodeEnum::PCR_Allocate.into()),
2199                auth_handle,
2200                auth_size: (size_of::<common::CmdAuth>() as u32).into(),
2201                auth,
2202                pcr_allocation,
2203            };
2204
2205            cmd.header.size = new_u32_be(cmd.payload_size() as u32);
2206
2207            Ok(cmd)
2208        }
2209
2210        pub fn serialize(&self) -> Vec<u8> {
2211            let mut buffer = Vec::new();
2212
2213            buffer.extend_from_slice(self.header.as_bytes());
2214            buffer.extend_from_slice(self.auth_handle.as_bytes());
2215            buffer.extend_from_slice(self.auth_size.as_bytes());
2216            buffer.extend_from_slice(self.auth.as_bytes());
2217            buffer.extend_from_slice(&self.pcr_allocation.serialize());
2218
2219            buffer
2220        }
2221
2222        pub fn payload_size(&self) -> usize {
2223            let mut payload_size = 0;
2224
2225            payload_size += size_of_val(&self.header);
2226            payload_size += size_of_val(&self.auth_handle);
2227            payload_size += size_of_val(&self.auth_size);
2228            payload_size += size_of_val(&self.auth);
2229            payload_size += self.pcr_allocation.payload_size();
2230
2231            payload_size
2232        }
2233    }
2234
2235    #[repr(C)]
2236    #[derive(Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
2237    pub struct PcrAllocateReply {
2238        pub header: ReplyHeader,
2239        pub auth_size: u32_be,
2240        pub allocation_success: u8,
2241        pub max_pcr: u32_be,
2242        pub size_needed: u32_be,
2243        pub size_available: u32_be,
2244
2245        pub auth: common::ReplyAuth,
2246    }
2247
2248    impl TpmCommand for PcrAllocateCmd {
2249        type Reply = PcrAllocateReply;
2250    }
2251
2252    impl TpmReply for PcrAllocateReply {
2253        type Command = PcrAllocateCmd;
2254
2255        fn deserialize(bytes: &[u8]) -> Option<Self> {
2256            Some(Self::read_from_prefix(bytes).ok()?.0) // TODO: zerocopy: tpm better error? (https://github.com/microsoft/openvmm/issues/759)
2257        }
2258
2259        fn payload_size(&self) -> usize {
2260            size_of::<Self>()
2261        }
2262    }
2263
2264    // === ChangeSeed === //
2265
2266    #[repr(C)]
2267    #[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
2268    pub struct ChangeSeedCmd {
2269        header: CmdHeader,
2270        auth_handle: ReservedHandle,
2271        auth_size: u32_be,
2272        auth: common::CmdAuth,
2273    }
2274
2275    impl ChangeSeedCmd {
2276        pub fn new(
2277            session: SessionTag,
2278            auth_handle: ReservedHandle,
2279            auth: common::CmdAuth,
2280            command_code: CommandCodeEnum,
2281        ) -> Self {
2282            Self {
2283                header: CmdHeader::new::<Self>(session, command_code.into()),
2284                auth_handle,
2285                auth_size: (size_of::<common::CmdAuth>() as u32).into(),
2286                auth,
2287            }
2288        }
2289    }
2290
2291    #[repr(C)]
2292    #[derive(Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
2293    pub struct ChangeSeedReply {
2294        pub header: ReplyHeader,
2295        pub param_size: u32_be,
2296
2297        pub auth: common::ReplyAuth,
2298    }
2299
2300    impl TpmCommand for ChangeSeedCmd {
2301        type Reply = ChangeSeedReply;
2302    }
2303
2304    impl TpmReply for ChangeSeedReply {
2305        type Command = ChangeSeedCmd;
2306
2307        fn deserialize(bytes: &[u8]) -> Option<Self> {
2308            Some(Self::read_from_prefix(bytes).ok()?.0) // TODO: zerocopy: option-to-error (https://github.com/microsoft/openvmm/issues/759)
2309        }
2310
2311        fn payload_size(&self) -> usize {
2312            size_of::<Self>()
2313        }
2314    }
2315
2316    // === CreatePrimary === //
2317
2318    #[repr(C)]
2319    #[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
2320    pub struct CreatePrimaryCmd {
2321        pub header: CmdHeader,
2322        primary_handle: ReservedHandle,
2323        // Authorization area
2324        auth_size: u32_be,
2325        auth: common::CmdAuth,
2326        // Parameters
2327        in_sensitive: Tpm2bSensitiveCreate,
2328        in_public: Tpm2bPublic,
2329        outside_info: Tpm2bBuffer,
2330        creation_pcr: TpmlPcrSelection,
2331    }
2332
2333    impl CreatePrimaryCmd {
2334        pub fn new(
2335            session: SessionTag,
2336            primary_handle: ReservedHandle,
2337            auth: common::CmdAuth,
2338            in_sensitive_user_auth: &[u8],
2339            in_sensitive_data: &[u8],
2340            in_public: TpmtPublic,
2341            outside_info: &[u8],
2342            creation_pcr: &[PcrSelection],
2343        ) -> Result<Self, TpmProtoError> {
2344            let sensitive_create =
2345                TpmsSensitiveCreate::new(in_sensitive_user_auth, in_sensitive_data)?;
2346            let in_sensitive = Tpm2bSensitiveCreate::new(sensitive_create);
2347            let in_public = Tpm2bPublic::new(in_public);
2348            let outside_info =
2349                Tpm2bBuffer::new(outside_info).map_err(TpmProtoError::CreatePrimaryOutsideInfo)?;
2350            let creation_pcr = TpmlPcrSelection::new(creation_pcr)
2351                .map_err(TpmProtoError::CreatePrimaryCreationPcr)?;
2352
2353            let mut cmd = Self {
2354                header: CmdHeader::new::<Self>(session, CommandCodeEnum::CreatePrimary.into()),
2355                primary_handle,
2356                auth_size: (size_of::<common::CmdAuth>() as u32).into(),
2357                auth,
2358                in_sensitive,
2359                in_public,
2360                outside_info,
2361                creation_pcr,
2362            };
2363
2364            cmd.header.size = new_u32_be(cmd.payload_size() as u32);
2365
2366            Ok(cmd)
2367        }
2368
2369        pub fn serialize(&self) -> Vec<u8> {
2370            let mut buffer = Vec::new();
2371
2372            buffer.extend_from_slice(self.header.as_bytes());
2373            buffer.extend_from_slice(self.primary_handle.as_bytes());
2374            buffer.extend_from_slice(self.auth_size.as_bytes());
2375            buffer.extend_from_slice(self.auth.as_bytes());
2376            buffer.extend_from_slice(&self.in_sensitive.serialize());
2377            buffer.extend_from_slice(&self.in_public.serialize());
2378            buffer.extend_from_slice(&self.outside_info.serialize());
2379            buffer.extend_from_slice(&self.creation_pcr.serialize());
2380
2381            buffer
2382        }
2383
2384        pub fn payload_size(&self) -> usize {
2385            let mut payload_size = 0;
2386
2387            payload_size += size_of_val(&self.header);
2388            payload_size += size_of_val(&self.primary_handle);
2389            payload_size += size_of_val(&self.auth_size);
2390            payload_size += size_of_val(&self.auth);
2391            payload_size += self.in_sensitive.payload_size();
2392            payload_size += self.in_public.payload_size();
2393            payload_size += self.outside_info.payload_size();
2394            payload_size += self.creation_pcr.payload_size();
2395
2396            payload_size
2397        }
2398    }
2399
2400    #[repr(C)]
2401    #[derive(Debug, FromBytes, IntoBytes, Immutable, KnownLayout)]
2402    pub struct CreatePrimaryReply {
2403        pub header: ReplyHeader,
2404        pub object_handle: ReservedHandle,
2405        // Parameter size
2406        param_size: u32_be,
2407        // Parameters
2408        pub out_public: Tpm2bPublic,
2409        creation_data: Tpm2bCreationData,
2410        creation_hash: Tpm2bBuffer,
2411        creation_ticket: TpmtTkCreation,
2412        name: Tpm2bBuffer,
2413        // Authorization area
2414        auth: common::ReplyAuth,
2415    }
2416
2417    impl TpmCommand for CreatePrimaryCmd {
2418        type Reply = CreatePrimaryReply;
2419    }
2420
2421    impl TpmReply for CreatePrimaryReply {
2422        type Command = CreatePrimaryCmd;
2423
2424        fn deserialize(bytes: &[u8]) -> Option<Self> {
2425            let mut start = 0;
2426            let mut end = size_of::<ReplyHeader>();
2427            let header = ReplyHeader::read_from_prefix(&bytes[start..end]).ok()?.0; // TODO: zerocopy: use-rest-of-range, option-to-error (https://github.com/microsoft/openvmm/issues/759)
2428
2429            // Handle the command failure.
2430            if header.size.get() as usize == end {
2431                let mut cmd = CreatePrimaryReply::new_zeroed();
2432                cmd.header = header;
2433                return Some(cmd);
2434            }
2435
2436            start = end;
2437            end += size_of::<ReservedHandle>();
2438            let object_handle = ReservedHandle::read_from_prefix(&bytes[start..end]).ok()?.0; // TODO: zerocopy: use-rest-of-range, option-to-error (https://github.com/microsoft/openvmm/issues/759)
2439
2440            start = end;
2441            end += size_of::<u32_be>();
2442            let param_size = u32_be::read_from_bytes(&bytes[start..end]).ok()?; // TODO: zerocopy: simplify (https://github.com/microsoft/openvmm/issues/759)
2443
2444            start = end;
2445            let out_public = Tpm2bPublic::deserialize(&bytes[start..])?;
2446            end += out_public.payload_size();
2447
2448            start = end;
2449            let creation_data = Tpm2bCreationData::deserialize(&bytes[start..])?;
2450            end += creation_data.payload_size();
2451
2452            start = end;
2453            let creation_hash = Tpm2bBuffer::deserialize(&bytes[start..])?;
2454            end += creation_hash.payload_size();
2455
2456            start = end;
2457            let creation_ticket = TpmtTkCreation::deserialize(&bytes[start..])?;
2458            end += creation_ticket.payload_size();
2459
2460            start = end;
2461            let name = Tpm2bBuffer::deserialize(&bytes[start..])?;
2462            end += name.payload_size();
2463
2464            start = end;
2465            end += size_of::<common::ReplyAuth>();
2466            let auth = common::ReplyAuth::read_from_prefix(&bytes[start..end])
2467                .ok()?
2468                .0; // TODO: zerocopy: use-rest-of-range, option-to-error (https://github.com/microsoft/openvmm/issues/759)
2469
2470            if header.size.get() as usize != end {
2471                return None;
2472            }
2473
2474            Some(Self {
2475                header,
2476                object_handle,
2477                param_size,
2478                out_public,
2479                creation_data,
2480                creation_hash,
2481                creation_ticket,
2482                name,
2483                auth,
2484            })
2485        }
2486
2487        fn payload_size(&self) -> usize {
2488            let mut payload_size = 0;
2489
2490            payload_size += size_of_val(&self.header);
2491            payload_size += size_of_val(&self.object_handle);
2492            payload_size += size_of_val(&self.param_size);
2493            payload_size += self.out_public.payload_size();
2494            payload_size += self.creation_data.payload_size();
2495            payload_size += self.creation_hash.payload_size();
2496            payload_size += self.creation_ticket.payload_size();
2497            payload_size += self.name.payload_size();
2498            payload_size += size_of_val(&self.auth);
2499
2500            payload_size
2501        }
2502    }
2503
2504    // === FlushContext === //
2505
2506    #[repr(C)]
2507    #[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
2508    pub struct FlushContextCmd {
2509        pub header: CmdHeader,
2510        // Parameter
2511        flush_handle: ReservedHandle,
2512    }
2513
2514    impl FlushContextCmd {
2515        pub fn new(flush_handle: ReservedHandle) -> Self {
2516            Self {
2517                header: CmdHeader::new::<Self>(
2518                    SessionTagEnum::NoSessions.into(),
2519                    CommandCodeEnum::FlushContext.into(),
2520                ),
2521                flush_handle,
2522            }
2523        }
2524    }
2525
2526    #[repr(C)]
2527    #[derive(Debug, FromBytes, IntoBytes, Immutable, KnownLayout)]
2528    pub struct FlushContextReply {
2529        pub header: ReplyHeader,
2530    }
2531
2532    impl TpmCommand for FlushContextCmd {
2533        type Reply = FlushContextReply;
2534    }
2535
2536    impl TpmReply for FlushContextReply {
2537        type Command = FlushContextCmd;
2538
2539        fn deserialize(bytes: &[u8]) -> Option<Self> {
2540            Some(Self::read_from_prefix(bytes).ok()?.0) // TODO: zerocopy: tpm better error? (https://github.com/microsoft/openvmm/issues/759)
2541        }
2542
2543        fn payload_size(&self) -> usize {
2544            size_of::<Self>()
2545        }
2546    }
2547
2548    // === EvictControl === //
2549
2550    #[repr(C)]
2551    #[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
2552    pub struct EvictControlCmd {
2553        header: CmdHeader,
2554        auth_handle: ReservedHandle,
2555        object_handle: ReservedHandle,
2556        // Authorization area
2557        auth_size: u32_be,
2558        auth: common::CmdAuth,
2559        // Parameter
2560        persistent_handle: ReservedHandle,
2561    }
2562
2563    impl EvictControlCmd {
2564        pub fn new(
2565            session: SessionTag,
2566            auth_handle: ReservedHandle,
2567            object_handle: ReservedHandle,
2568            auth: common::CmdAuth,
2569            persistent_handle: ReservedHandle,
2570        ) -> Self {
2571            Self {
2572                header: CmdHeader::new::<Self>(session, CommandCodeEnum::EvictControl.into()),
2573                auth_handle,
2574                object_handle,
2575                auth_size: (size_of::<common::CmdAuth>() as u32).into(),
2576                auth,
2577                persistent_handle,
2578            }
2579        }
2580    }
2581
2582    #[repr(C)]
2583    #[derive(Debug, FromBytes, IntoBytes, Immutable, KnownLayout)]
2584    pub struct EvictControlReply {
2585        pub header: ReplyHeader,
2586    }
2587
2588    impl TpmCommand for EvictControlCmd {
2589        type Reply = EvictControlReply;
2590    }
2591
2592    impl TpmReply for EvictControlReply {
2593        type Command = EvictControlCmd;
2594
2595        fn deserialize(bytes: &[u8]) -> Option<Self> {
2596            Some(Self::read_from_prefix(bytes).ok()?.0) // TODO: zerocopy: error-to-option (https://github.com/microsoft/openvmm/issues/759)
2597        }
2598
2599        fn payload_size(&self) -> usize {
2600            size_of::<Self>()
2601        }
2602    }
2603
2604    // === ReadPublic === //
2605
2606    #[repr(C)]
2607    #[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
2608    pub struct ReadPublicCmd {
2609        header: CmdHeader,
2610        object_handle: ReservedHandle,
2611    }
2612
2613    impl ReadPublicCmd {
2614        pub fn new(session: SessionTag, object_handle: ReservedHandle) -> Self {
2615            Self {
2616                header: CmdHeader::new::<Self>(session, CommandCodeEnum::ReadPublic.into()),
2617                object_handle,
2618            }
2619        }
2620    }
2621
2622    #[repr(C)]
2623    #[derive(Debug, FromBytes, IntoBytes, Immutable, KnownLayout)]
2624    pub struct ReadPublicReply {
2625        pub header: ReplyHeader,
2626        pub out_public: Tpm2bPublic,
2627        name: Tpm2bBuffer,
2628        qualified_name: Tpm2bBuffer,
2629    }
2630
2631    impl TpmCommand for ReadPublicCmd {
2632        type Reply = ReadPublicReply;
2633    }
2634
2635    impl TpmReply for ReadPublicReply {
2636        type Command = ReadPublicCmd;
2637
2638        fn deserialize(bytes: &[u8]) -> Option<Self> {
2639            let mut start = 0;
2640            let mut end = size_of::<ReplyHeader>();
2641
2642            let header = ReplyHeader::read_from_prefix(&bytes[start..end]).ok()?.0; // TODO: zerocopy: use-rest-of-range, option-to-error (https://github.com/microsoft/openvmm/issues/759)
2643
2644            // Handle the command failure.
2645            if header.size.get() as usize == end {
2646                return Some(Self {
2647                    header,
2648                    out_public: Tpm2bPublic::new_zeroed(),
2649                    name: Tpm2bBuffer::new_zeroed(),
2650                    qualified_name: Tpm2bBuffer::new_zeroed(),
2651                });
2652            }
2653
2654            start = end;
2655            let out_public = Tpm2bPublic::deserialize(&bytes[start..])?;
2656            end += out_public.payload_size();
2657
2658            start = end;
2659            let name = Tpm2bBuffer::deserialize(&bytes[start..])?;
2660            end += name.payload_size();
2661
2662            start = end;
2663            let qualified_name = Tpm2bBuffer::deserialize(&bytes[start..])?;
2664            end += qualified_name.payload_size();
2665
2666            if header.size.get() as usize != end {
2667                return None;
2668            }
2669
2670            Some(Self {
2671                header,
2672                out_public,
2673                name,
2674                qualified_name,
2675            })
2676        }
2677
2678        fn payload_size(&self) -> usize {
2679            let mut payload_size = 0;
2680
2681            payload_size += size_of::<ReplyHeader>();
2682            payload_size += self.out_public.payload_size();
2683            payload_size += self.name.payload_size();
2684            payload_size += self.qualified_name.payload_size();
2685
2686            payload_size
2687        }
2688    }
2689
2690    // === Nv DefineSpace === //
2691
2692    #[repr(C)]
2693    #[derive(FromBytes, IntoBytes, Immutable, KnownLayout)]
2694    pub struct NvDefineSpaceCmd {
2695        header: CmdHeader,
2696        auth_handle: ReservedHandle,
2697        // Authorization area
2698        auth_size: u32_be,
2699        auth_cmd: common::CmdAuth,
2700        // Parameters
2701        auth: Tpm2bBuffer,
2702        public_info: Tpm2bNvPublic,
2703    }
2704
2705    impl NvDefineSpaceCmd {
2706        pub fn new(
2707            session: SessionTag,
2708            auth_handle: ReservedHandle,
2709            auth_cmd: common::CmdAuth,
2710            auth: u64,
2711            public_info: TpmsNvPublic,
2712        ) -> Result<Self, TpmProtoError> {
2713            let auth = new_u64_be(auth);
2714            let auth =
2715                Tpm2bBuffer::new(auth.as_bytes()).map_err(TpmProtoError::NvDefineSpaceAuth)?;
2716            let public_info =
2717                Tpm2bNvPublic::new(public_info).map_err(TpmProtoError::NvDefineSpacePublicInfo)?;
2718
2719            let mut cmd = Self {
2720                header: CmdHeader::new::<Self>(session, CommandCodeEnum::NV_DefineSpace.into()),
2721                auth_handle,
2722                auth_size: (size_of::<common::CmdAuth>() as u32).into(),
2723                auth_cmd,
2724                auth,
2725                public_info,
2726            };
2727
2728            cmd.header.size = new_u32_be(cmd.payload_size() as u32);
2729
2730            Ok(cmd)
2731        }
2732
2733        pub fn serialize(&self) -> Vec<u8> {
2734            let mut buffer = Vec::new();
2735
2736            buffer.extend_from_slice(self.header.as_bytes());
2737            buffer.extend_from_slice(self.auth_handle.as_bytes());
2738            buffer.extend_from_slice(self.auth_size.as_bytes());
2739            buffer.extend_from_slice(self.auth_cmd.as_bytes());
2740            buffer.extend_from_slice(&self.auth.serialize());
2741            buffer.extend_from_slice(&self.public_info.serialize());
2742
2743            buffer
2744        }
2745
2746        pub fn payload_size(&self) -> usize {
2747            let mut payload_size = 0;
2748
2749            payload_size += size_of_val(&self.header);
2750            payload_size += size_of_val(&self.auth_handle);
2751            payload_size += size_of_val(&self.auth_size);
2752            payload_size += size_of_val(&self.auth_cmd);
2753            payload_size += self.auth.payload_size();
2754            payload_size += self.public_info.payload_size();
2755
2756            payload_size
2757        }
2758    }
2759
2760    #[repr(C)]
2761    #[derive(Debug, FromBytes, IntoBytes, Immutable, KnownLayout)]
2762    pub struct NvDefineSpaceReply {
2763        pub header: ReplyHeader,
2764    }
2765
2766    impl TpmCommand for NvDefineSpaceCmd {
2767        type Reply = NvDefineSpaceReply;
2768    }
2769
2770    impl TpmReply for NvDefineSpaceReply {
2771        type Command = NvDefineSpaceCmd;
2772
2773        fn deserialize(bytes: &[u8]) -> Option<Self> {
2774            Some(Self::read_from_prefix(bytes).ok()?.0) // TODO: zerocopy: tpm better error? (https://github.com/microsoft/openvmm/issues/759)
2775        }
2776
2777        fn payload_size(&self) -> usize {
2778            size_of::<Self>()
2779        }
2780    }
2781
2782    // === Nv UndefineSpace === //
2783
2784    #[repr(C)]
2785    #[derive(FromBytes, IntoBytes, Immutable, KnownLayout)]
2786    pub struct NvUndefineSpaceCmd {
2787        header: CmdHeader,
2788        auth_handle: ReservedHandle,
2789        nv_index: u32_be,
2790        // Authorization area
2791        auth_size: u32_be,
2792        auth: common::CmdAuth,
2793    }
2794
2795    impl NvUndefineSpaceCmd {
2796        pub fn new(
2797            session: SessionTag,
2798            auth_handle: ReservedHandle,
2799            auth: common::CmdAuth,
2800            nv_index: u32,
2801        ) -> Self {
2802            Self {
2803                header: CmdHeader::new::<Self>(session, CommandCodeEnum::NV_UndefineSpace.into()),
2804                auth_handle,
2805                nv_index: nv_index.into(),
2806                auth_size: (size_of::<common::CmdAuth>() as u32).into(),
2807                auth,
2808            }
2809        }
2810    }
2811
2812    #[repr(C)]
2813    #[derive(Debug, FromBytes, IntoBytes, Immutable, KnownLayout)]
2814    pub struct NvUndefineSpaceReply {
2815        pub header: ReplyHeader,
2816    }
2817
2818    impl TpmCommand for NvUndefineSpaceCmd {
2819        type Reply = NvUndefineSpaceReply;
2820    }
2821
2822    impl TpmReply for NvUndefineSpaceReply {
2823        type Command = NvUndefineSpaceCmd;
2824
2825        fn deserialize(bytes: &[u8]) -> Option<Self> {
2826            Some(Self::read_from_prefix(bytes).ok()?.0) // TODO: zerocopy: tpm better error? (https://github.com/microsoft/openvmm/issues/759)
2827        }
2828
2829        fn payload_size(&self) -> usize {
2830            size_of::<Self>()
2831        }
2832    }
2833
2834    // === Nv ReadPublic === //
2835
2836    #[repr(C)]
2837    #[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
2838    pub struct NvReadPublicCmd {
2839        header: CmdHeader,
2840        nv_index: u32_be,
2841    }
2842
2843    impl NvReadPublicCmd {
2844        pub fn new(session: SessionTag, nv_index: u32) -> Self {
2845            Self {
2846                header: CmdHeader::new::<Self>(session, CommandCodeEnum::NV_ReadPublic.into()),
2847                nv_index: nv_index.into(),
2848            }
2849        }
2850    }
2851
2852    #[repr(C)]
2853    #[derive(Debug, FromBytes, IntoBytes, Immutable, KnownLayout)]
2854    pub struct NvReadPublicReply {
2855        pub header: ReplyHeader,
2856        // Parameters
2857        pub nv_public: Tpm2bNvPublic,
2858        nv_name: Tpm2bBuffer,
2859    }
2860
2861    impl TpmCommand for NvReadPublicCmd {
2862        type Reply = NvReadPublicReply;
2863    }
2864
2865    impl TpmReply for NvReadPublicReply {
2866        type Command = NvReadPublicCmd;
2867
2868        fn deserialize(bytes: &[u8]) -> Option<Self> {
2869            let mut start = 0;
2870            let mut end = size_of::<ReplyHeader>();
2871
2872            let header = ReplyHeader::read_from_prefix(&bytes[start..end]).ok()?.0; // TODO: zerocopy: use-rest-of-range, option-to-error (https://github.com/microsoft/openvmm/issues/759)
2873
2874            // Handle the command failure.
2875            if header.size.get() as usize == end {
2876                return Some(Self {
2877                    header,
2878                    nv_public: Tpm2bNvPublic::new_zeroed(),
2879                    nv_name: Tpm2bBuffer::new_zeroed(),
2880                });
2881            }
2882
2883            start = end;
2884            let nv_public = Tpm2bNvPublic::deserialize(&bytes[start..])?;
2885            end += nv_public.payload_size();
2886
2887            start = end;
2888            let nv_name = Tpm2bBuffer::deserialize(&bytes[start..])?;
2889            end += nv_name.payload_size();
2890
2891            if header.size.get() as usize != end {
2892                return None;
2893            }
2894
2895            Some(Self {
2896                header,
2897                nv_public,
2898                nv_name,
2899            })
2900        }
2901
2902        fn payload_size(&self) -> usize {
2903            let mut size = 0;
2904
2905            size += size_of::<ReplyHeader>();
2906            size += self.nv_public.payload_size();
2907            size += self.nv_name.payload_size();
2908
2909            size
2910        }
2911    }
2912
2913    // === Nv Write === //
2914
2915    #[repr(C)]
2916    #[derive(FromBytes, IntoBytes, Immutable, KnownLayout)]
2917    pub struct NvWriteCmd {
2918        header: CmdHeader,
2919        auth_handle: ReservedHandle,
2920        pub nv_index: u32_be,
2921        // Authorization area
2922        auth_size: u32_be,
2923        auth: common::CmdAuth,
2924        auth_value: u64_be,
2925        // Parameters
2926        pub data: Tpm2bBuffer,
2927        pub offset: u16_be,
2928    }
2929
2930    impl NvWriteCmd {
2931        pub fn new(
2932            session: SessionTag,
2933            auth_handle: ReservedHandle,
2934            auth: common::CmdAuth,
2935            auth_value: u64,
2936            nv_index: u32,
2937            data: &[u8],
2938            offset: u16,
2939        ) -> Result<Self, TpmProtoError> {
2940            let data = Tpm2bBuffer::new(data).map_err(TpmProtoError::NvWriteData)?;
2941            // If `auth_handle` is not the owner, assuming password-based authorization is used.
2942            let auth_value_size = if auth_handle != TPM20_RH_OWNER {
2943                size_of::<u64_be>() as u32
2944            } else {
2945                0
2946            };
2947
2948            let mut cmd = Self {
2949                header: CmdHeader::new::<Self>(session, CommandCodeEnum::NV_Write.into()),
2950                auth_handle,
2951                nv_index: nv_index.into(),
2952                auth_size: (size_of::<common::CmdAuth>() as u32 + auth_value_size).into(),
2953                auth,
2954                auth_value: auth_value.into(),
2955                data,
2956                offset: offset.into(),
2957            };
2958
2959            cmd.header.size = new_u32_be(cmd.payload_size() as u32);
2960
2961            Ok(cmd)
2962        }
2963
2964        pub fn update_write_data(&mut self, data: &[u8], offset: u16) -> Result<(), TpmProtoError> {
2965            let data = Tpm2bBuffer::new(data).map_err(TpmProtoError::NvWriteData)?;
2966
2967            self.data = data;
2968            self.offset = offset.into();
2969            self.header.size = new_u32_be(self.payload_size() as u32);
2970
2971            Ok(())
2972        }
2973
2974        pub fn serialize(&self) -> Vec<u8> {
2975            let mut buffer = Vec::new();
2976
2977            buffer.extend_from_slice(self.header.as_bytes());
2978            buffer.extend_from_slice(self.auth_handle.as_bytes());
2979            buffer.extend_from_slice(self.nv_index.as_bytes());
2980            buffer.extend_from_slice(self.auth_size.as_bytes());
2981            buffer.extend_from_slice(self.auth.as_bytes());
2982            if self.auth_handle != TPM20_RH_OWNER {
2983                buffer.extend_from_slice(self.auth_value.as_bytes());
2984            }
2985            buffer.extend_from_slice(&self.data.serialize());
2986            buffer.extend_from_slice(self.offset.as_bytes());
2987
2988            buffer
2989        }
2990
2991        pub fn payload_size(&self) -> usize {
2992            let mut payload_size = 0;
2993
2994            payload_size += size_of_val(&self.header);
2995            payload_size += size_of_val(&self.auth_handle);
2996            payload_size += size_of_val(&self.nv_index);
2997            payload_size += size_of_val(&self.auth_size);
2998            payload_size += size_of_val(&self.auth);
2999            if self.auth_handle != TPM20_RH_OWNER {
3000                payload_size += size_of_val(&self.auth_value);
3001            }
3002            payload_size += self.data.payload_size();
3003            payload_size += size_of_val(&self.offset);
3004
3005            payload_size
3006        }
3007    }
3008
3009    #[repr(C)]
3010    #[derive(Debug, FromBytes, IntoBytes, Immutable, KnownLayout)]
3011    pub struct NvWriteReply {
3012        pub header: ReplyHeader,
3013    }
3014
3015    impl TpmCommand for NvWriteCmd {
3016        type Reply = NvWriteReply;
3017    }
3018
3019    impl TpmReply for NvWriteReply {
3020        type Command = NvWriteCmd;
3021
3022        fn deserialize(bytes: &[u8]) -> Option<Self> {
3023            Some(Self::read_from_prefix(bytes).ok()?.0) // TODO: zerocopy: tpm better error? (https://github.com/microsoft/openvmm/issues/759)
3024        }
3025
3026        fn payload_size(&self) -> usize {
3027            size_of::<Self>()
3028        }
3029    }
3030
3031    // === Nv Read === //
3032
3033    #[repr(C)]
3034    #[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
3035    pub struct NvReadCmd {
3036        header: CmdHeader,
3037        auth_handle: ReservedHandle,
3038        pub nv_index: u32_be,
3039        // Authorization area
3040        auth_size: u32_be,
3041        auth: common::CmdAuth,
3042        // Parameters
3043        size: u16_be,
3044        pub offset: u16_be,
3045    }
3046
3047    impl NvReadCmd {
3048        pub fn new(
3049            session: SessionTag,
3050            auth_handle: ReservedHandle,
3051            nv_index: u32,
3052            auth: common::CmdAuth,
3053            size: u16,
3054            offset: u16,
3055        ) -> Self {
3056            Self {
3057                header: CmdHeader::new::<Self>(session, CommandCodeEnum::NV_Read.into()),
3058                auth_handle,
3059                nv_index: nv_index.into(),
3060                auth_size: (size_of::<common::CmdAuth>() as u32).into(),
3061                auth,
3062                size: size.into(),
3063                offset: offset.into(),
3064            }
3065        }
3066
3067        pub fn update_read_parameters(&mut self, size: u16, offset: u16) {
3068            self.size = size.into();
3069            self.offset = offset.into();
3070        }
3071
3072        pub fn deserialize(bytes: &[u8]) -> Option<Self> {
3073            let mut start = 0;
3074            let mut end = size_of::<CmdHeader>();
3075            if bytes.len() < end {
3076                return None;
3077            }
3078            let header = CmdHeader::read_from_prefix(&bytes[start..end]).ok()?.0; // TODO: zerocopy: use-rest-of-range, option-to-error (https://github.com/microsoft/openvmm/issues/759)
3079
3080            if header.command_code != CommandCodeEnum::NV_Read.into() {
3081                return None;
3082            }
3083
3084            start = end;
3085            end += size_of::<ReservedHandle>();
3086            if bytes.len() < end {
3087                return None;
3088            }
3089            let auth_handle = ReservedHandle::read_from_prefix(&bytes[start..end]).ok()?.0; // TODO: zerocopy: use-rest-of-range, option-to-error (https://github.com/microsoft/openvmm/issues/759)
3090
3091            start = end;
3092            end += size_of::<u32_be>();
3093            if bytes.len() < end {
3094                return None;
3095            }
3096            let nv_index = u32_be::read_from_prefix(&bytes[start..end]).ok()?.0; // TODO: zerocopy: use-rest-of-range, option-to-error (https://github.com/microsoft/openvmm/issues/759)
3097
3098            start = end;
3099            end += size_of::<u32_be>();
3100            if bytes.len() < end {
3101                return None;
3102            }
3103            let auth_size = u32_be::read_from_prefix(&bytes[start..end]).ok()?.0; // TODO: zerocopy: use-rest-of-range, option-to-error (https://github.com/microsoft/openvmm/issues/759)
3104
3105            // Skip authorization area
3106            end += auth_size.get() as usize;
3107
3108            start = end;
3109            end += size_of::<u16_be>();
3110            if bytes.len() < end {
3111                return None;
3112            }
3113            let size = u16_be::read_from_prefix(&bytes[start..end]).ok()?.0; // TODO: zerocopy: use-rest-of-range, option-to-error (https://github.com/microsoft/openvmm/issues/759)
3114
3115            start = end;
3116            end += size_of::<u16_be>();
3117            if bytes.len() < end {
3118                return None;
3119            }
3120            let offset = u16_be::read_from_prefix(&bytes[start..end]).ok()?.0; // TODO: zerocopy: use-rest-of-range, option-to-error (https://github.com/microsoft/openvmm/issues/759)
3121
3122            Some(Self {
3123                header,
3124                auth_handle,
3125                nv_index,
3126                auth_size,
3127                auth: common::CmdAuth::new(ReservedHandle(0.into()), 0, 0, 0),
3128                size,
3129                offset,
3130            })
3131        }
3132    }
3133
3134    #[repr(C)]
3135    #[derive(Debug, FromBytes, IntoBytes, Immutable, KnownLayout)]
3136    pub struct NvReadReply {
3137        pub header: ReplyHeader,
3138        pub parameter_size: u32_be,
3139        // Parameter
3140        pub data: Tpm2bBuffer,
3141        // Authorization area
3142        pub auth: common::ReplyAuth,
3143    }
3144
3145    impl TpmCommand for NvReadCmd {
3146        type Reply = NvReadReply;
3147    }
3148
3149    impl TpmReply for NvReadReply {
3150        type Command = NvReadCmd;
3151
3152        fn deserialize(bytes: &[u8]) -> Option<Self> {
3153            let mut start = 0;
3154            let mut end = size_of::<ReplyHeader>();
3155
3156            let header = ReplyHeader::read_from_prefix(&bytes[start..end]).ok()?.0; // TODO: zerocopy: use-rest-of-range, option-to-error (https://github.com/microsoft/openvmm/issues/759)
3157
3158            // Handle the command failure.
3159            if header.size.get() as usize == end {
3160                return Some(Self {
3161                    header,
3162                    parameter_size: 0.into(),
3163                    data: Tpm2bBuffer::new_zeroed(),
3164                    auth: common::ReplyAuth::new_zeroed(),
3165                });
3166            }
3167
3168            start = end;
3169            end += size_of::<u32_be>();
3170            if bytes.len() < end {
3171                return None;
3172            }
3173            let parameter_size = u32_be::read_from_prefix(&bytes[start..end]).ok()?.0; // TODO: zerocopy: use-rest-of-range, option-to-error (https://github.com/microsoft/openvmm/issues/759)
3174
3175            start = end;
3176            let data = Tpm2bBuffer::deserialize(&bytes[start..])?;
3177            end += data.payload_size();
3178
3179            start = end;
3180            end += size_of::<common::ReplyAuth>();
3181            if bytes.len() < end {
3182                return None;
3183            }
3184            let auth = common::ReplyAuth::read_from_prefix(&bytes[start..end])
3185                .ok()?
3186                .0; // TODO: zerocopy: use-rest-of-range, option-to-error (https://github.com/microsoft/openvmm/issues/759)
3187
3188            if header.size.get() as usize != end {
3189                return None;
3190            }
3191
3192            Some(Self {
3193                header,
3194                parameter_size,
3195                data,
3196                auth,
3197            })
3198        }
3199
3200        fn payload_size(&self) -> usize {
3201            let mut size = 0;
3202
3203            size += size_of::<ReplyHeader>();
3204            size += self.data.payload_size();
3205
3206            size
3207        }
3208    }
3209
3210    // === Import === //
3211
3212    #[repr(C)]
3213    #[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
3214    pub struct ImportCmd {
3215        pub header: CmdHeader,
3216        pub auth_handle: ReservedHandle,
3217        // Authorization area
3218        pub auth_size: u32_be,
3219        pub auth: common::CmdAuth,
3220        // Parameters
3221        // `TPM2B_DATA`
3222        pub encryption_key: Tpm2bBuffer,
3223        // `TPM2B_PUBLIC`
3224        pub object_public: Tpm2bPublic,
3225        // `TPM2B_PRIVATE`
3226        pub duplicate: Tpm2bBuffer,
3227        // `TPM2B_ENCRYPTED_SECRET`
3228        pub in_sym_seed: Tpm2bBuffer,
3229        // `TPMT_SYM_DEF_OBJECT`
3230        pub symmetric_alg: TpmtSymDefObject,
3231    }
3232
3233    impl ImportCmd {
3234        pub fn new(
3235            session: SessionTag,
3236            auth_handle: ReservedHandle,
3237            auth: common::CmdAuth,
3238            encryption_key: &Tpm2bBuffer,
3239            object_public: &Tpm2bPublic,
3240            duplicate: &Tpm2bBuffer,
3241            in_sym_seed: &Tpm2bBuffer,
3242            symmetric_alg: &TpmtSymDefObject,
3243        ) -> Self {
3244            let mut cmd = Self {
3245                header: CmdHeader::new::<Self>(session, CommandCodeEnum::Import.into()),
3246                auth_handle,
3247                auth_size: (size_of::<common::CmdAuth>() as u32).into(),
3248                auth,
3249                encryption_key: *encryption_key,
3250                object_public: *object_public,
3251                duplicate: *duplicate,
3252                in_sym_seed: *in_sym_seed,
3253                symmetric_alg: *symmetric_alg,
3254            };
3255
3256            cmd.header.size = new_u32_be(cmd.payload_size() as u32);
3257
3258            cmd
3259        }
3260
3261        /// Deserialize the command payload assuming no inner wrapping key
3262        pub fn deserialize_no_wrapping_key(bytes: &[u8]) -> Option<Self> {
3263            let mut start = 0;
3264            let mut end = 0;
3265
3266            // When there is no inner wrapper for `duplicate`, `encryption_key`
3267            // should be an empty buffer and `symmetric_alg` should be `TPM_ALG_NULL`.
3268            // See Table 42, Section 13.3.2, "Trusted Platform Module Library Part 3: Commands", revision 1.38.
3269            let encryption_key = Tpm2bBuffer::new_zeroed();
3270            let symmetric_alg = TpmtSymDefObject::new(AlgIdEnum::NULL.into(), None, None);
3271
3272            let object_public = Tpm2bPublic::deserialize(&bytes[start..])?;
3273            end += object_public.payload_size();
3274
3275            start = end;
3276            let duplicate = Tpm2bBuffer::deserialize(&bytes[start..])?;
3277            end += duplicate.payload_size();
3278
3279            start = end;
3280            let in_sym_seed = Tpm2bBuffer::deserialize(&bytes[start..])?;
3281            end += in_sym_seed.payload_size();
3282
3283            // Handle zero paddings applied to valid payload
3284            if bytes.len() < end {
3285                return None;
3286            }
3287
3288            Some(Self {
3289                header: CmdHeader::new_zeroed(),
3290                auth_handle: ReservedHandle(0.into()),
3291                auth_size: 0.into(),
3292                auth: common::CmdAuth::new_zeroed(),
3293                encryption_key,
3294                object_public,
3295                duplicate,
3296                in_sym_seed,
3297                symmetric_alg,
3298            })
3299        }
3300
3301        pub fn serialize(&self) -> Vec<u8> {
3302            let mut buffer = Vec::new();
3303
3304            buffer.extend_from_slice(self.header.as_bytes());
3305            buffer.extend_from_slice(self.auth_handle.as_bytes());
3306            buffer.extend_from_slice(self.auth_size.as_bytes());
3307            buffer.extend_from_slice(self.auth.as_bytes());
3308            buffer.extend_from_slice(&self.encryption_key.serialize());
3309            buffer.extend_from_slice(&self.object_public.serialize());
3310            buffer.extend_from_slice(&self.duplicate.serialize());
3311            buffer.extend_from_slice(&self.in_sym_seed.serialize());
3312            buffer.extend_from_slice(&self.symmetric_alg.serialize());
3313
3314            buffer
3315        }
3316
3317        pub fn payload_size(&self) -> usize {
3318            let mut payload_size = 0;
3319
3320            payload_size += size_of_val(&self.header);
3321            payload_size += size_of_val(&self.auth_handle);
3322            payload_size += size_of_val(&self.auth_size);
3323            payload_size += size_of_val(&self.auth);
3324            payload_size += self.encryption_key.payload_size();
3325            payload_size += self.object_public.payload_size();
3326            payload_size += self.duplicate.payload_size();
3327            payload_size += self.in_sym_seed.payload_size();
3328            payload_size += self.symmetric_alg.payload_size();
3329
3330            payload_size
3331        }
3332    }
3333
3334    #[repr(C)]
3335    #[derive(Debug, FromBytes, IntoBytes, Immutable, KnownLayout)]
3336    pub struct ImportReply {
3337        pub header: ReplyHeader,
3338        pub parameter_size: u32_be,
3339        // Parameter
3340        // `TPM2B_PRIVATE`
3341        pub out_private: Tpm2bBuffer,
3342        // Authorization area
3343        pub auth: common::ReplyAuth,
3344    }
3345
3346    impl TpmCommand for ImportCmd {
3347        type Reply = ImportReply;
3348    }
3349
3350    impl TpmReply for ImportReply {
3351        type Command = ImportCmd;
3352
3353        fn deserialize(bytes: &[u8]) -> Option<Self> {
3354            let mut start = 0;
3355            let mut end = size_of::<ReplyHeader>();
3356
3357            let header = ReplyHeader::read_from_prefix(&bytes[start..end]).ok()?.0; // TODO: zerocopy: use-rest-of-range, option-to-error (https://github.com/microsoft/openvmm/issues/759)
3358
3359            // Handle the command failure.
3360            if header.size.get() as usize == end {
3361                return Some(Self {
3362                    header,
3363                    parameter_size: 0.into(),
3364                    out_private: Tpm2bBuffer::new_zeroed(),
3365                    auth: common::ReplyAuth::new_zeroed(),
3366                });
3367            }
3368
3369            start = end;
3370            end += size_of::<u32_be>();
3371            if bytes.len() < end {
3372                return None;
3373            }
3374            let parameter_size = u32_be::read_from_prefix(&bytes[start..end]).ok()?.0; // TODO: zerocopy: use-rest-of-range, option-to-error (https://github.com/microsoft/openvmm/issues/759)
3375            let expected_auth_start = end + parameter_size.get() as usize;
3376
3377            start = end;
3378            let out_private = Tpm2bBuffer::deserialize(&bytes[start..])?;
3379            end += out_private.payload_size();
3380
3381            start = end;
3382            if start != expected_auth_start {
3383                return None;
3384            }
3385            end += size_of::<common::ReplyAuth>();
3386            if bytes.len() < end {
3387                return None;
3388            }
3389            let auth = common::ReplyAuth::read_from_prefix(&bytes[start..end])
3390                .ok()?
3391                .0; // TODO: zerocopy: use-rest-of-range, option-to-error (https://github.com/microsoft/openvmm/issues/759)
3392
3393            if header.size.get() as usize != end {
3394                return None;
3395            }
3396
3397            Some(Self {
3398                header,
3399                parameter_size,
3400                out_private,
3401                auth,
3402            })
3403        }
3404
3405        fn payload_size(&self) -> usize {
3406            let mut size = 0;
3407
3408            size += size_of::<ReplyHeader>();
3409            size += self.out_private.payload_size();
3410
3411            size
3412        }
3413    }
3414
3415    // === Load === //
3416
3417    #[repr(C)]
3418    #[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
3419    pub struct LoadCmd {
3420        header: CmdHeader,
3421        auth_handle: ReservedHandle,
3422        // Authorization area
3423        auth_size: u32_be,
3424        auth: common::CmdAuth,
3425        // Parameters
3426        // `TPM2B_PRIVATE`
3427        in_private: Tpm2bBuffer,
3428        // `TPM2B_PUBLIC`
3429        in_public: Tpm2bPublic,
3430    }
3431
3432    impl LoadCmd {
3433        pub fn new(
3434            session: SessionTag,
3435            auth_handle: ReservedHandle,
3436            auth: common::CmdAuth,
3437            in_private: &Tpm2bBuffer,
3438            in_public: &Tpm2bPublic,
3439        ) -> Self {
3440            let mut cmd = Self {
3441                header: CmdHeader::new::<Self>(session, CommandCodeEnum::Load.into()),
3442                auth_handle,
3443                auth_size: (size_of::<common::CmdAuth>() as u32).into(),
3444                auth,
3445                in_private: *in_private,
3446                in_public: *in_public,
3447            };
3448
3449            cmd.header.size = new_u32_be(cmd.payload_size() as u32);
3450
3451            cmd
3452        }
3453
3454        pub fn serialize(&self) -> Vec<u8> {
3455            let mut buffer = Vec::new();
3456
3457            buffer.extend_from_slice(self.header.as_bytes());
3458            buffer.extend_from_slice(self.auth_handle.as_bytes());
3459            buffer.extend_from_slice(self.auth_size.as_bytes());
3460            buffer.extend_from_slice(self.auth.as_bytes());
3461            buffer.extend_from_slice(&self.in_private.serialize());
3462            buffer.extend_from_slice(&self.in_public.serialize());
3463
3464            buffer
3465        }
3466
3467        pub fn payload_size(&self) -> usize {
3468            let mut payload_size = 0;
3469
3470            payload_size += size_of_val(&self.header);
3471            payload_size += size_of_val(&self.auth_handle);
3472            payload_size += size_of_val(&self.auth_size);
3473            payload_size += size_of_val(&self.auth);
3474            payload_size += self.in_private.payload_size();
3475            payload_size += self.in_public.payload_size();
3476
3477            payload_size
3478        }
3479    }
3480
3481    #[repr(C)]
3482    #[derive(Debug, FromBytes, IntoBytes, Immutable, KnownLayout)]
3483    pub struct LoadReply {
3484        pub header: ReplyHeader,
3485        pub object_handle: ReservedHandle,
3486        pub parameter_size: u32_be,
3487        // Parameter
3488        // `TPM2B_NAME`
3489        pub name: Tpm2bBuffer,
3490        // Authorization area
3491        pub auth: common::ReplyAuth,
3492    }
3493
3494    impl TpmCommand for LoadCmd {
3495        type Reply = LoadReply;
3496    }
3497
3498    impl TpmReply for LoadReply {
3499        type Command = LoadCmd;
3500
3501        fn deserialize(bytes: &[u8]) -> Option<Self> {
3502            let mut start = 0;
3503            let mut end = size_of::<ReplyHeader>();
3504
3505            let header = ReplyHeader::read_from_prefix(&bytes[start..end]).ok()?.0; // TODO: zerocopy: use-rest-of-range, option-to-error (https://github.com/microsoft/openvmm/issues/759)
3506
3507            // Handle the command failure.
3508            if header.size.get() as usize == end {
3509                return Some(Self {
3510                    header,
3511                    object_handle: ReservedHandle::new_zeroed(),
3512                    parameter_size: 0.into(),
3513                    name: Tpm2bBuffer::new_zeroed(),
3514                    auth: common::ReplyAuth::new_zeroed(),
3515                });
3516            }
3517
3518            start = end;
3519            end += size_of::<ReservedHandle>();
3520            if bytes.len() < end {
3521                return None;
3522            }
3523            let object_handle = ReservedHandle::read_from_prefix(&bytes[start..end]).ok()?.0; // TODO: zerocopy: use-rest-of-range, option-to-error (https://github.com/microsoft/openvmm/issues/759)
3524
3525            start = end;
3526            end += size_of::<u32_be>();
3527            if bytes.len() < end {
3528                return None;
3529            }
3530            let parameter_size = u32_be::read_from_prefix(&bytes[start..end]).ok()?.0; // TODO: zerocopy: use-rest-of-range, option-to-error (https://github.com/microsoft/openvmm/issues/759)
3531            let expected_auth_start = end + parameter_size.get() as usize;
3532
3533            start = end;
3534            let name = Tpm2bBuffer::deserialize(&bytes[start..])?;
3535            end += name.payload_size();
3536
3537            start = end;
3538            if start != expected_auth_start {
3539                return None;
3540            }
3541            end += size_of::<common::ReplyAuth>();
3542            if bytes.len() < end {
3543                return None;
3544            }
3545            let auth = common::ReplyAuth::read_from_prefix(&bytes[start..end])
3546                .ok()?
3547                .0; // TODO: zerocopy: use-rest-of-range, option-to-error (https://github.com/microsoft/openvmm/issues/759)
3548
3549            if header.size.get() as usize != end {
3550                return None;
3551            }
3552
3553            Some(Self {
3554                header,
3555                object_handle,
3556                parameter_size,
3557                name,
3558                auth,
3559            })
3560        }
3561
3562        fn payload_size(&self) -> usize {
3563            let mut size = 0;
3564
3565            size += size_of::<ReplyHeader>();
3566            size += size_of::<ReservedHandle>();
3567            size += self.name.payload_size();
3568
3569            size
3570        }
3571    }
3572}
3573
3574#[cfg(test)]
3575mod tests {
3576    use super::protocol::common::*;
3577    use super::protocol::*;
3578    use super::*;
3579
3580    #[test]
3581    fn test_create_primary() {
3582        const AK_PUB_EXPECTED_CMD: [u8; 321] = [
3583            0x80, 0x02, 0x00, 0x00, 0x01, 0x41, 0x00, 0x00, 0x01, 0x31, 0x40, 0x00, 0x00, 0x0b,
3584            0x00, 0x00, 0x00, 0x09, 0x40, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3585            0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x18, 0x00, 0x01, 0x00, 0x0b, 0x00, 0x05, 0x04,
3586            0x72, 0x00, 0x00, 0x00, 0x10, 0x00, 0x14, 0x00, 0x0b, 0x08, 0x00, 0x00, 0x00, 0x00,
3587            0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3588            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3589            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3590            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3591            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3592            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3593            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3594            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3595            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3596            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3597            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3598            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3599            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3600            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3601            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3602            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3603            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3604            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3605            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3606        ];
3607
3608        const AK_PUB_REPLY_SUCCEED: [u8; 488] = [
3609            0x80, 0x02, 0x00, 0x00, 0x01, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
3610            0x00, 0x00, 0x01, 0xd1, 0x01, 0x18, 0x00, 0x01, 0x00, 0x0b, 0x00, 0x05, 0x04, 0x72,
3611            0x00, 0x00, 0x00, 0x10, 0x00, 0x14, 0x00, 0x0b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
3612            0x01, 0x00, 0xc8, 0x38, 0xd1, 0x52, 0x00, 0x00, 0xe9, 0x3c, 0x89, 0x4c, 0x52, 0xfb,
3613            0x79, 0x7b, 0xc4, 0x14, 0x28, 0x5f, 0xaa, 0x50, 0x78, 0x9a, 0x31, 0x2b, 0x4d, 0xfe,
3614            0xad, 0xad, 0x97, 0x28, 0x49, 0xb2, 0x39, 0x77, 0x5e, 0x06, 0x49, 0xb7, 0x93, 0xf5,
3615            0x2f, 0x84, 0x85, 0x2e, 0x17, 0x87, 0x52, 0x96, 0x36, 0x74, 0x76, 0x21, 0x5f, 0xc2,
3616            0x90, 0x81, 0xf7, 0xe9, 0xd8, 0xac, 0x07, 0x60, 0xaf, 0x83, 0xa2, 0x08, 0xda, 0x94,
3617            0x77, 0x2c, 0x73, 0x9c, 0xd4, 0x80, 0x47, 0x43, 0xa6, 0x4e, 0x36, 0xc3, 0x7e, 0xe2,
3618            0x9c, 0xfb, 0xf1, 0x7e, 0x36, 0x8e, 0x7a, 0x86, 0xde, 0x3d, 0x4e, 0x8a, 0x3a, 0xce,
3619            0x7a, 0xa1, 0x58, 0xf6, 0xdb, 0x49, 0x3e, 0xc2, 0x2e, 0xcb, 0x4a, 0xbc, 0x19, 0x81,
3620            0xd5, 0x5d, 0x4f, 0x57, 0x39, 0xf5, 0x9e, 0x02, 0x56, 0x91, 0x37, 0xc2, 0x87, 0x96,
3621            0x26, 0xd8, 0x4a, 0x45, 0x16, 0x01, 0xe0, 0x2e, 0x20, 0x95, 0x75, 0xb8, 0x20, 0x6d,
3622            0x83, 0x54, 0x65, 0x3d, 0x66, 0xf4, 0x8a, 0x43, 0x84, 0x9f, 0xa6, 0xc5, 0x2c, 0x08,
3623            0xe7, 0x59, 0x8e, 0x1f, 0x6d, 0xea, 0x32, 0x5b, 0x36, 0x8e, 0xd1, 0xf3, 0x09, 0x60,
3624            0x86, 0xdb, 0x55, 0xc9, 0xf0, 0xf9, 0x79, 0x87, 0x71, 0x1c, 0x7c, 0x98, 0xa4, 0xc8,
3625            0x91, 0x77, 0xa7, 0x95, 0x82, 0x19, 0xcc, 0x9d, 0xde, 0x4d, 0x7b, 0xf7, 0xc1, 0x31,
3626            0x5b, 0xae, 0x45, 0x6e, 0x6b, 0xf1, 0xaf, 0x89, 0x07, 0x91, 0x80, 0x9d, 0xe5, 0x49,
3627            0xfc, 0x5e, 0xb2, 0x15, 0x67, 0xcf, 0x05, 0xbb, 0xb3, 0x98, 0x54, 0x34, 0x45, 0x2c,
3628            0xc3, 0x3d, 0x09, 0x8e, 0x8d, 0x60, 0xba, 0x67, 0xd9, 0xbe, 0x1c, 0x2a, 0x2c, 0x2a,
3629            0xfa, 0xed, 0x26, 0x81, 0x96, 0x48, 0x17, 0xb3, 0xa6, 0x90, 0x9a, 0x78, 0xa5, 0xac,
3630            0x80, 0xb2, 0xbe, 0xff, 0x3d, 0x35, 0x00, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
3631            0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f,
3632            0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b,
3633            0x78, 0x52, 0xb8, 0x55, 0x01, 0x00, 0x10, 0x00, 0x04, 0x40, 0x00, 0x00, 0x0b, 0x00,
3634            0x04, 0x40, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x20, 0x28, 0xd0, 0x26, 0xfa, 0xfd,
3635            0x74, 0x91, 0x06, 0x74, 0x3e, 0x27, 0xc4, 0x28, 0x05, 0x51, 0x58, 0x5e, 0x5d, 0x17,
3636            0x66, 0x8e, 0xb5, 0x21, 0x83, 0x5e, 0xd6, 0x01, 0x27, 0xef, 0xfc, 0x05, 0xd4, 0x80,
3637            0x21, 0x40, 0x00, 0x00, 0x0b, 0x00, 0x30, 0xfb, 0xfe, 0xd4, 0xe7, 0x9f, 0xc5, 0x2f,
3638            0xfd, 0x7c, 0xe0, 0x4a, 0x97, 0xb5, 0xec, 0x61, 0x59, 0x4d, 0x43, 0x19, 0x29, 0xc0,
3639            0x4f, 0xef, 0xda, 0xdc, 0xe1, 0x48, 0x4d, 0xbd, 0x3d, 0x47, 0x0e, 0xe3, 0x2f, 0xd4,
3640            0xf9, 0x57, 0x4f, 0x77, 0x0f, 0x58, 0x5c, 0x73, 0x58, 0xc2, 0x2d, 0xd7, 0x4a, 0x00,
3641            0x22, 0x00, 0x0b, 0x92, 0x57, 0x64, 0x38, 0x21, 0xf9, 0x68, 0xe9, 0xfc, 0x47, 0xfa,
3642            0xbf, 0x9c, 0x56, 0x49, 0x7a, 0x63, 0xc2, 0xc0, 0x8a, 0x12, 0x80, 0x49, 0x73, 0xc3,
3643            0x8b, 0x00, 0x06, 0x99, 0xe9, 0xfc, 0x22, 0x00, 0x00, 0x01, 0x00, 0x00,
3644        ];
3645
3646        const EK_PUB_EXPECTED_CMD: [u8; 355] = [
3647            0x80, 0x02, 0x00, 0x00, 0x01, 0x63, 0x00, 0x00, 0x01, 0x31, 0x40, 0x00, 0x00, 0x0b,
3648            0x00, 0x00, 0x00, 0x09, 0x40, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3649            0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x3a, 0x00, 0x01, 0x00, 0x0b, 0x00, 0x03, 0x00,
3650            0xb2, 0x00, 0x20, 0x83, 0x71, 0x97, 0x67, 0x44, 0x84, 0xb3, 0xf8, 0x1a, 0x90, 0xcc,
3651            0x8d, 0x46, 0xa5, 0xd7, 0x24, 0xfd, 0x52, 0xd7, 0x6e, 0x06, 0x52, 0x0b, 0x64, 0xf2,
3652            0xa1, 0xda, 0x1b, 0x33, 0x14, 0x69, 0xaa, 0x00, 0x06, 0x00, 0x80, 0x00, 0x43, 0x00,
3653            0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3654            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3655            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3656            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3657            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3658            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3659            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3660            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3661            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3662            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3663            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3664            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3665            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3666            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3667            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3668            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3669            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3670            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3671            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3672            0x00, 0x00, 0x00, 0x00, 0x00,
3673        ];
3674
3675        const EK_PUB_REPLY_SUCCEED: [u8; 522] = [
3676            0x80, 0x02, 0x00, 0x00, 0x02, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
3677            0x00, 0x00, 0x01, 0xf3, 0x01, 0x3a, 0x00, 0x01, 0x00, 0x0b, 0x00, 0x03, 0x00, 0xb2,
3678            0x00, 0x20, 0x83, 0x71, 0x97, 0x67, 0x44, 0x84, 0xb3, 0xf8, 0x1a, 0x90, 0xcc, 0x8d,
3679            0x46, 0xa5, 0xd7, 0x24, 0xfd, 0x52, 0xd7, 0x6e, 0x06, 0x52, 0x0b, 0x64, 0xf2, 0xa1,
3680            0xda, 0x1b, 0x33, 0x14, 0x69, 0xaa, 0x00, 0x06, 0x00, 0x80, 0x00, 0x43, 0x00, 0x10,
3681            0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x9e, 0x9c, 0x1b, 0x40, 0x00, 0x00,
3682            0xea, 0x2f, 0xd5, 0xd7, 0xde, 0x9b, 0x18, 0x83, 0x55, 0x00, 0x09, 0x53, 0x13, 0xa8,
3683            0x88, 0x10, 0x24, 0x46, 0x44, 0xa8, 0x2d, 0x62, 0xd3, 0x24, 0xe5, 0xf9, 0xcd, 0xca,
3684            0x61, 0xb7, 0xd8, 0x15, 0x98, 0xf8, 0x56, 0x64, 0x14, 0x7b, 0x40, 0x5a, 0x47, 0xbd,
3685            0xd1, 0xc8, 0x7d, 0x1f, 0x93, 0x72, 0x3f, 0x03, 0xe0, 0x29, 0x38, 0x08, 0x03, 0xae,
3686            0x62, 0x13, 0x10, 0xf5, 0x88, 0x5f, 0x86, 0x84, 0x82, 0xfb, 0xda, 0xd8, 0x78, 0xfd,
3687            0x02, 0x9e, 0x88, 0x5c, 0xaf, 0x30, 0xd4, 0x3d, 0x41, 0xb2, 0xb7, 0x7a, 0x36, 0xa5,
3688            0x95, 0x37, 0x08, 0x44, 0x20, 0x10, 0xb3, 0x6c, 0xd0, 0x6d, 0xe9, 0xab, 0xce, 0x35,
3689            0xc0, 0x82, 0x52, 0x06, 0x41, 0x4c, 0xc5, 0x48, 0x5b, 0xe6, 0x22, 0x00, 0x7e, 0x1d,
3690            0x4b, 0x68, 0x80, 0x34, 0xe9, 0xea, 0x6e, 0xf9, 0xf7, 0xf7, 0x84, 0xbe, 0x56, 0xdf,
3691            0xea, 0x85, 0x97, 0x1b, 0x03, 0x5c, 0x5c, 0x9f, 0xf4, 0x72, 0xef, 0xe7, 0xfe, 0x5e,
3692            0x73, 0x2f, 0xf1, 0xdd, 0x40, 0x80, 0x16, 0x8d, 0x1b, 0x95, 0xee, 0xec, 0x21, 0x1c,
3693            0x30, 0x84, 0x25, 0x08, 0x8d, 0x0e, 0xda, 0x5b, 0x00, 0x9c, 0x49, 0x8b, 0xc8, 0xb3,
3694            0x48, 0x9a, 0xc9, 0x19, 0x0f, 0x68, 0xc7, 0x0a, 0x7a, 0x65, 0x35, 0xa0, 0x09, 0x23,
3695            0x88, 0x3f, 0x97, 0x53, 0x4e, 0xbc, 0x08, 0xc0, 0x5b, 0x69, 0x94, 0xcc, 0xd9, 0xb9,
3696            0xea, 0x8c, 0x20, 0x9e, 0x1a, 0xf9, 0x57, 0x08, 0x1a, 0xe0, 0x2d, 0x88, 0x56, 0x1f,
3697            0x9f, 0x50, 0x2e, 0x12, 0xf2, 0x69, 0x9a, 0xdf, 0x30, 0x56, 0xc1, 0xf0, 0x31, 0xef,
3698            0x64, 0xd5, 0x34, 0x02, 0x15, 0xf4, 0xd7, 0x7b, 0x76, 0xd9, 0x99, 0x24, 0x83, 0x99,
3699            0xa5, 0x05, 0xc1, 0xcd, 0xa6, 0xbd, 0xc3, 0x3d, 0x7c, 0x1e, 0x94, 0xdd, 0x00, 0x37,
3700            0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14,
3701            0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b,
3702            0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55, 0x01, 0x00, 0x10, 0x00,
3703            0x04, 0x40, 0x00, 0x00, 0x0b, 0x00, 0x04, 0x40, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
3704            0x20, 0x28, 0xd0, 0x26, 0xfa, 0xfd, 0x74, 0x91, 0x06, 0x74, 0x3e, 0x27, 0xc4, 0x28,
3705            0x05, 0x51, 0x58, 0x5e, 0x5d, 0x17, 0x66, 0x8e, 0xb5, 0x21, 0x83, 0x5e, 0xd6, 0x01,
3706            0x27, 0xef, 0xfc, 0x05, 0xd4, 0x80, 0x21, 0x40, 0x00, 0x00, 0x0b, 0x00, 0x30, 0xe2,
3707            0xf2, 0x64, 0xc3, 0xd7, 0x9e, 0xc1, 0x07, 0xbb, 0x49, 0x74, 0x67, 0xd3, 0xc7, 0xf6,
3708            0xb7, 0x8c, 0xe3, 0x2e, 0x28, 0x36, 0xa6, 0x1f, 0x6f, 0x0b, 0xbd, 0xe3, 0x8e, 0x77,
3709            0xa1, 0x8c, 0x50, 0xe4, 0xaa, 0xa4, 0x01, 0x61, 0xb4, 0x7a, 0x4a, 0x3b, 0x5d, 0xac,
3710            0xe1, 0xd1, 0x65, 0x69, 0x1e, 0x00, 0x22, 0x00, 0x0b, 0xe5, 0x6f, 0x0f, 0xae, 0x8d,
3711            0x0f, 0x91, 0xb9, 0x84, 0x17, 0xc3, 0x86, 0x13, 0xa6, 0x12, 0xbe, 0xec, 0x85, 0xf9,
3712            0x0b, 0xd3, 0xfe, 0x4f, 0x3d, 0x79, 0x7d, 0x6d, 0x3c, 0xc5, 0xcc, 0xb1, 0x5b, 0x00,
3713            0x00, 0x01, 0x00, 0x00,
3714        ];
3715
3716        const REPLY_FAIL: [u8; 10] = [0x80, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x02, 0xda];
3717
3718        // Create AK pub
3719        let symmetric = TpmtSymDefObject::new(AlgIdEnum::NULL.into(), None, None);
3720        let scheme = TpmtRsaScheme::new(AlgIdEnum::RSASSA.into(), Some(AlgIdEnum::SHA256.into()));
3721        let rsa_params = TpmsRsaParams::new(symmetric, scheme, 2048, 0);
3722
3723        let object_attributes = TpmaObjectBits::new()
3724            .with_fixed_tpm(true)
3725            .with_fixed_parent(true)
3726            .with_sensitive_data_origin(true)
3727            .with_user_with_auth(true)
3728            .with_no_da(true)
3729            .with_restricted(true)
3730            .with_sign_encrypt(true);
3731
3732        let result = TpmtPublic::new(
3733            AlgIdEnum::RSA.into(),
3734            AlgIdEnum::SHA256.into(),
3735            object_attributes,
3736            &[],
3737            rsa_params,
3738            &[0u8; 256],
3739        );
3740        assert!(result.is_ok());
3741        let in_public = result.unwrap();
3742
3743        let result = CreatePrimaryCmd::new(
3744            SessionTagEnum::Sessions.into(),
3745            TPM20_RH_ENDORSEMENT,
3746            CmdAuth::new(TPM20_RS_PW, 0, 0, 0),
3747            &[],
3748            &[],
3749            in_public,
3750            &[],
3751            &[],
3752        );
3753        assert!(result.is_ok());
3754        let cmd = result.unwrap();
3755
3756        let bytes = cmd.serialize();
3757
3758        assert_eq!(bytes, AK_PUB_EXPECTED_CMD);
3759
3760        let mut reply = [0u8; 4096];
3761        reply[..AK_PUB_REPLY_SUCCEED.len()].copy_from_slice(&AK_PUB_REPLY_SUCCEED);
3762
3763        let response = CreatePrimaryReply::deserialize(&reply);
3764        assert!(response.is_some());
3765        let response = response.unwrap();
3766        assert_eq!(response.header.response_code.get(), 0x0);
3767        assert_eq!(response.object_handle.0.get(), 0x80000000);
3768
3769        reply[..REPLY_FAIL.len()].copy_from_slice(&REPLY_FAIL);
3770
3771        let response = CreatePrimaryReply::deserialize(&reply);
3772        assert!(response.is_some());
3773        let response = response.unwrap();
3774        assert_eq!(response.header.response_code.get(), 0x2da);
3775
3776        // Create EK pub
3777        const AUTH_POLICY_A_SHA_256: [u8; 32] = [
3778            0x83, 0x71, 0x97, 0x67, 0x44, 0x84, 0xB3, 0xF8, 0x1A, 0x90, 0xCC, 0x8D, 0x46, 0xA5,
3779            0xD7, 0x24, 0xFD, 0x52, 0xD7, 0x6E, 0x06, 0x52, 0x0B, 0x64, 0xF2, 0xA1, 0xDA, 0x1B,
3780            0x33, 0x14, 0x69, 0xAA,
3781        ];
3782        let symmetric = TpmtSymDefObject::new(
3783            AlgIdEnum::AES.into(),
3784            Some(128),
3785            Some(AlgIdEnum::CFB.into()),
3786        );
3787        let scheme = TpmtRsaScheme::new(AlgIdEnum::NULL.into(), None);
3788        let rsa_params = TpmsRsaParams::new(symmetric, scheme, 2048, 0);
3789
3790        let object_attributes = TpmaObjectBits::new()
3791            .with_fixed_tpm(true)
3792            .with_fixed_parent(true)
3793            .with_sensitive_data_origin(true)
3794            .with_admin_with_policy(true)
3795            .with_restricted(true)
3796            .with_decrypt(true);
3797
3798        let result = TpmtPublic::new(
3799            AlgIdEnum::RSA.into(),
3800            AlgIdEnum::SHA256.into(),
3801            object_attributes,
3802            &AUTH_POLICY_A_SHA_256,
3803            rsa_params,
3804            &[0u8; 256],
3805        );
3806        assert!(result.is_ok());
3807        let in_public = result.unwrap();
3808
3809        let result = CreatePrimaryCmd::new(
3810            SessionTagEnum::Sessions.into(),
3811            TPM20_RH_ENDORSEMENT,
3812            CmdAuth::new(TPM20_RS_PW, 0, 0, 0),
3813            &[],
3814            &[],
3815            in_public,
3816            &[],
3817            &[],
3818        );
3819        assert!(result.is_ok());
3820        let cmd = result.unwrap();
3821
3822        let bytes = cmd.serialize();
3823
3824        assert_eq!(bytes, EK_PUB_EXPECTED_CMD);
3825
3826        reply[..EK_PUB_REPLY_SUCCEED.len()].copy_from_slice(&EK_PUB_REPLY_SUCCEED);
3827
3828        let response = CreatePrimaryReply::deserialize(&reply);
3829        assert!(response.is_some());
3830        let response = response.unwrap();
3831        assert_eq!(response.header.response_code.get(), 0x0);
3832        assert_eq!(response.object_handle.0.get(), 0x80000000);
3833    }
3834
3835    #[test]
3836    fn test_read_public() {
3837        const REPLY_SUCCEED: [u8; 364] = [
3838            0x80, 0x01, 0x00, 0x00, 0x01, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x01, 0x18, 0x00, 0x01,
3839            0x00, 0x0b, 0x00, 0x05, 0x04, 0x72, 0x00, 0x00, 0x00, 0x10, 0x00, 0x14, 0x00, 0x0b,
3840            0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xa6, 0xaf, 0x71, 0xec, 0x00, 0x00,
3841            0xe0, 0x69, 0xa5, 0xc5, 0xcd, 0x94, 0x59, 0x3b, 0x79, 0xe6, 0xee, 0x14, 0xd3, 0x50,
3842            0xfb, 0x0b, 0xa9, 0x03, 0x51, 0xbf, 0x23, 0xc5, 0x15, 0xdc, 0xbc, 0x4a, 0x3b, 0xaa,
3843            0xef, 0x12, 0x3c, 0x24, 0x47, 0xf2, 0x81, 0xf6, 0x85, 0xf4, 0x8c, 0x16, 0x14, 0x10,
3844            0x3c, 0x3b, 0x2e, 0x7b, 0x04, 0x5e, 0x25, 0x66, 0xcd, 0x8d, 0x86, 0x0b, 0x8c, 0x2b,
3845            0x5f, 0xca, 0x36, 0x1d, 0x5f, 0xff, 0xbf, 0x70, 0x63, 0x79, 0x5b, 0x7f, 0x93, 0x94,
3846            0x6d, 0xbd, 0x6e, 0x4f, 0x22, 0x94, 0x93, 0x87, 0xe1, 0x63, 0x4d, 0xa4, 0x9a, 0x2f,
3847            0xad, 0x90, 0x4c, 0xc9, 0x37, 0x14, 0x59, 0xd3, 0x03, 0x6d, 0x37, 0x98, 0xd4, 0x85,
3848            0x19, 0x9b, 0x93, 0x7e, 0x61, 0x93, 0x6d, 0x1c, 0xe0, 0xe6, 0x72, 0x71, 0x81, 0x45,
3849            0xe0, 0xea, 0x5f, 0xb4, 0x6a, 0x9a, 0x3e, 0x86, 0x60, 0x86, 0xaf, 0xfc, 0x86, 0x0f,
3850            0x0d, 0xe8, 0x81, 0x46, 0x59, 0xad, 0xeb, 0x6f, 0xef, 0x38, 0x5e, 0x53, 0xea, 0x91,
3851            0xcb, 0xa9, 0xf8, 0x31, 0xcd, 0x52, 0x85, 0x55, 0xa8, 0x91, 0x68, 0xd8, 0xdd, 0x20,
3852            0x67, 0x21, 0x30, 0x03, 0xcd, 0x48, 0x3b, 0xb0, 0x33, 0x16, 0xb4, 0xf0, 0x06, 0x55,
3853            0xdf, 0x15, 0xd2, 0x65, 0x55, 0x2f, 0xec, 0xec, 0xc5, 0x74, 0xea, 0xd8, 0x0f, 0x29,
3854            0xac, 0x24, 0x38, 0x32, 0x34, 0x1f, 0xb3, 0x20, 0x28, 0xf6, 0x55, 0xfb, 0x51, 0xf1,
3855            0x22, 0xa3, 0x5e, 0x38, 0xc6, 0xa5, 0xa4, 0xe0, 0xc2, 0xa3, 0x50, 0x27, 0xf6, 0x1d,
3856            0x55, 0x8e, 0x95, 0xe9, 0x95, 0x26, 0x8e, 0x70, 0x35, 0x7b, 0x73, 0xbb, 0x8e, 0xf2,
3857            0xdc, 0x37, 0x30, 0x99, 0x20, 0x2e, 0x1f, 0x09, 0xbd, 0x85, 0x24, 0x44, 0x05, 0x8f,
3858            0x11, 0xc4, 0xb5, 0x71, 0xc1, 0x2e, 0x52, 0xf6, 0x2e, 0x6f, 0x9a, 0x11, 0x00, 0x22,
3859            0x00, 0x0b, 0x61, 0xca, 0x8b, 0xec, 0x0f, 0x9e, 0xc1, 0x38, 0x35, 0xd3, 0x43, 0x58,
3860            0x77, 0xdf, 0x53, 0x82, 0xe7, 0xb2, 0xff, 0x7b, 0xe4, 0x6c, 0xfb, 0x34, 0xa4, 0x28,
3861            0xdd, 0xda, 0xcb, 0xe9, 0x50, 0x50, 0x00, 0x22, 0x00, 0x0b, 0x51, 0xfa, 0x43, 0xbd,
3862            0x35, 0x01, 0xd6, 0x66, 0xa0, 0x4d, 0xc8, 0x03, 0x4f, 0xa1, 0x64, 0xa0, 0x91, 0x63,
3863            0x3c, 0x27, 0xd5, 0x90, 0xa3, 0x7a, 0xae, 0xbc, 0x52, 0xcc, 0x4e, 0x9a, 0xa3, 0x66,
3864        ];
3865
3866        const REPLY_FAIL: [u8; 10] = [0x80, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x01, 0x8b];
3867
3868        let mut reply = [0u8; 4096];
3869        reply[..REPLY_SUCCEED.len()].copy_from_slice(&REPLY_SUCCEED);
3870
3871        let response: Option<ReadPublicReply> = ReadPublicReply::deserialize(&reply);
3872        assert!(response.is_some());
3873        let response = response.unwrap();
3874        assert_eq!(response.header.response_code.get(), 0x0);
3875
3876        reply[..REPLY_FAIL.len()].copy_from_slice(&REPLY_FAIL);
3877
3878        let response = ReadPublicReply::deserialize(&reply);
3879        assert!(response.is_some());
3880        let response = response.unwrap();
3881        assert_eq!(response.header.response_code.get(), 0x18b);
3882    }
3883
3884    #[test]
3885    fn test_nv_read_public() {
3886        const REPLY_SUCCEED: [u8; 62] = [
3887            0x80, 0x01, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x01, 0x40,
3888            0x00, 0x01, 0x00, 0x0b, 0x42, 0x06, 0x00, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x22,
3889            0x00, 0x0b, 0xc1, 0x0f, 0x8d, 0x61, 0x77, 0xea, 0xd0, 0x29, 0x52, 0xa6, 0x2d, 0x3a,
3890            0x39, 0xc7, 0x22, 0x0b, 0xb9, 0xa1, 0xe1, 0xfe, 0x08, 0x68, 0xa8, 0x6f, 0x5f, 0x10,
3891            0xd6, 0x86, 0x83, 0x28, 0x79, 0x3e,
3892        ];
3893
3894        const REPLY_FAIL: [u8; 10] = [0x80, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x01, 0x8b];
3895
3896        let mut reply = [0u8; 4096];
3897        reply[..REPLY_SUCCEED.len()].copy_from_slice(&REPLY_SUCCEED);
3898
3899        let response = NvReadPublicReply::deserialize(&reply);
3900        assert!(response.is_some());
3901        let response = response.unwrap();
3902        assert_eq!(response.header.response_code.get(), 0x0);
3903
3904        reply[..REPLY_FAIL.len()].copy_from_slice(&REPLY_FAIL);
3905
3906        let response = NvReadPublicReply::deserialize(&reply);
3907        assert!(response.is_some());
3908        let response = response.unwrap();
3909        assert_eq!(response.header.response_code.get(), 0x18b);
3910    }
3911
3912    #[test]
3913    fn test_define_space() {
3914        const EXPECTED_CMD: [u8; 53] = [
3915            0x80, 0x02, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x01, 0x2a, 0x40, 0x00, 0x00, 0x0c,
3916            0x00, 0x00, 0x00, 0x09, 0x40, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3917            0x08, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00, 0x00, 0x0e, 0x01, 0xc1, 0x01,
3918            0xd0, 0x00, 0x0b, 0x42, 0x06, 0x00, 0x04, 0x00, 0x00, 0x10, 0x00,
3919        ];
3920
3921        let auth_value: u64 = 0x7766554433221100;
3922
3923        let attributes = TpmaNvBits::new()
3924            .with_nv_authread(true)
3925            .with_nv_authwrite(true)
3926            .with_nv_ownerread(true)
3927            .with_nv_platformcreate(true)
3928            .with_nv_no_da(true);
3929
3930        let result = TpmsNvPublic::new(0x1c101d0, AlgIdEnum::SHA256.into(), attributes, &[], 4096);
3931        assert!(result.is_ok());
3932        let nv_public = result.unwrap();
3933
3934        let result = NvDefineSpaceCmd::new(
3935            SessionTagEnum::Sessions.into(),
3936            TPM20_RH_PLATFORM,
3937            CmdAuth::new(TPM20_RS_PW, 0, 0, 0),
3938            auth_value,
3939            nv_public,
3940        );
3941        assert!(result.is_ok());
3942        let cmd = result.unwrap();
3943
3944        let bytes = cmd.serialize();
3945        assert_eq!(bytes, EXPECTED_CMD);
3946    }
3947
3948    #[test]
3949    fn test_nv_write_authwrite() {
3950        const EXPECTED_CMD: [u8; 171] = [
3951            0x80, 0x02, 0x00, 0x00, 0x00, 0xab, 0x00, 0x00, 0x01, 0x37, 0x01, 0xc1, 0x01, 0xd0,
3952            0x01, 0xc1, 0x01, 0xd0, 0x00, 0x00, 0x00, 0x11, 0x40, 0x00, 0x00, 0x09, 0x00, 0x00,
3953            0x00, 0x00, 0x08, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00, 0x00, 0x80, 0x01,
3954            0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
3955            0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
3956            0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
3957            0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
3958            0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
3959            0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
3960            0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
3961            0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
3962            0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
3963            0x01, 0x00, 0x00,
3964        ];
3965        let auth_value: u64 = 0x7766554433221100;
3966
3967        let result = NvWriteCmd::new(
3968            SessionTagEnum::Sessions.into(),
3969            ReservedHandle(0x1c101d0.into()),
3970            CmdAuth::new(TPM20_RS_PW, 0, 0, size_of_val(&auth_value) as u16),
3971            auth_value,
3972            0x1c101d0,
3973            &[1u8; 128],
3974            0,
3975        );
3976        assert!(result.is_ok());
3977        let cmd = result.unwrap();
3978
3979        let bytes = cmd.serialize();
3980        assert_eq!(bytes, EXPECTED_CMD);
3981    }
3982
3983    #[test]
3984    fn test_nv_write_ownerwrite() {
3985        const EXPECTED_CMD: [u8; 163] = [
3986            0x80, 0x02, 0x00, 0x00, 0x00, 0xa3, 0x00, 0x00, 0x01, 0x37, 0x40, 0x00, 0x00, 0x01,
3987            0x01, 0xc1, 0x01, 0xd0, 0x00, 0x00, 0x00, 0x09, 0x40, 0x00, 0x00, 0x09, 0x00, 0x00,
3988            0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
3989            0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
3990            0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
3991            0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
3992            0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
3993            0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
3994            0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
3995            0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
3996            0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
3997            0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00,
3998        ];
3999
4000        let result = NvWriteCmd::new(
4001            SessionTagEnum::Sessions.into(),
4002            TPM20_RH_OWNER,
4003            CmdAuth::new(TPM20_RS_PW, 0, 0, 0),
4004            0,
4005            0x1c101d0,
4006            &[1u8; 128],
4007            0,
4008        );
4009        assert!(result.is_ok());
4010        let cmd = result.unwrap();
4011
4012        let bytes = cmd.serialize();
4013        assert_eq!(bytes, EXPECTED_CMD);
4014    }
4015
4016    #[test]
4017    fn test_nv_read() {
4018        const REPLY_SUCCEED: [u8; 85] = [
4019            0x80, 0x02, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42,
4020            0x00, 0x40, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc,
4021            0xdd, 0xee, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4022            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4023            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4024            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
4025            0x00,
4026        ];
4027
4028        const EXPECTED_DATA: [u8; 64] = [
4029            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
4030            0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4031            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4032            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4033            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4034        ];
4035
4036        let mut reply = [0u8; 4096];
4037        reply[..REPLY_SUCCEED.len()].copy_from_slice(&REPLY_SUCCEED);
4038
4039        let response = NvReadReply::deserialize(&reply);
4040        assert!(response.is_some());
4041        let response = response.unwrap();
4042        assert_eq!(response.header.response_code.get(), 0x0);
4043        assert_eq!(response.data.buffer[..EXPECTED_DATA.len()], EXPECTED_DATA);
4044    }
4045}