From 1206b684282e5e221b07c86607e8f644410d4331 Mon Sep 17 00:00:00 2001 From: Roee Kasher Date: Tue, 24 Feb 2026 18:15:06 +0200 Subject: [PATCH 01/13] Adding Rust support to TSS.MSR --- .gitignore | 3 + README.md | 7 +- TSS.CPP/Src/TpmExtensions.cpp.snips | 2 +- TSS.CPP/include/TpmTypes.h | 2 +- TSS.JS/src/TpmBase.ts | 2 +- TSS.Java/pom.xml | 12 +- TSS.NET/TSS.Net/X_TpmDefs.cs | 118 +- TSS.Rust/Cargo.lock | 601 + TSS.Rust/Cargo.toml | 35 + TSS.Rust/README.md | 64 + TSS.Rust/clippy.toml | 17 + TSS.Rust/examples/README.md | 72 + TSS.Rust/examples/tpm_samples.rs | 2851 ++ TSS.Rust/src/auth_session.rs | 288 + TSS.Rust/src/crypto.rs | 272 + TSS.Rust/src/device.rs | 967 + TSS.Rust/src/error.rs | 105 + TSS.Rust/src/lib.rs | 12 + TSS.Rust/src/policy.rs | 656 + TSS.Rust/src/tpm2.rs | 7642 ++++++ TSS.Rust/src/tpm2_helpers.rs | 55 + TSS.Rust/src/tpm2_impl.rs | 1309 + TSS.Rust/src/tpm_buffer.rs | 373 + TSS.Rust/src/tpm_extensions.rs.snips | 13 + TSS.Rust/src/tpm_structure.rs | 109 + TSS.Rust/src/tpm_type_extensions.rs | 450 + TSS.Rust/src/tpm_types.rs | 34775 +++++++++++++++++++++++++ TssCodeGen/README.md | 10 +- TssCodeGen/src/CGenJava.cs | 2 +- TssCodeGen/src/CGenRust.cs | 1064 + TssCodeGen/src/CodeGenBase.cs | 126 +- TssCodeGen/src/Expression.cs | 26 +- TssCodeGen/src/TargetLang.cs | 102 +- TssCodeGen/src/TpmTranslations.cs | 23 +- TssCodeGen/src/TpmTypes.cs | 10 +- 35 files changed, 52059 insertions(+), 116 deletions(-) create mode 100644 TSS.Rust/Cargo.lock create mode 100644 TSS.Rust/Cargo.toml create mode 100644 TSS.Rust/README.md create mode 100644 TSS.Rust/clippy.toml create mode 100644 TSS.Rust/examples/README.md create mode 100644 TSS.Rust/examples/tpm_samples.rs create mode 100644 TSS.Rust/src/auth_session.rs create mode 100644 TSS.Rust/src/crypto.rs create mode 100644 TSS.Rust/src/device.rs create mode 100644 TSS.Rust/src/error.rs create mode 100644 TSS.Rust/src/lib.rs create mode 100644 TSS.Rust/src/policy.rs create mode 100644 TSS.Rust/src/tpm2.rs create mode 100644 TSS.Rust/src/tpm2_helpers.rs create mode 100644 TSS.Rust/src/tpm2_impl.rs create mode 100644 TSS.Rust/src/tpm_buffer.rs create mode 100644 TSS.Rust/src/tpm_extensions.rs.snips create mode 100644 TSS.Rust/src/tpm_structure.rs create mode 100644 TSS.Rust/src/tpm_type_extensions.rs create mode 100644 TSS.Rust/src/tpm_types.rs create mode 100644 TssCodeGen/src/CGenRust.cs diff --git a/.gitignore b/.gitignore index 78ccd411..ac400dbe 100644 --- a/.gitignore +++ b/.gitignore @@ -229,3 +229,6 @@ FakesAssemblies/ /Tpm2Tester/TestSuite/Properties/launchSettings.json *.map *.json + +# Rust +target/ diff --git a/README.md b/README.md index 407b25fb..75bd38e3 100644 --- a/README.md +++ b/README.md @@ -20,9 +20,9 @@ All flavors of TPM 2.0 devices mentioned in the previous section communicate wit In order to facilitate the development of applications and services using TPM 2.0, Microsoft has developed a series of TSS implementations for different programming languages. All these implementations provide complete representation of the TPM 2.0 API (commands, data structures, enumerations, unions) using the means of the corresponding languages, and some of them - additional functionality that greatly simplifies communications with TPM 2.0. All TSS.MSR implementations provide abstraction for Windows/Linux/Simulator TPM 2.0 devices. -### [TSS.Net] and [TSS.CPP] +### [TSS.Net], [TSS.CPP] and [TSS.Rust] -TSS.Net and TSS.CPP are written in C# and C++ correspondingly, and are the richest TSS implementations in this collection. Besides complete abstraction of the TPM 2.0 interface, they implement additional functionality, such as: +TSS.Net, TSS.CPP and TSS.Rust are written in C#, C++ and Rust correspondingly, and are the richest TSS implementations in this collection. Besides complete abstraction of the TPM 2.0 interface, they implement additional functionality, such as: * automatic handling of HMAC and policy sessions; * expected audit, policy and cpHashes computation; @@ -48,6 +48,8 @@ Along with it comes a [sample test suite][TestSuite] that not only demonstrates TSS.Net is a cross-platform .NET Standard library and requires Visual Studio 2017 or above to build it. It can target one of the following .NET framework flavors: .NET 4.7.2, .NET Core 2.1 (for both Windows and Linux), .NET Standard 2.0, and .NET UWP 10.0. You can download the latest versions of the .NET Framework [here](https://www.microsoft.com/net/download/windows). +TSS.Rust requires Rust 1.70 or above and uses Cargo as its build system. + TSS.Java uses Java SE 8 or above, TSS.JS requires Node.js 4.8.4 or higher, and TSS.Py supports Python 2.7 and 3.5+. ## Platform Crypto Provider Toolkit @@ -70,6 +72,7 @@ For private feedback please use tssdotnet@microsoft.com (for all managed languag [TSS.Net]: ./TSS.NET [TSS.CPP]: ./TSS.CPP +[TSS.Rust]: ./TSS.Rust [TSS.Java]: ./TSS.Java [TSS.JS]: ./TSS.JS [TSS.Py]: ./TSS.Py diff --git a/TSS.CPP/Src/TpmExtensions.cpp.snips b/TSS.CPP/Src/TpmExtensions.cpp.snips index a1f1331a..b235c709 100644 --- a/TSS.CPP/Src/TpmExtensions.cpp.snips +++ b/TSS.CPP/Src/TpmExtensions.cpp.snips @@ -193,7 +193,7 @@ static vector GetSelectionArray(TPM_ALG_ID hashAlg, UINT32 p /// Is the PCR with index _pcr selected in this TPMS_PCR_SELECTION. bool PcrIsSelected(UINT32 pcr) { - return pcrSelect[pcr / 8] = (1 << (pcr % 8)) != 0; + return (pcrSelect[pcr / 8] >> (pcr % 8)) & 1; } /// Return the current PCR-selection as a UINT32 array. diff --git a/TSS.CPP/include/TpmTypes.h b/TSS.CPP/include/TpmTypes.h index c10d14d9..7b7b8af1 100644 --- a/TSS.CPP/include/TpmTypes.h +++ b/TSS.CPP/include/TpmTypes.h @@ -3653,7 +3653,7 @@ class _DLLEXP_ TPMS_PCR_SELECTION : public TpmStructure /// Is the PCR with index _pcr selected in this TPMS_PCR_SELECTION. bool PcrIsSelected(UINT32 pcr) { - return pcrSelect[pcr / 8] = (1 << (pcr % 8)) != 0; + return (pcrSelect[pcr / 8] >> (pcr % 8)) & 1; } /// Return the current PCR-selection as a UINT32 array. diff --git a/TSS.JS/src/TpmBase.ts b/TSS.JS/src/TpmBase.ts index 66361a54..9abfc160 100644 --- a/TSS.JS/src/TpmBase.ts +++ b/TSS.JS/src/TpmBase.ts @@ -205,7 +205,7 @@ export class TpmBase { // If the caller has not provided a session for a handle that requires authorization, // a password session is automatically created. - if (this.sessions == null) + if (this.sessions == null) this.sessions = new Array(numAuthHandles); else if (this.sessions.length < numAuthHandles) this.sessions = this.sessions.concat(new Array(numAuthHandles - this.sessions.length)); diff --git a/TSS.Java/pom.xml b/TSS.Java/pom.xml index f4b832e4..cabff8e6 100644 --- a/TSS.Java/pom.xml +++ b/TSS.Java/pom.xml @@ -31,13 +31,13 @@ org.bouncycastle - bcprov-jdk15on - 1.67 + bcprov-jdk18on + 1.78 net.java.dev.jna jna - 4.4.0 + 5.14.0 @@ -53,7 +53,7 @@ maven-compiler-plugin - 3.6.1 + 3.12.1 1.8 1.8 @@ -95,11 +95,11 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.0.0-M1 + 3.6.3 8 - -Xdoclint:none + all,-missing diff --git a/TSS.NET/TSS.Net/X_TpmDefs.cs b/TSS.NET/TSS.Net/X_TpmDefs.cs index 658a55fa..26af3b57 100644 --- a/TSS.NET/TSS.Net/X_TpmDefs.cs +++ b/TSS.NET/TSS.Net/X_TpmDefs.cs @@ -3815,38 +3815,45 @@ public enum AlgorithmAttr : uint /// SET (1): an asymmetric algorithm with public and private portions /// CLEAR (0): not an asymmetric algorithm [EnumMember] + [SpecTypeName("Asymmetric")] Asymmetric = 0x1, /// SET (1): a symmetric block cipher /// CLEAR (0): not a symmetric block cipher [EnumMember] + [SpecTypeName("Symmetric")] Symmetric = 0x2, /// SET (1): a hash algorithm /// CLEAR (0): not a hash algorithm [EnumMember] + [SpecTypeName("Hash")] Hash = 0x4, /// SET (1): an algorithm that may be used as an object type /// CLEAR (0): an algorithm that is not used as an object type [EnumMember] + [SpecTypeName("Object")] Object = 0x8, /// SET (1): a signing algorithm. The setting of asymmetric, symmetric, and hash /// will indicate the type of signing algorithm. /// CLEAR (0): not a signing algorithm [EnumMember] + [SpecTypeName("Signing")] Signing = 0x100, /// SET (1): an encryption/decryption algorithm. The setting of asymmetric, /// symmetric, and hash will indicate the type of encryption/decryption algorithm. /// CLEAR (0): not an encryption/decryption algorithm [EnumMember] + [SpecTypeName("Encrypting")] Encrypting = 0x200, /// SET (1): a method such as a key derivative function (KDF) /// CLEAR (0): not a method [EnumMember] + [SpecTypeName("Method")] Method = 0x400 } @@ -3866,6 +3873,7 @@ public enum ObjectAttr : uint /// NOTE fixedTPM does not indicate that key material resides on a single TPM (see /// sensitiveDataOrigin). [EnumMember] + [SpecTypeName("FixedTPM")] FixedTPM = 0x2, /// SET (1): Previously saved contexts of this object may not be loaded after @@ -3873,12 +3881,14 @@ public enum ObjectAttr : uint /// CLEAR (0): Saved contexts of this object may be used after a Shutdown(STATE) and /// subsequent Startup(). [EnumMember] + [SpecTypeName("StClear")] StClear = 0x4, /// SET (1): The parent of the object may not change. /// CLEAR (0): The parent of the object may change as the result of a TPM2_Duplicate() of /// the object. [EnumMember] + [SpecTypeName("FixedParent")] FixedParent = 0x10, /// SET (1): Indicates that, when the object was created with TPM2_Create() or @@ -3886,6 +3896,7 @@ public enum ObjectAttr : uint /// CLEAR (0): A portion of the sensitive data, other than the authValue, was provided by /// the caller. [EnumMember] + [SpecTypeName("SensitiveDataOrigin")] SensitiveDataOrigin = 0x20, /// SET (1): Approval of USER role actions with this object may be with an HMAC @@ -3893,6 +3904,7 @@ public enum ObjectAttr : uint /// CLEAR (0): Approval of USER role actions with this object may only be done with a /// policy session. [EnumMember] + [SpecTypeName("UserWithAuth")] UserWithAuth = 0x40, /// SET (1): Approval of ADMIN role actions with this object may only be done @@ -3900,11 +3912,13 @@ public enum ObjectAttr : uint /// CLEAR (0): Approval of ADMIN role actions with this object may be with an HMAC session /// or with a password using the authValue of the object or a policy session. [EnumMember] + [SpecTypeName("AdminWithPolicy")] AdminWithPolicy = 0x80, /// SET (1): The object is not subject to dictionary attack protections. /// CLEAR (0): The object is subject to dictionary attack protections. [EnumMember] + [SpecTypeName("NoDA")] NoDA = 0x400, /// SET (1): If the object is duplicated, then symmetricAlg shall not be @@ -3912,33 +3926,39 @@ public enum ObjectAttr : uint /// CLEAR (0): The object may be duplicated without an inner wrapper on the private /// portion of the object and the new parent may be TPM_RH_NULL. [EnumMember] + [SpecTypeName("EncryptedDuplication")] EncryptedDuplication = 0x800, /// SET (1): Key usage is restricted to manipulate structures of known format; /// the parent of this key shall have restricted SET. /// CLEAR (0): Key usage is not restricted to use on special formats. [EnumMember] + [SpecTypeName("Restricted")] Restricted = 0x10000, /// SET (1): The private portion of the key may be used to decrypt. /// CLEAR (0): The private portion of the key may not be used to decrypt. [EnumMember] + [SpecTypeName("Decrypt")] Decrypt = 0x20000, /// SET (1): For a symmetric cipher object, the private portion of the key may /// be used to encrypt. For other objects, the private portion of the key may be used to sign. /// CLEAR (0): The private portion of the key may not be used to sign or encrypt. [EnumMember] + [SpecTypeName("Sign")] Sign = 0x40000, /// Alias to the sign value. [EnumMember] + [SpecTypeName("Encrypt")] Encrypt = 0x40000, /// SET (1): An asymmetric key that may not be used to sign with TPM2_Sign() /// CLEAR (0): A key that may be used with TPM2_Sign() if sign is SET /// NOTE: This attribute only has significance if sign is SET. [EnumMember] + [SpecTypeName("X509sign")] X509sign = 0x80000 } @@ -3967,6 +3987,7 @@ public enum SessionAttr : byte /// same handle but logically is not the same session. /// This attribute has no effect if the command does not complete successfully. [EnumMember] + [SpecTypeName("ContinueSession")] ContinueSession = 0x1, /// SET (1): In a command, this setting indicates that the command should only @@ -3976,6 +3997,7 @@ public enum SessionAttr : byte /// CLEAR (0): In a command, indicates that the session need not be exclusive at the start /// of the command. In a response, indicates that the session is not exclusive. [EnumMember] + [SpecTypeName("AuditExclusive")] AuditExclusive = 0x2, /// SET (1): In a command, this setting indicates that the audit digest of the @@ -3984,6 +4006,7 @@ public enum SessionAttr : byte /// CLEAR (0): In a command, indicates that the audit digest should not be initialized. /// This bit is always CLEAR in a response. [EnumMember] + [SpecTypeName("AuditReset")] AuditReset = 0x4, /// SET (1): In a command, this setting indicates that the first parameter in @@ -3997,6 +4020,7 @@ public enum SessionAttr : byte /// Such a session is provided for purposes of encrypting a parameter and not for authorization. /// This attribute may be SET in combination with any other session attributes. [EnumMember] + [SpecTypeName("Decrypt")] Decrypt = 0x20, /// SET (1): In a command, this setting indicates that the TPM should use this @@ -4010,6 +4034,7 @@ public enum SessionAttr : byte /// Such a session is provided for purposes of encrypting a parameter and not for /// authorization. [EnumMember] + [SpecTypeName("Encrypt")] Encrypt = 0x40, /// SET (1): In a command or response, this setting indicates that the session @@ -4019,6 +4044,7 @@ public enum SessionAttr : byte /// CLEAR (0): Session is not used for audit. /// If SET in the command, then this attribute will be SET in the response. [EnumMember] + [SpecTypeName("Audit")] Audit = 0x80 } @@ -4033,47 +4059,58 @@ public enum LocalityAttr : byte None = 0, [EnumMember] + [SpecTypeName("LocZero")] LocZero = 0x1, [Obsolete("Use LocalityAttr.LocZero instead")] TpmLocZero = 0x1, [EnumMember] + [SpecTypeName("LocOne")] LocOne = 0x2, [Obsolete("Use LocalityAttr.LocOne instead")] TpmLocOne = 0x2, [EnumMember] + [SpecTypeName("LocTwo")] LocTwo = 0x4, [Obsolete("Use LocalityAttr.LocTwo instead")] TpmLocTwo = 0x4, [EnumMember] + [SpecTypeName("LocThree")] LocThree = 0x8, [Obsolete("Use LocalityAttr.LocThree instead")] TpmLocThree = 0x8, [EnumMember] + [SpecTypeName("LocFour")] LocFour = 0x10, [Obsolete("Use LocalityAttr.LocFour instead")] TpmLocFour = 0x10, /// If any of these bits is set, an extended locality is indicated [EnumMember] + [SpecTypeName("")] ExtendedBitMask = 0xE0, [EnumMember] + [SpecTypeName("")] ExtendedBitOffset = 5, [EnumMember] + [SpecTypeName("")] ExtendedBitLength = 3, [EnumMember] + [SpecTypeName("")] ExtendedBit0 = 0x20, [EnumMember] + [SpecTypeName("")] ExtendedBit1 = 0x40, [EnumMember] + [SpecTypeName("")] ExtendedBit2 = 0x80 } @@ -4093,34 +4130,40 @@ public enum PermanentAttr : uint /// the last TPM2_Clear(). /// CLEAR (0): ownerAuth has not been changed since TPM2_Clear(). [EnumMember] + [SpecTypeName("OwnerAuthSet")] OwnerAuthSet = 0x1, /// SET (1): TPM2_HierarchyChangeAuth() with endorsementAuth has been executed /// since the last TPM2_Clear(). /// CLEAR (0): endorsementAuth has not been changed since TPM2_Clear(). [EnumMember] + [SpecTypeName("EndorsementAuthSet")] EndorsementAuthSet = 0x2, /// SET (1): TPM2_HierarchyChangeAuth() with lockoutAuth has been executed since /// the last TPM2_Clear(). /// CLEAR (0): lockoutAuth has not been changed since TPM2_Clear(). [EnumMember] + [SpecTypeName("LockoutAuthSet")] LockoutAuthSet = 0x4, /// SET (1): TPM2_Clear() is disabled. /// CLEAR (0): TPM2_Clear() is enabled. /// NOTE See TPM2_ClearControl in TPM 2.0 Part 3 for details on changing this attribute. [EnumMember] + [SpecTypeName("DisableClear")] DisableClear = 0x100, /// SET (1): The TPM is in lockout, when failedTries is equal to maxTries. [EnumMember] + [SpecTypeName("InLockout")] InLockout = 0x200, /// SET (1): The EPS was created by the TPM. /// CLEAR (0): The EPS was created outside of the TPM using a manufacturer-specific /// process. [EnumMember] + [SpecTypeName("TpmGeneratedEPS")] TpmGeneratedEPS = 0x400 } @@ -4140,6 +4183,7 @@ public enum StartupClearAttr : uint /// NOTE See TPM2_HierarchyControl in TPM 2.0 Part 3 for details on changing this /// attribute. [EnumMember] + [SpecTypeName("PhEnable")] PhEnable = 0x1, /// SET (1): The Storage hierarchy is enabled and ownerAuth or ownerPolicy may @@ -4150,6 +4194,7 @@ public enum StartupClearAttr : uint /// NOTE See TPM2_HierarchyControl in TPM 2.0 Part 3 for details on changing this /// attribute. [EnumMember] + [SpecTypeName("ShEnable")] ShEnable = 0x2, /// SET (1): The EPS hierarchy is enabled and Endorsement Authorization may be @@ -4159,6 +4204,7 @@ public enum StartupClearAttr : uint /// NOTE See TPM2_HierarchyControl in TPM 2.0 Part 3 for details on changing this /// attribute. [EnumMember] + [SpecTypeName("EhEnable")] EhEnable = 0x4, /// SET (1): NV indices that have TPMA_NV_PLATFORMCREATE SET may be read or @@ -4175,6 +4221,7 @@ public enum StartupClearAttr : uint /// does not exist, it also returns this error code if the index is disabled. Otherwise, /// the TPM would leak the existence of an index even when disabled. [EnumMember] + [SpecTypeName("PhEnableNV")] PhEnableNV = 0x8, /// SET (1): The TPM received a TPM2_Shutdown() and a matching TPM2_Startup(). @@ -4183,6 +4230,7 @@ public enum StartupClearAttr : uint /// by a TPM2_Startup() of any type. However, the TPM will return an error if /// TPM2_Startup(TPM_SU_STATE) was not preceded by TPM2_Shutdown(TPM_SU_STATE). [EnumMember] + [SpecTypeName("Orderly")] Orderly = 0x80000000 } @@ -4202,6 +4250,7 @@ public enum MemoryAttr : uint /// CLEAR (0): indicates that the memory used for authorization sessions is not shared /// with memory used for transient objects [EnumMember] + [SpecTypeName("SharedRAM")] SharedRAM = 0x1, /// SET (1): indicates that the NV memory used for persistent objects is shared @@ -4209,6 +4258,7 @@ public enum MemoryAttr : uint /// CLEAR (0): indicates that the persistent objects and NV Index values are allocated /// from separate sections of NV [EnumMember] + [SpecTypeName("SharedNV")] SharedNV = 0x2, /// SET (1): indicates that the TPM copies persistent objects to a @@ -4217,6 +4267,7 @@ public enum MemoryAttr : uint /// CLEAR (0): indicates that the TPM does not use transient-object slots when persistent /// objects are referenced [EnumMember] + [SpecTypeName("ObjectCopiedToRam")] ObjectCopiedToRam = 0x4 } @@ -4233,57 +4284,71 @@ public enum CcAttr : uint /// Indicates the command being selected [EnumMember] + [SpecTypeName("")] commandIndexBitMask = 0xFFFF, [EnumMember] + [SpecTypeName("")] commandIndexBitOffset = 0, [EnumMember] + [SpecTypeName("")] commandIndexBitLength = 16, /// SET (1): indicates that the command may write to NV /// CLEAR (0): indicates that the command does not write to NV [EnumMember] + [SpecTypeName("Nv")] Nv = 0x400000, /// SET (1): This command could flush any number of loaded contexts. /// CLEAR (0): no additional changes other than indicated by the flushed attribute [EnumMember] + [SpecTypeName("Extensive")] Extensive = 0x800000, /// SET (1): The context associated with any transient handle in the command /// will be flushed when this command completes. /// CLEAR (0): No context is flushed as a side effect of this command. [EnumMember] + [SpecTypeName("Flushed")] Flushed = 0x1000000, /// Indicates the number of the handles in the handle area for this command [EnumMember] + [SpecTypeName("")] cHandlesBitMask = 0xE000000, [EnumMember] + [SpecTypeName("")] cHandlesBitOffset = 25, [EnumMember] + [SpecTypeName("")] cHandlesBitLength = 3, /// SET (1): indicates the presence of the handle area in the response [EnumMember] + [SpecTypeName("RHandle")] RHandle = 0x10000000, /// SET (1): indicates that the command is vendor-specific /// CLEAR (0): indicates that the command is defined in a version of this specification [EnumMember] + [SpecTypeName("V")] V = 0x20000000, /// Allocated for software; shall be zero [EnumMember] - ResBitMask = 0xC0000000, + [SpecTypeName("")] + ResBitMask = unchecked ((uint)(0xC0000000)), [EnumMember] + [SpecTypeName("")] ResBitOffset = 30, [EnumMember] + [SpecTypeName("")] ResBitLength = 2 } @@ -4300,6 +4365,7 @@ public enum ModesAttr : uint /// SET (1): indicates that the TPM is designed to comply with all of the FIPS /// 140-2 requirements at Level 1 or higher. [EnumMember] + [SpecTypeName("Fips1402")] Fips1402 = 0x1 } @@ -4317,43 +4383,53 @@ public enum X509KeyUsageAttr : uint /// Attributes.Decrypt SET [EnumMember] + [SpecTypeName("DecipherOnly")] DecipherOnly = 0x800000, /// Attributes.Decrypt SET [EnumMember] + [SpecTypeName("EncipherOnly")] EncipherOnly = 0x1000000, /// Attributes.sign SET [EnumMember] + [SpecTypeName("CRLSign")] CRLSign = 0x2000000, /// Attributes.sign SET [EnumMember] + [SpecTypeName("KeyCertSign")] KeyCertSign = 0x4000000, /// Attributes.Decrypt SET [EnumMember] + [SpecTypeName("KeyAgreement")] KeyAgreement = 0x8000000, /// Attributes.Decrypt SET [EnumMember] + [SpecTypeName("DataEncipherment")] DataEncipherment = 0x10000000, /// Asymmetric key with decrypt and restricted SET key has the attributes of a /// parent key [EnumMember] + [SpecTypeName("KeyEncipherment")] KeyEncipherment = 0x20000000, /// FixedTPM SET in Subject Key (objectHandle) [EnumMember] + [SpecTypeName("Nonrepudiation")] Nonrepudiation = 0x40000000, /// Alias to the nonrepudiation value. [EnumMember] + [SpecTypeName("ContentCommitment")] ContentCommitment = 0x40000000, /// Sign SET in Subject Key (objectHandle) [EnumMember] + [SpecTypeName("DigitalSignature")] DigitalSignature = 0x80000000 } @@ -4372,10 +4448,12 @@ public enum ActAttr : uint /// SET (1): The ACT has signaled /// CLEAR (0): The ACT has not signaled [EnumMember] + [SpecTypeName("Signaled")] Signaled = 0x1, /// Preserves the state of signaled, depending on the power cycle [EnumMember] + [SpecTypeName("PreserveSignaled")] PreserveSignaled = 0x2 } @@ -4392,22 +4470,28 @@ public enum NvIndex : uint /// The Index of the NV location [EnumMember] + [SpecTypeName("")] indexBitMask = 0xFFFFFF, [EnumMember] + [SpecTypeName("")] indexBitOffset = 0, [EnumMember] + [SpecTypeName("")] indexBitLength = 24, /// Constant value of TPM_HT_NV_INDEX indicating the NV Index range [EnumMember] - RhNvBitMask = 0xFF000000, + [SpecTypeName("")] + RhNvBitMask = unchecked ((uint)(0xFF000000)), [EnumMember] + [SpecTypeName("")] RhNvBitOffset = 24, [EnumMember] + [SpecTypeName("")] RhNvBitLength = 8 } @@ -4424,11 +4508,13 @@ public enum NvAttr : uint /// CLEAR (0): Writing of the Index data cannot be authorized with Platform Authorization. /// [EnumMember] + [SpecTypeName("Ppwrite")] Ppwrite = 0x1, /// SET (1): The Index data can be written if Owner Authorization is provided. /// CLEAR (0): Writing of the Index data cannot be authorized with Owner Authorization. [EnumMember] + [SpecTypeName("Ownerwrite")] Ownerwrite = 0x2, /// SET (1): Authorizations to change the Index contents that require USER role @@ -4436,6 +4522,7 @@ public enum NvAttr : uint /// CLEAR (0): Authorizations to change the Index contents that require USER role may not /// be provided with an HMAC session or password. [EnumMember] + [SpecTypeName("Authwrite")] Authwrite = 0x4, /// SET (1): Authorizations to change the Index contents that require USER role @@ -4445,47 +4532,57 @@ public enum NvAttr : uint /// NOTE TPM2_NV_ChangeAuth() always requires that authorization be provided in a policy /// session. [EnumMember] + [SpecTypeName("Policywrite")] Policywrite = 0x8, /// Ordinary contains data that is opaque to the TPM that can only be modified /// using TPM2_NV_Write(). [EnumMember] + [SpecTypeName("Ordinary")] Ordinary = 0x0, /// Counter contains an 8-octet value that is to be used as a counter and can /// only be modified with TPM2_NV_Increment() [EnumMember] + [SpecTypeName("Counter")] Counter = 0x10, /// Bit Field contains an 8-octet value to be used as a bit field and can only /// be modified with TPM2_NV_SetBits(). [EnumMember] + [SpecTypeName("Bits")] Bits = 0x20, /// Extend contains a digest-sized value used like a PCR. The Index can only be /// modified using TPM2_NV_Extend(). The extend will use the nameAlg of the Index. [EnumMember] + [SpecTypeName("Extend")] Extend = 0x40, /// PIN Fail - contains pinCount that increments on a PIN authorization failure /// and a pinLimit [EnumMember] + [SpecTypeName("PinFail")] PinFail = 0x80, /// PIN Pass - contains pinCount that increments on a PIN authorization success /// and a pinLimit [EnumMember] + [SpecTypeName("PinPass")] PinPass = 0x90, /// The type of the index. /// NOTE A TPM is not required to support all TPM_NT values [EnumMember] + [SpecTypeName("")] TpmNtBitMask = 0xF0, [EnumMember] + [SpecTypeName("")] TpmNtBitOffset = 4, [EnumMember] + [SpecTypeName("")] TpmNtBitLength = 4, /// SET (1): Index may not be deleted unless the authPolicy is satisfied using @@ -4495,11 +4592,13 @@ public enum NvAttr : uint /// NOTE An Index with this attribute and a policy that cannot be satisfied (e.g., an /// Empty Policy) cannot be deleted. [EnumMember] + [SpecTypeName("PolicyDelete")] PolicyDelete = 0x400, /// SET (1): Index cannot be written. /// CLEAR (0): Index can be written. [EnumMember] + [SpecTypeName("Writelocked")] Writelocked = 0x800, /// SET (1): A partial write of the Index data is not allowed. The write size @@ -4507,12 +4606,14 @@ public enum NvAttr : uint /// CLEAR (0): Partial writes are allowed. This setting is required if the .dataSize of /// the Index is larger than NV_MAX_BUFFER_SIZE for the implementation. [EnumMember] + [SpecTypeName("Writeall")] Writeall = 0x1000, /// SET (1): TPM2_NV_WriteLock() may be used to prevent further writes to this location. /// CLEAR (0): TPM2_NV_WriteLock() does not block subsequent writes if /// TPMA_NV_WRITE_STCLEAR is also CLEAR. [EnumMember] + [SpecTypeName("Writedefine")] Writedefine = 0x2000, /// SET (1): TPM2_NV_WriteLock() may be used to prevent further writes to this @@ -4520,33 +4621,39 @@ public enum NvAttr : uint /// CLEAR (0): TPM2_NV_WriteLock() does not block subsequent writes if TPMA_NV_WRITEDEFINE /// is also CLEAR. [EnumMember] + [SpecTypeName("WriteStclear")] WriteStclear = 0x4000, /// SET (1): If TPM2_NV_GlobalWriteLock() is successful, TPMA_NV_WRITELOCKED is set. /// CLEAR (0): TPM2_NV_GlobalWriteLock() has no effect on the writing of the data at this /// Index. [EnumMember] + [SpecTypeName("Globallock")] Globallock = 0x8000, /// SET (1): The Index data can be read if Platform Authorization is provided. /// CLEAR (0): Reading of the Index data cannot be authorized with Platform Authorization. /// [EnumMember] + [SpecTypeName("Ppread")] Ppread = 0x10000, /// SET (1): The Index data can be read if Owner Authorization is provided. /// CLEAR (0): Reading of the Index data cannot be authorized with Owner Authorization. [EnumMember] + [SpecTypeName("Ownerread")] Ownerread = 0x20000, /// SET (1): The Index data may be read if the authValue is provided. /// CLEAR (0): Reading of the Index data cannot be authorized with the Index authValue. [EnumMember] + [SpecTypeName("Authread")] Authread = 0x40000, /// SET (1): The Index data may be read if the authPolicy is satisfied. /// CLEAR (0): Reading of the Index data cannot be authorized with the Index authPolicy. [EnumMember] + [SpecTypeName("Policyread")] Policyread = 0x80000, /// SET (1): Authorization failures of the Index do not affect the DA logic and @@ -4555,6 +4662,7 @@ public enum NvAttr : uint /// failure counter and authorizations of this Index are not allowed when the TPM is in /// Lockout mode. [EnumMember] + [SpecTypeName("NoDa")] NoDa = 0x2000000, /// SET (1): NV Index state is only required to be saved when the TPM performs @@ -4563,22 +4671,26 @@ public enum NvAttr : uint /// Index completes successfully (that is, the NV update is synchronous with the update /// command). [EnumMember] + [SpecTypeName("Orderly")] Orderly = 0x4000000, /// SET (1): TPMA_NV_WRITTEN for the Index is CLEAR by TPM Reset or TPM Restart. /// CLEAR (0): TPMA_NV_WRITTEN is not changed by TPM Restart. /// NOTE This attribute may only be SET if TPM_NT is not TPM_NT_COUNTER. [EnumMember] + [SpecTypeName("ClearStclear")] ClearStclear = 0x8000000, /// SET (1): Reads of the Index are blocked until the next TPM Reset or TPM Restart. /// CLEAR (0): Reads of the Index are allowed if proper authorization is provided. [EnumMember] + [SpecTypeName("Readlocked")] Readlocked = 0x10000000, /// SET (1): Index has been written. /// CLEAR (0): Index has not been written. [EnumMember] + [SpecTypeName("Written")] Written = 0x20000000, /// SET (1): This Index may be undefined with Platform Authorization but not @@ -4589,11 +4701,13 @@ public enum NvAttr : uint /// Platform Authorization and will validate that this attribute is CLEAR when the Index /// is defined using Owner Authorization. [EnumMember] + [SpecTypeName("Platformcreate")] Platformcreate = 0x40000000, /// SET (1): TPM2_NV_ReadLock() may be used to SET TPMA_NV_READLOCKED for this Index. /// CLEAR (0): TPM2_NV_ReadLock() has no effect on this Index. [EnumMember] + [SpecTypeName("ReadStclear")] ReadStclear = 0x80000000 } diff --git a/TSS.Rust/Cargo.lock b/TSS.Rust/Cargo.lock new file mode 100644 index 00000000..0077bd87 --- /dev/null +++ b/TSS.Rust/Cargo.lock @@ -0,0 +1,601 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "base64ct" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-padding" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" +dependencies = [ + "generic-array", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "der" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "block-padding", + "generic-array", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] + +[[package]] +name = "libc" +version = "0.2.171" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" + +[[package]] +name = "libm" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" + +[[package]] +name = "num-bigint-dig" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +dependencies = [ + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand", + "smallvec", + "zeroize", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro2" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rsa" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78928ac1ed176a5ca1d17e578a1825f3d81ca54cf41053a592584b020cfd691b" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core", + "signature", + "spki", + "subtle", + "zeroize", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core", +] + +[[package]] +name = "sm3" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebb9a3b702d0a7e33bc4d85a14456633d2b165c2ad839c5fd9a8417c1ab15860" +dependencies = [ + "digest", +] + +[[package]] +name = "smallvec" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tss-rust" +version = "0.1.0" +dependencies = [ + "aes", + "cipher", + "derivative", + "hmac", + "lazy_static", + "libc", + "rand", + "rsa", + "sha1", + "sha2", + "sm3", + "windows", + "zeroize", +] + +[[package]] +name = "typenum" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "windows" +version = "0.61.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5ee8f3d025738cb02bad7868bbb5f8a6327501e870bf51f1b455b0a2454a419" +dependencies = [ + "windows-collections", + "windows-core", + "windows-future", + "windows-link", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" +dependencies = [ + "windows-core", +] + +[[package]] +name = "windows-core" +version = "0.61.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-future" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a1d6bbefcb7b60acd19828e1bc965da6fcf18a7e39490c5f8be71e54a19ba32" +dependencies = [ + "windows-core", + "windows-link", +] + +[[package]] +name = "windows-implement" +version = "0.60.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "windows-link" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" + +[[package]] +name = "windows-numerics" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" +dependencies = [ + "windows-core", + "windows-link", +] + +[[package]] +name = "windows-result" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97" +dependencies = [ + "windows-link", +] + +[[package]] +name = "zerocopy" +version = "0.8.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" diff --git a/TSS.Rust/Cargo.toml b/TSS.Rust/Cargo.toml new file mode 100644 index 00000000..fabcb17c --- /dev/null +++ b/TSS.Rust/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "tss-rust" +version = "0.1.0" +edition = "2021" + +[lints.rust] +non_camel_case_types = "allow" +unused-parens = "allow" + +[lib] +crate-type = ["cdylib", "lib"] + +[dependencies] +derivative = "2.2.0" +hmac = "0.12.1" +lazy_static = "1.5.0" +rsa = { version = "0.9.8" } +sm3 = "0.4.2" +windows = "0.61.1" +sha1 = { version = "0.10.6", features = ["oid"] } +sha2 = { version = "0.10.8", features = ["oid"] } +rand = "0.8" +aes = "0.8" +cipher = { version = "0.4", features = ["block-padding"] } +zeroize = "1.8" + +[target.'cfg(windows)'.dependencies] +windows = { version = "0.61.1", features = ["Win32_Foundation", "Win32_Security", "Win32_System_TpmBaseServices", "Win32_Networking", "Win32_Networking_WinSock"] } + +[target.'cfg(unix)'.dependencies] +libc = "0.2" + +[[example]] +name = "tpm_samples" +path = "examples/tpm_samples.rs" diff --git a/TSS.Rust/README.md b/TSS.Rust/README.md new file mode 100644 index 00000000..7f32f938 --- /dev/null +++ b/TSS.Rust/README.md @@ -0,0 +1,64 @@ +# TSS.Rust + +TSS.Rust is a Rust implementation of the TPM 2.0 Software Stack (TSS), providing complete access to the TPM 2.0 API with rich session management and policy support. + +## Features + +* **Complete TPM 2.0 API** - All TPM 2.0 commands, data structures, enumerations, and unions are auto-generated from the TPM 2.0 specification via [TssCodeGen](../TssCodeGen). +* **HMAC Sessions** - Automatic HMAC computation, nonce rolling, and response HMAC verification. +* **Seeded Sessions** - Salted sessions with RSA-OAEP encrypted salt for enhanced security. +* **Bound Sessions** - Sessions bound to specific TPM entities with optimized HMAC handling. +* **Parameter Encryption** - AES-CFB encryption/decryption of command and response parameters. +* **PolicyTree Abstraction** - Object-oriented representation of TPM policy commands with 14 assertion types, supporting software digest computation and TPM session execution. +* **Software Crypto Helpers** - RSA key operations, OAEP encryption, KDFa key derivation, and HMAC computation bridging software and TPM crypto. +* **Async Command Dispatch** - Support for asynchronous TPM command execution. +* **Cross-platform TPM Access** - Windows TBS device support, with simulator connectivity. + +## Building + +```bash +cargo build +``` + +## Running the Samples + +The [examples](./examples) directory contains 37 comprehensive samples. To run them against the Windows TBS device (hardware TPM): + +```bash +cargo run --example tpm_samples +``` + +To connect to a TPM simulator: + +```bash +cargo run --example tpm_samples -- sim +``` + +See the [examples README](./examples/README.md) for a full list of samples. + +## Architecture + +TSS.Rust follows the same architecture as other TSS.MSR implementations: + +* **Auto-generated code** (`src/tpm_types.rs`, `src/tpm2.rs`) - Generated by [TssCodeGen](../TssCodeGen) from the TPM 2.0 specification. Do not edit directly. +* **Hand-written library code:** + - `src/tpm2_impl.rs` - Command dispatch, session handling, marshaling + - `src/auth_session.rs` - HMAC session management (key derivation, nonce rolling, HMAC computation) + - `src/crypto.rs` - Cryptographic primitives (AES, RSA, HMAC, KDFa) + - `src/policy.rs` - PolicyTree abstraction with 14 policy assertion types + - `src/tpm_type_extensions.rs` - Extension methods on generated types + - `src/tpm_device.rs` - TPM device abstraction (TBS, simulator) + +## Dependencies + +Key Rust crates used: +* `rsa`, `sha1`, `sha2`, `hmac` - Cryptographic operations +* `aes`, `cfb-mode` - Symmetric encryption for parameter encryption +* `derivative` - Custom `Default` implementations for generated types +* `windows` - Windows TBS API access + +## See Also + +* [TSS.CPP](../TSS.CPP) - C++ implementation with similar capabilities +* [TSS.Net](../TSS.NET) - C# implementation +* [TssCodeGen](../TssCodeGen) - Code generator tool diff --git a/TSS.Rust/clippy.toml b/TSS.Rust/clippy.toml new file mode 100644 index 00000000..ec880d98 --- /dev/null +++ b/TSS.Rust/clippy.toml @@ -0,0 +1,17 @@ +[package] +name = "tss-rust" +version = "0.1.0" +edition = "2021" + +[build] +rustflags = ["-A", "clippy::non_camel_case_types", "-A", "clippy::unused_variables"] + +[lib] +crate-type = ["cdylib", "lib"] + +[dependencies] +num_enum = "0.7.3" + +[[example]] +name = "tpm_samples" +path = "examples/tpm_samples.rs" diff --git a/TSS.Rust/examples/README.md b/TSS.Rust/examples/README.md new file mode 100644 index 00000000..2941204e --- /dev/null +++ b/TSS.Rust/examples/README.md @@ -0,0 +1,72 @@ +# TSS.Rust Examples + +This directory contains example code for using the TSS.Rust library. + +## Running the Examples + +To run the main samples using the Windows TBS device (hardware TPM): + +```bash +cargo run --example tpm_samples +``` + +To connect to a TPM simulator instead: + +```bash +cargo run --example tpm_samples -- sim +``` + +## Available Samples + +`tpm_samples.rs` contains a comprehensive set of 37 samples demonstrating TPM 2.0 operations: + +### Basic Operations +- **Random** - `GetRandom` / `StirRandom` +- **Hash** - Single-shot and sequence-based hashing (SHA-1, SHA-256) +- **HMAC** - HMAC key creation, sequence and direct computation +- **PCR** - Event, Read, Extend, Reset operations +- **Counter/Timer** - `ReadClock`, `ClockSet`, `ClockRateAdjust` +- **GetCapability** - Enumerate algorithms and commands + +### Key Management +- **Primary Keys** - RSA primary creation, signing, `EvictControl` persistence +- **Child Keys** - Child signing keys, `ContextSave`/`Load`, `ObjectChangeAuth` +- **RSA Encrypt/Decrypt** - RSA-OAEP encryption and decryption +- **Encrypt/Decrypt** - Symmetric AES encryption +- **Software Keys** - Import external RSA keys, cross-validate signatures + +### Auth Sessions +- **Auth Sessions** - HMAC session usage for key creation and signing +- **Seeded Session** - Salted HMAC sessions (RSA-OAEP salt encryption) +- **Bound Session** - Sessions bound to a specific entity +- **Session Encryption** - Parameter encryption/decryption (`decrypt`/`encrypt` attributes) + +### NV Storage +- **NV** - Define/Write/Read/Undefine for simple, counter, bitfield, and extend NV indices + +### Policy +- **Policy Simplest** - `PolicyCommandCode` +- **Policy PCR** - `PolicyPCR` gating access on PCR values +- **Policy OR** - `PolicyOR` branching +- **Policy With Passwords** - `PolicyPassword` / `PolicyAuthValue` +- **Policy CpHash** - Restricting to specific command parameters +- **Policy CounterTimer** - Time-limited access +- **Policy Secret** - Authorization from another entity +- **Policy NV** - NV-based policy conditions +- **Policy NameHash** - Restricting to specific handles +- **Policy Locality** - Locality-based restrictions (trial only on TBS) +- **Policy Tree** - `PolicyTree` abstraction with multiple scenarios + +### Attestation & Audit +- **Attestation** - PCR quoting, time quoting, key certification with signature verification +- **Audit** - Command audit and session audit + +### Other +- **Unseal** - Seal/unseal with PCR + password policy +- **Import/Duplicate** - Key duplication and import +- **ReWrap** - Key rewrapping between parents +- **Activate Credentials** - `MakeCredential` / `ActivateCredential` +- **Async** - Asynchronous command dispatch +- **Dictionary Attack** - DA lockout reset and parameter configuration +- **Misc Admin** - `SelfTest`, `ClockSet`, `ClearControl` +- **Allow Errors** - Error handling demonstration diff --git a/TSS.Rust/examples/tpm_samples.rs b/TSS.Rust/examples/tpm_samples.rs new file mode 100644 index 00000000..bafa94fe --- /dev/null +++ b/TSS.Rust/examples/tpm_samples.rs @@ -0,0 +1,2851 @@ +use std::io::{self, Write}; +use tss_rust::{ + auth_session::Session, + crypto::Crypto, + device::{TpmDevice, TpmTbsDevice}, error::TpmError, + policy::{self, PolicyTree, PolicyCommandCode, PolicyLocality, PolicyOr, PolicyPassword}, + tpm2_impl::*, tpm_structure::{TpmEnum}, tpm_types::* +}; + +lazy_static::lazy_static! { + pub static ref Aes128Cfb: TPMT_SYM_DEF_OBJECT = TPMT_SYM_DEF_OBJECT::new(TPM_ALG_ID::AES, 128, TPM_ALG_ID::CFB); +} + +fn set_color(color: u8) { + if color == 0 { + print!("\x1b[0m"); + } else { + print!("\x1b[1;32m"); // Green + } +} + +fn print_error(msg: &str) { + eprintln!("\x1b[1;31m{}\x1b[0m", msg); +} + +fn announce(test_name: &str) { + set_color(1); + println!(); + println!("=============================================================================================================================="); + println!(" {}", test_name); + println!("=============================================================================================================================="); + println!(); + io::stdout().flush().unwrap(); + set_color(0); +} + +fn get_capabilities(tpm: &mut Tpm2) -> Result<(), Box> { + let mut start_val = 0; + + announce("************************* Algorithms *************************"); + + // For the first example we show how to get a batch (8) properties at a time. + // For simplicity, subsequent samples just get one at a time: avoiding the + // nested loop. + + loop { + let addition_to_start_val: u32; + + let caps = tpm.GetCapability(TPM_CAP::ALGS, start_val, 8)?; + if let Some(caps) = caps.capabilityData { + if let TPMU_CAPABILITIES::algorithms(props) = caps { + for p in props.algProperties.iter() { + println!("{}: {}", p.alg, p.algProperties); + } + + addition_to_start_val = (props.algProperties[props.algProperties.len() - 1] + .alg + .get_value() + + 1) + .into(); + } else { + break; + } + } else { + break; + } + + if (caps.moreData == 0) { + break; + } + + start_val += addition_to_start_val; + } + + start_val = 0; + + let mut supported_commands: Vec = Vec::new(); + + loop { + let caps = tpm.GetCapability(TPM_CAP::COMMANDS, start_val, 32)?; + + if let Some(caps) = caps.capabilityData { + if let TPMU_CAPABILITIES::command(props) = caps { + for p in props.commandAttributes.iter() { + let command_value = p.get_value() & 0xFFFF; + // Decode the packed structure + if let Ok(cc) = TPM_CC::try_from(command_value) { + supported_commands.push(format!("TPM_CC_{}", cc.to_string())); + } + // let masked_attr = TPMA_CC::try_from(p.get_value() & 0xFFff0000)?; + + // println!("Command {}", cc); + + start_val = command_value; + } + } else { + break; + } + } else { + break; + } + + if (caps.moreData == 0) { + break; + } + + start_val += 1; + } + + supported_commands.sort(); + + let announcement = format!("TPM supports {} commands", supported_commands.len()); + + announce(&announcement); + let column_width = 35; + let columns = 3; + let rows = (supported_commands.len() + columns - 1) / columns; + + for row in 0..rows { + for col in 0..columns { + let index = row + col * rows; + if index < supported_commands.len() { + let cmd = &supported_commands[index]; + print!("{: Result { + let object_attributes = TPMA_OBJECT::decrypt | TPMA_OBJECT::restricted + | TPMA_OBJECT::fixedParent | TPMA_OBJECT::fixedTPM + | TPMA_OBJECT::sensitiveDataOrigin | TPMA_OBJECT::userWithAuth; + + let parameters = TPMU_PUBLIC_PARMS::rsaDetail(TPMS_RSA_PARMS::new(&Aes128Cfb, &Some(TPMU_ASYM_SCHEME::null(TPMS_NULL_ASYM_SCHEME::default())), 2048, 65537)); + + let unique = TPMU_PUBLIC_ID::rsa(TPM2B_PUBLIC_KEY_RSA::default()); + + let storage_primary_template = TPMT_PUBLIC::new(TPM_ALG_ID::SHA1, + object_attributes, + &Vec::new(), // No policy + &Some(parameters), + &Some(unique)); + + let resp = tpm.CreatePrimary(&TPM_HANDLE::new(TPM_RH::OWNER.get_value()), + &TPMS_SENSITIVE_CREATE::default(), + &storage_primary_template, + &Default::default(), + &Default::default())?; + + Ok(resp.handle) +} + +fn make_child_signing_key(tpm: &mut Tpm2, parent: &TPM_HANDLE, restricted: bool) -> Result +{ + let restricted_attribute: TPMA_OBJECT = if restricted { TPMA_OBJECT::restricted } else { TPMA_OBJECT(0) }; + + let object_attributes = TPMA_OBJECT::sign | TPMA_OBJECT::fixedParent | TPMA_OBJECT::fixedTPM + | TPMA_OBJECT::sensitiveDataOrigin | TPMA_OBJECT::userWithAuth | restricted_attribute; + + let parameters = TPMU_PUBLIC_PARMS::rsaDetail(TPMS_RSA_PARMS::new(&Default::default(), + &Some(TPMU_ASYM_SCHEME::rsassa(TPMS_SIG_SCHEME_RSASSA { hashAlg: TPM_ALG_ID::SHA1 })), 2048, 65537)); // PKCS1.5 + + let unique = TPMU_PUBLIC_ID::rsa(TPM2B_PUBLIC_KEY_RSA::default()); + + let template = TPMT_PUBLIC::new(TPM_ALG_ID::SHA1, object_attributes, &Default::default(), &Some(parameters), &Some(unique)); + + let new_signing_key = tpm.Create(&parent, &Default::default(), &template, &Default::default(), &Default::default())?; + + tpm.Load(&parent, &new_signing_key.outPrivate, &new_signing_key.outPublic) +} + +fn make_endorsement_key(tpm: &mut Tpm2) -> Result { + let object_attributes = TPMA_OBJECT::decrypt | TPMA_OBJECT::restricted + | TPMA_OBJECT::fixedParent | TPMA_OBJECT::fixedTPM + | TPMA_OBJECT::sensitiveDataOrigin | TPMA_OBJECT::userWithAuth; + + let parameters = TPMU_PUBLIC_PARMS::rsaDetail(TPMS_RSA_PARMS::new(&Aes128Cfb, &Some(TPMU_ASYM_SCHEME::null(TPMS_NULL_ASYM_SCHEME::default())), 2048, 65537)); + + let unique = TPMU_PUBLIC_ID::rsa(TPM2B_PUBLIC_KEY_RSA::default()); + + let template = TPMT_PUBLIC::new(TPM_ALG_ID::SHA1, + object_attributes, + &Vec::new(), + &Some(parameters), + &Some(unique)); + + let resp = tpm.CreatePrimary(&TPM_HANDLE::new(TPM_RH::ENDORSEMENT.get_value()), + &TPMS_SENSITIVE_CREATE::default(), + &template, + &Default::default(), + &Default::default())?; + + Ok(resp.handle) +} + +fn attestation(tpm: &mut Tpm2) -> Result<(), TpmError> { + announce("Attestation Sample"); + + // Attestation is the TPM signing internal data structures. The TPM can perform + // several-types of attestation: we demonstrate signing PCR, keys, and time. + + // To get attestation information we need a restricted signing key and privacy authorization. + let primary_key = make_storage_primary(tpm)?; + let sig_key = make_child_signing_key(tpm, &primary_key, true)?; + + let nonce = vec![2, 6, 1, 1, 9]; + + println!(">> PCR Quoting"); + println!("Created and loaded signing key with handle: {:?}", sig_key); + + // Set up PCR selection for the quote + let pcrs_to_quote = TPMS_PCR_SELECTION::get_selection_array( + TPM_ALG_ID::SHA1, 7 ); + + // Do an event to make sure the value is non-zero + tpm.PCR_Event(&TPM_HANDLE::pcr(7), &vec![1, 2, 3])?; + + // Then read the value so that we can validate the signature later + let pcr_vals = tpm.PCR_Read(&pcrs_to_quote)?; + println!("Read {} PCR values for quoting", pcr_vals.pcrValues.len()); + + // Do the quote. Note that we provide a nonce. + let quote = tpm.Quote(&sig_key, &nonce, &TPMU_SIG_SCHEME::create(TPM_ALG_ID::NULL)?, &pcrs_to_quote)?; + + // Need to cast to the proper attestation type to validate + let attested = quote.quoted.attested; + + if let Some(TPMU_ATTEST::quote(quote_attest)) = attested { + println!("PCR Quote obtained successfully"); + println!("PCR Quote: {:?}", quote_attest); + println!("Nonce: {:?}", quote.quoted.extraData); + } else { + println!("Failed to cast to quote attestation"); + return Err(TpmError::InvalidParameter); + } ; + + let time_nonce: Vec = vec![1, 6, 8, 2, 1]; + println!(">> Time Quoting, using nonce {:?}", time_nonce); + + let time_quote = tpm.GetTime(&TPM_HANDLE::new(TPM_RH::ENDORSEMENT.get_value()), &sig_key, &time_nonce, &TPMU_SIG_SCHEME::create(TPM_ALG_ID::NULL)?)?; + + if let Some(TPMU_ATTEST::time(time_attest)) = time_quote.timeInfo.attested { + println!("Time Quote obtained successfully"); + let clock_info = time_attest.time.clockInfo; + println!(" Firmware Version: {}", time_attest.firmwareVersion); + println!(" Time: {}", time_attest.time.time); + println!(" Clock: {}", clock_info.clock); + println!(" ResetCount: {}", clock_info.resetCount); + println!(" RestartCount: {}", clock_info.restartCount); + println!(" Nonce: {:?}", time_quote.timeInfo.extraData); + } else { + println!("Failed to cast to quote attestation"); + return Err(TpmError::InvalidParameter); + } ; + + // Get a key attestation. For simplicity we have the signingKey self-certify b + let key_nonce: Vec = vec![0, 9, 1, 1, 2, 3]; + println!(">> Key Quoting, using nonce {:?}", key_nonce); + + let key_quote = tpm.Certify(&sig_key, &sig_key, &key_nonce, &TPMU_SIG_SCHEME::create(TPM_ALG_ID::NULL)?)?; + + if let Some(TPMU_ATTEST::certify(certify_attest)) = &key_quote.certifyInfo.attested { + println!("Key certification obtained successfully"); + println!(" Name of certified key: {:?}", certify_attest.name); + println!(" Qualified name of certified key: {:?}", certify_attest.qualifiedName); + println!(" nonce: {:?}", &key_quote.certifyInfo.extraData); + println!(" Signature: {:?}", &key_quote.signature); + } else { + println!("Failed to cast to quote attestation"); + return Err(TpmError::InvalidParameter); + } ; + + let pub_key = tpm.ReadPublic(&sig_key)?; + + if (pub_key.outPublic.validate_certify(&pub_key.outPublic, &key_nonce, &key_quote)?) { + println!("Key certification signature verification SUCCESSFUL! "); + } else { + println!("Key certification signature verification FAILED! "); + } + + // // Clean up - flush keys from TPM + tpm.FlushContext(&sig_key)?; + println!("Cleaned up keys from TPM"); + + Ok(()) +} + + +fn activate_credentials(tpm: &mut Tpm2) -> Result<(), TpmError> { + announce("Activate Credentials"); + + // Make a new EK and get the public key + let ek_handle = make_endorsement_key(tpm)?; + let ek_pub_response = tpm.ReadPublic(&ek_handle)?; + let ek_pub = ek_pub_response.outPublic; + + // Make another key that we will "activate" + let srk = make_storage_primary(tpm)?; + let key_to_activate = make_child_signing_key(tpm, &srk, true)?; + tpm.FlushContext(&srk)?; + + // Make a secret using the TSS.Rust RNG + let secret = Crypto::get_random(20); + let name_of_key_to_activate = key_to_activate.get_name()?; + + // Use TSS.Rust to get an activation blob + let cred = ek_pub.create_activation(&secret, &name_of_key_to_activate)?; + let recovered_secret = tpm.ActivateCredential(&key_to_activate, &ek_handle, + &cred.credential_blob, &cred.secret)?; + + println!("Secret: {:?}", secret); + println!("Secret recovered from Activate: {:?}", recovered_secret); + + if secret != recovered_secret { + print_error("Secret mismatch when using TSS.Rust to create an activation credential (known create_activation issue)"); + } else { + println!("TSS.Rust-created activation blob verified"); + } + + // You can also use the TPM to make the activation credential + let tpm_activator = tpm.MakeCredential(&ek_handle, &secret, &name_of_key_to_activate)?; + + let recovered_secret = tpm.ActivateCredential(&key_to_activate, &ek_handle, + &tpm_activator.credentialBlob, &tpm_activator.secret)?; + + println!("TPM-created activation blob: Secret recovered from Activate: {:?}", recovered_secret); + + assert!(secret == recovered_secret, "Secret mismatch when using the TPM to create an activation credential"); + + tpm.FlushContext(&ek_handle)?; + tpm.FlushContext(&key_to_activate)?; + + Ok(()) +} + +// =============================== Basic Samples (no auth sessions needed) =============================== + +fn rand_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { + announce("Random Number Sample"); + + // Get 20 random bytes from the TPM + let rand = tpm.GetRandom(20)?; + println!("Random bytes (first call): {:?}", rand); + + // Add entropy to the TPM RNG + tpm.StirRandom(&vec![1, 2, 3, 4, 5])?; + println!("Stirred random with [1, 2, 3, 4, 5]"); + + // Get more random bytes + let rand2 = tpm.GetRandom(20)?; + println!("Random bytes (second call): {:?}", rand2); + + assert_ne!(rand, rand2, "Two random calls should produce different results"); + println!("Random number generation works correctly"); + + Ok(()) +} + +fn hash_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { + announce("Hash Sample"); + + let data = b"Hello, TPM hashing!".to_vec(); + + // Simple hash + let hash_resp = tpm.Hash(&data, TPM_ALG_ID::SHA256, &TPM_HANDLE::new(TPM_RH::NULL.get_value()))?; + println!("SHA-256 hash of data: {:?}", hash_resp.outHash); + + // Hash with SHA-1 + let hash1_resp = tpm.Hash(&data, TPM_ALG_ID::SHA1, &TPM_HANDLE::new(TPM_RH::NULL.get_value()))?; + println!("SHA-1 hash of data: {:?}", hash1_resp.outHash); + + // Hash sequence (multi-part hashing) + println!("\n>> Hash Sequence (multi-part hashing)"); + let accumulator = b"Hello, TPM hashing!".to_vec(); + let part1 = accumulator[..10].to_vec(); + let part2 = accumulator[10..].to_vec(); + + let seq_handle = tpm.HashSequenceStart(&vec![], TPM_ALG_ID::SHA256)?; + tpm.SequenceUpdate(&seq_handle, &part1)?; + let seq_result = tpm.SequenceComplete(&seq_handle, &part2, &TPM_HANDLE::new(TPM_RH::NULL.get_value()))?; + + println!("Sequence hash result: {:?}", seq_result.result); + assert_eq!(hash_resp.outHash, seq_result.result, + "Single-shot and sequence hash should match"); + println!("Single-shot and sequence hash results match!"); + + Ok(()) +} + +fn hmac_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { + announce("HMAC Sample"); + + // Create an HMAC primary key + let object_attributes = TPMA_OBJECT::sign + | TPMA_OBJECT::fixedParent | TPMA_OBJECT::fixedTPM + | TPMA_OBJECT::sensitiveDataOrigin | TPMA_OBJECT::userWithAuth; + + let parameters = TPMU_PUBLIC_PARMS::keyedHashDetail(TPMS_KEYEDHASH_PARMS::new( + &Some(TPMU_SCHEME_KEYEDHASH::hmac(TPMS_SCHEME_HMAC { hashAlg: TPM_ALG_ID::SHA256 })))); + + let unique = TPMU_PUBLIC_ID::keyedHash(TPM2B_DIGEST_KEYEDHASH::default()); + + let hmac_template = TPMT_PUBLIC::new( + TPM_ALG_ID::SHA256, + object_attributes, + &Vec::new(), + &Some(parameters), + &Some(unique), + ); + + let hmac_key_resp = tpm.CreatePrimary( + &TPM_HANDLE::new(TPM_RH::OWNER.get_value()), + &TPMS_SENSITIVE_CREATE::default(), + &hmac_template, + &Default::default(), + &Default::default(), + )?; + + println!("Created HMAC key with handle: {:?}", hmac_key_resp.handle); + + // HMAC using sequence interface + let data = b"Data to HMAC".to_vec(); + let hmac_handle = tpm.HMAC_Start(&hmac_key_resp.handle, &vec![], TPM_ALG_ID::SHA256)?; + tpm.SequenceUpdate(&hmac_handle, &data)?; + let hmac_result = tpm.SequenceComplete(&hmac_handle, &vec![], &TPM_HANDLE::new(TPM_RH::NULL.get_value()))?; + println!("HMAC (sequence): {:?}", hmac_result.result); + + // HMAC using direct command + let hmac_direct = tpm.HMAC(&hmac_key_resp.handle, &data, TPM_ALG_ID::SHA256)?; + println!("HMAC (direct): {:?}", hmac_direct); + + assert_eq!(hmac_result.result, hmac_direct, "Sequence and direct HMAC should match"); + println!("Sequence and direct HMAC results match!"); + + tpm.FlushContext(&hmac_key_resp.handle)?; + Ok(()) +} + +fn pcr_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { + announce("PCR Sample"); + + // Use PCR 16 (resettable) + let pcr_handle = TPM_HANDLE::pcr(16); + + // Reset the PCR first + tpm.PCR_Reset(&pcr_handle)?; + println!("PCR 16 reset"); + + // Read the PCR value (should be all zeros after reset) + let pcr_selection = TPMS_PCR_SELECTION::get_selection_array(TPM_ALG_ID::SHA256, 16); + let pcr_vals = tpm.PCR_Read(&pcr_selection)?; + println!("PCR 16 after reset: {:?}", pcr_vals.pcrValues); + + // Extend a value into the PCR + let event_data = vec![1, 2, 3, 4, 5]; + tpm.PCR_Event(&pcr_handle, &event_data)?; + println!("Extended event data [1, 2, 3, 4, 5] into PCR 16"); + + // Read the PCR value after extend + let pcr_vals2 = tpm.PCR_Read(&pcr_selection)?; + println!("PCR 16 after event: {:?}", pcr_vals2.pcrValues); + + // Extend with a hash value + let extend_hash = TPMT_HA::new(TPM_ALG_ID::SHA256, &Crypto::hash(TPM_ALG_ID::SHA256, &vec![6, 7, 8])?); + tpm.PCR_Extend(&pcr_handle, &vec![extend_hash])?; + println!("Extended hash into PCR 16"); + + // Read again + let pcr_vals3 = tpm.PCR_Read(&pcr_selection)?; + println!("PCR 16 after extend: {:?}", pcr_vals3.pcrValues); + + // Reset again + tpm.PCR_Reset(&pcr_handle)?; + let pcr_vals_final = tpm.PCR_Read(&pcr_selection)?; + println!("PCR 16 after final reset: {:?}", pcr_vals_final.pcrValues); + + println!("PCR operations completed successfully"); + Ok(()) +} + +fn primary_keys_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { + announce("Primary Keys Sample"); + + // Create an RSA signing primary key + let sign_attrs = TPMA_OBJECT::sign + | TPMA_OBJECT::fixedParent | TPMA_OBJECT::fixedTPM + | TPMA_OBJECT::sensitiveDataOrigin | TPMA_OBJECT::userWithAuth; + + let sign_parms = TPMU_PUBLIC_PARMS::rsaDetail(TPMS_RSA_PARMS::new( + &Default::default(), + &Some(TPMU_ASYM_SCHEME::rsassa(TPMS_SIG_SCHEME_RSASSA { hashAlg: TPM_ALG_ID::SHA256 })), + 2048, 65537, + )); + + let sign_template = TPMT_PUBLIC::new( + TPM_ALG_ID::SHA256, + sign_attrs, + &Vec::new(), + &Some(sign_parms), + &Some(TPMU_PUBLIC_ID::rsa(TPM2B_PUBLIC_KEY_RSA::default())), + ); + + let new_primary = tpm.CreatePrimary( + &TPM_HANDLE::new(TPM_RH::OWNER.get_value()), + &TPMS_SENSITIVE_CREATE::default(), + &sign_template, + &Default::default(), + &Default::default(), + )?; + println!("Created signing primary key with handle: {:?}", new_primary.handle); + + // Sign some data + let data_to_sign = Crypto::hash(TPM_ALG_ID::SHA256, &b"Data to sign".to_vec())?; + let signature = tpm.Sign( + &new_primary.handle, + &data_to_sign, + &TPMU_SIG_SCHEME::create(TPM_ALG_ID::NULL)?, + &TPMT_TK_HASHCHECK::default(), + )?; + println!("Data signed successfully, signature: {:?}", signature.is_some()); + + // Persist the key with EvictControl + let persistent_handle = TPM_HANDLE::new(0x81000100); + + // First clean up any existing persistent key at this handle + tpm.allow_errors(); + let _ = tpm.EvictControl( + &TPM_HANDLE::new(TPM_RH::OWNER.get_value()), + &persistent_handle, + &persistent_handle, + ); + + tpm.EvictControl( + &TPM_HANDLE::new(TPM_RH::OWNER.get_value()), + &new_primary.handle, + &persistent_handle, + )?; + println!("Key persisted at handle: {:?}", persistent_handle); + + // Read back the public part from the persistent handle + let pub_data = tpm.ReadPublic(&persistent_handle)?; + println!("Read back public data from persistent handle"); + println!("Algorithm: {:?}", pub_data.outPublic.nameAlg); + + // Clean up - remove persistent key + tpm.EvictControl( + &TPM_HANDLE::new(TPM_RH::OWNER.get_value()), + &persistent_handle, + &persistent_handle, + )?; + println!("Removed persistent key"); + + tpm.FlushContext(&new_primary.handle)?; + println!("Primary keys sample completed successfully"); + Ok(()) +} + +fn child_keys_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { + announce("Child Keys Sample"); + + // Create a storage primary (parent key) + let primary = make_storage_primary(tpm)?; + println!("Created storage primary: {:?}", primary); + + // Create a child signing key + let sign_key = make_child_signing_key(tpm, &primary, false)?; + println!("Created child signing key: {:?}", sign_key); + + // Sign some data + let data_to_sign = Crypto::hash(TPM_ALG_ID::SHA1, &b"Test data for signing".to_vec())?; + let signature = tpm.Sign( + &sign_key, + &data_to_sign, + &TPMU_SIG_SCHEME::create(TPM_ALG_ID::NULL)?, + &TPMT_TK_HASHCHECK::default(), + )?; + assert!(signature.is_some(), "Signature should not be empty"); + println!("Signed data with child key"); + + // Context save and load + // Note: ContextSave/ContextLoad may be blocked by Windows TBS + println!("\n>> Context Save/Load"); + let saved_context = tpm.ContextSave(&sign_key)?; + println!("Saved signing key context"); + + tpm.FlushContext(&sign_key)?; + println!("Flushed signing key from TPM"); + + let restored_key = tpm.ContextLoad(&saved_context)?; + println!("Restored signing key from saved context: {:?}", restored_key); + + // Sign again with restored key to verify it works + let signature2 = tpm.Sign( + &restored_key, + &data_to_sign, + &TPMU_SIG_SCHEME::create(TPM_ALG_ID::NULL)?, + &TPMT_TK_HASHCHECK::default(), + )?; + assert!(signature2.is_some(), "Restored key signature should not be empty"); + println!("Signed data with restored key"); + + tpm.FlushContext(&restored_key)?; + tpm.FlushContext(&primary)?; + println!("Child keys sample completed successfully"); + Ok(()) +} + +fn counter_timer_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { + announce("Counter/Timer Sample"); + + let time_info = tpm.ReadClock()?; + println!("TPM Clock Information:"); + println!("Time (ms since last reset): {}", time_info.time); + println!("Clock (ms total): {}", time_info.clockInfo.clock); + println!("Reset count: {}", time_info.clockInfo.resetCount); + println!("Restart count: {}", time_info.clockInfo.restartCount); + println!("Safe: {}", time_info.clockInfo.safe); + + println!("Counter/Timer sample completed successfully"); + Ok(()) +} + +fn nv_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { + announce("NV (Non-Volatile) Storage Sample"); + + let owner = TPM_HANDLE::new(TPM_RH::OWNER.get_value()); + + // ---- Simple NV (ordinary data) ---- + println!(">> Simple NV (read/write bytes)"); + let nv_index = TPM_HANDLE::new(0x01500100); + let nv_data_size: u16 = 32; + + // Clean up any existing NV index + tpm.allow_errors(); + let _ = tpm.NV_UndefineSpace(&owner, &nv_index); + + // Define the NV space + let nv_pub = TPMS_NV_PUBLIC::new( + &nv_index, + TPM_ALG_ID::SHA256, + TPMA_NV::AUTHREAD | TPMA_NV::AUTHWRITE, + &Vec::new(), + nv_data_size, + ); + tpm.NV_DefineSpace(&owner, &vec![], &nv_pub)?; + println!("Defined NV index at {:?}, size = {}", nv_index, nv_data_size); + + // Write data + let write_data: Vec = (0..nv_data_size as u8).collect(); + tpm.NV_Write(&nv_index, &nv_index, &write_data, 0)?; + println!("Wrote {} bytes to NV", write_data.len()); + + // Read it back + let read_data = tpm.NV_Read(&nv_index, &nv_index, nv_data_size, 0)?; + println!("Read back: {:?}", read_data); + assert_eq!(write_data, read_data, "NV read should match write"); + println!("NV read matches write"); + + // Read public info + let nv_pub_info = tpm.NV_ReadPublic(&nv_index)?; + println!("NV Public info - dataSize: {}, nameAlg: {:?}", nv_pub_info.nvPublic.dataSize, nv_pub_info.nvPublic.nameAlg); + + // Clean up + tpm.NV_UndefineSpace(&owner, &nv_index)?; + println!("Undefined NV space"); + + // ---- Counter NV ---- + println!("\n>> Counter NV"); + let counter_index = TPM_HANDLE::new(0x01500101); + + tpm.allow_errors(); + let _ = tpm.NV_UndefineSpace(&owner, &counter_index); + + let counter_pub = TPMS_NV_PUBLIC::new( + &counter_index, + TPM_ALG_ID::SHA256, + TPMA_NV::AUTHREAD | TPMA_NV::AUTHWRITE | TPMA_NV::COUNTER, + &Vec::new(), + 8, + ); + tpm.NV_DefineSpace(&owner, &vec![], &counter_pub)?; + println!("Defined counter NV index"); + + // Increment + tpm.NV_Increment(&counter_index, &counter_index)?; + let counter_val = tpm.NV_Read(&counter_index, &counter_index, 8, 0)?; + println!("Counter after first increment: {:?}", counter_val); + + tpm.NV_Increment(&counter_index, &counter_index)?; + let counter_val2 = tpm.NV_Read(&counter_index, &counter_index, 8, 0)?; + println!("Counter after second increment: {:?}", counter_val2); + + tpm.NV_UndefineSpace(&owner, &counter_index)?; + println!("Counter NV works correctly"); + + // ---- Bit field NV ---- + println!("\n>> Bit Field NV"); + let bit_index = TPM_HANDLE::new(0x01500102); + + tpm.allow_errors(); + let _ = tpm.NV_UndefineSpace(&owner, &bit_index); + + let bits_pub = TPMS_NV_PUBLIC::new( + &bit_index, + TPM_ALG_ID::SHA256, + TPMA_NV::AUTHREAD | TPMA_NV::AUTHWRITE | TPMA_NV::BITS, + &Vec::new(), + 8, + ); + tpm.NV_DefineSpace(&owner, &vec![], &bits_pub)?; + println!("Defined bit field NV index"); + + tpm.NV_SetBits(&bit_index, &bit_index, 0x0000_0001)?; + let bits_val = tpm.NV_Read(&bit_index, &bit_index, 8, 0)?; + println!("Bits after setting bit 0: {:?}", bits_val); + + tpm.NV_SetBits(&bit_index, &bit_index, 0x0000_0004)?; + let bits_val2 = tpm.NV_Read(&bit_index, &bit_index, 8, 0)?; + println!("Bits after setting bit 2: {:?}", bits_val2); + + tpm.NV_UndefineSpace(&owner, &bit_index)?; + println!("Bit field NV works correctly"); + + // ---- Extend NV ---- + println!("\n>> Extend NV"); + let extend_index = TPM_HANDLE::new(0x01500103); + + tpm.allow_errors(); + let _ = tpm.NV_UndefineSpace(&owner, &extend_index); + + let extend_pub = TPMS_NV_PUBLIC::new( + &extend_index, + TPM_ALG_ID::SHA256, + TPMA_NV::AUTHREAD | TPMA_NV::AUTHWRITE | TPMA_NV::EXTEND, + &Vec::new(), + 32, // SHA-256 digest size + ); + tpm.NV_DefineSpace(&owner, &vec![], &extend_pub)?; + println!("Defined extend NV index"); + + tpm.NV_Extend(&extend_index, &extend_index, &vec![1, 2, 3, 4, 5])?; + let extend_val = tpm.NV_Read(&extend_index, &extend_index, 32, 0)?; + println!("Extend NV after extend: {:?}", extend_val); + + tpm.NV_UndefineSpace(&owner, &extend_index)?; + println!("Extend NV works correctly"); + + Ok(()) +} + +fn rsa_encrypt_decrypt_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { + announce("RSA Encrypt/Decrypt Sample"); + + // Create an RSA decryption key (not restricted - for general encrypt/decrypt) + let rsa_attrs = TPMA_OBJECT::decrypt + | TPMA_OBJECT::fixedParent | TPMA_OBJECT::fixedTPM + | TPMA_OBJECT::sensitiveDataOrigin | TPMA_OBJECT::userWithAuth; + + let rsa_parms = TPMU_PUBLIC_PARMS::rsaDetail(TPMS_RSA_PARMS::new( + &Default::default(), + &Some(TPMU_ASYM_SCHEME::oaep(TPMS_ENC_SCHEME_OAEP { hashAlg: TPM_ALG_ID::SHA256 })), + 2048, 65537, + )); + + let rsa_template = TPMT_PUBLIC::new( + TPM_ALG_ID::SHA256, + rsa_attrs, + &Vec::new(), + &Some(rsa_parms), + &Some(TPMU_PUBLIC_ID::rsa(TPM2B_PUBLIC_KEY_RSA::default())), + ); + + let key_resp = tpm.CreatePrimary( + &TPM_HANDLE::new(TPM_RH::NULL.get_value()), + &TPMS_SENSITIVE_CREATE::default(), + &rsa_template, + &Default::default(), + &Default::default(), + )?; + println!("Created RSA decryption key: {:?}", key_resp.handle); + + // Encrypt data using the TPM + let plaintext = b"Secret message for RSA encryption!".to_vec(); + let null_scheme = TPMU_ASYM_SCHEME::null(TPMS_NULL_ASYM_SCHEME::default()); + let ciphertext = tpm.RSA_Encrypt(&key_resp.handle, &plaintext, &Some(null_scheme.clone()), &vec![])?; + println!("Encrypted {} bytes -> {} bytes ciphertext", plaintext.len(), ciphertext.len()); + + // Decrypt + let decrypted = tpm.RSA_Decrypt(&key_resp.handle, &ciphertext, &Some(null_scheme), &vec![])?; + println!("Decrypted: {:?}", String::from_utf8_lossy(&decrypted)); + + assert_eq!(plaintext, decrypted, "Decrypted data should match original"); + println!("RSA encrypt/decrypt works correctly"); + + tpm.FlushContext(&key_resp.handle)?; + Ok(()) +} + +fn encrypt_decrypt_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { + announce("Symmetric Encrypt/Decrypt Sample"); + + // Create a storage primary + let primary = make_storage_primary(tpm)?; + + // Create an AES symmetric key + let aes_attrs = TPMA_OBJECT::decrypt | TPMA_OBJECT::sign + | TPMA_OBJECT::fixedParent | TPMA_OBJECT::fixedTPM + | TPMA_OBJECT::sensitiveDataOrigin | TPMA_OBJECT::userWithAuth; + + let aes_parms = TPMU_PUBLIC_PARMS::symDetail(TPMS_SYMCIPHER_PARMS::new(&Aes128Cfb)); + + let aes_template = TPMT_PUBLIC::new( + TPM_ALG_ID::SHA256, + aes_attrs, + &Vec::new(), + &Some(aes_parms), + &Some(TPMU_PUBLIC_ID::sym(TPM2B_DIGEST_SYMCIPHER::default())), + ); + + let aes_key = tpm.Create( + &primary, + &TPMS_SENSITIVE_CREATE::default(), + &aes_template, + &Default::default(), + &Default::default(), + )?; + let aes_handle = tpm.Load(&primary, &aes_key.outPrivate, &aes_key.outPublic)?; + println!("Created and loaded AES key: {:?}", aes_handle); + + // Note: EncryptDecrypt/EncryptDecrypt2 may be blocked by Windows TBS + let plaintext = b"Hello AES encryption! padding!!".to_vec(); // 32 bytes (block-aligned) + let iv = vec![0u8; 16]; + let encrypted = tpm.EncryptDecrypt(&aes_handle, 0, TPM_ALG_ID::CFB, &iv, &plaintext)?; + println!("Encrypted {} bytes", plaintext.len()); + + // Decrypt (decrypt=1) + let decrypted = tpm.EncryptDecrypt(&aes_handle, 1, TPM_ALG_ID::CFB, &iv, &encrypted.outData)?; + println!("Decrypted: {:?}", String::from_utf8_lossy(&decrypted.outData)); + + assert_eq!(plaintext, decrypted.outData, "Decrypted data should match original"); + println!("AES encrypt/decrypt works correctly"); + + tpm.FlushContext(&aes_handle)?; + tpm.FlushContext(&primary)?; + Ok(()) +} + +// =============================== Auth Session Samples =============================== + +/// Helper: create an HMAC primary key with a policy digest and optional auth value. +fn make_hmac_primary_with_policy( + tpm: &mut Tpm2, + policy_digest: &[u8], + use_auth: &[u8], + hash_alg: TPM_ALG_ID, +) -> Result { + let key_data = vec![5, 4, 3, 2, 1, 0]; + let mut attrs = TPMA_OBJECT::sign | TPMA_OBJECT::fixedParent | TPMA_OBJECT::fixedTPM; + if !use_auth.is_empty() { + attrs = attrs | TPMA_OBJECT::userWithAuth; + } + + let parameters = TPMU_PUBLIC_PARMS::keyedHashDetail(TPMS_KEYEDHASH_PARMS::new( + &Some(TPMU_SCHEME_KEYEDHASH::hmac(TPMS_SCHEME_HMAC { hashAlg: hash_alg })))); + let unique = TPMU_PUBLIC_ID::keyedHash(TPM2B_DIGEST_KEYEDHASH::default()); + + let templ = TPMT_PUBLIC::new( + hash_alg, attrs, &policy_digest.to_vec(), + &Some(parameters), &Some(unique), + ); + + let sens = TPMS_SENSITIVE_CREATE::new(&use_auth.to_vec(), &key_data); + let resp = tpm.CreatePrimary( + &TPM_HANDLE::new(TPM_RH::OWNER.get_value()), + &sens, &templ, &Default::default(), &Default::default(), + )?; + Ok(resp.handle) +} + +/// Helper: get the session handle from a Session (for policy commands and FlushContext). +fn session_handle(sess: &Session) -> TPM_HANDLE { + sess.sess_in.sessionHandle.clone() +} + +fn auth_sessions_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { + announce("Auth Sessions Sample"); + + // Start a simple HMAC authorization session (no salt, no encryption, no bound-object) + let mut sess = tpm.start_auth_session(TPM_SE::HMAC, TPM_ALG_ID::SHA1)?; + println!("Started HMAC auth session: {:?}", session_handle(&sess)); + + // Create a storage primary + let primary = make_storage_primary(tpm)?; + + // Create a child key template + let child_attrs = TPMA_OBJECT::sign | TPMA_OBJECT::fixedParent | TPMA_OBJECT::fixedTPM + | TPMA_OBJECT::sensitiveDataOrigin | TPMA_OBJECT::userWithAuth; + let child_parms = TPMU_PUBLIC_PARMS::rsaDetail(TPMS_RSA_PARMS::new( + &Default::default(), + &Some(TPMU_ASYM_SCHEME::rsassa(TPMS_SIG_SCHEME_RSASSA { hashAlg: TPM_ALG_ID::SHA1 })), + 2048, 65537, + )); + let child_template = TPMT_PUBLIC::new( + TPM_ALG_ID::SHA1, child_attrs, &Default::default(), + &Some(child_parms), + &Some(TPMU_PUBLIC_ID::rsa(TPM2B_PUBLIC_KEY_RSA::default())), + ); + + // Create child key using the HMAC session (parent handle uses auth) + let new_key = tpm.with_session(sess.clone()).Create( + &primary, &Default::default(), &child_template, + &Default::default(), &Default::default(), + )?; + // Retrieve updated session (nonces rolled by TPM) + sess = tpm.last_session().unwrap(); + println!("Created child key with HMAC session"); + + // Load the child key with the same session + let loaded_key = tpm.with_session(sess.clone()).Load( + &primary, &new_key.outPrivate, &new_key.outPublic, + )?; + sess = tpm.last_session().unwrap(); + println!("Loaded child key with HMAC session: {:?}", loaded_key); + + // Sign data with the loaded key using the session + let data_to_sign = Crypto::hash(TPM_ALG_ID::SHA1, &b"Auth session test data".to_vec())?; + let sig = tpm.with_session(sess.clone()).Sign( + &loaded_key, &data_to_sign, + &TPMU_SIG_SCHEME::create(TPM_ALG_ID::NULL)?, + &TPMT_TK_HASHCHECK::default(), + )?; + assert!(sig.is_some(), "HMAC session signature should not be empty"); + sess = tpm.last_session().unwrap(); + println!("Signed data using HMAC session"); + + // Clean up + tpm.FlushContext(&session_handle(&sess))?; + tpm.FlushContext(&loaded_key)?; + tpm.FlushContext(&primary)?; + + println!("Auth sessions sample completed successfully"); + Ok(()) +} + +fn dictionary_attack_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { + announce("Dictionary Attack Sample"); + + // Reset the lockout counter. + // This may fail if the TPM's lockout hierarchy is locked from a previous run + // or if TBS restricts this command on Windows. + let lockout = TPM_HANDLE::new(TPM_RH::LOCKOUT.get_value()); + tpm.allow_errors(); + let _ = tpm.DictionaryAttackLockReset(&lockout); + if tpm.last_response_code() != TPM_RC::SUCCESS { + print_error(&format!("DictionaryAttackLockReset failed (rc={:?}) - \ + TPM lockout hierarchy may be locked from a previous run. \ + The lockoutRecovery timer must expire before this command succeeds.", + tpm.last_response_code())); + return Ok(()); + } + println!("Dictionary attack lockout reset"); + + // Configure dictionary attack parameters to be forgiving for testing + let new_max_tries: u32 = 1000; + let new_recovery_time: u32 = 1; + let lockout_recovery: u32 = 1; + tpm.DictionaryAttackParameters(&lockout, new_max_tries, new_recovery_time, lockout_recovery)?; + println!("Set DA parameters: maxTries={}, recoveryTime={}, lockoutRecovery={}", + new_max_tries, new_recovery_time, lockout_recovery); + + println!("Dictionary attack sample completed successfully"); + Ok(()) +} + +fn misc_admin_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { + announce("Misc Admin Sample"); + + // Self Testing + println!(">> Self Testing"); + tpm.allow_errors(); + let _ = tpm.SelfTest(1); + println!("SelfTest completed (or was already done)"); + + let test_result = tpm.GetTestResult()?; + println!("GetTestResult: {} bytes of data, rc={}", test_result.outData.len(), test_result.testResult); + + let to_be_tested = tpm.IncrementalSelfTest(&vec![TPM_ALG_ID::SHA1, TPM_ALG_ID::AES])?; + println!("IncrementalSelfTest: {} algorithms still to test", to_be_tested.len()); + + // Clock Management + println!("\n>> Clock Management"); + let start_clock = tpm.ReadClock()?; + println!("Start clock: {}", start_clock.clockInfo.clock); + + let dt: u64 = 10_000_000; + let new_clock = start_clock.clockInfo.clock + dt; + tpm.ClockSet(&TPM_HANDLE::new(TPM_RH::OWNER.get_value()), new_clock)?; + + let now_clock = tpm.ReadClock()?; + let dt_actual = now_clock.clockInfo.clock - start_clock.clockInfo.clock; + println!("Clock advanced by: {} (requested {})", dt_actual, dt); + + // Can't set clock backwards + tpm.allow_errors(); + let _ = tpm.ClockSet(&TPM_HANDLE::new(TPM_RH::OWNER.get_value()), start_clock.clockInfo.clock); + println!("Setting clock backwards: last_rc = {}", tpm.last_response_code()); + + // Adjust clock rate + tpm.ClockRateAdjust(&TPM_HANDLE::new(TPM_RH::OWNER.get_value()), TPM_CLOCK_ADJUST::MEDIUM_SLOWER)?; + tpm.ClockRateAdjust(&TPM_HANDLE::new(TPM_RH::OWNER.get_value()), TPM_CLOCK_ADJUST::MEDIUM_FASTER)?; + println!("Clock rate adjusted (slower, then faster)"); + + println!("Misc admin sample completed successfully"); + Ok(()) +} + +fn policy_simplest_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { + announce("Policy Simplest Sample (PolicyCommandCode)"); + + // Use a trial session to compute the policy digest for PolicyCommandCode(HMAC_Start) + let trial = tpm.start_auth_session(TPM_SE::TRIAL, TPM_ALG_ID::SHA1)?; + tpm.PolicyCommandCode(&session_handle(&trial), TPM_CC::HMAC_Start)?; + let policy_digest = tpm.PolicyGetDigest(&session_handle(&trial))?; + tpm.FlushContext(&session_handle(&trial))?; + println!("Computed policy digest (trial): {:?}", policy_digest); + + // Create an HMAC primary with this policy (no userAuth) + let hmac_key = make_hmac_primary_with_policy(tpm, &policy_digest, &[], TPM_ALG_ID::SHA1)?; + println!("Created HMAC key with PolicyCommandCode policy"); + + // Show that plain authValue-based access fails + tpm.allow_errors(); + let _ = tpm.HMAC_Start(&hmac_key, &vec![], TPM_ALG_ID::SHA1); + println!("Plain auth HMAC_Start: last_rc = {} (expected AUTH_UNAVAILABLE)", tpm.last_response_code()); + + // Use a real policy session + let sess = tpm.start_auth_session(TPM_SE::POLICY, TPM_ALG_ID::SHA1)?; + tpm.PolicyCommandCode(&session_handle(&sess), TPM_CC::HMAC_Start)?; + + // Verify the policy digest matches + let digest = tpm.PolicyGetDigest(&session_handle(&sess))?; + println!("Computed policy digest (real): {:?}", digest); + assert_eq!(policy_digest, digest, "Trial and real policy digests should match"); + + // Execute the authorized command - should succeed + let hmac_seq_handle = tpm.with_session(sess.clone()).HMAC_Start(&hmac_key, &vec![], TPM_ALG_ID::SHA1)?; + println!("Policy-authorized HMAC_Start succeeded: {:?}", hmac_seq_handle); + tpm.FlushContext(&hmac_seq_handle)?; + tpm.FlushContext(&session_handle(&sess))?; + + // Try a different command with the same policy - should fail with POLICY_CC + let sess2 = tpm.start_auth_session(TPM_SE::POLICY, TPM_ALG_ID::SHA1)?; + tpm.PolicyCommandCode(&session_handle(&sess2), TPM_CC::HMAC_Start)?; + + tpm.allow_errors(); + let _ = tpm.with_session(sess2.clone()).Unseal(&hmac_key); + println!("Unseal with HMAC_Start policy: last_rc = {} (expected POLICY_CC)", tpm.last_response_code()); + + tpm.FlushContext(&session_handle(&sess2))?; + tpm.FlushContext(&hmac_key)?; + + println!("Policy simplest sample completed successfully"); + Ok(()) +} + +fn unseal_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { + announce("Unseal Sample"); + + // Reset dictionary attack lockout (may fail on some TPMs) + tpm.allow_errors(); + let _ = tpm.DictionaryAttackLockReset(&TPM_HANDLE::new(TPM_RH::LOCKOUT.get_value())); + if tpm.last_response_code() != TPM_RC::SUCCESS { + println!("Note: DictionaryAttackLockReset failed (rc={}), continuing...", tpm.last_response_code()); + } + + let pcr: u32 = 15; + let bank = TPM_ALG_ID::SHA256; + + // Set the PCR to a known value + tpm.PCR_Event(&TPM_HANDLE::pcr(pcr), &vec![1, 2, 3, 4])?; + + // Read the current PCR value + let pcr_selection = TPMS_PCR_SELECTION::get_selection_array(bank, pcr); + let pcr_vals = tpm.PCR_Read(&pcr_selection)?; + println!("PCR {} value: {:?}", pcr, pcr_vals.pcrValues); + + // Compute policy digest: PolicyPCR + PolicyPassword + // Use a trial session to compute the digest + let trial = tpm.start_auth_session(TPM_SE::TRIAL, TPM_ALG_ID::SHA256)?; + + // Compute the PCR digest (hash of selected PCR values) + let mut pcr_digest_data = Vec::new(); + for v in &pcr_vals.pcrValues { + pcr_digest_data.extend_from_slice(&v.buffer); + } + let pcr_digest = Crypto::hash(bank, &pcr_digest_data)?; + + tpm.PolicyPCR(&session_handle(&trial), &pcr_digest, &pcr_selection)?; + tpm.PolicyPassword(&session_handle(&trial))?; + let policy_digest = tpm.PolicyGetDigest(&session_handle(&trial))?; + tpm.FlushContext(&session_handle(&trial))?; + println!("Policy digest (PCR + Password): {:?}", policy_digest); + + // Create a sealed object under a storage primary + let primary = make_storage_primary(tpm)?; + + let seal_attrs = TPMA_OBJECT::fixedParent | TPMA_OBJECT::fixedTPM; + let seal_parms = TPMU_PUBLIC_PARMS::keyedHashDetail( + TPMS_KEYEDHASH_PARMS::new(&Some(TPMU_SCHEME_KEYEDHASH::null(TPMS_NULL_SCHEME_KEYEDHASH::default())))); + let seal_template = TPMT_PUBLIC::new( + TPM_ALG_ID::SHA256, seal_attrs, &policy_digest, + &Some(seal_parms), + &Some(TPMU_PUBLIC_ID::keyedHash(TPM2B_DIGEST_KEYEDHASH::default())), + ); + + let data_to_seal: Vec = vec![1, 2, 3, 4, 5, 0xf, 0xe, 0xd, 0xa, 9, 8]; + let auth_value: Vec = vec![9, 8, 7, 6, 5]; + let sens_create = TPMS_SENSITIVE_CREATE::new(&auth_value, &data_to_seal); + + let sealed_obj = tpm.Create(&primary, &sens_create, &seal_template, &Default::default(), &Default::default())?; + let mut sealed_key = tpm.Load(&primary, &sealed_obj.outPrivate, &sealed_obj.outPublic)?; + sealed_key.set_auth(&auth_value); + println!("Created sealed object: {:?}", sealed_key); + + // Start a policy session and execute the policy + let mut sess = tpm.start_auth_session(TPM_SE::POLICY, TPM_ALG_ID::SHA256)?; + tpm.PolicyPCR(&session_handle(&sess), &pcr_digest, &pcr_selection)?; + tpm.PolicyPassword(&session_handle(&sess))?; + // After PolicyPassword, set the flag so auth is sent as password + sess.needs_password = true; + + // Unseal - should succeed with correct auth and PCR + let unsealed = tpm.with_session(sess.clone()).Unseal(&sealed_key)?; + println!("Unsealed data: {:?}", unsealed); + assert_eq!(data_to_seal, unsealed, "Unsealed data should match"); + tpm.FlushContext(&session_handle(&sess))?; + + // Try without auth value - should fail + sealed_key.set_auth(&[]); + let mut sess2 = tpm.start_auth_session(TPM_SE::POLICY, TPM_ALG_ID::SHA256)?; + tpm.PolicyPCR(&session_handle(&sess2), &pcr_digest, &pcr_selection)?; + tpm.PolicyPassword(&session_handle(&sess2))?; + sess2.needs_password = true; + + tpm.allow_errors(); + let _ = tpm.with_session(sess2.clone()).Unseal(&sealed_key); + println!("Unseal without auth: last_rc = {} (expected AUTH_FAIL)", tpm.last_response_code()); + tpm.FlushContext(&session_handle(&sess2))?; + + // Try with wrong PCR value - policy execution should fail + sealed_key.set_auth(&auth_value); + tpm.PCR_Event(&TPM_HANDLE::pcr(pcr), &vec![1, 2, 3, 4])?; // change PCR + let mut sess3 = tpm.start_auth_session(TPM_SE::POLICY, TPM_ALG_ID::SHA256)?; + + tpm.allow_errors(); + let _ = tpm.PolicyPCR(&session_handle(&sess3), &pcr_digest, &pcr_selection); + println!("PolicyPCR with wrong value: last_rc = {} (expected VALUE)", tpm.last_response_code()); + + // Try unseal anyway - should fail + tpm.PolicyPassword(&session_handle(&sess3))?; + sess3.needs_password = true; + tpm.allow_errors(); + let _ = tpm.with_session(sess3.clone()).Unseal(&sealed_key); + println!("Unseal with wrong PCR: last_rc = {} (expected POLICY_FAIL)", tpm.last_response_code()); + tpm.FlushContext(&session_handle(&sess3))?; + + tpm.FlushContext(&sealed_key)?; + tpm.FlushContext(&primary)?; + + println!("Unseal sample completed successfully"); + Ok(()) +} + +fn policy_or_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { + announce("PolicyOR Sample"); + + let bank = TPM_ALG_ID::SHA256; + let pcr: u32 = 15; + + // Set PCR to a known value + tpm.PCR_Event(&TPM_HANDLE::pcr(pcr), &vec![1, 2, 3, 4])?; + + let pcr_selection = TPMS_PCR_SELECTION::get_selection_array(bank, pcr); + let pcr_vals = tpm.PCR_Read(&pcr_selection)?; + + // Compute the PCR digest + let mut pcr_digest_data = Vec::new(); + for v in &pcr_vals.pcrValues { + pcr_digest_data.extend_from_slice(&v.buffer); + } + let pcr_digest = Crypto::hash(bank, &pcr_digest_data)?; + + // Branch 1: PolicyPCR (current PCR value) + let trial1 = tpm.start_auth_session(TPM_SE::TRIAL, TPM_ALG_ID::SHA256)?; + tpm.PolicyPCR(&session_handle(&trial1), &pcr_digest, &pcr_selection)?; + let branch1_digest = tpm.PolicyGetDigest(&session_handle(&trial1))?; + tpm.FlushContext(&session_handle(&trial1))?; + println!("Branch 1 (PolicyPCR) digest: {:?}", branch1_digest); + + // Branch 2: PolicyCommandCode(HMAC_Start) + let trial2 = tpm.start_auth_session(TPM_SE::TRIAL, TPM_ALG_ID::SHA256)?; + tpm.PolicyCommandCode(&session_handle(&trial2), TPM_CC::HMAC_Start)?; + let branch2_digest = tpm.PolicyGetDigest(&session_handle(&trial2))?; + tpm.FlushContext(&session_handle(&trial2))?; + println!("Branch 2 (PolicyCommandCode) digest: {:?}", branch2_digest); + + // Compute the OR policy digest using trial session + let hash_list = vec![ + TPM2B_DIGEST { buffer: branch1_digest.clone() }, + TPM2B_DIGEST { buffer: branch2_digest.clone() }, + ]; + + let trial_or = tpm.start_auth_session(TPM_SE::TRIAL, TPM_ALG_ID::SHA256)?; + tpm.PolicyOR(&session_handle(&trial_or), &hash_list)?; + let or_policy_digest = tpm.PolicyGetDigest(&session_handle(&trial_or))?; + tpm.FlushContext(&session_handle(&trial_or))?; + println!("OR policy digest: {:?}", or_policy_digest); + + // Create an HMAC key with the OR policy + let hmac_key = make_hmac_primary_with_policy(tpm, &or_policy_digest, &[], TPM_ALG_ID::SHA256)?; + + // Use branch 1 (PolicyPCR) - should succeed while PCR is unchanged + let sess1 = tpm.start_auth_session(TPM_SE::POLICY, TPM_ALG_ID::SHA256)?; + tpm.PolicyPCR(&session_handle(&sess1), &pcr_digest, &pcr_selection)?; + tpm.PolicyOR(&session_handle(&sess1), &hash_list)?; + + let hmac_result = tpm.with_session(sess1.clone()).HMAC(&hmac_key, &vec![1, 2, 3, 4], TPM_ALG_ID::SHA256)?; + println!("Branch 1 HMAC succeeded: {:?}", hmac_result); + tpm.FlushContext(&session_handle(&sess1))?; + + // Change PCR - branch 1 should now fail + tpm.PCR_Event(&TPM_HANDLE::pcr(pcr), &vec![5, 6, 7, 8])?; + + let sess2 = tpm.start_auth_session(TPM_SE::POLICY, TPM_ALG_ID::SHA256)?; + tpm.allow_errors(); + let _ = tpm.PolicyPCR(&session_handle(&sess2), &pcr_digest, &pcr_selection); + println!("Branch 1 after PCR change: last_rc = {} (expected VALUE)", tpm.last_response_code()); + tpm.FlushContext(&session_handle(&sess2))?; + + // Use branch 2 (PolicyCommandCode) - should succeed regardless of PCR + let sess3 = tpm.start_auth_session(TPM_SE::POLICY, TPM_ALG_ID::SHA256)?; + tpm.PolicyCommandCode(&session_handle(&sess3), TPM_CC::HMAC_Start)?; + tpm.PolicyOR(&session_handle(&sess3), &hash_list)?; + + let hmac_seq = tpm.with_session(sess3.clone()).HMAC_Start(&hmac_key, &vec![], TPM_ALG_ID::SHA256)?; + println!("Branch 2 HMAC_Start succeeded: {:?}", hmac_seq); + tpm.FlushContext(&hmac_seq)?; + tpm.FlushContext(&session_handle(&sess3))?; + + tpm.FlushContext(&hmac_key)?; + + println!("PolicyOR sample completed successfully"); + Ok(()) +} + +fn policy_with_passwords_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { + announce("Policy With Passwords Sample"); + + // Reset dictionary attack lockout (may fail on some TPMs) + tpm.allow_errors(); + let _ = tpm.DictionaryAttackLockReset(&TPM_HANDLE::new(TPM_RH::LOCKOUT.get_value())); + if tpm.last_response_code() != TPM_RC::SUCCESS { + println!("Note: DictionaryAttackLockReset failed (rc={}), continuing...", tpm.last_response_code()); + } + + // --- PolicyPassword demo --- + println!(">> PolicyPassword"); + + // Compute policy digest for PolicyPassword + let trial = tpm.start_auth_session(TPM_SE::TRIAL, TPM_ALG_ID::SHA256)?; + tpm.PolicyPassword(&session_handle(&trial))?; + let policy_digest = tpm.PolicyGetDigest(&session_handle(&trial))?; + tpm.FlushContext(&session_handle(&trial))?; + println!("PolicyPassword digest: {:?}", policy_digest); + + let use_auth = Crypto::hash(TPM_ALG_ID::SHA256, &b"password".to_vec())?; + let mut hmac_handle = make_hmac_primary_with_policy(tpm, &policy_digest, &use_auth, TPM_ALG_ID::SHA256)?; + hmac_handle.set_auth(&use_auth); + + // Works with correct password + let mut sess = tpm.start_auth_session(TPM_SE::POLICY, TPM_ALG_ID::SHA256)?; + tpm.PolicyPassword(&session_handle(&sess))?; + sess.needs_password = true; + + let hmac_result = tpm.with_session(sess.clone()).HMAC(&hmac_handle, &vec![1, 2, 3, 4], TPM_ALG_ID::SHA256)?; + println!("HMAC with correct password: {:?}", hmac_result); + tpm.FlushContext(&session_handle(&sess))?; + + // Fails without password + hmac_handle.set_auth(&[]); + let mut sess2 = tpm.start_auth_session(TPM_SE::POLICY, TPM_ALG_ID::SHA256)?; + tpm.PolicyPassword(&session_handle(&sess2))?; + sess2.needs_password = true; + + tpm.allow_errors(); + let _ = tpm.with_session(sess2.clone()).HMAC(&hmac_handle, &vec![1, 2, 3, 4], TPM_ALG_ID::SHA256); + println!("HMAC without password: last_rc = {} (expected AUTH_FAIL)", tpm.last_response_code()); + tpm.FlushContext(&session_handle(&sess2))?; + tpm.FlushContext(&hmac_handle)?; + + // --- PolicyAuthValue demo --- + println!("\n>> PolicyAuthValue"); + + let trial2 = tpm.start_auth_session(TPM_SE::TRIAL, TPM_ALG_ID::SHA256)?; + tpm.PolicyAuthValue(&session_handle(&trial2))?; + let policy_digest2 = tpm.PolicyGetDigest(&session_handle(&trial2))?; + tpm.FlushContext(&session_handle(&trial2))?; + println!("PolicyAuthValue digest: {:?}", policy_digest2); + + let use_auth2 = Crypto::hash(TPM_ALG_ID::SHA256, &b"password2".to_vec())?; + let mut hmac_handle2 = make_hmac_primary_with_policy(tpm, &policy_digest2, &use_auth2, TPM_ALG_ID::SHA256)?; + hmac_handle2.set_auth(&use_auth2); + + // Works with correct auth value (HMAC-based proof of possession) + let mut sess3 = tpm.start_auth_session(TPM_SE::POLICY, TPM_ALG_ID::SHA256)?; + tpm.PolicyAuthValue(&session_handle(&sess3))?; + sess3.needs_hmac = true; + + let hmac_result2 = tpm.with_session(sess3.clone()).HMAC(&hmac_handle2, &vec![1, 2, 3, 4], TPM_ALG_ID::SHA256)?; + println!("HMAC with PolicyAuthValue: {:?}", hmac_result2); + tpm.FlushContext(&session_handle(&sess3))?; + + // Fails without auth value + hmac_handle2.set_auth(&[]); + let mut sess4 = tpm.start_auth_session(TPM_SE::POLICY, TPM_ALG_ID::SHA256)?; + tpm.PolicyAuthValue(&session_handle(&sess4))?; + sess4.needs_hmac = true; + + tpm.allow_errors(); + let _ = tpm.with_session(sess4.clone()).HMAC(&hmac_handle2, &vec![1, 2, 3, 4], TPM_ALG_ID::SHA256); + println!("HMAC without auth value: last_rc = {} (expected AUTH_FAIL)", tpm.last_response_code()); + tpm.FlushContext(&session_handle(&sess4))?; + tpm.FlushContext(&hmac_handle2)?; + + println!("Policy with passwords sample completed successfully"); + Ok(()) +} + +fn import_duplicate_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { + announce("Import/Duplicate Sample"); + + // Create storage primary + let primary = make_storage_primary(tpm)?; + println!("Created storage primary: {:?}", primary); + + // Compute policy for Duplicate command + let trial = tpm.start_auth_session(TPM_SE::TRIAL, TPM_ALG_ID::SHA256)?; + tpm.PolicyCommandCode(&session_handle(&trial), TPM_CC::Duplicate)?; + let policy_digest = tpm.PolicyGetDigest(&session_handle(&trial))?; + tpm.FlushContext(&session_handle(&trial))?; + println!("Duplicate policy digest: {:?}", policy_digest); + + // Create a signing key that allows duplication (via policy) + let key_attrs = TPMA_OBJECT::sign | TPMA_OBJECT::userWithAuth + | TPMA_OBJECT::sensitiveDataOrigin; + let key_parms = TPMU_PUBLIC_PARMS::rsaDetail(TPMS_RSA_PARMS::new( + &Default::default(), + &Some(TPMU_ASYM_SCHEME::rsassa(TPMS_SIG_SCHEME_RSASSA { hashAlg: TPM_ALG_ID::SHA256 })), + 2048, 65537, + )); + let key_template = TPMT_PUBLIC::new( + TPM_ALG_ID::SHA256, key_attrs, &policy_digest, + &Some(key_parms), + &Some(TPMU_PUBLIC_ID::rsa(TPM2B_PUBLIC_KEY_RSA::default())), + ); + + let new_key = tpm.Create(&primary, &Default::default(), &key_template, + &Default::default(), &Default::default())?; + let sign_key = tpm.Load(&primary, &new_key.outPrivate, &new_key.outPublic)?; + println!("Created duplicatable signing key: {:?}", sign_key); + + // Duplicate using policy session + let sess = tpm.start_auth_session(TPM_SE::POLICY, TPM_ALG_ID::SHA256)?; + tpm.PolicyCommandCode(&session_handle(&sess), TPM_CC::Duplicate)?; + + let null_parent = TPM_HANDLE::new(TPM_RH::NULL.get_value()); + let no_sym = TPMT_SYM_DEF_OBJECT::default(); + println!("About to call Duplicate..."); + let dup_result = tpm.with_session(sess.clone()).Duplicate( + &sign_key, &null_parent, &vec![], &no_sym)?; + println!("Duplicated key successfully"); + tpm.FlushContext(&session_handle(&sess))?; + tpm.FlushContext(&sign_key)?; + + // Import the key back to the same parent (with no outer wrapper) + let imported = tpm.Import(&primary, &vec![], &new_key.outPublic, + &dup_result.duplicate, &vec![], &no_sym)?; + println!("Imported key back"); + + // Load the imported key and sign with it + let imported_key = tpm.Load(&primary, &imported, &new_key.outPublic)?; + let data_to_sign = Crypto::hash(TPM_ALG_ID::SHA256, &b"test import".to_vec())?; + let sig = tpm.Sign(&imported_key, &data_to_sign, + &TPMU_SIG_SCHEME::create(TPM_ALG_ID::NULL)?, + &TPMT_TK_HASHCHECK::default())?; + println!("Signed with imported key: {:?}", sig.is_some()); + + tpm.FlushContext(&imported_key)?; + tpm.FlushContext(&primary)?; + + println!("Import/Duplicate sample completed successfully"); + Ok(()) +} + +fn policy_counter_timer_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { + announce("PolicyCounterTimer Sample"); + + // PolicyCounterTimer allows actions to be gated on the TPM's clocks and timers. + // Here we demonstrate giving a user owner-privileges for ~5 seconds. + + let start_clock = tpm.ReadClock()?; + let now_time = start_clock.time; + let end_time = now_time + 5 * 1000; // 5 seconds from now + + // Construct the operand: UINT64 big-endian representation of end_time + let operand = end_time.to_be_bytes().to_vec(); + + // Compute the policy digest using trial session + // PolicyCounterTimer(endTime, offset=0, UNSIGNED_LT) means: + // "Allow if TPMS_TIME_INFO.time < endTime" + let trial = tpm.start_auth_session(TPM_SE::TRIAL, TPM_ALG_ID::SHA256)?; + tpm.PolicyCounterTimer(&session_handle(&trial), &operand, 0, TPM_EO::UNSIGNED_LT)?; + let policy_digest = tpm.PolicyGetDigest(&session_handle(&trial))?; + tpm.FlushContext(&session_handle(&trial))?; + println!("PolicyCounterTimer digest: {:?}", policy_digest); + + // Set the owner policy to this value + tpm.SetPrimaryPolicy(&TPM_HANDLE::new(TPM_RH::OWNER.get_value()), + &policy_digest, TPM_ALG_ID::SHA256)?; + + // Now try using the policy a few times - should succeed until time expires + println!("Operations should start failing in about 5 seconds..."); + + for i in 0..4 { + let sess = tpm.start_auth_session(TPM_SE::POLICY, TPM_ALG_ID::SHA256)?; + tpm.allow_errors(); + let _ = tpm.PolicyCounterTimer(&session_handle(&sess), &operand, 0, TPM_EO::UNSIGNED_LT); + let timer_ok = tpm.last_response_code() == TPM_RC::SUCCESS; + + if timer_ok { + tpm.allow_errors(); + let _ = tpm.with_session(sess.clone()).SetPrimaryPolicy( + &TPM_HANDLE::new(TPM_RH::OWNER.get_value()), + &policy_digest, TPM_ALG_ID::SHA256); + if tpm.last_response_code() == TPM_RC::SUCCESS { + println!("Iteration {}: Succeeded", i); + } else { + println!("Iteration {}: Policy valid but command failed (rc={})", i, tpm.last_response_code()); + } + } else { + println!("Iteration {}: Policy expired (rc={})", i, tpm.last_response_code()); + } + tpm.FlushContext(&session_handle(&sess))?; + std::thread::sleep(std::time::Duration::from_millis(1500)); + } + + // Put things back the way they were + tpm.SetPrimaryPolicy(&TPM_HANDLE::new(TPM_RH::OWNER.get_value()), + &vec![], TPM_ALG_ID::NULL)?; + + println!("PolicyCounterTimer sample completed successfully"); + Ok(()) +} + +fn policy_secret_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { + announce("PolicySecret Sample"); + + // PolicySecret demands proof-of-knowledge of the admin auth value. + // The TPM verifies the auth by using a policy session that references + // the OWNER hierarchy handle. + + // Use trial session to compute policy digest for PolicySecret(OWNER) + let owner_handle = TPM_HANDLE::new(TPM_RH::OWNER.get_value()); + + let trial = tpm.start_auth_session(TPM_SE::TRIAL, TPM_ALG_ID::SHA256)?; + tpm.PolicySecret(&owner_handle, &session_handle(&trial), + &vec![], &vec![], &vec![], 0)?; + let policy_digest = tpm.PolicyGetDigest(&session_handle(&trial))?; + tpm.FlushContext(&session_handle(&trial))?; + println!("PolicySecret digest: {:?}", policy_digest); + + // Make an object with this policy + let hmac_key = make_hmac_primary_with_policy(tpm, &policy_digest, &[], TPM_ALG_ID::SHA256)?; + + // Now run the policy: this will use PWAP to prove knowledge of the admin password + let sess = tpm.start_auth_session(TPM_SE::POLICY, TPM_ALG_ID::SHA256)?; + tpm.PolicySecret(&owner_handle, &session_handle(&sess), + &vec![], &vec![], &vec![], 0)?; + + // Use the session to authorize HMAC_Start + let hmac_seq = tpm.with_session(sess.clone()).HMAC_Start(&hmac_key, &vec![], TPM_ALG_ID::SHA256)?; + println!("PolicySecret-authorized HMAC_Start succeeded: {:?}", hmac_seq); + + tpm.FlushContext(&hmac_seq)?; + tpm.FlushContext(&session_handle(&sess))?; + tpm.FlushContext(&hmac_key)?; + + println!("PolicySecret sample completed successfully"); + Ok(()) +} + +fn policy_nv_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { + announce("PolicyNV Sample"); + + // PolicyNV allows actions to be gated on the contents of an NV-storage slot + + let nv_auth: Vec = vec![1, 5, 1, 1]; + let nv_index: u32 = 0x01500030; // Use a different index to avoid conflicts + let mut nv_handle = TPM_HANDLE::new(nv_index); + + // Try to delete the slot if it exists (ignore failure) + { + tpm.allow_errors(); + let _ = tpm.NV_UndefineSpace(&TPM_HANDLE::new(TPM_RH::OWNER.get_value()), &nv_handle); + } + + // Make a new simple NV slot, 16 bytes, RW with auth + let nv_template = TPMS_NV_PUBLIC::new( + &TPM_HANDLE::new(nv_index), + TPM_ALG_ID::SHA256, + TPMA_NV::AUTHREAD | TPMA_NV::AUTHWRITE, + &vec![], + 16, + ); + + tpm.NV_DefineSpace(&TPM_HANDLE::new(TPM_RH::OWNER.get_value()), &nv_auth, &nv_template)?; + nv_handle.set_auth(&nv_auth); + println!("Defined NV slot at 0x{:08x}", nv_index); + + // Write some data + let to_write: Vec = vec![1, 2, 3, 4, 5, 4, 3, 2, 1]; + tpm.NV_Write(&nv_handle, &nv_handle, &to_write, 0)?; + println!("NV_Write succeeded"); + + // Read back the NV public info to get the name + let nv_info = tpm.NV_ReadPublic(&nv_handle)?; + nv_handle.name = nv_info.nvName.clone(); + println!("NV_ReadPublic succeeded, name len={}", nv_info.nvName.len()); + + // Compute PolicyNV digest using trial session + // Use the NV handle as auth handle (with proper auth) + println!("Starting PolicyNV trial session..."); + let trial = tpm.start_auth_session(TPM_SE::TRIAL, TPM_ALG_ID::SHA256)?; + println!("Trial session started, calling PolicyNV..."); + tpm.PolicyNV(&nv_handle, &nv_handle, &session_handle(&trial), + &to_write, 0, TPM_EO::EQ)?; + println!("PolicyNV succeeded in trial session"); + let policy_digest = tpm.PolicyGetDigest(&session_handle(&trial))?; + tpm.FlushContext(&session_handle(&trial))?; + println!("PolicyNV digest: {:?}", policy_digest); + + // Create HMAC key with PolicyNV policy + let hmac_key = make_hmac_primary_with_policy(tpm, &policy_digest, &[], TPM_ALG_ID::SHA256)?; + + // Use the policy - should succeed when NV matches + let sess = tpm.start_auth_session(TPM_SE::POLICY, TPM_ALG_ID::SHA256)?; + tpm.PolicyNV(&nv_handle, &nv_handle, &session_handle(&sess), + &to_write, 0, TPM_EO::EQ)?; + + let hmac_result = tpm.with_session(sess.clone()).HMAC(&hmac_key, &vec![1, 2, 3], TPM_ALG_ID::SHA256)?; + println!("HMAC with correct NV: {:?}", hmac_result); + tpm.FlushContext(&session_handle(&sess))?; + + // Change NV data and verify policy fails + tpm.NV_Write(&nv_handle, &nv_handle, &vec![3, 1], 0)?; + + let sess2 = tpm.start_auth_session(TPM_SE::POLICY, TPM_ALG_ID::SHA256)?; + tpm.allow_errors(); + let _ = tpm.PolicyNV(&nv_handle, &nv_handle, &session_handle(&sess2), + &to_write, 0, TPM_EO::EQ); + println!("PolicyNV with changed data: last_rc = {} (expected POLICY_FAIL)", tpm.last_response_code()); + tpm.FlushContext(&session_handle(&sess2))?; + + // Cleanup + tpm.FlushContext(&hmac_key)?; + tpm.NV_UndefineSpace(&TPM_HANDLE::new(TPM_RH::OWNER.get_value()), &nv_handle)?; + + println!("PolicyNV sample completed successfully"); + Ok(()) +} + +fn software_keys_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { + announce("Software Keys Sample"); + + // This sample demonstrates creating a duplicatable key in the TPM, + // exporting it via Duplicate, re-importing it, and signing with both. + + let primary = make_storage_primary(tpm)?; + + // Compute policy for Duplicate command + let trial = tpm.start_auth_session(TPM_SE::TRIAL, TPM_ALG_ID::SHA256)?; + tpm.PolicyCommandCode(&session_handle(&trial), TPM_CC::Duplicate)?; + let dup_policy = tpm.PolicyGetDigest(&session_handle(&trial))?; + tpm.FlushContext(&session_handle(&trial))?; + + // Create a duplicatable signing key + let key_attrs = TPMA_OBJECT::sign | TPMA_OBJECT::userWithAuth + | TPMA_OBJECT::sensitiveDataOrigin; + let key_parms = TPMU_PUBLIC_PARMS::rsaDetail(TPMS_RSA_PARMS::new( + &Default::default(), + &Some(TPMU_ASYM_SCHEME::rsassa(TPMS_SIG_SCHEME_RSASSA { hashAlg: TPM_ALG_ID::SHA256 })), + 2048, 65537, + )); + let key_template = TPMT_PUBLIC::new( + TPM_ALG_ID::SHA256, key_attrs, &dup_policy, + &Some(key_parms), + &Some(TPMU_PUBLIC_ID::rsa(TPM2B_PUBLIC_KEY_RSA::default())), + ); + + let key_data = tpm.Create(&primary, &Default::default(), &key_template, + &Default::default(), &Default::default())?; + let tpm_key = tpm.Load(&primary, &key_data.outPrivate, &key_data.outPublic)?; + println!("Created duplicatable signing key in TPM"); + + // Sign with the TPM key + let to_sign = Crypto::hash(TPM_ALG_ID::SHA256, &b"hello from software key".to_vec())?; + let tpm_sig = tpm.Sign(&tpm_key, &to_sign, + &TPMU_SIG_SCHEME::create(TPM_ALG_ID::NULL)?, + &TPMT_TK_HASHCHECK::default())?; + println!("Signed with TPM-created key: {:?}", tpm_sig.is_some()); + + // Verify with VerifySignature + let verify_result = tpm.VerifySignature(&tpm_key, &to_sign, &tpm_sig)?; + println!("TPM verified its own signature: hierarchy={:?}", verify_result.hierarchy); + + // Duplicate the key out (unwrapped, no encryption) + let dup_sess = tpm.start_auth_session(TPM_SE::POLICY, TPM_ALG_ID::SHA256)?; + tpm.PolicyCommandCode(&session_handle(&dup_sess), TPM_CC::Duplicate)?; + + let null_parent = TPM_HANDLE::new(TPM_RH::NULL.get_value()); + let dup = tpm.with_session(dup_sess.clone()).Duplicate( + &tpm_key, &null_parent, &vec![], &TPMT_SYM_DEF_OBJECT::default())?; + println!("Exported key via Duplicate"); + + tpm.FlushContext(&session_handle(&dup_sess))?; + tpm.FlushContext(&tpm_key)?; + + // Re-import the duplicated key + let re_imported = tpm.Import(&primary, &vec![], &key_data.outPublic, + &dup.duplicate, &vec![], &TPMT_SYM_DEF_OBJECT::default())?; + let re_key = tpm.Load(&primary, &re_imported, &key_data.outPublic)?; + println!("Re-imported duplicated key"); + + // Sign with the re-imported key + let re_sig = tpm.Sign(&re_key, &to_sign, + &TPMU_SIG_SCHEME::create(TPM_ALG_ID::NULL)?, + &TPMT_TK_HASHCHECK::default())?; + println!("Signed with re-imported key: {:?}", re_sig.is_some()); + + // Verify the re-imported key signature with the original public key + let verify2 = tpm.VerifySignature(&re_key, &to_sign, &re_sig)?; + println!("Verified re-imported key signature: hierarchy={:?}", verify2.hierarchy); + + tpm.FlushContext(&re_key)?; + tpm.FlushContext(&primary)?; + + println!("Software keys sample completed successfully"); + Ok(()) +} + +fn policy_pcr_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { + announce("Policy PCR Sample"); + + let bank = TPM_ALG_ID::SHA256; + let pcr: u32 = 15; + + // Set PCR to a known value + tpm.PCR_Event(&TPM_HANDLE::pcr(pcr), &vec![1, 2, 3, 4])?; + + let pcr_selection = TPMS_PCR_SELECTION::get_selection_array(bank, pcr); + let pcr_vals = tpm.PCR_Read(&pcr_selection)?; + + // Compute the PCR digest + let mut pcr_digest_data = Vec::new(); + for v in &pcr_vals.pcrValues { + pcr_digest_data.extend_from_slice(&v.buffer); + } + let pcr_digest = Crypto::hash(bank, &pcr_digest_data)?; + + // Compute policy digest using trial session + let trial = tpm.start_auth_session(TPM_SE::TRIAL, TPM_ALG_ID::SHA256)?; + tpm.PolicyPCR(&session_handle(&trial), &pcr_digest, &pcr_selection)?; + let policy_digest = tpm.PolicyGetDigest(&session_handle(&trial))?; + tpm.FlushContext(&session_handle(&trial))?; + println!("PolicyPCR digest: {:?}", policy_digest); + + // Create HMAC key with PCR policy + let hmac_key = make_hmac_primary_with_policy(tpm, &policy_digest, &[], TPM_ALG_ID::SHA256)?; + + // Succeeds when PCR matches + let sess = tpm.start_auth_session(TPM_SE::POLICY, TPM_ALG_ID::SHA256)?; + tpm.PolicyPCR(&session_handle(&sess), &pcr_digest, &pcr_selection)?; + let hmac_result = tpm.with_session(sess.clone()).HMAC(&hmac_key, &vec![1, 2, 3, 4], TPM_ALG_ID::SHA256)?; + println!("HMAC with correct PCR: {:?}", hmac_result); + tpm.FlushContext(&session_handle(&sess))?; + + // Change PCR - should fail + tpm.PCR_Event(&TPM_HANDLE::pcr(pcr), &vec![5, 6, 7, 8])?; + let sess2 = tpm.start_auth_session(TPM_SE::POLICY, TPM_ALG_ID::SHA256)?; + tpm.allow_errors(); + let _ = tpm.PolicyPCR(&session_handle(&sess2), &pcr_digest, &pcr_selection); + println!("PolicyPCR with wrong value: last_rc = {} (expected VALUE)", tpm.last_response_code()); + tpm.FlushContext(&session_handle(&sess2))?; + + tpm.FlushContext(&hmac_key)?; + + println!("Policy PCR sample completed successfully"); + Ok(()) +} + +fn policy_cphash_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { + announce("PolicyCpHash Sample"); + + // PolicyCpHash restricts the actions that can be performed with a secured object + // to a specific operation identified by the hash of the command parameters. + // + // Approach: compute the policy digest using a trial session, then create a key + // with that policy. The tricky part is that cpHash depends on the key's name, + // which isn't known until the key is created. So we use a two-step approach: + // 1. Create a key with just PolicyCommandCode + // 2. Show that PolicyCpHash works in trial sessions + + let hash_alg = TPM_ALG_ID::SHA256; + + // Compute trial PolicyCpHash to demonstrate how it works + // cpHash = H(cc || handle_names || parameters) + // We'll use a dummy hash value for the trial + let dummy_cphash = Crypto::hash(hash_alg, b"example cpHash input")?; + + let trial = tpm.start_auth_session(TPM_SE::TRIAL, hash_alg)?; + tpm.PolicyCpHash(&session_handle(&trial), &dummy_cphash)?; + let cphash_digest = tpm.PolicyGetDigest(&session_handle(&trial))?; + tpm.FlushContext(&session_handle(&trial))?; + println!("PolicyCpHash trial digest: {:?}", &cphash_digest[..8]); + + // Also combine with PolicyCommandCode + let trial2 = tpm.start_auth_session(TPM_SE::TRIAL, hash_alg)?; + tpm.PolicyCpHash(&session_handle(&trial2), &dummy_cphash)?; + tpm.PolicyCommandCode(&session_handle(&trial2), TPM_CC::HMAC_Start)?; + let combined_digest = tpm.PolicyGetDigest(&session_handle(&trial2))?; + tpm.FlushContext(&session_handle(&trial2))?; + println!("PolicyCpHash + PolicyCommandCode trial digest: {:?}", &combined_digest[..8]); + println!("(Demonstrates policy digest computation - cpHash restricts to specific parameters)"); + + println!("PolicyCpHash sample completed successfully"); + Ok(()) +} + +fn policy_name_hash_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { + announce("PolicyNameHash Sample"); + + // PolicyNameHash restricts a policy to only authorize operations when specific + // handles are used. We demonstrate computing the policy digest. + // + // Note: PolicyNameHash is typically used to restrict which handles can be used + // with admin operations. Since modifying hierarchy auth on a real TPM is risky + // (DA lockout can prevent recovery), we demonstrate the policy computation + // using trial sessions. + + let hash_alg = TPM_ALG_ID::SHA256; + + // Compute nameHash for the OWNER handle + let owner_name = TPM_HANDLE::new(TPM_RH::OWNER.get_value()).get_name()?; + let name_hash = Crypto::hash(hash_alg, &owner_name)?; + println!("nameHash(OWNER): {:?}", &name_hash[..8]); + + // Build policy digest using trial session + let trial = tpm.start_auth_session(TPM_SE::TRIAL, hash_alg)?; + tpm.PolicyNameHash(&session_handle(&trial), &name_hash)?; + let policy_digest = tpm.PolicyGetDigest(&session_handle(&trial))?; + tpm.FlushContext(&session_handle(&trial))?; + println!("PolicyNameHash trial digest: {:?}", &policy_digest[..8]); + + // Combine with PolicyCommandCode for a more realistic policy + let trial2 = tpm.start_auth_session(TPM_SE::TRIAL, hash_alg)?; + tpm.PolicyNameHash(&session_handle(&trial2), &name_hash)?; + tpm.PolicyCommandCode(&session_handle(&trial2), TPM_CC::HierarchyChangeAuth)?; + let combined_digest = tpm.PolicyGetDigest(&session_handle(&trial2))?; + tpm.FlushContext(&session_handle(&trial2))?; + println!("PolicyNameHash + PolicyCommandCode trial digest: {:?}", &combined_digest[..8]); + println!("(Demonstrates policy that restricts HierarchyChangeAuth to OWNER handle only)"); + + println!("PolicyNameHash sample completed successfully"); + Ok(()) +} + +fn rewrap_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { + announce("ReWrap Sample"); + + // Make an exportable key with Duplicate policy, duplicate it with no encryption, + // then rewrap it to a new parent. + + let hash_alg = TPM_ALG_ID::SHA256; + + // Compute policy for Duplicate command + let trial = tpm.start_auth_session(TPM_SE::TRIAL, hash_alg)?; + tpm.PolicyCommandCode(&session_handle(&trial), TPM_CC::Duplicate)?; + let dup_policy = tpm.PolicyGetDigest(&session_handle(&trial))?; + tpm.FlushContext(&session_handle(&trial))?; + + // Create a duplicatable storage primary + let dup_attrs = TPMA_OBJECT::decrypt | TPMA_OBJECT::restricted + | TPMA_OBJECT::sensitiveDataOrigin | TPMA_OBJECT::userWithAuth; + let dup_parms = TPMU_PUBLIC_PARMS::rsaDetail(TPMS_RSA_PARMS::new( + &Aes128Cfb, + &Some(TPMU_ASYM_SCHEME::null(TPMS_NULL_ASYM_SCHEME::default())), + 2048, 65537, + )); + let dup_template = TPMT_PUBLIC::new( + hash_alg, dup_attrs, &dup_policy, + &Some(dup_parms), + &Some(TPMU_PUBLIC_ID::rsa(TPM2B_PUBLIC_KEY_RSA::default())), + ); + + let dup_key_resp = tpm.CreatePrimary( + &TPM_HANDLE::new(TPM_RH::OWNER.get_value()), + &TPMS_SENSITIVE_CREATE::default(), + &dup_template, + &Default::default(), + &Default::default(), + )?; + let dup_key = dup_key_resp.handle; + + // Make a new storage parent + let new_parent = make_storage_primary(tpm)?; + + // Duplicate the key to NULL parent (plaintext export, no encryption) + let sess = tpm.start_auth_session(TPM_SE::POLICY, hash_alg)?; + tpm.PolicyCommandCode(&session_handle(&sess), TPM_CC::Duplicate)?; + let dup_resp = tpm.with_session(sess.clone()).Duplicate( + &dup_key, &TPM_HANDLE::new(TPM_RH::NULL.get_value()), + &vec![], &Default::default(), + )?; + println!("Duplicated key (plaintext), duplicate size: {}", dup_resp.duplicate.buffer.len()); + tpm.FlushContext(&session_handle(&sess))?; + + // Rewrap from NULL parent to new parent + let rewrap_resp = tpm.Rewrap( + &TPM_HANDLE::new(TPM_RH::NULL.get_value()), + &new_parent, + &dup_resp.duplicate, + &dup_key.get_name()?, + &vec![], // No sym seed since duplicated to NULL + )?; + println!("Rewrapped key to new parent, outDuplicate size: {}", rewrap_resp.outDuplicate.buffer.len()); + + tpm.FlushContext(&dup_key)?; + tpm.FlushContext(&new_parent)?; + + println!("ReWrap sample completed successfully"); + Ok(()) +} + +fn audit_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { + announce("Audit Sample"); + + // The TPM supports command audit - keeping a running hash of commands/responses + // for commands in a specified list. + + let audit_alg = TPM_ALG_ID::SHA256; + let owner_handle = TPM_HANDLE::new(TPM_RH::OWNER.get_value()); + let empty_cc: Vec = vec![]; + + // Reset audit status + tpm.SetCommandCodeAuditStatus(&owner_handle, TPM_ALG_ID::NULL, &empty_cc, &empty_cc)?; + + // Start auditing GetRandom and StirRandom + let to_audit = vec![TPM_CC::GetRandom, TPM_CC::StirRandom]; + tpm.SetCommandCodeAuditStatus(&owner_handle, audit_alg, &empty_cc, &empty_cc)?; + tpm.SetCommandCodeAuditStatus(&owner_handle, TPM_ALG_ID::NULL, &to_audit, &empty_cc)?; + println!("Set up command audit for GetRandom and StirRandom"); + + // Read the audit digest before our commands + let audit_before = tpm.GetCommandAuditDigest( + &TPM_HANDLE::new(TPM_RH::ENDORSEMENT.get_value()), + &TPM_HANDLE::new(TPM_RH::NULL.get_value()), + &vec![], + &Some(TPMU_SIG_SCHEME::null(TPMS_NULL_SIG_SCHEME::default())), + )?; + println!("Audit digest before commands: {:?}", &audit_before.auditInfo.attested); + + // Execute some audited commands + let _ = tpm.GetRandom(20)?; + tpm.StirRandom(&vec![1, 2, 3, 4])?; + let _ = tpm.GetRandom(10)?; + tpm.StirRandom(&vec![9, 8, 7, 6])?; + println!("Executed 4 audited commands"); + + // Stop auditing + tpm.SetCommandCodeAuditStatus(&owner_handle, TPM_ALG_ID::NULL, &empty_cc, &empty_cc)?; + + // Read the audit digest after commands + let audit_after = tpm.GetCommandAuditDigest( + &TPM_HANDLE::new(TPM_RH::ENDORSEMENT.get_value()), + &TPM_HANDLE::new(TPM_RH::NULL.get_value()), + &vec![], + &Some(TPMU_SIG_SCHEME::null(TPMS_NULL_SIG_SCHEME::default())), + )?; + println!("Audit digest after commands: {:?}", &audit_after.auditInfo.attested); + + // Now demonstrate session audit + println!("\n>> Session Audit"); + + // Create a signing key for the session audit quote + let primary = make_storage_primary(tpm)?; + let sig_key = make_child_signing_key(tpm, &primary, true)?; + tpm.FlushContext(&primary)?; + + // Start an HMAC session with audit attribute + let audit_attrs = TPMA_SESSION::audit | TPMA_SESSION::continueSession; + let sess = tpm.start_auth_session_full( + TPM_SE::HMAC, audit_alg, + audit_attrs, + TPMT_SYM_DEF::default(), + )?; + + // Execute some commands in the audit session + tpm.with_session(sess.clone()).GetRandom(20)?; + let sess = tpm.last_session().unwrap(); + tpm.with_session(sess.clone()).StirRandom(&vec![1, 2, 3, 4])?; + let sess = tpm.last_session().unwrap(); + + // Get the session audit digest + let session_quote = tpm.GetSessionAuditDigest( + &TPM_HANDLE::new(TPM_RH::ENDORSEMENT.get_value()), + &sig_key, + &session_handle(&sess), + &vec![], + &Some(TPMU_SIG_SCHEME::null(TPMS_NULL_SIG_SCHEME::default())), + )?; + println!("Session audit quote obtained"); + println!("Session audit attested: {:?}", &session_quote.auditInfo.attested); + + tpm.FlushContext(&session_handle(&sess))?; + tpm.FlushContext(&sig_key)?; + + println!("Audit sample completed successfully"); + Ok(()) +} + +fn policy_locality_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { + announce("PolicyLocality Sample (trial only)"); + + // PolicyLocality restricts key usage to specific TPM localities. + // On real hardware (TBS), we can't change locality, so we only + // demonstrate computing the policy digest. + + let hash_alg = TPM_ALG_ID::SHA256; + + // Build policy digest using trial session + let trial = tpm.start_auth_session(TPM_SE::TRIAL, hash_alg)?; + tpm.PolicyLocality(&session_handle(&trial), TPMA_LOCALITY::LOC_ONE)?; + let policy_digest = tpm.PolicyGetDigest(&session_handle(&trial))?; + tpm.FlushContext(&session_handle(&trial))?; + + println!("PolicyLocality(LOC_ONE) digest: {:?}", &policy_digest[..8]); + + // Create a key with this policy + let hmac_key = make_hmac_primary_with_policy(tpm, &policy_digest, &[], hash_alg)?; + println!("Created HMAC key with locality policy"); + + // Try to use with a policy session - will fail since we can't set locality on TBS + let sess = tpm.start_auth_session(TPM_SE::POLICY, hash_alg)?; + tpm.allow_errors(); + let _ = tpm.PolicyLocality(&session_handle(&sess), TPMA_LOCALITY::LOC_ONE); + println!("PolicyLocality in real session: last_rc = {} (expected LOCALITY on TBS)", tpm.last_response_code()); + tpm.FlushContext(&session_handle(&sess))?; + + tpm.FlushContext(&hmac_key)?; + + println!("PolicyLocality sample completed (trial only on TBS)"); + Ok(()) +} + +fn async_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { + announce("Async Sample"); + + // The TPM supports asynchronous command dispatch: you send the command, + // then poll for completion, and finally retrieve the result. + // On Windows TBS, commands complete synchronously, but the API pattern + // is still useful for non-blocking designs and other transport layers. + + // Fast async operation: GetRandom + println!(">> Async GetRandom"); + { + let mut async_tpm = tpm.async_methods(); + async_tpm.GetRandom_async(16)?; + } + // On TBS, response is immediately available + { + let mut async_tpm = tpm.async_methods(); + let rand_data = async_tpm.GetRandom_complete()?; + println!("Async random data ({} bytes): {:?}", rand_data.len(), &rand_data[..8]); + } + + // Slow async operation: CreatePrimary + println!(">> Async CreatePrimary"); + let object_attributes = TPMA_OBJECT::sign | TPMA_OBJECT::fixedParent + | TPMA_OBJECT::fixedTPM | TPMA_OBJECT::sensitiveDataOrigin + | TPMA_OBJECT::userWithAuth; + let parameters = TPMU_PUBLIC_PARMS::rsaDetail(TPMS_RSA_PARMS::new( + &Default::default(), + &Some(TPMU_ASYM_SCHEME::rsassa(TPMS_SIG_SCHEME_RSASSA { hashAlg: TPM_ALG_ID::SHA256 })), + 2048, 65537, + )); + let template = TPMT_PUBLIC::new( + TPM_ALG_ID::SHA1, object_attributes, &Default::default(), + &Some(parameters), + &Some(TPMU_PUBLIC_ID::rsa(TPM2B_PUBLIC_KEY_RSA::default())), + ); + + { + let mut async_tpm = tpm.async_methods(); + async_tpm.CreatePrimary_async( + &TPM_HANDLE::new(TPM_RH::OWNER.get_value()), + &TPMS_SENSITIVE_CREATE::default(), + &template, + &Default::default(), + &Default::default(), + )?; + } + + let new_primary = { + let mut async_tpm = tpm.async_methods(); + async_tpm.CreatePrimary_complete()? + }; + + println!("Asynchronously created primary key: handle={:?}", new_primary.handle); + tpm.FlushContext(&new_primary.handle)?; + + println!("Async sample completed successfully"); + Ok(()) +} + +fn session_encryption_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { + announce("SessionEncryption Sample"); + + // Session encryption is transparent to the application programmer. + // Create a session with decrypt/encrypt attributes and the library handles + // the AES-CFB encryption/decryption of the first parameter automatically. + + // Part 1: Encrypt commands TO the TPM (decrypt attribute) + println!(">> Encrypt commands to TPM (TPMA_SESSION::decrypt)"); + let sess = tpm.start_auth_session_full( + TPM_SE::HMAC, TPM_ALG_ID::SHA256, + TPMA_SESSION::continueSession | TPMA_SESSION::decrypt, + TPMT_SYM_DEF::new(TPM_ALG_ID::AES, 128, TPM_ALG_ID::CFB), + )?; + + // StirRandom: the stirValue buffer will be encrypted before sending to TPM + tpm.with_session(sess.clone()).StirRandom(&vec![1, 1, 1, 1, 1, 1, 1, 1])?; + let sess = tpm.last_session().unwrap(); + println!("StirRandom with encrypted parameter succeeded"); + + // Do it again to verify continueSession nonce rolling works + tpm.with_session(sess.clone()).StirRandom(&vec![2, 2, 2, 2])?; + let sess = tpm.last_session().unwrap(); + println!("Second StirRandom with encrypted parameter succeeded"); + + tpm.FlushContext(&session_handle(&sess))?; + + // Part 2: Encrypt responses FROM the TPM (encrypt attribute) + println!("\n>> Encrypt responses from TPM (TPMA_SESSION::encrypt)"); + + // Create a primary key so we have something to read + let storage_primary = make_storage_primary(tpm)?; + + // Read public key without encryption + let plaintext_read = tpm.ReadPublic(&storage_primary)?; + + // Make an encrypting session for response + let enc_sess = tpm.start_auth_session_full( + TPM_SE::HMAC, TPM_ALG_ID::SHA256, + TPMA_SESSION::continueSession | TPMA_SESSION::encrypt, + TPMT_SYM_DEF::new(TPM_ALG_ID::AES, 128, TPM_ALG_ID::CFB), + )?; + + // ReadPublic with encrypted response - the library should decrypt automatically + let encrypted_read = tpm.with_session(enc_sess.clone()).ReadPublic(&storage_primary)?; + let enc_sess = tpm.last_session().unwrap(); + + // Compare: the decrypted response should match the plaintext + if plaintext_read.outPublic.nameAlg == encrypted_read.outPublic.nameAlg + && plaintext_read.name == encrypted_read.name + { + println!("Return parameter encryption succeeded: plaintext and decrypted responses match"); + } else { + println!("Warning: Responses differ (may indicate encryption/decryption issue)"); + } + + tpm.FlushContext(&session_handle(&enc_sess))?; + tpm.FlushContext(&storage_primary)?; + + println!("SessionEncryption sample completed successfully"); + Ok(()) +} + +fn policy_signed_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { + announce("PolicySigned"); + + // PolicySigned allows a policy to be satisfied by a signature from a specific key. + // We create a software RSA key, load its public part into the TPM, and then + // sign the nonce to satisfy the policy. + + let hash_alg = TPM_ALG_ID::SHA256; + + // Create a SW signing key + let mut sw_key = TSS_KEY::default(); + sw_key.publicPart = TPMT_PUBLIC { + nameAlg: hash_alg, + objectAttributes: TPMA_OBJECT( + TPMA_OBJECT::sign.get_value() | TPMA_OBJECT::userWithAuth.get_value(), + ), + authPolicy: vec![], + parameters: Some(TPMU_PUBLIC_PARMS::rsaDetail(TPMS_RSA_PARMS { + symmetric: TPMT_SYM_DEF_OBJECT::default(), + scheme: Some(TPMU_ASYM_SCHEME::rsassa(TPMS_SIG_SCHEME_RSASSA { + hashAlg: hash_alg, + })), + keyBits: 2048, + exponent: 0, + })), + unique: Some(TPMU_PUBLIC_ID::rsa(TPM2B_PUBLIC_KEY_RSA::default())), + }; + sw_key.create_key()?; + println!("Created software RSA-2048 signing key"); + + // Load the public part into the TPM (OWNER hierarchy for valid tickets) + let auth_key_handle = tpm.LoadExternal( + &TPMT_SENSITIVE::default(), + &sw_key.publicPart, + &TPM_HANDLE::new(TPM_RH::OWNER.get_value()), + )?; + println!("Loaded SW key public part into TPM: {:?}", auth_key_handle); + + // Step 1: Compute trial policy digest for PolicySigned + // Note: TPM checks signature scheme matches the key even in trial mode, + // so we must provide a properly-schemed signature (content doesn't matter). + let trial = tpm.start_auth_session(TPM_SE::TRIAL, hash_alg)?; + let policy_ref: Vec = vec![]; + + let dummy_hash = Crypto::hash(hash_alg, &[])?; + let dummy_sig = sw_key.sign(&dummy_hash, hash_alg)?; + tpm.PolicySigned( + &auth_key_handle, + &session_handle(&trial), + &vec![], // nonceTPM (ignored in trial) + &vec![], // cpHashA + &policy_ref, + 0, // expiration + &dummy_sig.signature, + )?; + let policy_digest = tpm.PolicyGetDigest(&session_handle(&trial))?; + tpm.FlushContext(&session_handle(&trial))?; + println!("PolicySigned trial digest: {:?}", &policy_digest[..8]); + + // Step 2: Start a real policy session + let policy_sess = tpm.start_auth_session(TPM_SE::POLICY, hash_alg)?; + let nonce_tpm = policy_sess.sess_out.nonce.clone(); + + // Step 3: Compute aHash = Hash(nonceTPM || expiration || cpHashA || policyRef) + let mut to_hash = Vec::new(); + to_hash.extend_from_slice(&nonce_tpm); + to_hash.extend_from_slice(&0i32.to_be_bytes()); // expiration = 0 + // cpHashA is empty, policyRef is empty + let a_hash = Crypto::hash(hash_alg, &to_hash)?; + + // Step 4: Sign the aHash with our SW key + let signature = sw_key.sign(&a_hash, hash_alg)?; + println!("Signed aHash ({} bytes) with SW key", a_hash.len()); + + // Step 5: Execute PolicySigned with the real signature + tpm.PolicySigned( + &auth_key_handle, + &session_handle(&policy_sess), + &nonce_tpm, + &vec![], // cpHashA + &policy_ref, + 0, // expiration + &signature.signature, + )?; + + // Verify the policy digest matches the trial + let actual_digest = tpm.PolicyGetDigest(&session_handle(&policy_sess))?; + if actual_digest == policy_digest { + println!("PolicySigned policy digest is correct"); + } else { + println!("Warning: policy digest mismatch"); + } + + // Demonstrate PolicyRestart + tpm.PolicyRestart(&session_handle(&policy_sess))?; + let reset_digest = tpm.PolicyGetDigest(&session_handle(&policy_sess))?; + if reset_digest.iter().all(|&b| b == 0) { + println!("PolicyRestart correctly reset the digest"); + } + + tpm.FlushContext(&session_handle(&policy_sess))?; + tpm.FlushContext(&auth_key_handle)?; + + println!("PolicySigned sample completed successfully"); + Ok(()) +} + +fn policy_authorize_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { + announce("PolicyAuthorize"); + + // PolicyAuthorize lets a key holder transform a policyHash into a new + // policyHash derived from a public key, if the corresponding private key + // holder authorizes the pre-policy-hash with a signature. + + let hash_alg = TPM_ALG_ID::SHA256; + + // Create a software signing key (the "authorizing" key) + let mut sw_key = TSS_KEY::default(); + sw_key.publicPart = TPMT_PUBLIC { + nameAlg: hash_alg, + objectAttributes: TPMA_OBJECT( + TPMA_OBJECT::sign.get_value() | TPMA_OBJECT::userWithAuth.get_value(), + ), + authPolicy: vec![], + parameters: Some(TPMU_PUBLIC_PARMS::rsaDetail(TPMS_RSA_PARMS { + symmetric: TPMT_SYM_DEF_OBJECT::default(), + scheme: Some(TPMU_ASYM_SCHEME::rsassa(TPMS_SIG_SCHEME_RSASSA { + hashAlg: hash_alg, + })), + keyBits: 2048, + exponent: 0, + })), + unique: Some(TPMU_PUBLIC_ID::rsa(TPM2B_PUBLIC_KEY_RSA::default())), + }; + sw_key.create_key()?; + println!("Created authorizing SW key"); + + // Load the public part into the TPM (OWNER hierarchy for valid tickets) + let auth_key_handle = tpm.LoadExternal( + &TPMT_SENSITIVE::default(), + &sw_key.publicPart, + &TPM_HANDLE::new(TPM_RH::OWNER.get_value()), + )?; + + // Get the authorizing key name + let key_name = sw_key.publicPart.get_name()?; + + // Step 1: Get the pre-policy digest we want to authorize (PolicyLocality(LOC_ONE)) + let trial_pre = tpm.start_auth_session(TPM_SE::TRIAL, hash_alg)?; + tpm.PolicyLocality(&session_handle(&trial_pre), TPMA_LOCALITY::LOC_ONE)?; + let pre_digest = tpm.PolicyGetDigest(&session_handle(&trial_pre))?; + tpm.FlushContext(&session_handle(&trial_pre))?; + println!("Pre-digest (PolicyLocality): {:?}", &pre_digest[..8]); + + // Step 2: Sign the approvedPolicy as defined in the spec: + // aHash = Hash(approvedPolicy || policyRef) + let policy_ref: Vec = vec![]; + let mut a_hash_data = Vec::new(); + a_hash_data.extend_from_slice(&pre_digest); + a_hash_data.extend_from_slice(&policy_ref); + let a_hash = Crypto::hash(hash_alg, &a_hash_data)?; + + let signature = sw_key.sign(&a_hash, hash_alg)?; + println!("Signed approvedPolicy with authorizing key"); + + // Step 3: Use VerifySignature to get a validation ticket + let check_ticket = tpm.VerifySignature( + &auth_key_handle, + &a_hash, + &signature.signature, + )?; + println!("Got verification ticket from TPM"); + + // Step 4: Execute the policy + // Start a real policy session + let policy_sess = tpm.start_auth_session(TPM_SE::POLICY, hash_alg)?; + + // First execute the sub-policy (PolicyLocality) + tpm.PolicyLocality(&session_handle(&policy_sess), TPMA_LOCALITY::LOC_ONE)?; + + // Then call PolicyAuthorize to transform the digest + tpm.PolicyAuthorize( + &session_handle(&policy_sess), + &pre_digest, + &policy_ref, + &key_name, + &check_ticket, + )?; + + let actual_digest = tpm.PolicyGetDigest(&session_handle(&policy_sess))?; + + // Compute expected: PolicyUpdate for PolicyAuthorize + // policyDigest_new = H(0...0 || TPM_CC_PolicyAuthorize || keyName || policyRef) + let hash_len = Crypto::hash(hash_alg, &[])?.len(); + let mut expected_data = vec![0u8; hash_len]; + expected_data.extend_from_slice(&TPM_CC::PolicyAuthorize.get_value().to_be_bytes()); + expected_data.extend_from_slice(&key_name); + // policyRef is empty, no need to extend + let expected_digest = Crypto::hash(hash_alg, &expected_data)?; + + if actual_digest == expected_digest { + println!("PolicyAuthorize digest is correct"); + } else { + println!("PolicyAuthorize digest: {:?}", &actual_digest[..8]); + println!("Expected digest: {:?}", &expected_digest[..8]); + } + + tpm.FlushContext(&session_handle(&policy_sess))?; + tpm.FlushContext(&auth_key_handle)?; + + println!("PolicyAuthorize sample completed successfully"); + Ok(()) +} + +fn admin_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { + announce("Administration"); + + // This sample demonstrates some TPM administration functions. + + // Note: Clear, ChangePPS, ChangeEPS, HierarchyControl, and SetPrimaryPolicy + // with locality require Platform auth or locality control, which are not + // available on TBS. Those are skipped here. + + // --- HierarchyChangeAuth --- + // We can change the authValue for the owner hierarchy. + println!(">> HierarchyChangeAuth"); + + let new_owner_auth = Crypto::hash(TPM_ALG_ID::SHA1, b"passw0rd")?; + println!("Setting OWNER auth to hash of 'passw0rd': {} bytes", new_owner_auth.len()); + + tpm.HierarchyChangeAuth( + &TPM_HANDLE::new(TPM_RH::OWNER.get_value()), + &new_owner_auth, + )?; + println!("OWNER auth changed successfully"); + + // TSS.Rust tracks changes of auth-values and updates the relevant handle. + // Because we have the new auth-value we can continue managing the TPM. + // Now set it back to empty. + tpm.HierarchyChangeAuth( + &TPM_HANDLE::new(TPM_RH::OWNER.get_value()), + &vec![], + )?; + println!("OWNER auth reset to empty"); + + // --- Demonstrate that primary keys are deterministic --- + println!("\n>> Primary key determinism"); + + match (|| -> Result<(), TpmError> { + let h1 = make_storage_primary(tpm)?; + let h2 = make_storage_primary(tpm)?; + + let pub1 = tpm.ReadPublic(&h1)?; + let pub2 = tpm.ReadPublic(&h2)?; + + if pub1.name == pub2.name { + println!("Two primary keys from same template have identical names (as expected)"); + } else { + println!("Warning: primary keys differ unexpectedly"); + } + + tpm.FlushContext(&h1)?; + tpm.FlushContext(&h2)?; + Ok(()) + })() { + Ok(()) => {} + Err(e) => println!("Primary key determinism test skipped ({})", e), + } + + println!("Admin sample completed successfully"); + Ok(()) +} + +/// Demonstrates the PolicyTree abstraction for declarative policy composition. +/// This replaces the manual trial-session + command-by-command approach with +/// a composable tree that can compute digests and execute policies automatically. +fn policy_tree_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { + announce("PolicyTree Sample"); + + let hash_alg = TPM_ALG_ID::SHA256; + + // ----------------------------------------------------------------------- + // 1) Simple PolicyTree: PolicyCommandCode restricting to HMAC_Start + // ----------------------------------------------------------------------- + let tree = PolicyTree::new() + .add(PolicyCommandCode::new(TPM_CC::HMAC_Start)); + + // Compute digest in software (no TPM trial session needed) + let sw_digest = tree.get_policy_digest(hash_alg)?; + + // Verify against a trial session on the TPM + let trial = tpm.start_auth_session(TPM_SE::TRIAL, hash_alg)?; + tpm.PolicyCommandCode(&session_handle(&trial), TPM_CC::HMAC_Start)?; + let tpm_digest = tpm.PolicyGetDigest(&session_handle(&trial))?; + tpm.FlushContext(&session_handle(&trial))?; + + assert_eq!(sw_digest, tpm_digest, "PolicyCommandCode: SW vs TPM digest mismatch"); + println!("PolicyTree digest (PolicyCommandCode) matches TPM trial: "); + + // ----------------------------------------------------------------------- + // 2) PolicyTree with multiple assertions chained + // ----------------------------------------------------------------------- + let tree2 = PolicyTree::new() + .add(PolicyLocality::new(TPMA_LOCALITY::LOC_ZERO)) + .add(PolicyCommandCode::new(TPM_CC::Sign)); + + let sw_digest2 = tree2.get_policy_digest(hash_alg)?; + + let trial2 = tpm.start_auth_session(TPM_SE::TRIAL, hash_alg)?; + tpm.PolicyLocality(&session_handle(&trial2), TPMA_LOCALITY::LOC_ZERO)?; + tpm.PolicyCommandCode(&session_handle(&trial2), TPM_CC::Sign)?; + let tpm_digest2 = tpm.PolicyGetDigest(&session_handle(&trial2))?; + tpm.FlushContext(&session_handle(&trial2))?; + + assert_eq!(sw_digest2, tpm_digest2, "Chained policy: SW vs TPM digest mismatch"); + println!("PolicyTree digest (Locality + CommandCode) matches TPM trial: "); + + // ----------------------------------------------------------------------- + // 3) PolicyOR via PolicyTree + // ----------------------------------------------------------------------- + // Branch 1: PolicyCommandCode(HMAC_Start) + let branch1: Vec> = vec![ + Box::new(PolicyCommandCode::new(TPM_CC::HMAC_Start)), + ]; + // Branch 2: PolicyCommandCode(Sign) + let branch2: Vec> = vec![ + Box::new(PolicyCommandCode::new(TPM_CC::Sign)), + ]; + + let or_tree = PolicyTree::new() + .add(PolicyOr::new(vec![branch1, branch2])); + + let sw_or_digest = or_tree.get_policy_digest(hash_alg)?; + + // Verify OR digest with TPM trial session + let trial_b1 = tpm.start_auth_session(TPM_SE::TRIAL, hash_alg)?; + tpm.PolicyCommandCode(&session_handle(&trial_b1), TPM_CC::HMAC_Start)?; + let b1_digest = tpm.PolicyGetDigest(&session_handle(&trial_b1))?; + tpm.FlushContext(&session_handle(&trial_b1))?; + + let trial_b2 = tpm.start_auth_session(TPM_SE::TRIAL, hash_alg)?; + tpm.PolicyCommandCode(&session_handle(&trial_b2), TPM_CC::Sign)?; + let b2_digest = tpm.PolicyGetDigest(&session_handle(&trial_b2))?; + tpm.FlushContext(&session_handle(&trial_b2))?; + + let hash_list = vec![ + TPM2B_DIGEST { buffer: b1_digest }, + TPM2B_DIGEST { buffer: b2_digest }, + ]; + + let trial_or = tpm.start_auth_session(TPM_SE::TRIAL, hash_alg)?; + tpm.PolicyOR(&session_handle(&trial_or), &hash_list)?; + let tpm_or_digest = tpm.PolicyGetDigest(&session_handle(&trial_or))?; + tpm.FlushContext(&session_handle(&trial_or))?; + + assert_eq!(sw_or_digest, tpm_or_digest, "PolicyOR: SW vs TPM digest mismatch"); + println!("PolicyTree digest (PolicyOR) matches TPM trial: "); + + // ----------------------------------------------------------------------- + // 4) Execute a PolicyTree against a real policy session + // ----------------------------------------------------------------------- + // Create an HMAC key with the simple PolicyCommandCode policy + let hmac_key = make_hmac_primary_with_policy(tpm, &sw_digest, &[], hash_alg)?; + + // Execute the policy tree against a real session + let policy_sess = tpm.start_auth_session(TPM_SE::POLICY, hash_alg)?; + let policy_sess = tree.execute(tpm, policy_sess)?; + + let hmac_seq = tpm.with_session(policy_sess.clone()).HMAC_Start(&hmac_key, &vec![], hash_alg)?; + println!("PolicyTree execute succeeded - HMAC_Start handle: {:?}", hmac_seq); + tpm.FlushContext(&hmac_seq)?; + tpm.FlushContext(&session_handle(&policy_sess))?; + tpm.FlushContext(&hmac_key)?; + + // ----------------------------------------------------------------------- + // 5) PolicyPassword via PolicyTree + // ----------------------------------------------------------------------- + let pw_tree = PolicyTree::new() + .add(PolicyPassword::new()); + + let pw_digest = pw_tree.get_policy_digest(hash_alg)?; + + let trial_pw = tpm.start_auth_session(TPM_SE::TRIAL, hash_alg)?; + tpm.PolicyPassword(&session_handle(&trial_pw))?; + let tpm_pw_digest = tpm.PolicyGetDigest(&session_handle(&trial_pw))?; + tpm.FlushContext(&session_handle(&trial_pw))?; + + assert_eq!(pw_digest, tpm_pw_digest, "PolicyPassword: SW vs TPM digest mismatch"); + println!("PolicyTree digest (PolicyPassword) matches TPM trial: "); + + println!("PolicyTree sample completed successfully"); + Ok(()) +} + +/// Demonstrates a salted (seeded) auth session. The salt is RSA-OAEP encrypted +/// to a storage primary's public key, providing protection even when authValues +/// are known or can be inferred. +fn seeded_session_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { + announce("SeededSession"); + + // Create a storage primary to use as the salt-encryption key + let salt_key = make_storage_primary(tpm)?; + + // Generate a random salt + let salt = Crypto::get_random(20); + println!("Salt ({} bytes): {:?}", salt.len(), &salt[..8]); + + // Start a salted HMAC session. + // start_auth_session_ex will ReadPublic on the salt key, encrypt the salt + // with RSA-OAEP (label "SECRET"), and derive the session key via KDFa. + let sess = tpm.start_auth_session_ex( + &salt_key, // tpmKey for salt encryption + &TPM_HANDLE::new(TPM_RH::NULL.get_value()), // no binding + TPM_SE::HMAC, + TPM_ALG_ID::SHA256, + TPMA_SESSION::continueSession, + TPMT_SYM_DEF::new(TPM_ALG_ID::AES, 128, TPM_ALG_ID::CFB), + &salt, + )?; + println!("Started salted HMAC session: {:?}", session_handle(&sess)); + + // Use the salted session to create a child key under the storage primary + let sign_parms = TPMU_PUBLIC_PARMS::rsaDetail(TPMS_RSA_PARMS::new( + &TPMT_SYM_DEF_OBJECT::new(TPM_ALG_ID::NULL, 0, TPM_ALG_ID::NULL), + &Some(TPMU_ASYM_SCHEME::rsassa(TPMS_SIG_SCHEME_RSASSA { hashAlg: TPM_ALG_ID::SHA256 })), + 2048, + 65537, + )); + let in_pub = TPMT_PUBLIC::new( + TPM_ALG_ID::SHA256, + TPMA_OBJECT::sign | TPMA_OBJECT::fixedParent | TPMA_OBJECT::fixedTPM + | TPMA_OBJECT::sensitiveDataOrigin | TPMA_OBJECT::userWithAuth, + &vec![], + &Some(sign_parms), + &Some(TPMU_PUBLIC_ID::rsa(TPM2B_PUBLIC_KEY_RSA::default())), + ); + + let created = tpm.with_session(sess.clone()).Create( + &salt_key, &TPMS_SENSITIVE_CREATE::default(), &in_pub, &vec![], &vec![], + )?; + let sess = tpm.last_session().unwrap_or(sess); + println!("Created child key under salted session"); + + // Load the child + let child_handle = tpm.with_session(sess.clone()).Load( + &salt_key, &created.outPrivate, &created.outPublic, + )?; + let sess = tpm.last_session().unwrap_or(sess); + println!("Loaded child key: {:?}", child_handle); + + tpm.FlushContext(&child_handle)?; + tpm.FlushContext(&session_handle(&sess))?; + tpm.FlushContext(&salt_key)?; + + println!("SeededSession sample completed successfully"); + Ok(()) +} + +/// Demonstrates a bound auth session. A bound session is associated with a +/// specific TPM entity. When the session is used with that entity, the HMAC +/// calculation uses the entity's auth value in the session key derivation. +fn bound_session_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { + announce("BoundSession"); + + // Set owner auth to a known non-empty value + let owner_auth: Vec = vec![0, 2, 1, 3, 5, 6]; + tpm.HierarchyChangeAuth(&TPM_HANDLE::new(TPM_RH::OWNER.get_value()), &owner_auth)?; + tpm.set_admin_auth(TPM_RH::OWNER, &owner_auth); + + // Run the actual test, then ALWAYS reset OWNER auth afterward + let result = bound_session_inner(tpm, &owner_auth); + + // Always reset owner auth, even if the test failed + tpm.allow_errors(); + let _ = tpm.HierarchyChangeAuth(&TPM_HANDLE::new(TPM_RH::OWNER.get_value()), &vec![]); + tpm.set_admin_auth(TPM_RH::OWNER, &vec![]); + + result +} + +fn bound_session_inner(tpm: &mut Tpm2, owner_auth: &[u8]) -> Result<(), TpmError> { + // Start a session bound to the owner handle + let mut owner_handle = TPM_HANDLE::new(TPM_RH::OWNER.get_value()); + owner_handle.auth_value = owner_auth.to_vec(); + + let sess = tpm.start_auth_session_ex( + &TPM_HANDLE::new(TPM_RH::NULL.get_value()), // no salt + &owner_handle, // bound to OWNER + TPM_SE::HMAC, + TPM_ALG_ID::SHA256, + TPMA_SESSION::continueSession, + TPMT_SYM_DEF::default(), + &[], // no salt + )?; + println!("Started bound session (bound to OWNER): {:?}", session_handle(&sess)); + + // Use the bound session to define an NV index (owner-authorized operation) + let nv_index: u32 = 0x01800099; + let nv_handle = TPM_HANDLE::new(nv_index); + + // Clean up in case it exists from a previous run + tpm.allow_errors(); + let _ = tpm.NV_UndefineSpace(&TPM_HANDLE::new(TPM_RH::OWNER.get_value()), &nv_handle); + + let nv_pub = TPMS_NV_PUBLIC::new( + &nv_handle, + TPM_ALG_ID::SHA256, + TPMA_NV::AUTHREAD | TPMA_NV::AUTHWRITE, + &vec![], + 16, + ); + + // Define NV space using the bound session (bound to OWNER, same entity) + let nv_auth: Vec = vec![5, 4, 3, 2, 1, 0]; + tpm.with_session(sess.clone()).NV_DefineSpace( + &TPM_HANDLE::new(TPM_RH::OWNER.get_value()), &nv_auth, &nv_pub, + )?; + let sess = tpm.last_session().unwrap_or(sess); + println!("Defined NV index with bound session (same-entity binding)"); + + // Read NV public to get the name + let nv_info = tpm.NV_ReadPublic(&nv_handle)?; + let mut nv_handle_with_auth = nv_handle.clone(); + nv_handle_with_auth.auth_value = nv_auth.clone(); + nv_handle_with_auth.set_name(&nv_info.nvName)?; + + // Write to NV using the bound session (different entity - the NV index) + tpm.with_session(sess.clone()).NV_Write( + &nv_handle_with_auth, &nv_handle_with_auth, &vec![0, 1, 2, 3], 0, + )?; + let sess = tpm.last_session().unwrap_or(sess); + println!("Wrote to NV index with bound session (different-entity binding)"); + + // After NV_Write, the TPM sets TPMA_NV::WRITTEN which changes the NV Name. + // We must re-read the public area to get the updated name for subsequent commands. + let nv_info = tpm.NV_ReadPublic(&nv_handle)?; + nv_handle_with_auth.set_name(&nv_info.nvName)?; + + // Read back + let read_data = tpm.with_session(sess.clone()).NV_Read( + &nv_handle_with_auth, &nv_handle_with_auth, 4, 0, + )?; + let sess = tpm.last_session().unwrap_or(sess); + println!("Read back NV data: {:?}", read_data); + assert_eq!(read_data, vec![0, 1, 2, 3], "NV read/write mismatch"); + + // Clean up NV and session + tpm.allow_errors(); + let _ = tpm.NV_UndefineSpace(&TPM_HANDLE::new(TPM_RH::OWNER.get_value()), &nv_handle); + tpm.FlushContext(&session_handle(&sess))?; + + println!("BoundSession sample completed successfully"); + Ok(()) +} + +fn reset_da_lockout(tpm: &mut Tpm2) { + tpm.allow_errors(); + let _ = tpm.DictionaryAttackLockReset(&TPM_HANDLE::new(TPM_RH::LOCKOUT.get_value())); + if tpm.last_response_code() != TPM_RC::SUCCESS { + if let Ok(da_info) = tpm.GetCapability(TPM_CAP::TPM_PROPERTIES, TPM_PT::LOCKOUT_COUNTER.get_value(), 4) { + if let Some(TPMU_CAPABILITIES::tpmProperties(props)) = &da_info.capabilityData { + for p in &props.tpmProperty { + match p.property { + TPM_PT::LOCKOUT_COUNTER => println!("DA failure count: {}", p.value), + TPM_PT::LOCKOUT_INTERVAL => println!("DA lockout interval: {} seconds", p.value), + TPM_PT::LOCKOUT_RECOVERY => println!("DA lockout recovery: {} seconds", p.value), + TPM_PT::MAX_AUTH_FAIL => println!("DA max auth fail: {}", p.value), + _ => {} + } + } + } + } + println!("Note: DictionaryAttackLockReset failed (rc={}), some auth-based samples may fail", tpm.last_response_code()); + } else { + println!("DA lockout cleared successfully"); + } +} + +fn recover_endorsement_hierarchy(tpm: &mut Tpm2) { + let hash_alg = TPM_ALG_ID::SHA256; + let endorsement_name = TPM_HANDLE::new(TPM_RH::ENDORSEMENT.get_value()).get_name().unwrap_or_default(); + let name_hash = Crypto::hash(hash_alg, &endorsement_name).unwrap_or_default(); + + tpm.allow_errors(); + if let Ok(sess) = tpm.start_auth_session(TPM_SE::POLICY, hash_alg) { + let _ = tpm.PolicyNameHash(&session_handle(&sess), &name_hash); + let _ = tpm.with_session(sess.clone()).HierarchyChangeAuth( + &TPM_HANDLE::new(TPM_RH::ENDORSEMENT.get_value()), + &vec![], + ); + let _ = tpm.FlushContext(&session_handle(&sess)); + } + tpm.allow_errors(); + let _ = tpm.SetPrimaryPolicy( + &TPM_HANDLE::new(TPM_RH::ENDORSEMENT.get_value()), + &vec![], + TPM_ALG_ID::NULL, + ); +} + +fn recover_owner_hierarchy(tpm: &mut Tpm2) { + let known_auths: Vec> = vec![ + Crypto::hash(TPM_ALG_ID::SHA1, b"passw0rd").unwrap_or_default(), + vec![0, 2, 1, 3, 5, 6], // bound_session_sample + ]; + for known_auth in &known_auths { + tpm.set_admin_auth(TPM_RH::OWNER, known_auth); + tpm.allow_errors(); + let _ = tpm.HierarchyChangeAuth(&TPM_HANDLE::new(TPM_RH::OWNER.get_value()), &vec![]); + if tpm.last_response_code() == TPM_RC::SUCCESS { + println!("Recovered OWNER auth"); + break; + } + } + tpm.set_admin_auth(TPM_RH::OWNER, &[]); +} + +fn main() -> Result<(), Box> { + let mut device = Box::new(TpmTbsDevice::new()); + device.connect()?; + let mut tpm = create_tpm_with_device(device); + + reset_da_lockout(&mut tpm); + recover_endorsement_hierarchy(&mut tpm); + recover_owner_hierarchy(&mut tpm); + + get_capabilities(&mut tpm)?; + + // ---- Samples ordered to match C++ RunAllSamples() ---- + + rand_sample(&mut tpm)?; + if let Err(e) = dictionary_attack_sample(&mut tpm) { + print_error(&format!("dictionary_attack_sample failed (TPM may be in lockout): {}", e)); + } + hash_sample(&mut tpm)?; + if let Err(e) = hmac_sample(&mut tpm) { + print_error(&format!("hmac_sample failed (may be DA lockout): {}", e)); + } + pcr_sample(&mut tpm)?; + if let Err(e) = policy_locality_sample(&mut tpm) { + print_error(&format!("policy_locality_sample failed: {}", e)); + } + // GetCapability already ran above + if let Err(e) = nv_sample(&mut tpm) { + print_error(&format!("nv_sample failed: {}", e)); + } + if let Err(e) = primary_keys_sample(&mut tpm) { + print_error(&format!("primary_keys_sample failed: {}", e)); + } + if let Err(e) = auth_sessions_sample(&mut tpm) { + print_error(&format!("auth_sessions_sample failed: {}", e)); + } + if let Err(e) = async_sample(&mut tpm) { + print_error(&format!("async_sample failed: {}", e)); + } + if let Err(e) = policy_simplest_sample(&mut tpm) { + print_error(&format!("policy_simplest_sample failed: {}", e)); + } + if let Err(e) = policy_pcr_sample(&mut tpm) { + print_error(&format!("policy_pcr_sample failed: {}", e)); + } + if let Err(e) = child_keys_sample(&mut tpm) { + print_error(&format!("child_keys_sample failed (likely TBS-blocked ContextSave): {}", e)); + } + if let Err(e) = policy_or_sample(&mut tpm) { + print_error(&format!("policy_or_sample failed: {}", e)); + } + counter_timer_sample(&mut tpm)?; + if let Err(e) = attestation(&mut tpm) { + print_error(&format!("attestation failed: {}", e)); + } + if let Err(e) = admin_sample(&mut tpm) { + print_error(&format!("admin_sample failed: {}", e)); + } + if let Err(e) = policy_cphash_sample(&mut tpm) { + print_error(&format!("policy_cphash_sample failed: {}", e)); + } + if let Err(e) = policy_counter_timer_sample(&mut tpm) { + print_error(&format!("policy_counter_timer_sample failed: {}", e)); + } + if let Err(e) = policy_with_passwords_sample(&mut tpm) { + print_error(&format!("policy_with_passwords_sample failed: {}", e)); + } + if let Err(e) = unseal_sample(&mut tpm) { + print_error(&format!("unseal_sample failed: {}", e)); + } + // Serializer - N/A for Rust + if let Err(e) = session_encryption_sample(&mut tpm) { + print_error(&format!("session_encryption_sample failed: {}", e)); + } + if let Err(e) = import_duplicate_sample(&mut tpm) { + print_error(&format!("import_duplicate_sample failed: {}", e)); + } + if let Err(e) = misc_admin_sample(&mut tpm) { + print_error(&format!("misc_admin_sample failed: {}", e)); + } + if let Err(e) = rsa_encrypt_decrypt_sample(&mut tpm) { + print_error(&format!("rsa_encrypt_decrypt_sample failed: {}", e)); + } + if let Err(e) = audit_sample(&mut tpm) { + print_error(&format!("audit_sample failed: {}", e)); + } + if let Err(e) = activate_credentials(&mut tpm) { + print_error(&format!("activate_credentials failed: {}", e)); + } + if let Err(e) = software_keys_sample(&mut tpm) { + print_error(&format!("software_keys_sample failed: {}", e)); + } + if let Err(e) = policy_signed_sample(&mut tpm) { + print_error(&format!("policy_signed_sample failed: {}", e)); + } + if let Err(e) = policy_authorize_sample(&mut tpm) { + print_error(&format!("policy_authorize_sample failed: {}", e)); + } + if let Err(e) = policy_secret_sample(&mut tpm) { + print_error(&format!("policy_secret_sample failed: {}", e)); + } + if let Err(e) = encrypt_decrypt_sample(&mut tpm) { + print_error(&format!("encrypt_decrypt_sample failed (likely TBS-blocked EncryptDecrypt): {}", e)); + } + if let Err(e) = policy_with_passwords_sample(&mut tpm) { + print_error(&format!("policy_with_passwords_sample (2nd run) failed: {}", e)); + } + // SeededSession - not yet implemented (needs RSA-encrypt salt) + if let Err(e) = policy_nv_sample(&mut tpm) { + print_error(&format!("policy_nv_sample failed: {}", e)); + } + if let Err(e) = policy_name_hash_sample(&mut tpm) { + print_error(&format!("policy_name_hash_sample failed: {}", e)); + } + if let Err(e) = rewrap_sample(&mut tpm) { + print_error(&format!("rewrap_sample failed: {}", e)); + } + if let Err(e) = policy_tree_sample(&mut tpm) { + print_error(&format!("policy_tree_sample failed: {}", e)); + } + if let Err(e) = seeded_session_sample(&mut tpm) { + print_error(&format!("seeded_session_sample failed: {}", e)); + } + if let Err(e) = bound_session_sample(&mut tpm) { + print_error(&format!("bound_session_sample failed: {}", e)); + } + // NVX - not yet implemented (needs Platform auth / simulator) + + announce( + "************************* 🦀🦀🦀 Generated by Tss.Rust 🦀🦀🦀 *************************", + ); + + Ok(()) +} diff --git a/TSS.Rust/src/auth_session.rs b/TSS.Rust/src/auth_session.rs new file mode 100644 index 00000000..fb3819f1 --- /dev/null +++ b/TSS.Rust/src/auth_session.rs @@ -0,0 +1,288 @@ +use crate::crypto::Crypto; +use crate::error::TpmError; +use crate::{tpm_structure::TpmEnum, tpm_types::*}; + +/// Authentication session for TPM commands +#[derive(Debug, Default, Clone)] +pub struct Session { + pub sess_in: TPMS_AUTH_COMMAND, + pub sess_out: TPMS_AUTH_RESPONSE, + + // Additional session properties + pub hash_alg: TPM_ALG_ID, + pub session_type: TPM_SE, + pub needs_hmac: bool, + pub needs_password: bool, + + /// Derived session key (from KDFa with "ATH" label) + pub session_key: Vec, + + /// Symmetric algorithm for parameter encryption + pub symmetric: TPMT_SYM_DEF, + + /// Handle of the entity this session is bound to (NULL if unbound) + pub bind_handle: u32, +} + +impl Session { + pub fn new( + session_handle: TPM_HANDLE, + nonce_tpm: &[u8], + session_attributes: TPMA_SESSION, + nonce_caller: &[u8], + ) -> Self { + Session { + sess_in: TPMS_AUTH_COMMAND::new( + &session_handle, + &nonce_caller.to_vec(), + session_attributes, + &Vec::new(), + ), + sess_out: TPMS_AUTH_RESPONSE::new( + &nonce_tpm.to_vec(), + session_attributes, + &Vec::new(), + ), + hash_alg: TPM_ALG_ID::SHA256, + session_type: TPM_SE::HMAC, + needs_hmac: true, + needs_password: false, + session_key: Vec::new(), + symmetric: TPMT_SYM_DEF::default(), + bind_handle: TPM_RH::NULL.get_value(), + } + } + + /// Create a password authorization session (PWAP) + pub fn pw(auth_value: Option>) -> Self { + let mut s = Session::default(); + s.sess_in.sessionHandle = TPM_HANDLE::new(TPM_RH::PW.get_value()); + s.sess_in.nonce = Vec::new(); + s.sess_in.sessionAttributes = TPMA_SESSION::continueSession; + let auth_value = auth_value.unwrap_or_default(); + s.sess_in.hmac = auth_value; + s.sess_out.sessionAttributes = TPMA_SESSION::continueSession; + s.session_type = TPM_SE::HMAC; + s.needs_hmac = false; + s.needs_password = true; + s.bind_handle = TPM_RH::NULL.get_value(); + + s + } + + /// Create a fully initialized HMAC or policy session from a TPM StartAuthSession response. + pub fn from_tpm_response( + session_handle: TPM_HANDLE, + session_type: TPM_SE, + hash_alg: TPM_ALG_ID, + nonce_caller: Vec, + nonce_tpm: Vec, + attributes: TPMA_SESSION, + symmetric: TPMT_SYM_DEF, + salt: &[u8], + bind_object: &TPM_HANDLE, + ) -> Result { + let mut sess = Session { + sess_in: TPMS_AUTH_COMMAND::new( + &session_handle, + &nonce_caller, + attributes, + &Vec::new(), + ), + sess_out: TPMS_AUTH_RESPONSE::new( + &nonce_tpm, + attributes, + &Vec::new(), + ), + hash_alg, + session_type, + needs_hmac: session_type == TPM_SE::HMAC, + needs_password: false, + session_key: Vec::new(), + symmetric, + bind_handle: bind_object.handle, + }; + + sess.calc_session_key(salt, bind_object)?; + Ok(sess) + } + + /// Derive the session key using KDFa with label "ATH". + /// SessionKey = KDFa(hashAlg, bindAuth || salt, "ATH", nonceTPM, nonceCaller, hashBits) + fn calc_session_key(&mut self, salt: &[u8], bind_object: &TPM_HANDLE) -> Result<(), TpmError> { + let null_handle = TPM_HANDLE::new(TPM_RH::NULL.get_value()); + let has_salt = !salt.is_empty(); + let is_bound = bind_object.handle != null_handle.handle; + + if !has_salt && !is_bound { + // No key derivation needed for unbound, unsalted sessions + return Ok(()); + } + + // hmacKey = bindAuth || salt + let mut hmac_key = Vec::new(); + if is_bound { + let bind_auth = trim_trailing_zeros(&bind_object.auth_value); + hmac_key.extend_from_slice(&bind_auth); + } + hmac_key.extend_from_slice(salt); + + let hash_bits = Crypto::digestSize(self.hash_alg) * 8; + self.session_key = Crypto::kdfa( + self.hash_alg, + &hmac_key, + "ATH", + &self.sess_out.nonce, // nonceTPM + &self.sess_in.nonce, // nonceCaller + hash_bits, + )?; + + Ok(()) + } + + /// Check if this is a password authorization session + pub fn is_pwap(&self) -> bool { + self.sess_in.sessionHandle.handle == TPM_RH::PW.get_value() + } + + /// Set authorization value for HMAC calculation + pub fn set_auth_value(&mut self, auth_value: Vec) { + if self.is_pwap() { + self.sess_in.hmac = auth_value; + } + } + + /// Get the hash algorithm used by this session + pub fn get_hash_alg(&self) -> TPM_ALG_ID { + self.hash_alg + } + + /// Generate an HMAC for authorization. + /// hmacKey = sessionKey || authValue + /// hmac = HMAC(hashAlg, hmacKey, parmHash || nonceNewer || nonceOlder || nonceDec || nonceEnc || sessionAttrs) + pub fn get_auth_hmac( + &self, + cp_hash: Vec, + is_command: bool, + nonce_tpm_dec: &[u8], + nonce_tpm_enc: &[u8], + associated_handle: Option<&TPM_HANDLE>, + ) -> Result, TpmError> { + // PWAP: return the auth value directly + if self.is_pwap() { + return Ok(self.sess_in.hmac.clone()); + } + + // PolicyPassword: return auth value directly + if self.needs_password { + return Ok(self.sess_in.hmac.clone()); + } + + // Determine nonce order based on direction + let (nonce_newer, nonce_older) = if is_command { + (&self.sess_in.nonce, &self.sess_out.nonce) + } else { + (&self.sess_out.nonce, &self.sess_in.nonce) + }; + + // Session attributes: use command attrs for commands, response attrs for responses + let session_attrs = if is_command { + vec![self.sess_in.sessionAttributes.get_value()] + } else { + vec![self.sess_out.sessionAttributes.get_value()] + }; + + // Get auth value from the associated handle + let mut auth = Vec::new(); + if let Some(handle) = associated_handle { + // For bound sessions: if the handle IS the bound entity, skip auth + // (it's already incorporated in the session key via KDFa). + let is_bound = self.bind_handle != TPM_RH::NULL.get_value() + && self.bind_handle != 0 + && handle.handle == self.bind_handle; + + if is_bound { + // Bound to same entity: auth already in session key, don't add again + } else if self.session_type != TPM_SE::POLICY || self.needs_hmac { + auth = trim_trailing_zeros(&handle.auth_value); + } + } + + // hmacKey = sessionKey || auth + let mut hmac_key = Vec::new(); + hmac_key.extend_from_slice(&self.session_key); + hmac_key.extend_from_slice(&auth); + + // Buffer to HMAC: parmHash || nonceNewer || nonceOlder || nonceDec || nonceEnc || sessionAttrs + let mut buf_to_hmac = Vec::new(); + buf_to_hmac.extend_from_slice(&cp_hash); + buf_to_hmac.extend_from_slice(nonce_newer); + buf_to_hmac.extend_from_slice(nonce_older); + buf_to_hmac.extend_from_slice(nonce_tpm_dec); + buf_to_hmac.extend_from_slice(nonce_tpm_enc); + buf_to_hmac.extend_from_slice(&session_attrs); + + Crypto::hmac(self.hash_alg, &hmac_key, &buf_to_hmac) + } + + /// Process parameter encryption/decryption using AES-CFB. + /// Key derivation: KDFa(hashAlg, sessionKey, "CFB", nonceNewer, nonceOlder, 256) + /// First keyBits/8 bytes = AES key, next 16 bytes = IV + pub fn param_xcrypt(&self, data: &[u8], is_command: bool) -> Result, TpmError> { + if data.is_empty() { + return Ok(Vec::new()); + } + + // Only AES-128/256 CFB is supported + if self.symmetric.algorithm != TPM_ALG_ID::AES || self.symmetric.mode != TPM_ALG_ID::CFB { + return Err(TpmError::GenericError( + "Only AES in CFB mode is supported for parameter encryption".to_string(), + )); + } + + let key_bits = self.symmetric.keyBits as usize; + if key_bits != 128 && key_bits != 256 { + return Err(TpmError::GenericError( + format!("Unsupported AES key size: {} bits", key_bits), + )); + } + + let key_size = key_bits / 8; + + // Determine nonce order: for requests, nonceNewer=nonceCaller, nonceOlder=nonceTPM + // For responses, nonceNewer=nonceTPM, nonceOlder=nonceCaller + let (nonce_newer, nonce_older) = if is_command { + (&self.sess_in.nonce, &self.sess_out.nonce) + } else { + (&self.sess_out.nonce, &self.sess_in.nonce) + }; + + // Derive key material: KDFa(hashAlg, sessionKey, "CFB", nonceNewer, nonceOlder, 256) + // Produces key_size + 16 bytes (key + IV) + let num_bits = (key_size + 16) * 8; + let key_info = Crypto::kdfa( + self.hash_alg, + &self.session_key, + "CFB", + nonce_newer, + nonce_older, + num_bits, + )?; + + let aes_key = &key_info[..key_size]; + let iv = &key_info[key_size..key_size + 16]; + + // For requests: encrypt (TPM will decrypt) + // For responses: decrypt (TPM encrypted it) + Crypto::cfb_xcrypt(is_command, aes_key, iv, data) + } +} + +/// Trim trailing zero bytes from a byte vector +fn trim_trailing_zeros(data: &[u8]) -> Vec { + let mut result = data.to_vec(); + while result.last() == Some(&0) { + result.pop(); + } + result +} diff --git a/TSS.Rust/src/crypto.rs b/TSS.Rust/src/crypto.rs new file mode 100644 index 00000000..865a78b8 --- /dev/null +++ b/TSS.Rust/src/crypto.rs @@ -0,0 +1,272 @@ +use crate::{error::TpmError, tpm_types::*}; +use hmac::{Hmac, Mac}; +use rsa::{BigUint, Pkcs1v15Sign, RsaPublicKey}; +use sha1::Sha1; +use sha2::{Digest as Sha2Digest, Sha256, Sha384, Sha512}; +use sm3::Sm3; +use rand::{rngs::OsRng, RngCore}; +use aes::Aes128; +use cipher::{BlockEncrypt, KeyInit}; +use cipher::generic_array::GenericArray; + +pub struct Crypto; + +impl Crypto { + // The function is called from an auto-generated file that expects this specific (non snake_cased) name + #[allow(non_snake_case)] + pub fn digestSize(alg: TPM_ALG_ID) -> usize { + match alg { + TPM_ALG_ID::SHA1 => 20, + TPM_ALG_ID::SHA256 => 32, + TPM_ALG_ID::SHA384 => 48, + TPM_ALG_ID::SHA512 => 64, + TPM_ALG_ID::SM3_256 => 32, + _ => 0, + } + } + + // Hash a byte buffer using the specified algorithm + pub fn hash(alg: TPM_ALG_ID, data: &[u8]) -> Result, TpmError> { + // If the data is empty, return an empty digest of correct size + if data.is_empty() { + return Ok(vec![0; Self::digestSize(alg)]); + } + + let digest = match alg { + TPM_ALG_ID::SHA1 => { + let mut hasher = Sha1::new(); + hasher.update(data); + hasher.finalize().to_vec() + } + TPM_ALG_ID::SHA256 => { + let mut hasher = Sha256::new(); + hasher.update(data); + hasher.finalize().to_vec() + } + TPM_ALG_ID::SHA384 => { + let mut hasher = Sha384::new(); + hasher.update(data); + hasher.finalize().to_vec() + } + TPM_ALG_ID::SHA512 => { + let mut hasher = Sha512::new(); + hasher.update(data); + hasher.finalize().to_vec() + } + TPM_ALG_ID::SM3_256 => { + let mut hasher = Sm3::new(); + hasher.update(data); + hasher.finalize().to_vec() + } + _ => { + return Err(TpmError::NotSupported(format!( + "Unsupported hash algorithm: {:?}", + alg + ))) + } + }; + + let expected_size = Self::digestSize(alg); + if (digest.len() != expected_size) { + return Err(TpmError::InvalidArraySize(format!( + "Hash output length mismatch: expected {}, got {}", + expected_size, + digest.len() + ))); + } + + Ok(digest) + } + + pub fn hmac(hash_alg: TPM_ALG_ID, key: &[u8], to_hash: &[u8]) -> Result, TpmError> { + // Choose the appropriate HMAC algorithm based on the hash algorithm + match hash_alg { + TPM_ALG_ID::SHA1 => { + let mut mac = as Mac>::new_from_slice(key).map_err(|_| { + TpmError::InvalidArraySize("HMAC can take key of any size".to_string()) + })?; + mac.update(to_hash); + Ok(mac.finalize().into_bytes().to_vec()) + } + TPM_ALG_ID::SHA256 => { + let mut mac = as Mac>::new_from_slice(key).map_err(|_| { + TpmError::InvalidArraySize("HMAC can take key of any size".to_string()) + })?; + mac.update(to_hash); + Ok(mac.finalize().into_bytes().to_vec()) + } + TPM_ALG_ID::SHA384 => { + let mut mac = as Mac>::new_from_slice(key).map_err(|_| { + TpmError::InvalidArraySize("HMAC can take key of any size".to_string()) + })?; + mac.update(to_hash); + Ok(mac.finalize().into_bytes().to_vec()) + } + TPM_ALG_ID::SHA512 => { + let mut mac = as Mac>::new_from_slice(key).map_err(|_| { + TpmError::InvalidArraySize("HMAC can take key of any size".to_string()) + })?; + mac.update(to_hash); + Ok(mac.finalize().into_bytes().to_vec()) + } + TPM_ALG_ID::SM3_256 => { + let mut mac = + as Mac>::new_from_slice(key).expect("HMAC can take key of any size"); + mac.update(to_hash); + Ok(mac.finalize().into_bytes().to_vec()) + } + _ => { + return Err(TpmError::NotSupported(format!( + "Unsupported hash algorithm: {:?}", + hash_alg + ))) + } + } + } + + pub fn validate_signature( + public_key: &TPMT_PUBLIC, + signed_blob_hash: Vec, + signature: &Option, + ) -> Result { + if !matches!(&public_key.parameters, Some(TPMU_PUBLIC_PARMS::rsaDetail(_))) { + return Err(TpmError::NotSupported( + "ValidateSignature: Only RSA is supported".to_string(), + )); + }; + + let signature = if let Some(TPMU_SIGNATURE::rsassa(signature)) = &signature { + signature + } else { + return Err(TpmError::NotSupported( + "ValidateSignature: Only RSASSA scheme is supported".to_string(), + )); + }; + + let rsa_pub_key = if let Some(TPMU_PUBLIC_ID::rsa(unique)) = &public_key.unique { + &unique.buffer + } else { + return Err(TpmError::NotSupported( + "ValidateSignature: Only RSA public key is supported".to_string(), + )); + }; + + let rsa_public_key = RsaPublicKey::new(BigUint::from_bytes_be(rsa_pub_key), BigUint::from_bytes_be(&[1, 0, 1])) + .map_err(|_| TpmError::InvalidArraySize("Invalid RSA public key".to_string()))?; + + Ok(rsa_public_key + .verify( + Pkcs1v15Sign::new::(), + &signed_blob_hash, + &signature.sig + ).is_ok()) + } + + // KDFa implementation as specified in TPM 2.0 Part 1 + pub fn kdfa( + hash_alg: TPM_ALG_ID, + key: &[u8], + label: &str, + context_u: &[u8], + context_v: &[u8], + bits: usize, + ) -> Result, TpmError> { + let bytes_needed = (bits + 7) / 8; + let mut result = Vec::new(); + let mut counter = 1u32; + + while result.len() < bytes_needed { + let mut to_hash = Vec::new(); + + // Counter in big-endian + to_hash.extend_from_slice(&counter.to_be_bytes()); + + // Label + to_hash.extend_from_slice(label.as_bytes()); + + // 00 byte separator + to_hash.push(0u8); + + // contextU + to_hash.extend_from_slice(context_u); + + // contextV + to_hash.extend_from_slice(context_v); + + // Number of bits in big-endian + to_hash.extend_from_slice(&(bits as u32).to_be_bytes()); + + // Perform HMAC + let hmac_result = Self::hmac(hash_alg, key, &to_hash)?; + result.extend_from_slice(&hmac_result); + + counter = counter.checked_add(1).ok_or_else(|| { + TpmError::InvalidArraySize("Counter overflow in KDFa".to_string()) + })?; + } + + // Truncate to exact size needed + result.truncate(bytes_needed); + Ok(result) + } + + // AES CFB encryption/decryption + pub fn cfb_xcrypt( + encrypt: bool, + key: &[u8], + iv: &[u8], + data: &[u8] + ) -> Result, TpmError> { + if data.is_empty() { + return Ok(Vec::new()); + } + + if key.len() != 16 && key.len() != 24 && key.len() != 32 { + return Err(TpmError::InvalidArraySize("Invalid AES key length".to_string())); + } + + if iv.len() != 16 { + return Err(TpmError::InvalidArraySize("IV must be 16 bytes".to_string())); + } + + let cipher = Aes128::new(GenericArray::from_slice(key)); + let mut result = Vec::with_capacity(data.len()); + let mut feedback = GenericArray::from_slice(iv).clone(); + + for chunk in data.chunks(16) { + // Encrypt the feedback (IV or previous ciphertext) + let mut encrypted_feedback = feedback.clone(); + cipher.encrypt_block(&mut encrypted_feedback); + + if encrypt { + // CFB encrypt: ciphertext = plaintext XOR encrypt(feedback) + // Next feedback = ciphertext + let mut ct_block = [0u8; 16]; + for (i, &b) in chunk.iter().enumerate() { + ct_block[i] = b ^ encrypted_feedback[i]; + result.push(ct_block[i]); + } + feedback.copy_from_slice(&ct_block); + } else { + // CFB decrypt: plaintext = ciphertext XOR encrypt(feedback) + // Next feedback = ciphertext (input) + let mut ct_block = [0u8; 16]; + ct_block[..chunk.len()].copy_from_slice(chunk); + for (i, &b) in chunk.iter().enumerate() { + result.push(b ^ encrypted_feedback[i]); + } + feedback.copy_from_slice(&ct_block); + } + } + + result.truncate(data.len()); + Ok(result) + } + + // Get random bytes + pub fn get_random(num_bytes: usize) -> Vec { + let mut result = vec![0u8; num_bytes]; + OsRng.fill_bytes(&mut result); + result + } +} diff --git a/TSS.Rust/src/device.rs b/TSS.Rust/src/device.rs new file mode 100644 index 00000000..381213e8 --- /dev/null +++ b/TSS.Rust/src/device.rs @@ -0,0 +1,967 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See the LICENSE file in the project root for full license information. + */ + +//! TPM device communication implementations + +use crate::error::TpmError; + +#[cfg(target_os = "windows")] +use std::os::raw::c_void; +#[cfg(target_os = "windows")] +use std::ptr; +use windows::Win32::System::TpmBaseServices::*; + +#[cfg(target_os = "linux")] +use std::fs::{File, OpenOptions}; +#[cfg(target_os = "linux")] +use std::os::unix::io::AsRawFd; + +/// Defines the TPM connection information flags +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u32)] +pub enum TpmConnInfo { + /// Platform hierarchy is enabled, and hardware platform functionality is available + TpmPlatformAvailable = 0x01, + /// Connection represents a TPM Resource Manager (TRM) + TpmUsesTrm = 0x02, + /// The TRM is in raw mode + TpmInRawMode = 0x04, + /// Physical presence signals are supported + TpmSupportsPP = 0x08, + /// System and TPM power control signals are not supported + TpmNoPowerCtl = 0x10, + /// TPM locality cannot be changed + TpmNoLocalityCtl = 0x20, + /// Connection medium is socket + TpmSocketConn = 0x1000, + /// Connection medium is OS/platform specific handle + TpmTbsConn = 0x2000, + /// Socket connection to old version of Intel's user mode TRM on Linux + TpmLinuxOldUserModeTrm = 0x4000, + /// Connection via TCG compliant TCTI connection interface + TpmTctiConn = 0x8000, +} + +/// Commands for TCP communication with TPM simulator +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u32)] +pub enum TcpTpmCommand { + SignalPowerOn = 1, + SignalPowerOff = 2, + SignalPPOn = 3, + SignalPPOff = 4, + SignalHashStart = 5, + SignalHashData = 6, + SignalHashEnd = 7, + SendCommand = 8, + SignalCancelOn = 9, + SignalCancelOff = 10, + SignalNvOn = 11, + SignalNvOff = 12, + SignalKeyCacheOn = 13, + SignalKeyCacheOff = 14, + RemoteHandshake = 15, + SetAlternativeResult = 16, + SessionEnd = 20, + Stop = 21, + TestFailureMode = 30, +} + +/// Main trait for TPM devices +pub trait TpmDevice { + /// Connect to the TPM device + fn connect(&mut self) -> Result; + + /// Close the connection to the TPM device + fn close(&mut self); + + /// Dispatch a command to the TPM + fn dispatch_command(&mut self, cmd_buf: &[u8]) -> Result<(), TpmError>; + + /// Get a response from the TPM + fn get_response(&mut self) -> Result, TpmError>; + + /// Check if a response is ready + fn response_is_ready(&self) -> Result; + + /// Power control + fn power_ctl(&mut self, _on: bool) -> Result<(), TpmError> { + Err(TpmError::NotSupported("power_ctl".to_string())) + } + + /// Assert physical presence + fn assert_physical_presence(&mut self, _on: bool) -> Result<(), TpmError> { + Err(TpmError::NotSupported( + "assert_physical_presence".to_string(), + )) + } + + /// Set locality for subsequent commands + fn set_locality(&mut self, _locality: u32) -> Result<(), TpmError> { + Err(TpmError::NotSupported("set_locality".to_string())) + } + + /// Check if platform is available + fn platform_available(&self) -> bool { + false + } + + /// Check if power control is available + fn power_ctl_available(&self) -> bool { + self.platform_available() && !self.has_flag(TpmConnInfo::TpmNoPowerCtl as u32) + } + + /// Check if locality control is available + fn locality_ctl_available(&self) -> bool { + self.platform_available() && !self.has_flag(TpmConnInfo::TpmNoLocalityCtl as u32) + } + + /// Check if physical presence can be asserted + fn implements_physical_presence(&self) -> bool { + self.has_flag(TpmConnInfo::TpmSupportsPP as u32) + } + + /// Power on convenience method + fn power_on(&mut self) -> Result<(), TpmError> { + self.power_ctl(true) + } + + /// Power off convenience method + fn power_off(&mut self) -> Result<(), TpmError> { + self.power_ctl(false) + } + + /// Power cycle convenience method + fn power_cycle(&mut self) -> Result<(), TpmError> { + self.power_ctl(false)?; + self.power_ctl(true) + } + + /// Physical presence on convenience method + fn pp_on(&mut self) -> Result<(), TpmError> { + self.assert_physical_presence(true) + } + + /// Physical presence off convenience method + fn pp_off(&mut self) -> Result<(), TpmError> { + self.assert_physical_presence(false) + } + + /// Check if a specific flag is set in TpmInfo + fn has_flag(&self, flag: u32) -> bool; + + /// Get the TpmInfo flags + fn get_tpm_info(&self) -> u32; +} + +// /// TPM device implementation for TCP connection (simulator) +// pub struct TpmTcpDevice { +// host_name: String, +// port: u16, +// command_socket: Option, +// signal_socket: Option, +// locality: u8, +// tpm_info: u32, +// } + +// impl TpmTcpDevice { +// /// Create a new TpmTcpDevice +// pub fn new(host_name: String, port: u16) -> Self { +// TpmTcpDevice { +// host_name, +// port, +// command_socket: None, +// signal_socket: None, +// locality: 0, +// tpm_info: 0, +// } +// } + +// /// Set the target for the TCP connection +// pub fn set_target(&mut self, host_name: String, port: u16) { +// self.host_name = host_name; +// self.port = port; +// self.locality = 0; +// } + +// /// Connect to the specified host and port +// pub fn connect_to(&mut self, host_name: String, port: u16) -> Result { +// self.set_target(host_name, port); +// self.connect() +// } + +// // Helper function to send an integer in network byte order +// fn send_int(socket: &mut TcpStream, value: u32) -> Result<(), TpmError> { +// let value_bytes = value.to_be_bytes(); +// socket +// .write_all(&value_bytes) +// .map_err(|e| TpmError::IoError(e.to_string())) +// } + +// // Helper function to receive an integer in network byte order +// fn receive_int(socket: &mut TcpStream) -> Result { +// let mut buffer = [0u8; 4]; +// socket +// .read_exact(&mut buffer) +// .map_err(|e| TpmError::IoError(e.to_string()))?; +// Ok(u32::from_be_bytes(buffer)) +// } + +// // Helper function to get acknowledgement from server +// fn get_ack(socket: &mut TcpStream) -> Result<(), TpmError> { +// let end_tag = Self::receive_int(socket)?; + +// if end_tag != 0 { +// if end_tag == 1 { +// return Err(TpmError::CommandFailed); +// } else { +// return Err(TpmError::BadEndTag); +// } +// } + +// Ok(()) +// } + +// // Helper function to send a command and get acknowledgement +// fn send_cmd_and_get_ack(socket: &mut TcpStream, cmd: TcpTpmCommand) -> Result<(), TpmError> { +// Self::send_int(socket, cmd as u32)?; +// Self::get_ack(socket) +// } + +// // Helper function to receive a variable-length array +// fn recv_var_array(socket: &mut TcpStream) -> Result, TpmError> { +// let len = Self::receive_int(socket)? as usize; +// let mut buffer = vec![0u8; len]; + +// socket +// .read_exact(&mut buffer) +// .map_err(|e| TpmError::IoError(e.to_string()))?; + +// Ok(buffer) +// } +// } + +// impl TpmDevice for TpmTcpDevice { +// fn connect(&mut self) -> Result { +// // Close any existing connections +// self.close(); + +// // Connect to the signal port first +// let signal_addr = format!("{}:{}", self.host_name, self.port + 1); +// let signal_socket = TcpStream::connect(signal_addr) +// .map_err(|e| TpmError::IoError(format!("Failed to connect to signal port: {}", e)))?; + +// // Connect to the command port +// let command_addr = format!("{}:{}", self.host_name, self.port); +// let command_socket = TcpStream::connect(command_addr) +// .map_err(|e| TpmError::IoError(format!("Failed to connect to command port: {}", e)))?; + +// // Set read and write timeouts +// command_socket +// .set_read_timeout(Some(Duration::from_secs(5))) +// .map_err(|e| TpmError::IoError(e.to_string()))?; +// signal_socket +// .set_read_timeout(Some(Duration::from_secs(5))) +// .map_err(|e| TpmError::IoError(e.to_string()))?; + +// // Store the sockets +// self.command_socket = Some(command_socket); +// self.signal_socket = Some(signal_socket); + +// // Make sure the TPM protocol is running +// if let Some(mut cmd_socket) = self.command_socket.as_ref().map(|s| s.try_clone().unwrap()) { +// // Client version is 1 +// const CLIENT_VERSION: u32 = 1; + +// Self::send_int(&mut cmd_socket, TcpTpmCommand::RemoteHandshake as u32)?; +// Self::send_int(&mut cmd_socket, CLIENT_VERSION)?; + +// let endpoint_ver = Self::receive_int(&mut cmd_socket)?; +// if endpoint_ver != CLIENT_VERSION { +// return Err(TpmError::IncompatibleTpm); +// } + +// // Get the endpoint TPM properties +// self.tpm_info = Self::receive_int(&mut cmd_socket)?; + +// Self::get_ack(&mut cmd_socket)?; + +// Ok(true) +// } else { +// Err(TpmError::NotConnected) +// } +// } + +// fn close(&mut self) { +// // Close command socket if open +// if let Some(_) = self.command_socket.take() { +// // Socket will be closed when dropped +// } + +// // Close signal socket if open +// if let Some(_) = self.signal_socket.take() { +// // Socket will be closed when dropped +// } +// } + +// fn dispatch_command(&mut self, cmd_buf: &[u8]) -> Result<(), TpmError> { +// if let Some(mut socket) = self.command_socket.as_ref().map(|s| s.try_clone().unwrap()) { +// // Send the command header +// Self::send_int(&mut socket, TcpTpmCommand::SendCommand as u32)?; +// socket +// .write_all(&[self.locality]) +// .map_err(|e| TpmError::IoError(e.to_string()))?; +// Self::send_int(&mut socket, cmd_buf.len() as u32)?; + +// // Send the command data +// socket +// .write_all(cmd_buf) +// .map_err(|e| TpmError::IoError(e.to_string()))?; + +// Ok(()) +// } else { +// Err(TpmError::NotConnected) +// } +// } + +// fn get_response(&mut self) -> Result, TpmError> { +// if let Some(mut socket) = self.command_socket.as_ref().map(|s| s.try_clone().unwrap()) { +// // Get the response +// let resp = Self::recv_var_array(&mut socket)?; + +// // Get the terminating ACK +// let ack = Self::receive_int(&mut socket)?; +// if ack != 0 { +// return Err(TpmError::BadEndTag); +// } + +// Ok(resp) +// } else { +// Err(TpmError::NotConnected) +// } +// } + +// fn response_is_ready(&self) -> Result { +// if let Some(socket) = &self.command_socket { +// // Create a read set with just this socket +// let mut read_set = [socket +// .try_clone() +// .map_err(|e| TpmError::IoError(e.to_string()))?]; + +// // Check if there's data to read with a zero timeout +// match socket::select( +// &mut read_set, +// &mut [], +// &mut [], +// Some(&Duration::from_secs(0)), +// ) { +// Ok(1) => Ok(true), +// Ok(_) => Ok(false), +// Err(e) => Err(TpmError::IoError(e.to_string())), +// } +// } else { +// Err(TpmError::NotConnected) +// } +// } + +// fn power_ctl(&mut self, on: bool) -> Result<(), TpmError> { +// if let Some(mut socket) = self.signal_socket.as_ref().map(|s| s.try_clone().unwrap()) { +// let power_cmd = if on { +// TcpTpmCommand::SignalPowerOn +// } else { +// TcpTpmCommand::SignalPowerOff +// }; + +// let nv_cmd = if on { +// TcpTpmCommand::SignalNvOn +// } else { +// TcpTpmCommand::SignalNvOff +// }; + +// Self::send_cmd_and_get_ack(&mut socket, power_cmd)?; +// Self::send_cmd_and_get_ack(&mut socket, nv_cmd)?; + +// Ok(()) +// } else { +// Err(TpmError::NotConnected) +// } +// } + +// fn assert_physical_presence(&mut self, on: bool) -> Result<(), TpmError> { +// if let Some(mut socket) = self.signal_socket.as_ref().map(|s| s.try_clone().unwrap()) { +// let pp_cmd = if on { +// TcpTpmCommand::SignalPPOn +// } else { +// TcpTpmCommand::SignalPPOff +// }; + +// Self::send_cmd_and_get_ack(&mut socket, pp_cmd) +// } else { +// Err(TpmError::NotConnected) +// } +// } + +// fn set_locality(&mut self, locality: u32) -> Result<(), TpmError> { +// if locality > 255 { +// return Err(TpmError::InvalidParameter); +// } + +// self.locality = locality as u8; +// Ok(()) +// } + +// fn platform_available(&self) -> bool { +// self.has_flag(TpmConnInfo::TpmPlatformAvailable as u32) +// } + +// fn has_flag(&self, flag: u32) -> bool { +// (self.tpm_info & flag) != 0 +// } + +// fn get_tpm_info(&self) -> u32 { +// self.tpm_info +// } +// } + +// Windows TBS (TPM Base Services) implementation +#[cfg(target_os = "windows")] +pub struct TpmTbsDevice { + context: *mut c_void, + result_buffer: [u8; 4096], + res_size: u32, + tpm_info: u32, +} + +#[cfg(target_os = "windows")] +impl TpmTbsDevice { + pub fn new() -> Self { + TpmTbsDevice { + context: ptr::null_mut(), + result_buffer: [0; 4096], + res_size: 0, + tpm_info: 0, + } + } +} + +#[cfg(target_os = "windows")] +impl TpmDevice for TpmTbsDevice { + fn connect(&mut self) -> Result { + if !self.context.is_null() { + return Ok(true); // Already connected + } + + let mut params = TBS_CONTEXT_PARAMS2::default(); + params.version = TBS_CONTEXT_VERSION_TWO; + params.Anonymous.Anonymous._bitfield = 4; + params.Anonymous.asUINT32 = 4; + + let context_ptr = &mut self.context as *mut *mut c_void; + let res = unsafe { + Tbsi_Context_Create( + ¶ms as *const TBS_CONTEXT_PARAMS2 as *const TBS_CONTEXT_PARAMS, + context_ptr, + ) + }; + + if res != TBS_SUCCESS { + return Err(TpmError::TbsError(format!( + "Failed to connect to TBS: {:?}", + res + ))); + } + + // Get device info to check if TPM 2.0 is available + let mut info = TPM_DEVICE_INFO::default(); + let res = unsafe { + Tbsi_GetDeviceInfo( + std::mem::size_of::() as u32, + &mut info as *mut _ as *mut c_void, + ) + }; + + if res != TBS_SUCCESS { + return Err(TpmError::TbsError("Failed to get device info".to_string())); + } else if info.tpmVersion != TPM_VERSION_20 { + unsafe { Tbsip_Context_Close(self.context) }; + self.context = ptr::null_mut(); + return Err(TpmError::TbsError( + "Platform does not contain a TPM 2.0".to_string(), + )); + } + + // Set appropriate flags + self.tpm_info = TpmConnInfo::TpmTbsConn as u32; + + Ok(true) + } + + fn close(&mut self) { + if !self.context.is_null() { + unsafe { Tbsip_Context_Close(self.context) }; + self.context = ptr::null_mut(); + } + + self.tpm_info = 0; + } + + fn dispatch_command(&mut self, cmd_buf: &[u8]) -> Result<(), TpmError> { + if self.context.is_null() { + return Err(TpmError::NotConnected); + } + + // Reset result buffer size + self.res_size = self.result_buffer.len() as u32; + + // Submit command to TBS + let res = unsafe { + Tbsip_Submit_Command( + self.context, + TBS_COMMAND_LOCALITY_ZERO, + TBS_COMMAND_PRIORITY_NORMAL, + cmd_buf, + self.result_buffer.as_mut_ptr(), + &mut self.res_size as *mut u32, + ) + }; + + if res != TBS_SUCCESS { + return Err(TpmError::TbsError(format!( + "TBS SubmitCommand error: 0x{:08x}", + res + ))); + } + + Ok(()) + } + + fn get_response(&mut self) -> Result, TpmError> { + if self.res_size == 0 { + return Err(TpmError::NoResponse); + } + + let resp = self.result_buffer[0..self.res_size as usize].to_vec(); + self.res_size = 0; + + Ok(resp) + } + + fn response_is_ready(&self) -> Result { + if self.context.is_null() { + return Err(TpmError::NotConnected); + } + + if self.res_size == 0 { + return Err(TpmError::UnexpectedState); + } + + // For Windows TBS, the response is always ready after dispatch_command + Ok(true) + } + + fn has_flag(&self, flag: u32) -> bool { + (self.tpm_info & flag) != 0 + } + + fn get_tpm_info(&self) -> u32 { + self.tpm_info + } +} + +// Linux TPM device implementation +#[cfg(target_os = "linux")] +pub struct TpmTbsDevice { + dev_tpm: Option, + socket: Option, + tpm_info: u32, +} + +#[cfg(target_os = "linux")] +impl TpmTbsDevice { + pub fn new() -> Self { + TpmTbsDevice { + dev_tpm: None, + socket: None, + tpm_info: 0, + } + } + + fn connect_to_linux_user_mode_trm(&mut self) -> Result { + use std::path::Path; + + // Check if TRM libraries exist + let old_trm = Path::new("/usr/lib/x86_64-linux-gnu/libtctisocket.so.0").exists() + || Path::new("/usr/lib/i386-linux-gnu/libtctisocket.so.0").exists(); + + let new_trm = Path::new("/usr/lib/x86_64-linux-gnu/libtcti-socket.so.0").exists() + || Path::new("/usr/lib/i386-linux-gnu/libtcti-socket.so.0").exists() + || Path::new("/usr/local/lib/libtss2-tcti-tabrmd.so.0").exists(); + + if !(old_trm || new_trm) { + return Ok(false); + } + + // Connect to user mode TRM + let mut socket = TcpStream::connect("127.0.0.1:2323") + .map_err(|e| TpmError::IoError(format!("Failed to connect to user TRM: {}", e)))?; + + // No handshake needed with user mode TRM + + self.socket = Some(socket); + self.tpm_info = TpmConnInfo::TpmSocketConn as u32 + | TpmConnInfo::TpmUsesTrm as u32 + | TpmConnInfo::TpmNoPowerCtl as u32 + | TpmConnInfo::TpmNoLocalityCtl as u32; + + if old_trm { + self.tpm_info |= TpmConnInfo::TpmLinuxOldUserModeTrm as u32; + } + + Ok(true) + } +} + +#[cfg(target_os = "linux")] +impl TpmDevice for TpmTbsDevice { + fn connect(&mut self) -> Result { + if self.tpm_info != 0 { + return Ok(true); // Already connected + } + + // Try to open the direct TPM device + match OpenOptions::new().read(true).write(true).open("/dev/tpm0") { + Ok(file) => { + self.dev_tpm = Some(file); + self.tpm_info = TpmConnInfo::TpmTbsConn as u32 + | TpmConnInfo::TpmNoPowerCtl as u32 + | TpmConnInfo::TpmNoLocalityCtl as u32; + return Ok(true); + } + Err(_) => { + // Try TPM resource manager + match OpenOptions::new() + .read(true) + .write(true) + .open("/dev/tpmrm0") + { + Ok(file) => { + self.dev_tpm = Some(file); + self.tpm_info = TpmConnInfo::TpmTbsConn as u32 + | TpmConnInfo::TpmUsesTrm as u32 + | TpmConnInfo::TpmNoPowerCtl as u32 + | TpmConnInfo::TpmNoLocalityCtl as u32; + return Ok(true); + } + Err(_) => { + // Try user mode TRM + return self.connect_to_linux_user_mode_trm(); + } + } + } + } + } + + fn close(&mut self) { + self.dev_tpm = None; + self.socket = None; + self.tpm_info = 0; + } + + fn dispatch_command(&mut self, cmd_buf: &[u8]) -> Result<(), TpmError> { + if self.tpm_info & (TpmConnInfo::TpmSocketConn as u32) != 0 { + // Socket-based communication + if let Some(socket) = self.socket.as_mut() { + // Send command to the TPM + let mut buf = vec![]; + + // Command header + buf.extend_from_slice(&(TcpTpmCommand::SendCommand as u32).to_be_bytes()); + buf.push(0); // locality + buf.extend_from_slice(&(cmd_buf.len() as u32).to_be_bytes()); + + if self.tpm_info & (TpmConnInfo::TpmLinuxOldUserModeTrm as u32) != 0 { + buf.push(0); // debugMsgLevel + buf.push(1); // commandSent + } + + // Send header and command buffer + socket + .write_all(&buf) + .map_err(|e| TpmError::IoError(e.to_string()))?; + socket + .write_all(cmd_buf) + .map_err(|e| TpmError::IoError(e.to_string()))?; + + Ok(()) + } else { + Err(TpmError::NotConnected) + } + } else if self.tpm_info & (TpmConnInfo::TpmTbsConn as u32) != 0 { + // TPM device file communication + if let Some(dev) = self.dev_tpm.as_mut() { + // Write command to TPM device + match dev.write_all(cmd_buf) { + Ok(_) => Ok(()), + Err(e) => Err(TpmError::IoError(format!( + "Failed to write TPM command: {}", + e + ))), + } + } else { + Err(TpmError::NotConnected) + } + } else { + Err(TpmError::InvalidTpmType) + } + } + + fn get_response(&mut self) -> Result, TpmError> { + if self.tpm_info & (TpmConnInfo::TpmSocketConn as u32) != 0 { + // Socket-based communication + if let Some(socket) = self.socket.as_mut() { + // Receive array length + let mut len_buf = [0u8; 4]; + socket + .read_exact(&mut len_buf) + .map_err(|e| TpmError::IoError(e.to_string()))?; + let len = u32::from_be_bytes(len_buf) as usize; + + // Read the response data + let mut resp = vec![0u8; len]; + socket + .read_exact(&mut resp) + .map_err(|e| TpmError::IoError(e.to_string()))?; + + // Get the terminating ACK + let mut ack_buf = [0u8; 4]; + socket + .read_exact(&mut ack_buf) + .map_err(|e| TpmError::IoError(e.to_string()))?; + let ack = u32::from_be_bytes(ack_buf); + + if ack != 0 { + return Err(TpmError::BadEndTag); + } + + Ok(resp) + } else { + Err(TpmError::NotConnected) + } + } else if self.tpm_info & (TpmConnInfo::TpmTbsConn as u32) != 0 { + // TPM device file communication + if let Some(dev) = self.dev_tpm.as_mut() { + // Buffer for response + let mut resp_buf = [0u8; 4096]; + + // Read from TPM device + match dev.read(&mut resp_buf) { + Ok(bytes_read) => { + if bytes_read < 10 { + // 10 is the mandatory response header size + return Err(TpmError::IoError(format!( + "Failed to read sufficient data from TPM: got {} bytes", + bytes_read + ))); + } + + Ok(resp_buf[0..bytes_read].to_vec()) + } + Err(e) => Err(TpmError::IoError(format!( + "Failed to read TPM response: {}", + e + ))), + } + } else { + Err(TpmError::NotConnected) + } + } else { + Err(TpmError::InvalidTpmType) + } + } + + fn response_is_ready(&self) -> Result { + // For Linux implementations, the response is typically ready after a blocking read + Ok(true) + } + + fn has_flag(&self, flag: u32) -> bool { + (self.tpm_info & flag) != 0 + } + + fn get_tpm_info(&self) -> u32 { + self.tpm_info + } +} + +// /// Socket utility module +// mod socket { +// use std::io; +// use std::net::TcpStream; +// use std::time::Duration; + +// #[cfg(unix)] +// pub fn select( +// read: &mut [TcpStream], +// write: &mut [TcpStream], +// except: &mut [TcpStream], +// timeout: Option<&Duration>, +// ) -> io::Result { +// use libc::{fd_set, select, timeval, FD_ISSET, FD_SET, FD_ZERO}; +// use std::os::unix::io::AsRawFd; + +// unsafe { +// let mut read_fds: fd_set = std::mem::zeroed(); +// let mut write_fds: fd_set = std::mem::zeroed(); +// let mut except_fds: fd_set = std::mem::zeroed(); + +// FD_ZERO(&mut read_fds); +// FD_ZERO(&mut write_fds); +// FD_ZERO(&mut except_fds); + +// let mut max_fd = 0; + +// for stream in read.iter() { +// let fd = stream.as_raw_fd(); +// FD_SET(fd, &mut read_fds); +// max_fd = std::cmp::max(max_fd, fd); +// } + +// for stream in write.iter() { +// let fd = stream.as_raw_fd(); +// FD_SET(fd, &mut write_fds); +// max_fd = std::cmp::max(max_fd, fd); +// } + +// for stream in except.iter() { +// let fd = stream.as_raw_fd(); +// FD_SET(fd, &mut except_fds); +// max_fd = std::cmp::max(max_fd, fd); +// } + +// let mut tv: timeval = std::mem::zeroed(); +// let tv_ptr = if let Some(timeout) = timeout { +// tv.tv_sec = timeout.as_secs() as _; +// tv.tv_usec = (timeout.subsec_micros()) as _; +// &mut tv as *mut timeval +// } else { +// std::ptr::null_mut() +// }; + +// let result = select( +// max_fd + 1, +// &mut read_fds, +// &mut write_fds, +// &mut except_fds, +// tv_ptr, +// ); + +// if result < 0 { +// return Err(io::Error::last_os_error()); +// } + +// // Count how many are ready +// let mut ready_count = 0; + +// for stream in read.iter() { +// if FD_ISSET(stream.as_raw_fd(), &read_fds) { +// ready_count += 1; +// } +// } + +// for stream in write.iter() { +// if FD_ISSET(stream.as_raw_fd(), &write_fds) { +// ready_count += 1; +// } +// } + +// for stream in except.iter() { +// if FD_ISSET(stream.as_raw_fd(), &except_fds) { +// ready_count += 1; +// } +// } + +// Ok(ready_count) +// } +// } + +// #[cfg(windows)] +// pub fn select( +// read: &mut [TcpStream], +// write: &mut [TcpStream], +// except: &mut [TcpStream], +// timeout: Option<&Duration>, +// ) -> io::Result { +// use std::os::windows::io::AsRawSocket; +// use windows::Win32::Networking::WinSock::{ +// fd_set, select, timeval, FD_ISSET, FD_SET, FD_ZERO, +// }; + +// unsafe { +// let mut read_fds: fd_set = std::mem::zeroed(); +// let mut write_fds: fd_set = std::mem::zeroed(); +// let mut except_fds: fd_set = std::mem::zeroed(); + +// FD_ZERO(&mut read_fds); +// FD_ZERO(&mut write_fds); +// FD_ZERO(&mut except_fds); + +// for stream in read.iter() { +// FD_SET(stream.as_raw_socket(), &mut read_fds); +// } + +// for stream in write.iter() { +// FD_SET(stream.as_raw_socket(), &mut write_fds); +// } + +// for stream in except.iter() { +// FD_SET(stream.as_raw_socket(), &mut except_fds); +// } + +// let mut tv: timeval = std::mem::zeroed(); +// let tv_ptr = if let Some(timeout) = timeout { +// tv.tv_sec = timeout.as_secs() as i32; +// tv.tv_usec = (timeout.subsec_micros()) as i32; +// &mut tv as *mut timeval +// } else { +// std::ptr::null_mut() +// }; + +// let result = select( +// 0, // ignored on Windows +// &mut read_fds, +// &mut write_fds, +// &mut except_fds, +// tv_ptr, +// ); + +// if result == -1 { +// return Err(io::Error::last_os_error()); +// } + +// // Count how many are ready +// let mut ready_count = 0; + +// for stream in read.iter() { +// if FD_ISSET(stream.as_raw_socket(), &read_fds) { +// ready_count += 1; +// } +// } + +// for stream in write.iter() { +// if FD_ISSET(stream.as_raw_socket(), &write_fds) { +// ready_count += 1; +// } +// } + +// for stream in except.iter() { +// if FD_ISSET(stream.as_raw_socket(), &except_fds) { +// ready_count += 1; +// } +// } + +// Ok(ready_count as usize) +// } +// } +// } diff --git a/TSS.Rust/src/error.rs b/TSS.Rust/src/error.rs new file mode 100644 index 00000000..f9739623 --- /dev/null +++ b/TSS.Rust/src/error.rs @@ -0,0 +1,105 @@ +//! Error types for TPM operations + +use std::error::Error; +use std::fmt; + +/// TPM Error types +#[derive(Debug)] +pub enum TpmError { + /// Buffer underflow occurred during deserialization + BufferUnderflow, + + /// Buffer overflow occurred during serialization + BufferOverflow, + + /// Invalid array size + InvalidArraySize(String), + + /// Invalid enum value + InvalidEnumValue, + + /// Invalid union type + InvalidUnion, + + /// Incorrect tag value + IncorrectTag(u32, u32), // expected, actual + + /// I/O error + IoError(String), + + /// Device communication error + DeviceError(String), + + /// Generic TPM error + GenericError(String), + + /// Operation not supported + NotSupported(String), + + /// TPM device not connected + NotConnected, + + /// Bad end tag received from TPM + BadEndTag, + + /// Command failed + CommandFailed, + + /// Invalid parameter provided + InvalidParameter, + + /// No response available + NoResponse, + + /// Unexpected device state + UnexpectedState, + + /// Incompatible TPM/proxy + IncompatibleTpm, + + /// Invalid TPM device type + InvalidTpmType, + + /// Windows TBS specific error + #[cfg(target_os = "windows")] + TbsError(String), +} + +impl fmt::Display for TpmError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::BufferUnderflow => write!(f, "Buffer underflow during deserialization"), + Self::BufferOverflow => write!(f, "Buffer overflow during serialization"), + Self::InvalidArraySize(msg) => write!(f, "Invalid array size: {}", msg), + Self::InvalidEnumValue => write!(f, "Invalid enum value"), + Self::InvalidUnion => write!(f, "Invalid union type"), + Self::IncorrectTag(expected, actual) => write!( + f, + "Incorrect tag: expected 0x{:X}, got 0x{:X}", + expected, actual + ), + Self::IoError(msg) => write!(f, "I/O error: {}", msg), + Self::DeviceError(msg) => write!(f, "Device error: {}", msg), + Self::GenericError(msg) => write!(f, "TPM error: {}", msg), + Self::NotSupported(operation) => write!(f, "Operation not supported: {}", operation), + Self::NotConnected => write!(f, "TPM device not connected"), + Self::BadEndTag => write!(f, "Bad end tag received from TPM"), + Self::CommandFailed => write!(f, "TPM command failed"), + Self::InvalidParameter => write!(f, "Invalid parameter provided"), + Self::NoResponse => write!(f, "No TPM response available"), + Self::UnexpectedState => write!(f, "TPM in unexpected state"), + Self::IncompatibleTpm => write!(f, "Incompatible TPM/proxy"), + Self::InvalidTpmType => write!(f, "Invalid TPM device type"), + #[cfg(target_os = "windows")] + Self::TbsError(msg) => write!(f, "TBS error: {}", msg), + } + } +} + +impl Error for TpmError {} + +impl From for TpmError { + fn from(error: std::io::Error) -> Self { + TpmError::IoError(error.to_string()) + } +} diff --git a/TSS.Rust/src/lib.rs b/TSS.Rust/src/lib.rs new file mode 100644 index 00000000..90cf32d3 --- /dev/null +++ b/TSS.Rust/src/lib.rs @@ -0,0 +1,12 @@ +pub mod auth_session; +pub mod crypto; +pub mod device; +pub mod error; +pub mod tpm2; +pub mod tpm2_helpers; +pub mod tpm2_impl; +pub mod tpm_buffer; +pub mod tpm_structure; +pub mod tpm_types; +pub mod tpm_type_extensions; +pub mod policy; diff --git a/TSS.Rust/src/policy.rs b/TSS.Rust/src/policy.rs new file mode 100644 index 00000000..8191e189 --- /dev/null +++ b/TSS.Rust/src/policy.rs @@ -0,0 +1,656 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See the LICENSE file in the project root for full license information. + */ + +//! Policy tree infrastructure for declarative TPM 2.0 policy composition. +//! +//! This module provides a `PolicyTree` that lets you compose policy assertions +//! (e.g., PolicyLocality, PolicyCommandCode, PolicyPCR, PolicyOR, etc.) into +//! a tree. The tree can then compute a policy digest (trial) or be executed +//! against a real policy session on the TPM. + +use crate::auth_session::Session; +use crate::crypto::Crypto; +use crate::error::TpmError; +use crate::tpm2_impl::Tpm2; +use crate::tpm_buffer::{TpmBuffer, TpmMarshaller}; +use crate::tpm_structure::TpmEnum; +use crate::tpm_types::*; + +// --------------------------------------------------------------------------- +// PolicyAssertion trait - base for all policy nodes +// --------------------------------------------------------------------------- + +/// Trait implemented by all policy assertion types. +pub trait PolicyAssertion { + /// Update a policy digest accumulator (used for trial/software digest computation). + fn update_policy_digest(&self, hash_alg: TPM_ALG_ID, accumulator: &mut Vec) -> Result<(), TpmError>; + + /// Execute this policy assertion against a live TPM policy session. + fn execute(&self, tpm: &mut Tpm2, session: &Session) -> Result; +} + +// --------------------------------------------------------------------------- +// Helper: PolicyUpdate - shared digest update logic per TPM spec +// --------------------------------------------------------------------------- + +/// `policyDigest = H(policyDigest || commandCode || arg2)` +/// Then: `policyDigest = H(policyDigest || arg3)` +fn policy_update( + hash_alg: TPM_ALG_ID, + accumulator: &mut Vec, + command_code: TPM_CC, + arg2: &[u8], + arg3: &[u8], +) -> Result<(), TpmError> { + // First extend: H(accumulator || CC || arg2) + let mut buf = Vec::new(); + buf.extend_from_slice(accumulator); + buf.extend_from_slice(&command_code.get_value().to_be_bytes()); + buf.extend_from_slice(arg2); + *accumulator = Crypto::hash(hash_alg, &buf)?; + + // Second extend (if arg3 is non-empty): H(accumulator || arg3) + if !arg3.is_empty() { + let mut buf2 = Vec::new(); + buf2.extend_from_slice(accumulator); + buf2.extend_from_slice(arg3); + *accumulator = Crypto::hash(hash_alg, &buf2)?; + } + Ok(()) +} + +/// Helper to get session handle from a Session +fn sess_handle(s: &Session) -> TPM_HANDLE { + s.sess_in.sessionHandle.clone() +} + +// --------------------------------------------------------------------------- +// PolicyTree +// --------------------------------------------------------------------------- + +/// A composable policy tree that can compute digests and execute against the TPM. +pub struct PolicyTree { + assertions: Vec>, +} + +impl PolicyTree { + /// Create an empty policy tree. + pub fn new() -> Self { + Self { assertions: Vec::new() } + } + + /// Add a policy assertion to the tree. Assertions execute in order (first added = first executed). + pub fn add(mut self, assertion: impl PolicyAssertion + 'static) -> Self { + self.assertions.push(Box::new(assertion)); + self + } + + /// Compute the policy digest in software (equivalent to a trial session). + pub fn get_policy_digest(&self, hash_alg: TPM_ALG_ID) -> Result, TpmError> { + compute_digest(&self.assertions, hash_alg) + } + + /// Execute all assertions in order against a live policy session. + /// Returns the updated session (with rolled nonces). + pub fn execute(&self, tpm: &mut Tpm2, session: Session) -> Result { + let mut sess = session; + for assertion in &self.assertions { + sess = assertion.execute(tpm, &sess)?; + } + Ok(sess) + } +} + +/// Compute the digest for a slice of assertions (used by PolicyTree and PolicyOr). +pub(crate) fn compute_digest( + assertions: &[Box], + hash_alg: TPM_ALG_ID, +) -> Result, TpmError> { + let hash_len = Crypto::hash(hash_alg, &[])?.len(); + let mut accumulator = vec![0u8; hash_len]; + for assertion in assertions { + assertion.update_policy_digest(hash_alg, &mut accumulator)?; + } + Ok(accumulator) +} + +// --------------------------------------------------------------------------- +// Concrete policy assertion types +// --------------------------------------------------------------------------- + +/// PolicyCommandCode - limits the authorized action to a specific command. +pub struct PolicyCommandCode { + pub command_code: TPM_CC, +} + +impl PolicyCommandCode { + pub fn new(command_code: TPM_CC) -> Self { + Self { command_code } + } +} + +impl PolicyAssertion for PolicyCommandCode { + fn update_policy_digest(&self, hash_alg: TPM_ALG_ID, acc: &mut Vec) -> Result<(), TpmError> { + let mut buf = Vec::new(); + buf.extend_from_slice(&self.command_code.get_value().to_be_bytes()); + policy_update(hash_alg, acc, TPM_CC::PolicyCommandCode, &buf, &[]) + } + + fn execute(&self, tpm: &mut Tpm2, session: &Session) -> Result { + tpm.PolicyCommandCode(&sess_handle(session), self.command_code)?; + Ok(tpm.last_session().unwrap_or_else(|| session.clone())) + } +} + +/// PolicyLocality - limits authorization to a specific locality. +pub struct PolicyLocality { + pub locality: TPMA_LOCALITY, +} + +impl PolicyLocality { + pub fn new(locality: TPMA_LOCALITY) -> Self { + Self { locality } + } +} + +impl PolicyAssertion for PolicyLocality { + fn update_policy_digest(&self, hash_alg: TPM_ALG_ID, acc: &mut Vec) -> Result<(), TpmError> { + // PolicyLocality: H(acc || TPM_CC_PolicyLocality || locality_byte) + let mut buf = Vec::new(); + buf.extend_from_slice(acc); + buf.extend_from_slice(&TPM_CC::PolicyLocality.get_value().to_be_bytes()); + buf.push(self.locality.get_value() as u8); + *acc = Crypto::hash(hash_alg, &buf)?; + Ok(()) + } + + fn execute(&self, tpm: &mut Tpm2, session: &Session) -> Result { + tpm.PolicyLocality(&sess_handle(session), self.locality)?; + Ok(tpm.last_session().unwrap_or_else(|| session.clone())) + } +} + +/// PolicyPCR - gates policy on PCR values. +pub struct PolicyPcr { + pub pcr_values: Vec, + pub pcr_selections: Vec, +} + +impl PolicyPcr { + pub fn new(pcr_values: Vec, pcr_selections: Vec) -> Self { + Self { pcr_values, pcr_selections } + } +} + +impl PolicyAssertion for PolicyPcr { + fn update_policy_digest(&self, hash_alg: TPM_ALG_ID, acc: &mut Vec) -> Result<(), TpmError> { + // Concatenate all PCR values and hash them + let mut pcr_data = Vec::new(); + for v in &self.pcr_values { + pcr_data.extend_from_slice(&v.buffer); + } + let pcr_digest = Crypto::hash(hash_alg, &pcr_data)?; + + // Marshal PCR selections + let mut sel_buf = TpmBuffer::new(None); + sel_buf.writeInt(self.pcr_selections.len() as u32); + for sel in &self.pcr_selections { + sel.toTpm(&mut sel_buf)?; + } + + let mut arg2 = Vec::new(); + arg2.extend_from_slice(sel_buf.trim()); + arg2.extend_from_slice(&pcr_digest); + policy_update(hash_alg, acc, TPM_CC::PolicyPCR, &arg2, &[]) + } + + fn execute(&self, tpm: &mut Tpm2, session: &Session) -> Result { + tpm.PolicyPCR(&sess_handle(session), &self.pcr_values[0].buffer, &self.pcr_selections)?; + Ok(tpm.last_session().unwrap_or_else(|| session.clone())) + } +} + +/// PolicyPassword - requires the object's authorization value be provided as a password. +pub struct PolicyPassword; + +impl PolicyPassword { + pub fn new() -> Self { Self } +} + +impl PolicyAssertion for PolicyPassword { + fn update_policy_digest(&self, hash_alg: TPM_ALG_ID, acc: &mut Vec) -> Result<(), TpmError> { + // PolicyPassword uses the same digest as PolicyAuthValue per spec + policy_update(hash_alg, acc, TPM_CC::PolicyAuthValue, &[], &[]) + } + + fn execute(&self, tpm: &mut Tpm2, session: &Session) -> Result { + tpm.PolicyPassword(&sess_handle(session))?; + let mut sess = tpm.last_session().unwrap_or_else(|| session.clone()); + sess.needs_password = true; + Ok(sess) + } +} + +/// PolicyAuthValue - requires auth-value HMAC during policy use. +pub struct PolicyAuthValue; + +impl PolicyAuthValue { + pub fn new() -> Self { Self } +} + +impl PolicyAssertion for PolicyAuthValue { + fn update_policy_digest(&self, hash_alg: TPM_ALG_ID, acc: &mut Vec) -> Result<(), TpmError> { + policy_update(hash_alg, acc, TPM_CC::PolicyAuthValue, &[], &[]) + } + + fn execute(&self, tpm: &mut Tpm2, session: &Session) -> Result { + tpm.PolicyAuthValue(&sess_handle(session))?; + let mut sess = tpm.last_session().unwrap_or_else(|| session.clone()); + sess.needs_hmac = true; + Ok(sess) + } +} + +/// PolicyCpHash - binds policy to specific command parameters. +pub struct PolicyCpHash { + pub cp_hash: Vec, +} + +impl PolicyCpHash { + pub fn new(cp_hash: Vec) -> Self { + Self { cp_hash } + } +} + +impl PolicyAssertion for PolicyCpHash { + fn update_policy_digest(&self, hash_alg: TPM_ALG_ID, acc: &mut Vec) -> Result<(), TpmError> { + policy_update(hash_alg, acc, TPM_CC::PolicyCpHash, &self.cp_hash, &[]) + } + + fn execute(&self, tpm: &mut Tpm2, session: &Session) -> Result { + tpm.PolicyCpHash(&sess_handle(session), &self.cp_hash)?; + Ok(tpm.last_session().unwrap_or_else(|| session.clone())) + } +} + +/// PolicyNameHash - binds policy to specific object handles. +pub struct PolicyNameHash { + pub name_hash: Vec, +} + +impl PolicyNameHash { + pub fn new(name_hash: Vec) -> Self { + Self { name_hash } + } +} + +impl PolicyAssertion for PolicyNameHash { + fn update_policy_digest(&self, hash_alg: TPM_ALG_ID, acc: &mut Vec) -> Result<(), TpmError> { + policy_update(hash_alg, acc, TPM_CC::PolicyNameHash, &self.name_hash, &[]) + } + + fn execute(&self, tpm: &mut Tpm2, session: &Session) -> Result { + tpm.PolicyNameHash(&sess_handle(session), &self.name_hash)?; + Ok(tpm.last_session().unwrap_or_else(|| session.clone())) + } +} + +/// PolicyCounterTimer - gates policy on TPMS_TIME_INFO contents. +pub struct PolicyCounterTimer { + pub operand_b: Vec, + pub offset: u16, + pub operation: TPM_EO, +} + +impl PolicyCounterTimer { + pub fn new(operand_b: Vec, offset: u16, operation: TPM_EO) -> Self { + Self { operand_b, offset, operation } + } + + /// Convenience: create from a u64 value (marshalled as 8 big-endian bytes). + pub fn from_u64(value: u64, offset: u16, operation: TPM_EO) -> Self { + Self { operand_b: value.to_be_bytes().to_vec(), offset, operation } + } +} + +impl PolicyAssertion for PolicyCounterTimer { + fn update_policy_digest(&self, hash_alg: TPM_ALG_ID, acc: &mut Vec) -> Result<(), TpmError> { + // arg2 = H(operandB || offset || operation) + let mut inner = Vec::new(); + inner.extend_from_slice(&self.operand_b); + inner.extend_from_slice(&self.offset.to_be_bytes()); + inner.extend_from_slice(&(self.operation.get_value() as u16).to_be_bytes()); + let arg_hash = Crypto::hash(hash_alg, &inner)?; + policy_update(hash_alg, acc, TPM_CC::PolicyCounterTimer, &arg_hash, &[]) + } + + fn execute(&self, tpm: &mut Tpm2, session: &Session) -> Result { + tpm.PolicyCounterTimer( + &sess_handle(session), &self.operand_b, self.offset, self.operation, + )?; + Ok(tpm.last_session().unwrap_or_else(|| session.clone())) + } +} + +/// PolicySecret - secret-based authorization (proves knowledge of an auth value). +pub struct PolicySecret { + pub auth_object_name: Vec, + pub policy_ref: Vec, + pub cp_hash_a: Vec, + pub expiration: i32, + pub include_tpm_nonce: bool, + /// The handle used during execution (set before calling execute). + pub auth_handle: TPM_HANDLE, +} + +impl PolicySecret { + pub fn new(auth_object_name: Vec, auth_handle: TPM_HANDLE) -> Self { + Self { + auth_object_name, + policy_ref: vec![], + cp_hash_a: vec![], + expiration: 0, + include_tpm_nonce: false, + auth_handle, + } + } +} + +impl PolicyAssertion for PolicySecret { + fn update_policy_digest(&self, hash_alg: TPM_ALG_ID, acc: &mut Vec) -> Result<(), TpmError> { + policy_update(hash_alg, acc, TPM_CC::PolicySecret, &self.auth_object_name, &self.policy_ref) + } + + fn execute(&self, tpm: &mut Tpm2, session: &Session) -> Result { + let nonce_tpm = if self.include_tpm_nonce { + session.sess_out.nonce.clone() + } else { + vec![] + }; + tpm.PolicySecret( + &self.auth_handle, &sess_handle(session), + &nonce_tpm, &self.cp_hash_a, &self.policy_ref, self.expiration, + )?; + Ok(tpm.last_session().unwrap_or_else(|| session.clone())) + } +} + +/// PolicySigned - asymmetrically signed authorization. +pub struct PolicySigned { + pub include_tpm_nonce: bool, + pub cp_hash_a: Vec, + pub policy_ref: Vec, + pub expiration: i32, + pub public_key: TPMT_PUBLIC, + /// If set, the library will sign automatically. Otherwise a callback is needed. + pub sw_key: Option, +} + +impl PolicySigned { + pub fn new(public_key: TPMT_PUBLIC) -> Self { + Self { + include_tpm_nonce: false, + cp_hash_a: vec![], + policy_ref: vec![], + expiration: 0, + public_key, + sw_key: None, + } + } + + /// Provide a software key so the library can sign automatically. + pub fn with_key(mut self, key: TSS_KEY) -> Self { + self.sw_key = Some(key); + self + } + + pub fn with_nonce(mut self) -> Self { + self.include_tpm_nonce = true; + self + } +} + +impl PolicyAssertion for PolicySigned { + fn update_policy_digest(&self, hash_alg: TPM_ALG_ID, acc: &mut Vec) -> Result<(), TpmError> { + let key_name = self.public_key.get_name()?; + policy_update(hash_alg, acc, TPM_CC::PolicySigned, &key_name, &self.policy_ref) + } + + fn execute(&self, tpm: &mut Tpm2, session: &Session) -> Result { + let nonce_tpm = if self.include_tpm_nonce { + session.sess_out.nonce.clone() + } else { + vec![] + }; + + // Determine hash alg from the key's scheme + let hash_alg = if let Some(TPMU_PUBLIC_PARMS::rsaDetail(ref params)) = self.public_key.parameters { + if let Some(TPMU_ASYM_SCHEME::rsassa(ref scheme)) = params.scheme { + scheme.hashAlg + } else { + self.public_key.nameAlg + } + } else { + self.public_key.nameAlg + }; + + // Compute aHash = Hash(nonceTPM || expiration || cpHashA || policyRef) + let mut to_hash = Vec::new(); + to_hash.extend_from_slice(&nonce_tpm); + to_hash.extend_from_slice(&self.expiration.to_be_bytes()); + to_hash.extend_from_slice(&self.cp_hash_a); + to_hash.extend_from_slice(&self.policy_ref); + let a_hash = Crypto::hash(hash_alg, &to_hash)?; + + let sw_key = self.sw_key.as_ref().ok_or_else(|| { + TpmError::GenericError("PolicySigned: no SW key set (callbacks not yet supported)".into()) + })?; + let signature = sw_key.sign(&a_hash, hash_alg)?; + + // Load the public key into the TPM (OWNER hierarchy for valid tickets) + let pub_key_handle = tpm.LoadExternal( + &TPMT_SENSITIVE::default(), + &self.public_key, + &TPM_HANDLE::new(TPM_RH::OWNER.get_value()), + )?; + + let result = tpm.PolicySigned( + &pub_key_handle, &sess_handle(session), + &nonce_tpm, &self.cp_hash_a, &self.policy_ref, self.expiration, + &signature.signature, + ); + + tpm.FlushContext(&pub_key_handle)?; + result?; + Ok(tpm.last_session().unwrap_or_else(|| session.clone())) + } +} + +/// PolicyNV - conditional gating based on NV Index contents. +pub struct PolicyNv { + pub operand_b: Vec, + pub offset: u16, + pub operation: TPM_EO, + pub nv_index_name: Vec, + pub auth_handle: TPM_HANDLE, + pub nv_index: TPM_HANDLE, +} + +impl PolicyNv { + pub fn new( + auth_handle: TPM_HANDLE, + nv_index: TPM_HANDLE, + nv_index_name: Vec, + operand_b: Vec, + offset: u16, + operation: TPM_EO, + ) -> Self { + Self { operand_b, offset, operation, nv_index_name, auth_handle, nv_index } + } +} + +impl PolicyAssertion for PolicyNv { + fn update_policy_digest(&self, hash_alg: TPM_ALG_ID, acc: &mut Vec) -> Result<(), TpmError> { + // arg2 = H(operandB || offset || operation) + let mut inner = Vec::new(); + inner.extend_from_slice(&self.operand_b); + inner.extend_from_slice(&self.offset.to_be_bytes()); + inner.extend_from_slice(&(self.operation.get_value() as u16).to_be_bytes()); + let args_hash = Crypto::hash(hash_alg, &inner)?; + policy_update(hash_alg, acc, TPM_CC::PolicyNV, &args_hash, &self.nv_index_name) + } + + fn execute(&self, tpm: &mut Tpm2, session: &Session) -> Result { + tpm.PolicyNV( + &self.auth_handle, &self.nv_index, &sess_handle(session), + &self.operand_b, self.offset, self.operation, + )?; + Ok(tpm.last_session().unwrap_or_else(|| session.clone())) + } +} + +/// PolicyOR - allows one of several policy branches to satisfy the policy. +pub struct PolicyOr { + pub branches: Vec>>, +} + +impl PolicyOr { + /// Create from pre-built branches (each branch is a Vec of boxed assertions). + pub fn new(branches: Vec>>) -> Self { + Self { branches } + } + + /// Convenience: create a two-branch PolicyOR from PolicyTrees. + pub fn from_trees(trees: Vec) -> Self { + let branches = trees.into_iter() + .map(|t| t.assertions) + .collect(); + Self { branches } + } +} + +impl PolicyAssertion for PolicyOr { + fn update_policy_digest(&self, hash_alg: TPM_ALG_ID, acc: &mut Vec) -> Result<(), TpmError> { + // PolicyOR: accumulator = H(0...0 || TPM_CC_PolicyOR || digest1 || digest2 || ...) + let hash_len = Crypto::hash(hash_alg, &[])?.len(); + let mut buf = Vec::new(); + buf.extend_from_slice(&vec![0u8; hash_len]); // reset to zero + buf.extend_from_slice(&TPM_CC::PolicyOR.get_value().to_be_bytes()); + for branch in &self.branches { + let branch_digest = compute_digest(branch, hash_alg)?; + buf.extend_from_slice(&branch_digest); + } + *acc = Crypto::hash(hash_alg, &buf)?; + Ok(()) + } + + fn execute(&self, tpm: &mut Tpm2, session: &Session) -> Result { + let hash_alg = session.get_hash_alg(); + let mut hash_list: Vec = Vec::new(); + for branch in &self.branches { + let digest = compute_digest(branch, hash_alg)?; + hash_list.push(TPM2B_DIGEST { buffer: digest }); + } + tpm.PolicyOR(&sess_handle(session), &hash_list)?; + Ok(tpm.last_session().unwrap_or_else(|| session.clone())) + } +} + +/// PolicyAuthorize - transforms a policy digest using a signing key's authorization. +pub struct PolicyAuthorize { + pub approved_policy: Vec, + pub policy_ref: Vec, + pub authorizing_key: TPMT_PUBLIC, + pub signature: TPMT_SIGNATURE, +} + +impl PolicyAuthorize { + pub fn new( + approved_policy: Vec, + policy_ref: Vec, + authorizing_key: TPMT_PUBLIC, + signature: TPMT_SIGNATURE, + ) -> Self { + Self { approved_policy, policy_ref, authorizing_key, signature } + } +} + +impl PolicyAssertion for PolicyAuthorize { + fn update_policy_digest(&self, hash_alg: TPM_ALG_ID, acc: &mut Vec) -> Result<(), TpmError> { + let key_name = self.authorizing_key.get_name()?; + // PolicyAuthorize resets the digest, then does PolicyUpdate + let hash_len = Crypto::hash(hash_alg, &[])?.len(); + *acc = vec![0u8; hash_len]; + policy_update(hash_alg, acc, TPM_CC::PolicyAuthorize, &key_name, &self.policy_ref) + } + + fn execute(&self, tpm: &mut Tpm2, session: &Session) -> Result { + let key_name = self.authorizing_key.get_name()?; + + // Load the authorizing key (OWNER hierarchy for valid tickets) + let key_handle = tpm.LoadExternal( + &TPMT_SENSITIVE::default(), + &self.authorizing_key, + &TPM_HANDLE::new(TPM_RH::OWNER.get_value()), + )?; + + // Compute aHash and get a verification ticket + let mut a_hash_data = Vec::new(); + a_hash_data.extend_from_slice(&self.approved_policy); + a_hash_data.extend_from_slice(&self.policy_ref); + let a_hash = Crypto::hash(self.authorizing_key.nameAlg, &a_hash_data)?; + + let check_ticket = tpm.VerifySignature( + &key_handle, &a_hash, &self.signature.signature, + )?; + + let result = tpm.PolicyAuthorize( + &sess_handle(session), + &self.approved_policy, + &self.policy_ref, + &key_name, + &check_ticket, + ); + + tpm.FlushContext(&key_handle)?; + result?; + Ok(tpm.last_session().unwrap_or_else(|| session.clone())) + } +} + +/// PolicyDuplicationSelect - qualifies duplication to a selected new parent. +pub struct PolicyDuplicationSelect { + pub object_name: Vec, + pub new_parent_name: Vec, + pub include_object: bool, +} + +impl PolicyDuplicationSelect { + pub fn new(object_name: Vec, new_parent_name: Vec, include_object: bool) -> Self { + Self { object_name, new_parent_name, include_object } + } +} + +impl PolicyAssertion for PolicyDuplicationSelect { + fn update_policy_digest(&self, hash_alg: TPM_ALG_ID, acc: &mut Vec) -> Result<(), TpmError> { + let mut arg2 = Vec::new(); + if self.include_object { + arg2.extend_from_slice(&self.object_name); + } + arg2.extend_from_slice(&self.new_parent_name); + arg2.push(if self.include_object { 1 } else { 0 }); + policy_update(hash_alg, acc, TPM_CC::PolicyDuplicationSelect, &arg2, &[]) + } + + fn execute(&self, tpm: &mut Tpm2, session: &Session) -> Result { + tpm.PolicyDuplicationSelect( + &sess_handle(session), + &self.object_name, + &self.new_parent_name, + if self.include_object { 1 } else { 0 }, + )?; + Ok(tpm.last_session().unwrap_or_else(|| session.clone())) + } +} diff --git a/TSS.Rust/src/tpm2.rs b/TSS.Rust/src/tpm2.rs new file mode 100644 index 00000000..5c2b08d7 --- /dev/null +++ b/TSS.Rust/src/tpm2.rs @@ -0,0 +1,7642 @@ +/* + * NOTE: this file is partially auto generated! + * + * All code after the point marked with the '// <>' comment + * is autogenerated from the TPM 2.0 Specification docs. + * + * DO NOT EDIT AUTOGENERATED PART - all manual changes will be lost! + */ + +//! TPM2 command implementations + +#![allow(non_snake_case)] + +use crate::error::TpmError; +use crate::tpm2_impl::*; +use crate::tpm_buffer::TpmBuffer; +use crate::tpm_buffer::TpmMarshaller; +use crate::tpm_structure::*; +use crate::tpm_types::*; + +impl Tpm2 { + pub fn async_methods(&mut self) -> AsyncMethods { + AsyncMethods { tpm: self } + } +} + +#[derive(Debug, Default, Clone)] +struct EmptyTpmResponse {} + +impl TpmMarshaller for EmptyTpmResponse { + fn toTpm(&self, _buf: &mut TpmBuffer) -> Result<(), TpmError> { + Ok(()) + } + + /** Populate this object from the TPM representation in the given marshaling buffer */ + fn initFromTpm(&mut self, _buf: &mut TpmBuffer) -> Result<(), TpmError> { + Ok(()) + } +} + +impl TpmStructure for EmptyTpmResponse { + fn serialize(&self, _buffer: &mut TpmBuffer) -> Result<(), TpmError> { + Ok(()) + } + + fn deserialize(&mut self, _buffer: &mut TpmBuffer) -> Result<(), TpmError> { + Ok(()) + } + + fn fromTpm(&self, _buffer: &mut TpmBuffer) -> Result<(), TpmError> { + Ok(()) + } + + fn fromBytes(&mut self, _buffer: &mut Vec) -> Result<(), TpmError> { + Ok(()) + } +} + +impl CmdStructure for EmptyTpmResponse {} + +impl RespStructure for EmptyTpmResponse { + fn get_handle(&self) -> TPM_HANDLE { + TPM_HANDLE::default() + } +} + +// <> +// ------------------------------------------------------------------------------------------------ +// DO NOT REMOVE the <> comment! +// DO NOT MODIFY any code below this point - all manual changes will be lost! +// ------------------------------------------------------------------------------------------------ + +impl Tpm2 { + /// TPM2_Startup() is always preceded by _TPM_Init, which is the physical indication that TPM + /// initialization is necessary because of a system-wide reset. TPM2_Startup() is only valid + /// after _TPM_Init. Additional TPM2_Startup() commands are not allowed after it has completed + /// successfully. If a TPM requires TPM2_Startup() and another command is received, or if the + /// TPM receives TPM2_Startup() when it is not required, the TPM shall return TPM_RC_INITIALIZE. + /// startupType: TPM_SU_CLEAR or TPM_SU_STATE + pub fn Startup( + &mut self, + startupType: TPM_SU, + ) -> Result<(), TpmError> { + let req = TPM2_Startup_REQUEST::new( + startupType, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::Startup, req, &mut resp)?; + Ok(()) + } + + /// This command is used to prepare the TPM for a power cycle. The shutdownType parameter + /// indicates how the subsequent TPM2_Startup() will be processed. + /// shutdownType: TPM_SU_CLEAR or TPM_SU_STATE + pub fn Shutdown( + &mut self, + shutdownType: TPM_SU, + ) -> Result<(), TpmError> { + let req = TPM2_Shutdown_REQUEST::new( + shutdownType, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::Shutdown, req, &mut resp)?; + Ok(()) + } + + /// This command causes the TPM to perform a test of its capabilities. If the fullTest is YES, + /// the TPM will test all functions. If fullTest = NO, the TPM will only test those functions + /// that have not previously been tested. + /// fullTest: YES if full test to be performed + /// NO if only test of untested functions required + pub fn SelfTest( + &mut self, + fullTest: u8, + ) -> Result<(), TpmError> { + let req = TPM2_SelfTest_REQUEST::new( + fullTest, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::SelfTest, req, &mut resp)?; + Ok(()) + } + + /// This command causes the TPM to perform a test of the selected algorithms. + /// toTest: List of algorithms that should be tested + /// toDoList - List of algorithms that need testing + pub fn IncrementalSelfTest( + &mut self, + toTest: &Vec, + ) -> Result, TpmError> { + let req = TPM2_IncrementalSelfTest_REQUEST::new( + toTest, + ); + + let mut resp = IncrementalSelfTestResponse::default(); + self.dispatch(TPM_CC::IncrementalSelfTest, req, &mut resp)?; + Ok(resp.toDoList) + } + + /// This command returns manufacturer-specific information regarding the results of a + /// self-test and an indication of the test status. + /// outData - Test result data + /// contains manufacturer-specific information + /// testResult - TBD + pub fn GetTestResult( + &mut self, + ) -> Result { + let req = TPM2_GetTestResult_REQUEST::default(); + + let mut resp = GetTestResultResponse::default(); + self.dispatch(TPM_CC::GetTestResult, req, &mut resp)?; + Ok(resp) + } + + /// This command is used to start an authorization session using alternative methods of + /// establishing the session key (sessionKey). The session key is then used to derive values + /// used for authorization and for encrypting parameters. + /// tpmKey: Handle of a loaded decrypt key used to encrypt salt + /// may be TPM_RH_NULL + /// Auth Index: None + /// bind: Entity providing the authValue + /// may be TPM_RH_NULL + /// Auth Index: None + /// nonceCaller: Initial nonceCaller, sets nonceTPM size for the session + /// shall be at least 16 octets + /// encryptedSalt: Value encrypted according to the type of tpmKey + /// If tpmKey is TPM_RH_NULL, this shall be the Empty Buffer. + /// sessionType: Indicates the type of the session; simple HMAC or policy (including a trial policy) + /// symmetric: The algorithm and key size for parameter encryption + /// may select TPM_ALG_NULL + /// authHash: Hash algorithm to use for the session + /// Shall be a hash algorithm supported by the TPM and not TPM_ALG_NULL + /// handle - Handle for the newly created session + /// nonceTPM - The initial nonce from the TPM, used in the computation of the sessionKey + pub fn StartAuthSession( + &mut self, + tpmKey: &TPM_HANDLE, + bind: &TPM_HANDLE, + nonceCaller: &Vec, + encryptedSalt: &Vec, + sessionType: TPM_SE, + symmetric: &TPMT_SYM_DEF, + authHash: TPM_ALG_ID, + ) -> Result { + let req = TPM2_StartAuthSession_REQUEST::new( + tpmKey, + bind, + nonceCaller, + encryptedSalt, + sessionType, + symmetric, + authHash, + ); + + let mut resp = StartAuthSessionResponse::default(); + self.dispatch(TPM_CC::StartAuthSession, req, &mut resp)?; + Ok(resp) + } + + /// This command allows a policy authorization session to be returned to its initial state. + /// This command is used after the TPM returns TPM_RC_PCR_CHANGED. That response code + /// indicates that a policy will fail because the PCR have changed after TPM2_PolicyPCR() was + /// executed. Restarting the session allows the authorizations to be replayed because the + /// session restarts with the same nonceTPM. If the PCR are valid for the policy, the policy + /// may then succeed. + /// sessionHandle: The handle for the policy session + pub fn PolicyRestart( + &mut self, + sessionHandle: &TPM_HANDLE, + ) -> Result<(), TpmError> { + let req = TPM2_PolicyRestart_REQUEST::new( + sessionHandle, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::PolicyRestart, req, &mut resp)?; + Ok(()) + } + + /// This command is used to create an object that can be loaded into a TPM using TPM2_Load(). + /// If the command completes successfully, the TPM will create the new object and return the + /// objects creation data (creationData), its public area (outPublic), and its encrypted + /// sensitive area (outPrivate). Preservation of the returned data is the responsibility of + /// the caller. The object will need to be loaded (TPM2_Load()) before it may be used. The + /// only difference between the inPublic TPMT_PUBLIC template and the outPublic TPMT_PUBLIC + /// object is in the unique field. + /// parentHandle: Handle of parent for new object + /// Auth Index: 1 + /// Auth Role: USER + /// inSensitive: The sensitive data + /// inPublic: The public template + /// outsideInfo: Data that will be included in the creation data for this object to provide + /// permanent, verifiable linkage between this object and some object owner data + /// creationPCR: PCR that will be used in creation data + /// outPrivate - The private portion of the object + /// outPublic - The public portion of the created object + /// creationData - Contains a TPMS_CREATION_DATA + /// creationHash - Digest of creationData using nameAlg of outPublic + /// creationTicket - Ticket used by TPM2_CertifyCreation() to validate that the creation + /// data was produced by the TPM + pub fn Create( + &mut self, + parentHandle: &TPM_HANDLE, + inSensitive: &TPMS_SENSITIVE_CREATE, + inPublic: &TPMT_PUBLIC, + outsideInfo: &Vec, + creationPCR: &Vec, + ) -> Result { + let req = TPM2_Create_REQUEST::new( + parentHandle, + inSensitive, + inPublic, + outsideInfo, + creationPCR, + ); + + let mut resp = CreateResponse::default(); + self.dispatch(TPM_CC::Create, req, &mut resp)?; + Ok(resp) + } + + /// This command is used to load objects into the TPM. This command is used when both a + /// TPM2B_PUBLIC and TPM2B_PRIVATE are to be loaded. If only a TPM2B_PUBLIC is to be loaded, + /// the TPM2_LoadExternal command is used. + /// parentHandle: TPM handle of parent key; shall not be a reserved handle + /// Auth Index: 1 + /// Auth Role: USER + /// inPrivate: The private portion of the object + /// inPublic: The public portion of the object + /// handle - Handle of type TPM_HT_TRANSIENT for the loaded object + /// name - Name of the loaded object + pub fn Load( + &mut self, + parentHandle: &TPM_HANDLE, + inPrivate: &TPM2B_PRIVATE, + inPublic: &TPMT_PUBLIC, + ) -> Result { + let req = TPM2_Load_REQUEST::new( + parentHandle, + inPrivate, + inPublic, + ); + + let mut resp = LoadResponse::default(); + self.dispatch(TPM_CC::Load, req, &mut resp)?; + Ok(resp.handle) + } + + /// This command is used to load an object that is not a Protected Object into the TPM. The + /// command allows loading of a public area or both a public and sensitive area. + /// inPrivate: The sensitive portion of the object (optional) + /// inPublic: The public portion of the object + /// hierarchy: Hierarchy with which the object area is associated + /// handle - Handle of type TPM_HT_TRANSIENT for the loaded object + /// name - Name of the loaded object + pub fn LoadExternal( + &mut self, + inPrivate: &TPMT_SENSITIVE, + inPublic: &TPMT_PUBLIC, + hierarchy: &TPM_HANDLE, + ) -> Result { + let req = TPM2_LoadExternal_REQUEST::new( + inPrivate, + inPublic, + hierarchy, + ); + + let mut resp = LoadExternalResponse::default(); + self.dispatch(TPM_CC::LoadExternal, req, &mut resp)?; + Ok(resp.handle) + } + + /// This command allows access to the public area of a loaded object. + /// objectHandle: TPM handle of an object + /// Auth Index: None + /// outPublic - Structure containing the public area of an object + /// name - Name of the object + /// qualifiedName - The Qualified Name of the object + pub fn ReadPublic( + &mut self, + objectHandle: &TPM_HANDLE, + ) -> Result { + let req = TPM2_ReadPublic_REQUEST::new( + objectHandle, + ); + + let mut resp = ReadPublicResponse::default(); + self.dispatch(TPM_CC::ReadPublic, req, &mut resp)?; + Ok(resp) + } + + /// This command enables the association of a credential with an object in a way that ensures + /// that the TPM has validated the parameters of the credentialed object. + /// activateHandle: Handle of the object associated with certificate in credentialBlob + /// Auth Index: 1 + /// Auth Role: ADMIN + /// keyHandle: Loaded key used to decrypt the TPMS_SENSITIVE in credentialBlob + /// Auth Index: 2 + /// Auth Role: USER + /// credentialBlob: The credential + /// secret: KeyHandle algorithm-dependent encrypted seed that protects credentialBlob + /// certInfo - The decrypted certificate information + /// the data should be no larger than the size of the digest of the nameAlg + /// associated with keyHandle + pub fn ActivateCredential( + &mut self, + activateHandle: &TPM_HANDLE, + keyHandle: &TPM_HANDLE, + credentialBlob: &TPMS_ID_OBJECT, + secret: &Vec, + ) -> Result, TpmError> { + let req = TPM2_ActivateCredential_REQUEST::new( + activateHandle, + keyHandle, + credentialBlob, + secret, + ); + + let mut resp = ActivateCredentialResponse::default(); + self.dispatch(TPM_CC::ActivateCredential, req, &mut resp)?; + Ok(resp.certInfo) + } + + /// This command allows the TPM to perform the actions required of a Certificate Authority + /// (CA) in creating a TPM2B_ID_OBJECT containing an activation credential. + /// handle: Loaded public area, used to encrypt the sensitive area containing the credential key + /// Auth Index: None + /// credential: The credential information + /// objectName: Name of the object to which the credential applies + /// credentialBlob - The credential + /// secret - Handle algorithm-dependent data that wraps the key that encrypts credentialBlob + pub fn MakeCredential( + &mut self, + handle: &TPM_HANDLE, + credential: &Vec, + objectName: &Vec, + ) -> Result { + let req = TPM2_MakeCredential_REQUEST::new( + handle, + credential, + objectName, + ); + + let mut resp = MakeCredentialResponse::default(); + self.dispatch(TPM_CC::MakeCredential, req, &mut resp)?; + Ok(resp) + } + + /// This command returns the data in a loaded Sealed Data Object. + /// itemHandle: Handle of a loaded data object + /// Auth Index: 1 + /// Auth Role: USER + /// outData - Unsealed data + /// Size of outData is limited to be no more than 128 octets. + pub fn Unseal( + &mut self, + itemHandle: &TPM_HANDLE, + ) -> Result, TpmError> { + let req = TPM2_Unseal_REQUEST::new( + itemHandle, + ); + + let mut resp = UnsealResponse::default(); + self.dispatch(TPM_CC::Unseal, req, &mut resp)?; + Ok(resp.outData) + } + + /// This command is used to change the authorization secret for a TPM-resident object. + /// objectHandle: Handle of the object + /// Auth Index: 1 + /// Auth Role: ADMIN + /// parentHandle: Handle of the parent + /// Auth Index: None + /// newAuth: New authorization value + /// outPrivate - Private area containing the new authorization value + pub fn ObjectChangeAuth( + &mut self, + objectHandle: &TPM_HANDLE, + parentHandle: &TPM_HANDLE, + newAuth: &Vec, + ) -> Result { + let req = TPM2_ObjectChangeAuth_REQUEST::new( + objectHandle, + parentHandle, + newAuth, + ); + + let mut resp = ObjectChangeAuthResponse::default(); + self.dispatch(TPM_CC::ObjectChangeAuth, req, &mut resp)?; + Ok(resp.outPrivate) + } + + /// This command creates an object and loads it in the TPM. This command allows creation of + /// any type of object (Primary, Ordinary, or Derived) depending on the type of parentHandle. + /// If parentHandle references a Primary Seed, then a Primary Object is created; if + /// parentHandle references a Storage Parent, then an Ordinary Object is created; and if + /// parentHandle references a Derivation Parent, then a Derived Object is generated. + /// parentHandle: Handle of a transient storage key, a persistent storage key, + /// TPM_RH_ENDORSEMENT, TPM_RH_OWNER, TPM_RH_PLATFORM+{PP}, or TPM_RH_NULL + /// Auth Index: 1 + /// Auth Role: USER + /// inSensitive: The sensitive data, see TPM 2.0 Part 1 Sensitive Values + /// inPublic: The public template + /// handle - Handle of type TPM_HT_TRANSIENT for created object + /// outPrivate - The sensitive area of the object (optional) + /// outPublic - The public portion of the created object + /// name - The name of the created object + pub fn CreateLoaded( + &mut self, + parentHandle: &TPM_HANDLE, + inSensitive: &TPMS_SENSITIVE_CREATE, + inPublic: &Vec, + ) -> Result { + let req = TPM2_CreateLoaded_REQUEST::new( + parentHandle, + inSensitive, + inPublic, + ); + + let mut resp = CreateLoadedResponse::default(); + self.dispatch(TPM_CC::CreateLoaded, req, &mut resp)?; + Ok(resp) + } + + /// This command duplicates a loaded object so that it may be used in a different hierarchy. + /// The new parent key for the duplicate may be on the same or different TPM or TPM_RH_NULL. + /// Only the public area of newParentHandle is required to be loaded. + /// objectHandle: Loaded object to duplicate + /// Auth Index: 1 + /// Auth Role: DUP + /// newParentHandle: Shall reference the public area of an asymmetric key + /// Auth Index: None + /// encryptionKeyIn: Optional symmetric encryption key + /// The size for this key is set to zero when the TPM is to generate the key. This + /// parameter may be encrypted. + /// symmetricAlg: Definition for the symmetric algorithm to be used for the inner wrapper + /// may be TPM_ALG_NULL if no inner wrapper is applied + /// encryptionKeyOut - If the caller provided an encryption key or if symmetricAlg was + /// TPM_ALG_NULL, then this will be the Empty Buffer; otherwise, it + /// shall contain the TPM-generated, symmetric encryption key for the + /// inner wrapper. + /// duplicate - Private area that may be encrypted by encryptionKeyIn; and may be doubly encrypted + /// outSymSeed - Seed protected by the asymmetric algorithms of new parent (NP) + pub fn Duplicate( + &mut self, + objectHandle: &TPM_HANDLE, + newParentHandle: &TPM_HANDLE, + encryptionKeyIn: &Vec, + symmetricAlg: &TPMT_SYM_DEF_OBJECT, + ) -> Result { + let req = TPM2_Duplicate_REQUEST::new( + objectHandle, + newParentHandle, + encryptionKeyIn, + symmetricAlg, + ); + + let mut resp = DuplicateResponse::default(); + self.dispatch(TPM_CC::Duplicate, req, &mut resp)?; + Ok(resp) + } + + /// This command allows the TPM to serve in the role as a Duplication Authority. If proper + /// authorization for use of the oldParent is provided, then an HMAC key and a symmetric key + /// are recovered from inSymSeed and used to integrity check and decrypt inDuplicate. A new + /// protection seed value is generated according to the methods appropriate for newParent and + /// the blob is re-encrypted and a new integrity value is computed. The re-encrypted blob is + /// returned in outDuplicate and the symmetric key returned in outSymKey. + /// oldParent: Parent of object + /// Auth Index: 1 + /// Auth Role: User + /// newParent: New parent of the object + /// Auth Index: None + /// inDuplicate: An object encrypted using symmetric key derived from inSymSeed + /// name: The Name of the object being rewrapped + /// inSymSeed: The seed for the symmetric key and HMAC key + /// needs oldParent private key to recover the seed and generate the symmetric key + /// outDuplicate - An object encrypted using symmetric key derived from outSymSeed + /// outSymSeed - Seed for a symmetric key protected by newParent asymmetric key + pub fn Rewrap( + &mut self, + oldParent: &TPM_HANDLE, + newParent: &TPM_HANDLE, + inDuplicate: &TPM2B_PRIVATE, + name: &Vec, + inSymSeed: &Vec, + ) -> Result { + let req = TPM2_Rewrap_REQUEST::new( + oldParent, + newParent, + inDuplicate, + name, + inSymSeed, + ); + + let mut resp = RewrapResponse::default(); + self.dispatch(TPM_CC::Rewrap, req, &mut resp)?; + Ok(resp) + } + + /// This command allows an object to be encrypted using the symmetric encryption values of a + /// Storage Key. After encryption, the object may be loaded and used in the new hierarchy. The + /// imported object (duplicate) may be singly encrypted, multiply encrypted, or unencrypted. + /// parentHandle: The handle of the new parent for the object + /// Auth Index: 1 + /// Auth Role: USER + /// encryptionKey: The optional symmetric encryption key used as the inner wrapper for duplicate + /// If symmetricAlg is TPM_ALG_NULL, then this parameter shall be the Empty Buffer. + /// objectPublic: The public area of the object to be imported + /// This is provided so that the integrity value for duplicate and the object + /// attributes can be checked. + /// NOTE Even if the integrity value of the object is not checked on input, the object + /// Name is required to create the integrity value for the imported object. + /// duplicate: The symmetrically encrypted duplicate object that may contain an inner + /// symmetric wrapper + /// inSymSeed: The seed for the symmetric key and HMAC key + /// inSymSeed is encrypted/encoded using the algorithms of newParent. + /// symmetricAlg: Definition for the symmetric algorithm to use for the inner wrapper + /// If this algorithm is TPM_ALG_NULL, no inner wrapper is present and encryptionKey + /// shall be the Empty Buffer. + /// outPrivate - The sensitive area encrypted with the symmetric key of parentHandle + pub fn Import( + &mut self, + parentHandle: &TPM_HANDLE, + encryptionKey: &Vec, + objectPublic: &TPMT_PUBLIC, + duplicate: &TPM2B_PRIVATE, + inSymSeed: &Vec, + symmetricAlg: &TPMT_SYM_DEF_OBJECT, + ) -> Result { + let req = TPM2_Import_REQUEST::new( + parentHandle, + encryptionKey, + objectPublic, + duplicate, + inSymSeed, + symmetricAlg, + ); + + let mut resp = ImportResponse::default(); + self.dispatch(TPM_CC::Import, req, &mut resp)?; + Ok(resp.outPrivate) + } + + /// This command performs RSA encryption using the indicated padding scheme according to IETF + /// RFC 8017. If the scheme of keyHandle is TPM_ALG_NULL, then the caller may use inScheme to + /// specify the padding scheme. If scheme of keyHandle is not TPM_ALG_NULL, then inScheme + /// shall either be TPM_ALG_NULL or be the same as scheme (TPM_RC_SCHEME). + /// keyHandle: Reference to public portion of RSA key to use for encryption + /// Auth Index: None + /// message: Message to be encrypted + /// NOTE 1 The data type was chosen because it limits the overall size of the input to + /// no greater than the size of the largest RSA public key. This may be larger than + /// allowed for keyHandle. + /// inScheme: The padding scheme to use if scheme associated with keyHandle is TPM_ALG_NULL + /// One of: TPMS_KEY_SCHEME_ECDH, TPMS_KEY_SCHEME_ECMQV, TPMS_SIG_SCHEME_RSASSA, + /// TPMS_SIG_SCHEME_RSAPSS, TPMS_SIG_SCHEME_ECDSA, TPMS_SIG_SCHEME_ECDAA, + /// TPMS_SIG_SCHEME_SM2, TPMS_SIG_SCHEME_ECSCHNORR, TPMS_ENC_SCHEME_RSAES, + /// TPMS_ENC_SCHEME_OAEP, TPMS_SCHEME_HASH, TPMS_NULL_ASYM_SCHEME. + /// label: Optional label L to be associated with the message + /// Size of the buffer is zero if no label is present + /// NOTE 2 See description of label above. + /// outData - Encrypted output + pub fn RSA_Encrypt( + &mut self, + keyHandle: &TPM_HANDLE, + message: &Vec, + inScheme: &Option, + label: &Vec, + ) -> Result, TpmError> { + let req = TPM2_RSA_Encrypt_REQUEST::new( + keyHandle, + message, + inScheme, + label, + ); + + let mut resp = RSA_EncryptResponse::default(); + self.dispatch(TPM_CC::RSA_Encrypt, req, &mut resp)?; + Ok(resp.outData) + } + + /// This command performs RSA decryption using the indicated padding scheme according to IETF + /// RFC 8017 ((PKCS#1). + /// keyHandle: RSA key to use for decryption + /// Auth Index: 1 + /// Auth Role: USER + /// cipherText: Cipher text to be decrypted + /// NOTE An encrypted RSA data block is the size of the public modulus. + /// inScheme: The padding scheme to use if scheme associated with keyHandle is TPM_ALG_NULL + /// One of: TPMS_KEY_SCHEME_ECDH, TPMS_KEY_SCHEME_ECMQV, TPMS_SIG_SCHEME_RSASSA, + /// TPMS_SIG_SCHEME_RSAPSS, TPMS_SIG_SCHEME_ECDSA, TPMS_SIG_SCHEME_ECDAA, + /// TPMS_SIG_SCHEME_SM2, TPMS_SIG_SCHEME_ECSCHNORR, TPMS_ENC_SCHEME_RSAES, + /// TPMS_ENC_SCHEME_OAEP, TPMS_SCHEME_HASH, TPMS_NULL_ASYM_SCHEME. + /// label: Label whose association with the message is to be verified + /// message - Decrypted output + pub fn RSA_Decrypt( + &mut self, + keyHandle: &TPM_HANDLE, + cipherText: &Vec, + inScheme: &Option, + label: &Vec, + ) -> Result, TpmError> { + let req = TPM2_RSA_Decrypt_REQUEST::new( + keyHandle, + cipherText, + inScheme, + label, + ); + + let mut resp = RSA_DecryptResponse::default(); + self.dispatch(TPM_CC::RSA_Decrypt, req, &mut resp)?; + Ok(resp.message) + } + + /// This command uses the TPM to generate an ephemeral key pair (de, Qe where Qe [de]G). It + /// uses the private ephemeral key and a loaded public key (QS) to compute the shared secret + /// value (P [hde]QS). + /// keyHandle: Handle of a loaded ECC key public area. + /// Auth Index: None + /// zPoint - Results of P h[de]Qs + /// pubPoint - Generated ephemeral public point (Qe) + pub fn ECDH_KeyGen( + &mut self, + keyHandle: &TPM_HANDLE, + ) -> Result { + let req = TPM2_ECDH_KeyGen_REQUEST::new( + keyHandle, + ); + + let mut resp = ECDH_KeyGenResponse::default(); + self.dispatch(TPM_CC::ECDH_KeyGen, req, &mut resp)?; + Ok(resp) + } + + /// This command uses the TPM to recover the Z value from a public point (QB) and a private + /// key (ds). It will perform the multiplication of the provided inPoint (QB) with the private + /// key (ds) and return the coordinates of the resultant point (Z = (xZ , yZ) [hds]QB; where h + /// is the cofactor of the curve). + /// keyHandle: Handle of a loaded ECC key + /// Auth Index: 1 + /// Auth Role: USER + /// inPoint: A public key + /// outPoint - X and Y coordinates of the product of the multiplication Z = (xZ , yZ) [hdS]QB + pub fn ECDH_ZGen( + &mut self, + keyHandle: &TPM_HANDLE, + inPoint: &TPMS_ECC_POINT, + ) -> Result { + let req = TPM2_ECDH_ZGen_REQUEST::new( + keyHandle, + inPoint, + ); + + let mut resp = ECDH_ZGenResponse::default(); + self.dispatch(TPM_CC::ECDH_ZGen, req, &mut resp)?; + Ok(resp.outPoint) + } + + /// This command returns the parameters of an ECC curve identified by its TCG-assigned curveID. + /// curveID: Parameter set selector + /// parameters - ECC parameters for the selected curve + pub fn ECC_Parameters( + &mut self, + curveID: TPM_ECC_CURVE, + ) -> Result { + let req = TPM2_ECC_Parameters_REQUEST::new( + curveID, + ); + + let mut resp = ECC_ParametersResponse::default(); + self.dispatch(TPM_CC::ECC_Parameters, req, &mut resp)?; + Ok(resp.parameters) + } + + /// This command supports two-phase key exchange protocols. The command is used in combination + /// with TPM2_EC_Ephemeral(). TPM2_EC_Ephemeral() generates an ephemeral key and returns the + /// public point of that ephemeral key along with a numeric value that allows the TPM to + /// regenerate the associated private key. + /// keyA: Handle of an unrestricted decryption key ECC + /// The private key referenced by this handle is used as dS,A + /// Auth Index: 1 + /// Auth Role: USER + /// inQsB: Other partys static public key (Qs,B = (Xs,B, Ys,B)) + /// inQeB: Other party's ephemeral public key (Qe,B = (Xe,B, Ye,B)) + /// inScheme: The key exchange scheme + /// counter: Value returned by TPM2_EC_Ephemeral() + /// outZ1 - X and Y coordinates of the computed value (scheme dependent) + /// outZ2 - X and Y coordinates of the second computed value (scheme dependent) + pub fn ZGen_2Phase( + &mut self, + keyA: &TPM_HANDLE, + inQsB: &TPMS_ECC_POINT, + inQeB: &TPMS_ECC_POINT, + inScheme: TPM_ALG_ID, + counter: u16, + ) -> Result { + let req = TPM2_ZGen_2Phase_REQUEST::new( + keyA, + inQsB, + inQeB, + inScheme, + counter, + ); + + let mut resp = ZGen_2PhaseResponse::default(); + self.dispatch(TPM_CC::ZGen_2Phase, req, &mut resp)?; + Ok(resp) + } + + /// This command performs ECC encryption as described in Part 1, Annex D. + /// keyHandle: Reference to public portion of ECC key to use for encryption + /// Auth Index: None + /// plainText: Plaintext to be encrypted + /// inScheme: The KDF to use if scheme associated with keyHandle is TPM_ALG_NULL + /// One of: TPMS_KDF_SCHEME_MGF1, TPMS_KDF_SCHEME_KDF1_SP800_56A, TPMS_KDF_SCHEME_KDF2, + /// TPMS_KDF_SCHEME_KDF1_SP800_108, TPMS_SCHEME_HASH, TPMS_NULL_KDF_SCHEME. + /// C1 - The public ephemeral key used for ECDH + /// C2 - The data block produced by the XOR process + /// C3 - The integrity value + pub fn ECC_Encrypt( + &mut self, + keyHandle: &TPM_HANDLE, + plainText: &Vec, + inScheme: &Option, + ) -> Result { + let req = TPM2_ECC_Encrypt_REQUEST::new( + keyHandle, + plainText, + inScheme, + ); + + let mut resp = ECC_EncryptResponse::default(); + self.dispatch(TPM_CC::ECC_Encrypt, req, &mut resp)?; + Ok(resp) + } + + /// This command performs ECC decryption. + /// keyHandle: ECC key to use for decryption + /// Auth Index: 1 + /// Auth Role: USER + /// C1: The public ephemeral key used for ECDH + /// C2: The data block produced by the XOR process + /// C3: The integrity value + /// inScheme: The KDF to use if scheme associated with keyHandle is TPM_ALG_NULL + /// One of: TPMS_KDF_SCHEME_MGF1, TPMS_KDF_SCHEME_KDF1_SP800_56A, TPMS_KDF_SCHEME_KDF2, + /// TPMS_KDF_SCHEME_KDF1_SP800_108, TPMS_SCHEME_HASH, TPMS_NULL_KDF_SCHEME. + /// plainText - Decrypted output + pub fn ECC_Decrypt( + &mut self, + keyHandle: &TPM_HANDLE, + C1: &TPMS_ECC_POINT, + C2: &Vec, + C3: &Vec, + inScheme: &Option, + ) -> Result, TpmError> { + let req = TPM2_ECC_Decrypt_REQUEST::new( + keyHandle, + C1, + C2, + C3, + inScheme, + ); + + let mut resp = ECC_DecryptResponse::default(); + self.dispatch(TPM_CC::ECC_Decrypt, req, &mut resp)?; + Ok(resp.plainText) + } + + /// NOTE 1 This command is deprecated, and TPM2_EncryptDecrypt2() is preferred. This should be + /// reflected in platform-specific specifications. + /// keyHandle: The symmetric key used for the operation + /// Auth Index: 1 + /// Auth Role: USER + /// decrypt: If YES, then the operation is decryption; if NO, the operation is encryption + /// mode: Symmetric encryption/decryption mode + /// this field shall match the default mode of the key or be TPM_ALG_NULL. + /// ivIn: An initial value as required by the algorithm + /// inData: The data to be encrypted/decrypted + /// outData - Encrypted or decrypted output + /// ivOut - Chaining value to use for IV in next round + pub fn EncryptDecrypt( + &mut self, + keyHandle: &TPM_HANDLE, + decrypt: u8, + mode: TPM_ALG_ID, + ivIn: &Vec, + inData: &Vec, + ) -> Result { + let req = TPM2_EncryptDecrypt_REQUEST::new( + keyHandle, + decrypt, + mode, + ivIn, + inData, + ); + + let mut resp = EncryptDecryptResponse::default(); + self.dispatch(TPM_CC::EncryptDecrypt, req, &mut resp)?; + Ok(resp) + } + + /// This command is identical to TPM2_EncryptDecrypt(), except that the inData parameter is + /// the first parameter. This permits inData to be parameter encrypted. + /// keyHandle: The symmetric key used for the operation + /// Auth Index: 1 + /// Auth Role: USER + /// inData: The data to be encrypted/decrypted + /// decrypt: If YES, then the operation is decryption; if NO, the operation is encryption + /// mode: Symmetric mode + /// this field shall match the default mode of the key or be TPM_ALG_NULL. + /// ivIn: An initial value as required by the algorithm + /// outData - Encrypted or decrypted output + /// ivOut - Chaining value to use for IV in next round + pub fn EncryptDecrypt2( + &mut self, + keyHandle: &TPM_HANDLE, + inData: &Vec, + decrypt: u8, + mode: TPM_ALG_ID, + ivIn: &Vec, + ) -> Result { + let req = TPM2_EncryptDecrypt2_REQUEST::new( + keyHandle, + inData, + decrypt, + mode, + ivIn, + ); + + let mut resp = EncryptDecrypt2Response::default(); + self.dispatch(TPM_CC::EncryptDecrypt2, req, &mut resp)?; + Ok(resp) + } + + /// This command performs a hash operation on a data buffer and returns the results. + /// data: Data to be hashed + /// hashAlg: Algorithm for the hash being computed shall not be TPM_ALG_NULL + /// hierarchy: Hierarchy to use for the ticket (TPM_RH_NULL allowed) + /// outHash - Results + /// validation - Ticket indicating that the sequence of octets used to compute outDigest + /// did not start with TPM_GENERATED_VALUE + /// will be a NULL ticket if the digest may not be signed with a restricted key + pub fn Hash( + &mut self, + data: &Vec, + hashAlg: TPM_ALG_ID, + hierarchy: &TPM_HANDLE, + ) -> Result { + let req = TPM2_Hash_REQUEST::new( + data, + hashAlg, + hierarchy, + ); + + let mut resp = HashResponse::default(); + self.dispatch(TPM_CC::Hash, req, &mut resp)?; + Ok(resp) + } + + /// This command performs an HMAC on the supplied data using the indicated hash algorithm. + /// handle: Handle for the symmetric signing key providing the HMAC key + /// Auth Index: 1 + /// Auth Role: USER + /// buffer: HMAC data + /// hashAlg: Algorithm to use for HMAC + /// outHMAC - The returned HMAC in a sized buffer + pub fn HMAC( + &mut self, + handle: &TPM_HANDLE, + buffer: &Vec, + hashAlg: TPM_ALG_ID, + ) -> Result, TpmError> { + let req = TPM2_HMAC_REQUEST::new( + handle, + buffer, + hashAlg, + ); + + let mut resp = HMACResponse::default(); + self.dispatch(TPM_CC::HMAC, req, &mut resp)?; + Ok(resp.outHMAC) + } + + /// This command performs an HMAC or a block cipher MAC on the supplied data using the + /// indicated algorithm. + /// handle: Handle for the symmetric signing key providing the MAC key + /// Auth Index: 1 + /// Auth Role: USER + /// buffer: MAC data + /// inScheme: Algorithm to use for MAC + /// outMAC - The returned MAC in a sized buffer + pub fn MAC( + &mut self, + handle: &TPM_HANDLE, + buffer: &Vec, + inScheme: TPM_ALG_ID, + ) -> Result, TpmError> { + let req = TPM2_MAC_REQUEST::new( + handle, + buffer, + inScheme, + ); + + let mut resp = MACResponse::default(); + self.dispatch(TPM_CC::MAC, req, &mut resp)?; + Ok(resp.outMAC) + } + + /// This command returns the next bytesRequested octets from the random number generator (RNG). + /// bytesRequested: Number of octets to return + /// randomBytes - The random octets + pub fn GetRandom( + &mut self, + bytesRequested: u16, + ) -> Result, TpmError> { + let req = TPM2_GetRandom_REQUEST::new( + bytesRequested, + ); + + let mut resp = GetRandomResponse::default(); + self.dispatch(TPM_CC::GetRandom, req, &mut resp)?; + Ok(resp.randomBytes) + } + + /// This command is used to add "additional information" to the RNG state. + /// inData: Additional information + pub fn StirRandom( + &mut self, + inData: &Vec, + ) -> Result<(), TpmError> { + let req = TPM2_StirRandom_REQUEST::new( + inData, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::StirRandom, req, &mut resp)?; + Ok(()) + } + + /// This command starts an HMAC sequence. The TPM will create and initialize an HMAC sequence + /// structure, assign a handle to the sequence, and set the authValue of the sequence object + /// to the value in auth. + /// handle: Handle of an HMAC key + /// Auth Index: 1 + /// Auth Role: USER + /// auth: Authorization value for subsequent use of the sequence + /// hashAlg: The hash algorithm to use for the HMAC + /// handle - A handle to reference the sequence + pub fn HMAC_Start( + &mut self, + handle: &TPM_HANDLE, + auth: &Vec, + hashAlg: TPM_ALG_ID, + ) -> Result { + let req = TPM2_HMAC_Start_REQUEST::new( + handle, + auth, + hashAlg, + ); + + let mut resp = HMAC_StartResponse::default(); + self.dispatch(TPM_CC::HMAC_Start, req, &mut resp)?; + Ok(resp.handle) + } + + /// This command starts a MAC sequence. The TPM will create and initialize a MAC sequence + /// structure, assign a handle to the sequence, and set the authValue of the sequence object + /// to the value in auth. + /// handle: Handle of a MAC key + /// Auth Index: 1 + /// Auth Role: USER + /// auth: Authorization value for subsequent use of the sequence + /// inScheme: The algorithm to use for the MAC + /// handle - A handle to reference the sequence + pub fn MAC_Start( + &mut self, + handle: &TPM_HANDLE, + auth: &Vec, + inScheme: TPM_ALG_ID, + ) -> Result { + let req = TPM2_MAC_Start_REQUEST::new( + handle, + auth, + inScheme, + ); + + let mut resp = MAC_StartResponse::default(); + self.dispatch(TPM_CC::MAC_Start, req, &mut resp)?; + Ok(resp.handle) + } + + /// This command starts a hash or an Event Sequence. If hashAlg is an implemented hash, then a + /// hash sequence is started. If hashAlg is TPM_ALG_NULL, then an Event Sequence is started. + /// If hashAlg is neither an implemented algorithm nor TPM_ALG_NULL, then the TPM shall return + /// TPM_RC_HASH. + /// auth: Authorization value for subsequent use of the sequence + /// hashAlg: The hash algorithm to use for the hash sequence + /// An Event Sequence starts if this is TPM_ALG_NULL. + /// handle - A handle to reference the sequence + pub fn HashSequenceStart( + &mut self, + auth: &Vec, + hashAlg: TPM_ALG_ID, + ) -> Result { + let req = TPM2_HashSequenceStart_REQUEST::new( + auth, + hashAlg, + ); + + let mut resp = HashSequenceStartResponse::default(); + self.dispatch(TPM_CC::HashSequenceStart, req, &mut resp)?; + Ok(resp.handle) + } + + /// This command is used to add data to a hash or HMAC sequence. The amount of data in buffer + /// may be any size up to the limits of the TPM. + /// sequenceHandle: Handle for the sequence object + /// Auth Index: 1 + /// Auth Role: USER + /// buffer: Data to be added to hash + pub fn SequenceUpdate( + &mut self, + sequenceHandle: &TPM_HANDLE, + buffer: &Vec, + ) -> Result<(), TpmError> { + let req = TPM2_SequenceUpdate_REQUEST::new( + sequenceHandle, + buffer, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::SequenceUpdate, req, &mut resp)?; + Ok(()) + } + + /// This command adds the last part of data, if any, to a hash/HMAC sequence and returns the result. + /// sequenceHandle: Authorization for the sequence + /// Auth Index: 1 + /// Auth Role: USER + /// buffer: Data to be added to the hash/HMAC + /// hierarchy: Hierarchy of the ticket for a hash + /// result - The returned HMAC or digest in a sized buffer + /// validation - Ticket indicating that the sequence of octets used to compute outDigest + /// did not start with TPM_GENERATED_VALUE + /// This is a NULL Ticket when the sequence is HMAC. + pub fn SequenceComplete( + &mut self, + sequenceHandle: &TPM_HANDLE, + buffer: &Vec, + hierarchy: &TPM_HANDLE, + ) -> Result { + let req = TPM2_SequenceComplete_REQUEST::new( + sequenceHandle, + buffer, + hierarchy, + ); + + let mut resp = SequenceCompleteResponse::default(); + self.dispatch(TPM_CC::SequenceComplete, req, &mut resp)?; + Ok(resp) + } + + /// This command adds the last part of data, if any, to an Event Sequence and returns the + /// result in a digest list. If pcrHandle references a PCR and not TPM_RH_NULL, then the + /// returned digest list is processed in the same manner as the digest list input parameter to + /// TPM2_PCR_Extend(). That is, if a bank contains a PCR associated with pcrHandle, it is + /// extended with the associated digest value from the list. + /// pcrHandle: PCR to be extended with the Event data + /// Auth Index: 1 + /// Auth Role: USER + /// sequenceHandle: Authorization for the sequence + /// Auth Index: 2 + /// Auth Role: USER + /// buffer: Data to be added to the Event + /// results - List of digests computed for the PCR + pub fn EventSequenceComplete( + &mut self, + pcrHandle: &TPM_HANDLE, + sequenceHandle: &TPM_HANDLE, + buffer: &Vec, + ) -> Result, TpmError> { + let req = TPM2_EventSequenceComplete_REQUEST::new( + pcrHandle, + sequenceHandle, + buffer, + ); + + let mut resp = EventSequenceCompleteResponse::default(); + self.dispatch(TPM_CC::EventSequenceComplete, req, &mut resp)?; + Ok(resp.results) + } + + /// The purpose of this command is to prove that an object with a specific Name is loaded in + /// the TPM. By certifying that the object is loaded, the TPM warrants that a public area with + /// a given Name is self-consistent and associated with a valid sensitive area. If a relying + /// party has a public area that has the same Name as a Name certified with this command, then + /// the values in that public area are correct. + /// objectHandle: Handle of the object to be certified + /// Auth Index: 1 + /// Auth Role: ADMIN + /// signHandle: Handle of the key used to sign the attestation structure + /// Auth Index: 2 + /// Auth Role: USER + /// qualifyingData: User provided qualifying data + /// inScheme: Signing scheme to use if the scheme for signHandle is TPM_ALG_NULL + /// One of: TPMS_SIG_SCHEME_RSASSA, TPMS_SIG_SCHEME_RSAPSS, TPMS_SIG_SCHEME_ECDSA, + /// TPMS_SIG_SCHEME_ECDAA, TPMS_SIG_SCHEME_SM2, TPMS_SIG_SCHEME_ECSCHNORR, + /// TPMS_SCHEME_HMAC, TPMS_SCHEME_HASH, TPMS_NULL_SIG_SCHEME. + /// certifyInfo - The structure that was signed + /// signature - The asymmetric signature over certifyInfo using the key referenced by signHandle + pub fn Certify( + &mut self, + objectHandle: &TPM_HANDLE, + signHandle: &TPM_HANDLE, + qualifyingData: &Vec, + inScheme: &Option, + ) -> Result { + let req = TPM2_Certify_REQUEST::new( + objectHandle, + signHandle, + qualifyingData, + inScheme, + ); + + let mut resp = CertifyResponse::default(); + self.dispatch(TPM_CC::Certify, req, &mut resp)?; + Ok(resp) + } + + /// This command is used to prove the association between an object and its creation data. The + /// TPM will validate that the ticket was produced by the TPM and that the ticket validates + /// the association between a loaded public area and the provided hash of the creation data + /// (creationHash). + /// signHandle: Handle of the key that will sign the attestation block + /// Auth Index: 1 + /// Auth Role: USER + /// objectHandle: The object associated with the creation data + /// Auth Index: None + /// qualifyingData: User-provided qualifying data + /// creationHash: Hash of the creation data produced by TPM2_Create() or TPM2_CreatePrimary() + /// inScheme: Signing scheme to use if the scheme for signHandle is TPM_ALG_NULL + /// One of: TPMS_SIG_SCHEME_RSASSA, TPMS_SIG_SCHEME_RSAPSS, TPMS_SIG_SCHEME_ECDSA, + /// TPMS_SIG_SCHEME_ECDAA, TPMS_SIG_SCHEME_SM2, TPMS_SIG_SCHEME_ECSCHNORR, + /// TPMS_SCHEME_HMAC, TPMS_SCHEME_HASH, TPMS_NULL_SIG_SCHEME. + /// creationTicket: Ticket produced by TPM2_Create() or TPM2_CreatePrimary() + /// certifyInfo - The structure that was signed + /// signature - The signature over certifyInfo + pub fn CertifyCreation( + &mut self, + signHandle: &TPM_HANDLE, + objectHandle: &TPM_HANDLE, + qualifyingData: &Vec, + creationHash: &Vec, + inScheme: &Option, + creationTicket: &TPMT_TK_CREATION, + ) -> Result { + let req = TPM2_CertifyCreation_REQUEST::new( + signHandle, + objectHandle, + qualifyingData, + creationHash, + inScheme, + creationTicket, + ); + + let mut resp = CertifyCreationResponse::default(); + self.dispatch(TPM_CC::CertifyCreation, req, &mut resp)?; + Ok(resp) + } + + /// This command is used to quote PCR values. + /// signHandle: Handle of key that will perform signature + /// Auth Index: 1 + /// Auth Role: USER + /// qualifyingData: Data supplied by the caller + /// inScheme: Signing scheme to use if the scheme for signHandle is TPM_ALG_NULL + /// One of: TPMS_SIG_SCHEME_RSASSA, TPMS_SIG_SCHEME_RSAPSS, TPMS_SIG_SCHEME_ECDSA, + /// TPMS_SIG_SCHEME_ECDAA, TPMS_SIG_SCHEME_SM2, TPMS_SIG_SCHEME_ECSCHNORR, + /// TPMS_SCHEME_HMAC, TPMS_SCHEME_HASH, TPMS_NULL_SIG_SCHEME. + /// PCRselect: PCR set to quote + /// quoted - The quoted information + /// signature - The signature over quoted + pub fn Quote( + &mut self, + signHandle: &TPM_HANDLE, + qualifyingData: &Vec, + inScheme: &Option, + PCRselect: &Vec, + ) -> Result { + let req = TPM2_Quote_REQUEST::new( + signHandle, + qualifyingData, + inScheme, + PCRselect, + ); + + let mut resp = QuoteResponse::default(); + self.dispatch(TPM_CC::Quote, req, &mut resp)?; + Ok(resp) + } + + /// This command returns a digital signature of the audit session digest. + /// privacyAdminHandle: Handle of the privacy administrator (TPM_RH_ENDORSEMENT) + /// Auth Index: 1 + /// Auth Role: USER + /// signHandle: Handle of the signing key + /// Auth Index: 2 + /// Auth Role: USER + /// sessionHandle: Handle of the audit session + /// Auth Index: None + /// qualifyingData: User-provided qualifying data may be zero-length + /// inScheme: Signing scheme to use if the scheme for signHandle is TPM_ALG_NULL + /// One of: TPMS_SIG_SCHEME_RSASSA, TPMS_SIG_SCHEME_RSAPSS, TPMS_SIG_SCHEME_ECDSA, + /// TPMS_SIG_SCHEME_ECDAA, TPMS_SIG_SCHEME_SM2, TPMS_SIG_SCHEME_ECSCHNORR, + /// TPMS_SCHEME_HMAC, TPMS_SCHEME_HASH, TPMS_NULL_SIG_SCHEME. + /// auditInfo - The audit information that was signed + /// signature - The signature over auditInfo + pub fn GetSessionAuditDigest( + &mut self, + privacyAdminHandle: &TPM_HANDLE, + signHandle: &TPM_HANDLE, + sessionHandle: &TPM_HANDLE, + qualifyingData: &Vec, + inScheme: &Option, + ) -> Result { + let req = TPM2_GetSessionAuditDigest_REQUEST::new( + privacyAdminHandle, + signHandle, + sessionHandle, + qualifyingData, + inScheme, + ); + + let mut resp = GetSessionAuditDigestResponse::default(); + self.dispatch(TPM_CC::GetSessionAuditDigest, req, &mut resp)?; + Ok(resp) + } + + /// This command returns the current value of the command audit digest, a digest of the + /// commands being audited, and the audit hash algorithm. These values are placed in an + /// attestation structure and signed with the key referenced by signHandle. + /// privacyHandle: Handle of the privacy administrator (TPM_RH_ENDORSEMENT) + /// Auth Index: 1 + /// Auth Role: USER + /// signHandle: The handle of the signing key + /// Auth Index: 2 + /// Auth Role: USER + /// qualifyingData: Other data to associate with this audit digest + /// inScheme: Signing scheme to use if the scheme for signHandle is TPM_ALG_NULL + /// One of: TPMS_SIG_SCHEME_RSASSA, TPMS_SIG_SCHEME_RSAPSS, TPMS_SIG_SCHEME_ECDSA, + /// TPMS_SIG_SCHEME_ECDAA, TPMS_SIG_SCHEME_SM2, TPMS_SIG_SCHEME_ECSCHNORR, + /// TPMS_SCHEME_HMAC, TPMS_SCHEME_HASH, TPMS_NULL_SIG_SCHEME. + /// auditInfo - The auditInfo that was signed + /// signature - The signature over auditInfo + pub fn GetCommandAuditDigest( + &mut self, + privacyHandle: &TPM_HANDLE, + signHandle: &TPM_HANDLE, + qualifyingData: &Vec, + inScheme: &Option, + ) -> Result { + let req = TPM2_GetCommandAuditDigest_REQUEST::new( + privacyHandle, + signHandle, + qualifyingData, + inScheme, + ); + + let mut resp = GetCommandAuditDigestResponse::default(); + self.dispatch(TPM_CC::GetCommandAuditDigest, req, &mut resp)?; + Ok(resp) + } + + /// This command returns the current values of Time and Clock. + /// privacyAdminHandle: Handle of the privacy administrator (TPM_RH_ENDORSEMENT) + /// Auth Index: 1 + /// Auth Role: USER + /// signHandle: The keyHandle identifier of a loaded key that can perform digital signatures + /// Auth Index: 2 + /// Auth Role: USER + /// qualifyingData: Data to tick stamp + /// inScheme: Signing scheme to use if the scheme for signHandle is TPM_ALG_NULL + /// One of: TPMS_SIG_SCHEME_RSASSA, TPMS_SIG_SCHEME_RSAPSS, TPMS_SIG_SCHEME_ECDSA, + /// TPMS_SIG_SCHEME_ECDAA, TPMS_SIG_SCHEME_SM2, TPMS_SIG_SCHEME_ECSCHNORR, + /// TPMS_SCHEME_HMAC, TPMS_SCHEME_HASH, TPMS_NULL_SIG_SCHEME. + /// timeInfo - Standard TPM-generated attestation block + /// signature - The signature over timeInfo + pub fn GetTime( + &mut self, + privacyAdminHandle: &TPM_HANDLE, + signHandle: &TPM_HANDLE, + qualifyingData: &Vec, + inScheme: &Option, + ) -> Result { + let req = TPM2_GetTime_REQUEST::new( + privacyAdminHandle, + signHandle, + qualifyingData, + inScheme, + ); + + let mut resp = GetTimeResponse::default(); + self.dispatch(TPM_CC::GetTime, req, &mut resp)?; + Ok(resp) + } + + /// The purpose of this command is to generate an X.509 certificate that proves an object with + /// a specific public key and attributes is loaded in the TPM. In contrast to TPM2_Certify, + /// which uses a TCG-defined data structure to convey attestation information, + /// TPM2_CertifyX509 encodes the attestation information in a DER-encoded X.509 certificate + /// that is compliant with RFC5280 Internet X.509 Public Key Infrastructure Certificate and + /// Certificate Revocation List (CRL) Profile. + /// objectHandle: Handle of the object to be certified + /// Auth Index: 1 + /// Auth Role: ADMIN + /// signHandle: Handle of the key used to sign the attestation structure + /// Auth Index: 2 + /// Auth Role: USER + /// reserved: Shall be an Empty Buffer + /// inScheme: Signing scheme to use if the scheme for signHandle is TPM_ALG_NULL + /// One of: TPMS_SIG_SCHEME_RSASSA, TPMS_SIG_SCHEME_RSAPSS, TPMS_SIG_SCHEME_ECDSA, + /// TPMS_SIG_SCHEME_ECDAA, TPMS_SIG_SCHEME_SM2, TPMS_SIG_SCHEME_ECSCHNORR, + /// TPMS_SCHEME_HMAC, TPMS_SCHEME_HASH, TPMS_NULL_SIG_SCHEME. + /// partialCertificate: A DER encoded partial certificate + /// addedToCertificate - A DER encoded SEQUENCE containing the DER encoded fields added to + /// partialCertificate to make it a complete RFC5280 TBSCertificate. + /// tbsDigest - The digest that was signed + /// signature - The signature over tbsDigest + pub fn CertifyX509( + &mut self, + objectHandle: &TPM_HANDLE, + signHandle: &TPM_HANDLE, + reserved: &Vec, + inScheme: &Option, + partialCertificate: &Vec, + ) -> Result { + let req = TPM2_CertifyX509_REQUEST::new( + objectHandle, + signHandle, + reserved, + inScheme, + partialCertificate, + ); + + let mut resp = CertifyX509Response::default(); + self.dispatch(TPM_CC::CertifyX509, req, &mut resp)?; + Ok(resp) + } + + /// TPM2_Commit() performs the first part of an ECC anonymous signing operation. The TPM will + /// perform the point multiplications on the provided points and return intermediate signing + /// values. The signHandle parameter shall refer to an ECC key and the signing scheme must be + /// anonymous (TPM_RC_SCHEME). + /// signHandle: Handle of the key that will be used in the signing operation + /// Auth Index: 1 + /// Auth Role: USER + /// P1: A point (M) on the curve used by signHandle + /// s2: Octet array used to derive x-coordinate of a base point + /// y2: Y coordinate of the point associated with s2 + /// K - ECC point K [ds](x2, y2) + /// L - ECC point L [r](x2, y2) + /// E - ECC point E [r]P1 + /// counter - Least-significant 16 bits of commitCount + pub fn Commit( + &mut self, + signHandle: &TPM_HANDLE, + P1: &TPMS_ECC_POINT, + s2: &Vec, + y2: &Vec, + ) -> Result { + let req = TPM2_Commit_REQUEST::new( + signHandle, + P1, + s2, + y2, + ); + + let mut resp = CommitResponse::default(); + self.dispatch(TPM_CC::Commit, req, &mut resp)?; + Ok(resp) + } + + /// TPM2_EC_Ephemeral() creates an ephemeral key for use in a two-phase key exchange protocol. + /// curveID: The curve for the computed ephemeral point + /// Q - Ephemeral public key Q [r]G + /// counter - Least-significant 16 bits of commitCount + pub fn EC_Ephemeral( + &mut self, + curveID: TPM_ECC_CURVE, + ) -> Result { + let req = TPM2_EC_Ephemeral_REQUEST::new( + curveID, + ); + + let mut resp = EC_EphemeralResponse::default(); + self.dispatch(TPM_CC::EC_Ephemeral, req, &mut resp)?; + Ok(resp) + } + + /// This command uses loaded keys to validate a signature on a message with the message digest + /// passed to the TPM. + /// keyHandle: Handle of public key that will be used in the validation + /// Auth Index: None + /// digest: Digest of the signed message + /// signature: Signature to be tested + /// One of: TPMS_SIGNATURE_RSASSA, TPMS_SIGNATURE_RSAPSS, TPMS_SIGNATURE_ECDSA, + /// TPMS_SIGNATURE_ECDAA, TPMS_SIGNATURE_SM2, TPMS_SIGNATURE_ECSCHNORR, TPMT_HA, + /// TPMS_SCHEME_HASH, TPMS_NULL_SIGNATURE. + /// validation - This ticket is produced by TPM2_VerifySignature(). This formulation is + /// used for multiple ticket uses. The ticket provides evidence that the TPM + /// has validated that a digest was signed by a key with the Name of keyName. + /// The ticket is computed by + pub fn VerifySignature( + &mut self, + keyHandle: &TPM_HANDLE, + digest: &Vec, + signature: &Option, + ) -> Result { + let req = TPM2_VerifySignature_REQUEST::new( + keyHandle, + digest, + signature, + ); + + let mut resp = VerifySignatureResponse::default(); + self.dispatch(TPM_CC::VerifySignature, req, &mut resp)?; + Ok(resp.validation) + } + + /// This command causes the TPM to sign an externally provided hash with the specified + /// symmetric or asymmetric signing key. + /// keyHandle: Handle of key that will perform signing + /// Auth Index: 1 + /// Auth Role: USER + /// digest: Digest to be signed + /// inScheme: Signing scheme to use if the scheme for keyHandle is TPM_ALG_NULL + /// One of: TPMS_SIG_SCHEME_RSASSA, TPMS_SIG_SCHEME_RSAPSS, TPMS_SIG_SCHEME_ECDSA, + /// TPMS_SIG_SCHEME_ECDAA, TPMS_SIG_SCHEME_SM2, TPMS_SIG_SCHEME_ECSCHNORR, + /// TPMS_SCHEME_HMAC, TPMS_SCHEME_HASH, TPMS_NULL_SIG_SCHEME. + /// validation: Proof that digest was created by the TPM + /// If keyHandle is not a restricted signing key, then this may be a NULL Ticket with + /// tag = TPM_ST_CHECKHASH. + /// signature - The signature + pub fn Sign( + &mut self, + keyHandle: &TPM_HANDLE, + digest: &Vec, + inScheme: &Option, + validation: &TPMT_TK_HASHCHECK, + ) -> Result, TpmError> { + let req = TPM2_Sign_REQUEST::new( + keyHandle, + digest, + inScheme, + validation, + ); + + let mut resp = SignResponse::default(); + self.dispatch(TPM_CC::Sign, req, &mut resp)?; + Ok(resp.signature) + } + + /// This command may be used by the Privacy Administrator or platform to change the audit + /// status of a command or to set the hash algorithm used for the audit digest, but not both + /// at the same time. + /// auth: TPM_RH_OWNER or TPM_RH_PLATFORM+{PP} + /// Auth Index: 1 + /// Auth Role: USER + /// auditAlg: Hash algorithm for the audit digest; if TPM_ALG_NULL, then the hash is not changed + /// setList: List of commands that will be added to those that will be audited + /// clearList: List of commands that will no longer be audited + pub fn SetCommandCodeAuditStatus( + &mut self, + auth: &TPM_HANDLE, + auditAlg: TPM_ALG_ID, + setList: &Vec, + clearList: &Vec, + ) -> Result<(), TpmError> { + let req = TPM2_SetCommandCodeAuditStatus_REQUEST::new( + auth, + auditAlg, + setList, + clearList, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::SetCommandCodeAuditStatus, req, &mut resp)?; + Ok(()) + } + + /// This command is used to cause an update to the indicated PCR. The digests parameter + /// contains one or more tagged digest values identified by an algorithm ID. For each digest, + /// the PCR associated with pcrHandle is Extended into the bank identified by the tag (hashAlg). + /// pcrHandle: Handle of the PCR + /// Auth Handle: 1 + /// Auth Role: USER + /// digests: List of tagged digest values to be extended + pub fn PCR_Extend( + &mut self, + pcrHandle: &TPM_HANDLE, + digests: &Vec, + ) -> Result<(), TpmError> { + let req = TPM2_PCR_Extend_REQUEST::new( + pcrHandle, + digests, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::PCR_Extend, req, &mut resp)?; + Ok(()) + } + + /// This command is used to cause an update to the indicated PCR. + /// pcrHandle: Handle of the PCR + /// Auth Handle: 1 + /// Auth Role: USER + /// eventData: Event data in sized buffer + /// digests - Table 80 shows the basic hash-agile structure used in this specification. To + /// handle hash agility, this structure uses the hashAlg parameter to indicate + /// the algorithm used to compute the digest and, by implication, the size of + /// the digest. + pub fn PCR_Event( + &mut self, + pcrHandle: &TPM_HANDLE, + eventData: &Vec, + ) -> Result, TpmError> { + let req = TPM2_PCR_Event_REQUEST::new( + pcrHandle, + eventData, + ); + + let mut resp = PCR_EventResponse::default(); + self.dispatch(TPM_CC::PCR_Event, req, &mut resp)?; + Ok(resp.digests) + } + + /// This command returns the values of all PCR specified in pcrSelectionIn. + /// pcrSelectionIn: The selection of PCR to read + /// pcrUpdateCounter - The current value of the PCR update counter + /// pcrSelectionOut - The PCR in the returned list + /// pcrValues - The contents of the PCR indicated in pcrSelectOut-˃ pcrSelection[] as + /// tagged digests + pub fn PCR_Read( + &mut self, + pcrSelectionIn: &Vec, + ) -> Result { + let req = TPM2_PCR_Read_REQUEST::new( + pcrSelectionIn, + ); + + let mut resp = PCR_ReadResponse::default(); + self.dispatch(TPM_CC::PCR_Read, req, &mut resp)?; + Ok(resp) + } + + /// This command is used to set the desired PCR allocation of PCR and algorithms. This command + /// requires Platform Authorization. + /// authHandle: TPM_RH_PLATFORM+{PP} + /// Auth Index: 1 + /// Auth Role: USER + /// pcrAllocation: The requested allocation + /// allocationSuccess - YES if the allocation succeeded + /// maxPCR - Maximum number of PCR that may be in a bank + /// sizeNeeded - Number of octets required to satisfy the request + /// sizeAvailable - Number of octets available. Computed before the allocation. + pub fn PCR_Allocate( + &mut self, + authHandle: &TPM_HANDLE, + pcrAllocation: &Vec, + ) -> Result { + let req = TPM2_PCR_Allocate_REQUEST::new( + authHandle, + pcrAllocation, + ); + + let mut resp = PCR_AllocateResponse::default(); + self.dispatch(TPM_CC::PCR_Allocate, req, &mut resp)?; + Ok(resp) + } + + /// This command is used to associate a policy with a PCR or group of PCR. The policy + /// determines the conditions under which a PCR may be extended or reset. + /// authHandle: TPM_RH_PLATFORM+{PP} + /// Auth Index: 1 + /// Auth Role: USER + /// authPolicy: The desired authPolicy + /// hashAlg: The hash algorithm of the policy + /// pcrNum: The PCR for which the policy is to be set + pub fn PCR_SetAuthPolicy( + &mut self, + authHandle: &TPM_HANDLE, + authPolicy: &Vec, + hashAlg: TPM_ALG_ID, + pcrNum: &TPM_HANDLE, + ) -> Result<(), TpmError> { + let req = TPM2_PCR_SetAuthPolicy_REQUEST::new( + authHandle, + authPolicy, + hashAlg, + pcrNum, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::PCR_SetAuthPolicy, req, &mut resp)?; + Ok(()) + } + + /// This command changes the authValue of a PCR or group of PCR. + /// pcrHandle: Handle for a PCR that may have an authorization value set + /// Auth Index: 1 + /// Auth Role: USER + /// auth: The desired authorization value + pub fn PCR_SetAuthValue( + &mut self, + pcrHandle: &TPM_HANDLE, + auth: &Vec, + ) -> Result<(), TpmError> { + let req = TPM2_PCR_SetAuthValue_REQUEST::new( + pcrHandle, + auth, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::PCR_SetAuthValue, req, &mut resp)?; + Ok(()) + } + + /// If the attribute of a PCR allows the PCR to be reset and proper authorization is provided, + /// then this command may be used to set the PCR in all banks to zero. The attributes of the + /// PCR may restrict the locality that can perform the reset operation. + /// pcrHandle: The PCR to reset + /// Auth Index: 1 + /// Auth Role: USER + pub fn PCR_Reset( + &mut self, + pcrHandle: &TPM_HANDLE, + ) -> Result<(), TpmError> { + let req = TPM2_PCR_Reset_REQUEST::new( + pcrHandle, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::PCR_Reset, req, &mut resp)?; + Ok(()) + } + + /// This command includes a signed authorization in a policy. The command ties the policy to a + /// signing key by including the Name of the signing key in the policyDigest + /// authObject: Handle for a key that will validate the signature + /// Auth Index: None + /// policySession: Handle for the policy session being extended + /// Auth Index: None + /// nonceTPM: The policy nonce for the session + /// This can be the Empty Buffer. + /// cpHashA: Digest of the command parameters to which this authorization is limited + /// This is not the cpHash for this command but the cpHash for the command to which + /// this policy session will be applied. If it is not limited, the parameter will be + /// the Empty Buffer. + /// policyRef: A reference to a policy relating to the authorization may be the Empty Buffer + /// Size is limited to be no larger than the nonce size supported on the TPM. + /// expiration: Time when authorization will expire, measured in seconds from the time that + /// nonceTPM was generated + /// If expiration is non-negative, a NULL Ticket is returned. See 23.2.5. + /// auth: Signed authorization (not optional) + /// One of: TPMS_SIGNATURE_RSASSA, TPMS_SIGNATURE_RSAPSS, TPMS_SIGNATURE_ECDSA, + /// TPMS_SIGNATURE_ECDAA, TPMS_SIGNATURE_SM2, TPMS_SIGNATURE_ECSCHNORR, TPMT_HA, + /// TPMS_SCHEME_HASH, TPMS_NULL_SIGNATURE. + /// timeout - Implementation-specific time value, used to indicate to the TPM when the + /// ticket expires + /// NOTE If policyTicket is a NULL Ticket, then this shall be the Empty Buffer. + /// policyTicket - Produced if the command succeeds and expiration in the command was + /// non-zero; this ticket will use the TPMT_ST_AUTH_SIGNED structure tag. + /// See 23.2.5 + pub fn PolicySigned( + &mut self, + authObject: &TPM_HANDLE, + policySession: &TPM_HANDLE, + nonceTPM: &Vec, + cpHashA: &Vec, + policyRef: &Vec, + expiration: i32, + auth: &Option, + ) -> Result { + let req = TPM2_PolicySigned_REQUEST::new( + authObject, + policySession, + nonceTPM, + cpHashA, + policyRef, + expiration, + auth, + ); + + let mut resp = PolicySignedResponse::default(); + self.dispatch(TPM_CC::PolicySigned, req, &mut resp)?; + Ok(resp) + } + + /// This command includes a secret-based authorization to a policy. The caller proves + /// knowledge of the secret value using an authorization session using the authValue + /// associated with authHandle. A password session, an HMAC session, or a policy session + /// containing TPM2_PolicyAuthValue() or TPM2_PolicyPassword() will satisfy this requirement. + /// authHandle: Handle for an entity providing the authorization + /// Auth Index: 1 + /// Auth Role: USER + /// policySession: Handle for the policy session being extended + /// Auth Index: None + /// nonceTPM: The policy nonce for the session + /// This can be the Empty Buffer. + /// cpHashA: Digest of the command parameters to which this authorization is limited + /// This not the cpHash for this command but the cpHash for the command to which this + /// policy session will be applied. If it is not limited, the parameter will be the + /// Empty Buffer. + /// policyRef: A reference to a policy relating to the authorization may be the Empty Buffer + /// Size is limited to be no larger than the nonce size supported on the TPM. + /// expiration: Time when authorization will expire, measured in seconds from the time that + /// nonceTPM was generated + /// If expiration is non-negative, a NULL Ticket is returned. See 23.2.5. + /// timeout - Implementation-specific time value used to indicate to the TPM when the + /// ticket expires + /// policyTicket - Produced if the command succeeds and expiration in the command was + /// non-zero ( See 23.2.5). This ticket will use the TPMT_ST_AUTH_SECRET + /// structure tag + pub fn PolicySecret( + &mut self, + authHandle: &TPM_HANDLE, + policySession: &TPM_HANDLE, + nonceTPM: &Vec, + cpHashA: &Vec, + policyRef: &Vec, + expiration: i32, + ) -> Result { + let req = TPM2_PolicySecret_REQUEST::new( + authHandle, + policySession, + nonceTPM, + cpHashA, + policyRef, + expiration, + ); + + let mut resp = PolicySecretResponse::default(); + self.dispatch(TPM_CC::PolicySecret, req, &mut resp)?; + Ok(resp) + } + + /// This command is similar to TPM2_PolicySigned() except that it takes a ticket instead of a + /// signed authorization. The ticket represents a validated authorization that had an + /// expiration time associated with it. + /// policySession: Handle for the policy session being extended + /// Auth Index: None + /// timeout: Time when authorization will expire + /// The contents are TPM specific. This shall be the value returned when ticket was produced. + /// cpHashA: Digest of the command parameters to which this authorization is limited + /// If it is not limited, the parameter will be the Empty Buffer. + /// policyRef: Reference to a qualifier for the policy may be the Empty Buffer + /// authName: Name of the object that provided the authorization + /// ticket: An authorization ticket returned by the TPM in response to a TPM2_PolicySigned() + /// or TPM2_PolicySecret() + pub fn PolicyTicket( + &mut self, + policySession: &TPM_HANDLE, + timeout: &Vec, + cpHashA: &Vec, + policyRef: &Vec, + authName: &Vec, + ticket: &TPMT_TK_AUTH, + ) -> Result<(), TpmError> { + let req = TPM2_PolicyTicket_REQUEST::new( + policySession, + timeout, + cpHashA, + policyRef, + authName, + ticket, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::PolicyTicket, req, &mut resp)?; + Ok(()) + } + + /// This command allows options in authorizations without requiring that the TPM evaluate all + /// of the options. If a policy may be satisfied by different sets of conditions, the TPM need + /// only evaluate one set that satisfies the policy. This command will indicate that one of + /// the required sets of conditions has been satisfied. + /// policySession: Handle for the policy session being extended + /// Auth Index: None + /// pHashList: The list of hashes to check for a match + pub fn PolicyOR( + &mut self, + policySession: &TPM_HANDLE, + pHashList: &Vec, + ) -> Result<(), TpmError> { + let req = TPM2_PolicyOR_REQUEST::new( + policySession, + pHashList, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::PolicyOR, req, &mut resp)?; + Ok(()) + } + + /// This command is used to cause conditional gating of a policy based on PCR. This command + /// together with TPM2_PolicyOR() allows one group of authorizations to occur when PCR are in + /// one state and a different set of authorizations when the PCR are in a different state. + /// policySession: Handle for the policy session being extended + /// Auth Index: None + /// pcrDigest: Expected digest value of the selected PCR using the hash algorithm of the + /// session; may be zero length + /// pcrs: The PCR to include in the check digest + pub fn PolicyPCR( + &mut self, + policySession: &TPM_HANDLE, + pcrDigest: &Vec, + pcrs: &Vec, + ) -> Result<(), TpmError> { + let req = TPM2_PolicyPCR_REQUEST::new( + policySession, + pcrDigest, + pcrs, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::PolicyPCR, req, &mut resp)?; + Ok(()) + } + + /// This command indicates that the authorization will be limited to a specific locality. + /// policySession: Handle for the policy session being extended + /// Auth Index: None + /// locality: The allowed localities for the policy + pub fn PolicyLocality( + &mut self, + policySession: &TPM_HANDLE, + locality: TPMA_LOCALITY, + ) -> Result<(), TpmError> { + let req = TPM2_PolicyLocality_REQUEST::new( + policySession, + locality, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::PolicyLocality, req, &mut resp)?; + Ok(()) + } + + /// This command is used to cause conditional gating of a policy based on the contents of an + /// NV Index. It is an immediate assertion. The NV index is validated during the + /// TPM2_PolicyNV() command, not when the session is used for authorization. + /// authHandle: Handle indicating the source of the authorization value + /// Auth Index: 1 + /// Auth Role: USER + /// nvIndex: The NV Index of the area to read + /// Auth Index: None + /// policySession: Handle for the policy session being extended + /// Auth Index: None + /// operandB: The second operand + /// offset: The octet offset in the NV Index for the start of operand A + /// operation: The comparison to make + pub fn PolicyNV( + &mut self, + authHandle: &TPM_HANDLE, + nvIndex: &TPM_HANDLE, + policySession: &TPM_HANDLE, + operandB: &Vec, + offset: u16, + operation: TPM_EO, + ) -> Result<(), TpmError> { + let req = TPM2_PolicyNV_REQUEST::new( + authHandle, + nvIndex, + policySession, + operandB, + offset, + operation, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::PolicyNV, req, &mut resp)?; + Ok(()) + } + + /// This command is used to cause conditional gating of a policy based on the contents of the + /// TPMS_TIME_INFO structure. + /// policySession: Handle for the policy session being extended + /// Auth Index: None + /// operandB: The second operand + /// offset: The octet offset in the TPMS_TIME_INFO structure for the start of operand A + /// operation: The comparison to make + pub fn PolicyCounterTimer( + &mut self, + policySession: &TPM_HANDLE, + operandB: &Vec, + offset: u16, + operation: TPM_EO, + ) -> Result<(), TpmError> { + let req = TPM2_PolicyCounterTimer_REQUEST::new( + policySession, + operandB, + offset, + operation, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::PolicyCounterTimer, req, &mut resp)?; + Ok(()) + } + + /// This command indicates that the authorization will be limited to a specific command code. + /// policySession: Handle for the policy session being extended + /// Auth Index: None + /// code: The allowed commandCode + pub fn PolicyCommandCode( + &mut self, + policySession: &TPM_HANDLE, + code: TPM_CC, + ) -> Result<(), TpmError> { + let req = TPM2_PolicyCommandCode_REQUEST::new( + policySession, + code, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::PolicyCommandCode, req, &mut resp)?; + Ok(()) + } + + /// This command indicates that physical presence will need to be asserted at the time the + /// authorization is performed. + /// policySession: Handle for the policy session being extended + /// Auth Index: None + pub fn PolicyPhysicalPresence( + &mut self, + policySession: &TPM_HANDLE, + ) -> Result<(), TpmError> { + let req = TPM2_PolicyPhysicalPresence_REQUEST::new( + policySession, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::PolicyPhysicalPresence, req, &mut resp)?; + Ok(()) + } + + /// This command is used to allow a policy to be bound to a specific command and command parameters. + /// policySession: Handle for the policy session being extended + /// Auth Index: None + /// cpHashA: The cpHash added to the policy + pub fn PolicyCpHash( + &mut self, + policySession: &TPM_HANDLE, + cpHashA: &Vec, + ) -> Result<(), TpmError> { + let req = TPM2_PolicyCpHash_REQUEST::new( + policySession, + cpHashA, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::PolicyCpHash, req, &mut resp)?; + Ok(()) + } + + /// This command allows a policy to be bound to a specific set of TPM entities without being + /// bound to the parameters of the command. This is most useful for commands such as + /// TPM2_Duplicate() and for TPM2_PCR_Event() when the referenced PCR requires a policy. + /// policySession: Handle for the policy session being extended + /// Auth Index: None + /// nameHash: The digest to be added to the policy + pub fn PolicyNameHash( + &mut self, + policySession: &TPM_HANDLE, + nameHash: &Vec, + ) -> Result<(), TpmError> { + let req = TPM2_PolicyNameHash_REQUEST::new( + policySession, + nameHash, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::PolicyNameHash, req, &mut resp)?; + Ok(()) + } + + /// This command allows qualification of duplication to allow duplication to a selected new parent. + /// policySession: Handle for the policy session being extended + /// Auth Index: None + /// objectName: The Name of the object to be duplicated + /// newParentName: The Name of the new parent + /// includeObject: If YES, the objectName will be included in the value in policySessionpolicyDigest + pub fn PolicyDuplicationSelect( + &mut self, + policySession: &TPM_HANDLE, + objectName: &Vec, + newParentName: &Vec, + includeObject: u8, + ) -> Result<(), TpmError> { + let req = TPM2_PolicyDuplicationSelect_REQUEST::new( + policySession, + objectName, + newParentName, + includeObject, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::PolicyDuplicationSelect, req, &mut resp)?; + Ok(()) + } + + /// This command allows policies to change. If a policy were static, then it would be + /// difficult to add users to a policy. This command lets a policy authority sign a new policy + /// so that it may be used in an existing policy. + /// policySession: Handle for the policy session being extended + /// Auth Index: None + /// approvedPolicy: Digest of the policy being approved + /// policyRef: A policy qualifier + /// keySign: Name of a key that can sign a policy addition + /// checkTicket: Ticket validating that approvedPolicy and policyRef were signed by keySign + pub fn PolicyAuthorize( + &mut self, + policySession: &TPM_HANDLE, + approvedPolicy: &Vec, + policyRef: &Vec, + keySign: &Vec, + checkTicket: &TPMT_TK_VERIFIED, + ) -> Result<(), TpmError> { + let req = TPM2_PolicyAuthorize_REQUEST::new( + policySession, + approvedPolicy, + policyRef, + keySign, + checkTicket, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::PolicyAuthorize, req, &mut resp)?; + Ok(()) + } + + /// This command allows a policy to be bound to the authorization value of the authorized entity. + /// policySession: Handle for the policy session being extended + /// Auth Index: None + pub fn PolicyAuthValue( + &mut self, + policySession: &TPM_HANDLE, + ) -> Result<(), TpmError> { + let req = TPM2_PolicyAuthValue_REQUEST::new( + policySession, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::PolicyAuthValue, req, &mut resp)?; + Ok(()) + } + + /// This command allows a policy to be bound to the authorization value of the authorized object. + /// policySession: Handle for the policy session being extended + /// Auth Index: None + pub fn PolicyPassword( + &mut self, + policySession: &TPM_HANDLE, + ) -> Result<(), TpmError> { + let req = TPM2_PolicyPassword_REQUEST::new( + policySession, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::PolicyPassword, req, &mut resp)?; + Ok(()) + } + + /// This command returns the current policyDigest of the session. This command allows the TPM + /// to be used to perform the actions required to pre-compute the authPolicy for an object. + /// policySession: Handle for the policy session + /// Auth Index: None + /// policyDigest - The current value of the policySessionpolicyDigest + pub fn PolicyGetDigest( + &mut self, + policySession: &TPM_HANDLE, + ) -> Result, TpmError> { + let req = TPM2_PolicyGetDigest_REQUEST::new( + policySession, + ); + + let mut resp = PolicyGetDigestResponse::default(); + self.dispatch(TPM_CC::PolicyGetDigest, req, &mut resp)?; + Ok(resp.policyDigest) + } + + /// This command allows a policy to be bound to the TPMA_NV_WRITTEN attributes. This is a + /// deferred assertion. Values are stored in the policy session context and checked when the + /// policy is used for authorization. + /// policySession: Handle for the policy session being extended + /// Auth Index: None + /// writtenSet: YES if NV Index is required to have been written + /// NO if NV Index is required not to have been written + pub fn PolicyNvWritten( + &mut self, + policySession: &TPM_HANDLE, + writtenSet: u8, + ) -> Result<(), TpmError> { + let req = TPM2_PolicyNvWritten_REQUEST::new( + policySession, + writtenSet, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::PolicyNvWritten, req, &mut resp)?; + Ok(()) + } + + /// This command allows a policy to be bound to a specific creation template. This is most + /// useful for an object creation command such as TPM2_Create(), TPM2_CreatePrimary(), or + /// TPM2_CreateLoaded(). + /// policySession: Handle for the policy session being extended + /// Auth Index: None + /// templateHash: The digest to be added to the policy + pub fn PolicyTemplate( + &mut self, + policySession: &TPM_HANDLE, + templateHash: &Vec, + ) -> Result<(), TpmError> { + let req = TPM2_PolicyTemplate_REQUEST::new( + policySession, + templateHash, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::PolicyTemplate, req, &mut resp)?; + Ok(()) + } + + /// This command provides a capability that is the equivalent of a revocable policy. With + /// TPM2_PolicyAuthorize(), the authorization ticket never expires, so the authorization may + /// not be withdrawn. With this command, the approved policy is kept in an NV Index location + /// so that the policy may be changed as needed to render the old policy unusable. + /// authHandle: Handle indicating the source of the authorization value + /// Auth Index: 1 + /// Auth Role: USER + /// nvIndex: The NV Index of the area to read + /// Auth Index: None + /// policySession: Handle for the policy session being extended + /// Auth Index: None + pub fn PolicyAuthorizeNV( + &mut self, + authHandle: &TPM_HANDLE, + nvIndex: &TPM_HANDLE, + policySession: &TPM_HANDLE, + ) -> Result<(), TpmError> { + let req = TPM2_PolicyAuthorizeNV_REQUEST::new( + authHandle, + nvIndex, + policySession, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::PolicyAuthorizeNV, req, &mut resp)?; + Ok(()) + } + + /// This command is used to create a Primary Object under one of the Primary Seeds or a + /// Temporary Object under TPM_RH_NULL. The command uses a TPM2B_PUBLIC as a template for the + /// object to be created. The size of the unique field shall not be checked for consistency + /// with the other object parameters. The command will create and load a Primary Object. The + /// sensitive area is not returned. + /// primaryHandle: TPM_RH_ENDORSEMENT, TPM_RH_OWNER, TPM_RH_PLATFORM+{PP}, or TPM_RH_NULL + /// Auth Index: 1 + /// Auth Role: USER + /// inSensitive: The sensitive data, see TPM 2.0 Part 1 Sensitive Values + /// inPublic: The public template + /// outsideInfo: Data that will be included in the creation data for this object to provide + /// permanent, verifiable linkage between this object and some object owner data + /// creationPCR: PCR that will be used in creation data + /// handle - Handle of type TPM_HT_TRANSIENT for created Primary Object + /// outPublic - The public portion of the created object + /// creationData - Contains a TPMT_CREATION_DATA + /// creationHash - Digest of creationData using nameAlg of outPublic + /// creationTicket - Ticket used by TPM2_CertifyCreation() to validate that the creation + /// data was produced by the TPM + /// name - The name of the created object + pub fn CreatePrimary( + &mut self, + primaryHandle: &TPM_HANDLE, + inSensitive: &TPMS_SENSITIVE_CREATE, + inPublic: &TPMT_PUBLIC, + outsideInfo: &Vec, + creationPCR: &Vec, + ) -> Result { + let req = TPM2_CreatePrimary_REQUEST::new( + primaryHandle, + inSensitive, + inPublic, + outsideInfo, + creationPCR, + ); + + let mut resp = CreatePrimaryResponse::default(); + self.dispatch(TPM_CC::CreatePrimary, req, &mut resp)?; + Ok(resp) + } + + /// This command enables and disables use of a hierarchy and its associated NV storage. The + /// command allows phEnable, phEnableNV, shEnable, and ehEnable to be changed when the proper + /// authorization is provided. + /// authHandle: TPM_RH_ENDORSEMENT, TPM_RH_OWNER or TPM_RH_PLATFORM+{PP} + /// Auth Index: 1 + /// Auth Role: USER + /// enable: The enable being modified + /// TPM_RH_ENDORSEMENT, TPM_RH_OWNER, TPM_RH_PLATFORM, or TPM_RH_PLATFORM_NV + /// state: YES if the enable should be SET, NO if the enable should be CLEAR + pub fn HierarchyControl( + &mut self, + authHandle: &TPM_HANDLE, + enable: &TPM_HANDLE, + state: u8, + ) -> Result<(), TpmError> { + let req = TPM2_HierarchyControl_REQUEST::new( + authHandle, + enable, + state, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::HierarchyControl, req, &mut resp)?; + Ok(()) + } + + /// This command allows setting of the authorization policy for the lockout (lockoutPolicy), + /// the platform hierarchy (platformPolicy), the storage hierarchy (ownerPolicy), and the + /// endorsement hierarchy (endorsementPolicy). On TPMs implementing Authenticated Countdown + /// Timers (ACT), this command may also be used to set the authorization policy for an ACT. + /// authHandle: TPM_RH_LOCKOUT, TPM_RH_ENDORSEMENT, TPM_RH_OWNER, TPMI_RH_ACT or TPM_RH_PLATFORM+{PP} + /// Auth Index: 1 + /// Auth Role: USER + /// authPolicy: An authorization policy digest; may be the Empty Buffer + /// If hashAlg is TPM_ALG_NULL, then this shall be an Empty Buffer. + /// hashAlg: The hash algorithm to use for the policy + /// If the authPolicy is an Empty Buffer, then this field shall be TPM_ALG_NULL. + pub fn SetPrimaryPolicy( + &mut self, + authHandle: &TPM_HANDLE, + authPolicy: &Vec, + hashAlg: TPM_ALG_ID, + ) -> Result<(), TpmError> { + let req = TPM2_SetPrimaryPolicy_REQUEST::new( + authHandle, + authPolicy, + hashAlg, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::SetPrimaryPolicy, req, &mut resp)?; + Ok(()) + } + + /// This replaces the current platform primary seed (PPS) with a value from the RNG and sets + /// platformPolicy to the default initialization value (the Empty Buffer). + /// authHandle: TPM_RH_PLATFORM+{PP} + /// Auth Index: 1 + /// Auth Role: USER + pub fn ChangePPS( + &mut self, + authHandle: &TPM_HANDLE, + ) -> Result<(), TpmError> { + let req = TPM2_ChangePPS_REQUEST::new( + authHandle, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::ChangePPS, req, &mut resp)?; + Ok(()) + } + + /// This replaces the current endorsement primary seed (EPS) with a value from the RNG and + /// sets the Endorsement hierarchy controls to their default initialization values: ehEnable + /// is SET, endorsementAuth and endorsementPolicy are both set to the Empty Buffer. It will + /// flush any resident objects (transient or persistent) in the Endorsement hierarchy and not + /// allow objects in the hierarchy associated with the previous EPS to be loaded. + /// authHandle: TPM_RH_PLATFORM+{PP} + /// Auth Handle: 1 + /// Auth Role: USER + pub fn ChangeEPS( + &mut self, + authHandle: &TPM_HANDLE, + ) -> Result<(), TpmError> { + let req = TPM2_ChangeEPS_REQUEST::new( + authHandle, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::ChangeEPS, req, &mut resp)?; + Ok(()) + } + + /// This command removes all TPM context associated with a specific Owner. + /// authHandle: TPM_RH_LOCKOUT or TPM_RH_PLATFORM+{PP} + /// Auth Handle: 1 + /// Auth Role: USER + pub fn Clear( + &mut self, + authHandle: &TPM_HANDLE, + ) -> Result<(), TpmError> { + let req = TPM2_Clear_REQUEST::new( + authHandle, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::Clear, req, &mut resp)?; + Ok(()) + } + + /// TPM2_ClearControl() disables and enables the execution of TPM2_Clear(). + /// auth: TPM_RH_LOCKOUT or TPM_RH_PLATFORM+{PP} + /// Auth Handle: 1 + /// Auth Role: USER + /// disable: YES if the disableOwnerClear flag is to be SET, NO if the flag is to be CLEAR. + pub fn ClearControl( + &mut self, + auth: &TPM_HANDLE, + disable: u8, + ) -> Result<(), TpmError> { + let req = TPM2_ClearControl_REQUEST::new( + auth, + disable, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::ClearControl, req, &mut resp)?; + Ok(()) + } + + /// This command allows the authorization secret for a hierarchy or lockout to be changed + /// using the current authorization value as the command authorization. + /// authHandle: TPM_RH_LOCKOUT, TPM_RH_ENDORSEMENT, TPM_RH_OWNER or TPM_RH_PLATFORM+{PP} + /// Auth Index: 1 + /// Auth Role: USER + /// newAuth: New authorization value + pub fn HierarchyChangeAuth( + &mut self, + authHandle: &TPM_HANDLE, + newAuth: &Vec, + ) -> Result<(), TpmError> { + let req = TPM2_HierarchyChangeAuth_REQUEST::new( + authHandle, + newAuth, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::HierarchyChangeAuth, req, &mut resp)?; + Ok(()) + } + + /// This command cancels the effect of a TPM lockout due to a number of successive + /// authorization failures. If this command is properly authorized, the lockout counter is set + /// to zero. + /// lockHandle: TPM_RH_LOCKOUT + /// Auth Index: 1 + /// Auth Role: USER + pub fn DictionaryAttackLockReset( + &mut self, + lockHandle: &TPM_HANDLE, + ) -> Result<(), TpmError> { + let req = TPM2_DictionaryAttackLockReset_REQUEST::new( + lockHandle, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::DictionaryAttackLockReset, req, &mut resp)?; + Ok(()) + } + + /// This command changes the lockout parameters. + /// lockHandle: TPM_RH_LOCKOUT + /// Auth Index: 1 + /// Auth Role: USER + /// newMaxTries: Count of authorization failures before the lockout is imposed + /// newRecoveryTime: Time in seconds before the authorization failure count is automatically decremented + /// A value of zero indicates that DA protection is disabled. + /// lockoutRecovery: Time in seconds after a lockoutAuth failure before use of lockoutAuth is allowed + /// A value of zero indicates that a reboot is required. + pub fn DictionaryAttackParameters( + &mut self, + lockHandle: &TPM_HANDLE, + newMaxTries: u32, + newRecoveryTime: u32, + lockoutRecovery: u32, + ) -> Result<(), TpmError> { + let req = TPM2_DictionaryAttackParameters_REQUEST::new( + lockHandle, + newMaxTries, + newRecoveryTime, + lockoutRecovery, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::DictionaryAttackParameters, req, &mut resp)?; + Ok(()) + } + + /// This command is used to determine which commands require assertion of Physical Presence + /// (PP) in addition to platformAuth/platformPolicy. + /// auth: TPM_RH_PLATFORM+PP + /// Auth Index: 1 + /// Auth Role: USER + Physical Presence + /// setList: List of commands to be added to those that will require that Physical Presence be + /// asserted + /// clearList: List of commands that will no longer require that Physical Presence be asserted + pub fn PP_Commands( + &mut self, + auth: &TPM_HANDLE, + setList: &Vec, + clearList: &Vec, + ) -> Result<(), TpmError> { + let req = TPM2_PP_Commands_REQUEST::new( + auth, + setList, + clearList, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::PP_Commands, req, &mut resp)?; + Ok(()) + } + + /// This command allows the platform to change the set of algorithms that are used by the TPM. + /// The algorithmSet setting is a vendor-dependent value. + /// authHandle: TPM_RH_PLATFORM + /// Auth Index: 1 + /// Auth Role: USER + /// algorithmSet: A TPM vendor-dependent value indicating the algorithm set selection + pub fn SetAlgorithmSet( + &mut self, + authHandle: &TPM_HANDLE, + algorithmSet: u32, + ) -> Result<(), TpmError> { + let req = TPM2_SetAlgorithmSet_REQUEST::new( + authHandle, + algorithmSet, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::SetAlgorithmSet, req, &mut resp)?; + Ok(()) + } + + /// This command uses platformPolicy and a TPM Vendor Authorization Key to authorize a Field + /// Upgrade Manifest. + /// authorization: TPM_RH_PLATFORM+{PP} + /// Auth Index:1 + /// Auth Role: ADMIN + /// keyHandle: Handle of a public area that contains the TPM Vendor Authorization Key that + /// will be used to validate manifestSignature + /// Auth Index: None + /// fuDigest: Digest of the first block in the field upgrade sequence + /// manifestSignature: Signature over fuDigest using the key associated with keyHandle (not optional) + /// One of: TPMS_SIGNATURE_RSASSA, TPMS_SIGNATURE_RSAPSS, TPMS_SIGNATURE_ECDSA, + /// TPMS_SIGNATURE_ECDAA, TPMS_SIGNATURE_SM2, TPMS_SIGNATURE_ECSCHNORR, TPMT_HA, + /// TPMS_SCHEME_HASH, TPMS_NULL_SIGNATURE. + pub fn FieldUpgradeStart( + &mut self, + authorization: &TPM_HANDLE, + keyHandle: &TPM_HANDLE, + fuDigest: &Vec, + manifestSignature: &Option, + ) -> Result<(), TpmError> { + let req = TPM2_FieldUpgradeStart_REQUEST::new( + authorization, + keyHandle, + fuDigest, + manifestSignature, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::FieldUpgradeStart, req, &mut resp)?; + Ok(()) + } + + /// This command will take the actual field upgrade image to be installed on the TPM. The + /// exact format of fuData is vendor-specific. This command is only possible following a + /// successful TPM2_FieldUpgradeStart(). If the TPM has not received a properly authorized + /// TPM2_FieldUpgradeStart(), then the TPM shall return TPM_RC_FIELDUPGRADE. + /// fuData: Field upgrade image data + /// nextDigest - Tagged digest of the next block + /// TPM_ALG_NULL if field update is complete + /// firstDigest - Tagged digest of the first block of the sequence + pub fn FieldUpgradeData( + &mut self, + fuData: &Vec, + ) -> Result { + let req = TPM2_FieldUpgradeData_REQUEST::new( + fuData, + ); + + let mut resp = FieldUpgradeDataResponse::default(); + self.dispatch(TPM_CC::FieldUpgradeData, req, &mut resp)?; + Ok(resp) + } + + /// This command is used to read a copy of the current firmware installed in the TPM. + /// sequenceNumber: The number of previous calls to this command in this sequence + /// set to 0 on the first call + /// fuData - Field upgrade image data + pub fn FirmwareRead( + &mut self, + sequenceNumber: u32, + ) -> Result, TpmError> { + let req = TPM2_FirmwareRead_REQUEST::new( + sequenceNumber, + ); + + let mut resp = FirmwareReadResponse::default(); + self.dispatch(TPM_CC::FirmwareRead, req, &mut resp)?; + Ok(resp.fuData) + } + + /// This command saves a session context, object context, or sequence object context outside + /// the TPM. + /// saveHandle: Handle of the resource to save + /// Auth Index: None + /// context - This structure is used in TPM2_ContextLoad() and TPM2_ContextSave(). If the + /// values of the TPMS_CONTEXT structure in TPM2_ContextLoad() are not the same + /// as the values when the context was saved (TPM2_ContextSave()), then the TPM + /// shall not load the context. + pub fn ContextSave( + &mut self, + saveHandle: &TPM_HANDLE, + ) -> Result { + let req = TPM2_ContextSave_REQUEST::new( + saveHandle, + ); + + let mut resp = ContextSaveResponse::default(); + self.dispatch(TPM_CC::ContextSave, req, &mut resp)?; + Ok(resp.context) + } + + /// This command is used to reload a context that has been saved by TPM2_ContextSave(). + /// context: The context blob + /// handle - The handle assigned to the resource after it has been successfully loaded + pub fn ContextLoad( + &mut self, + context: &TPMS_CONTEXT, + ) -> Result { + let req = TPM2_ContextLoad_REQUEST::new( + context, + ); + + let mut resp = ContextLoadResponse::default(); + self.dispatch(TPM_CC::ContextLoad, req, &mut resp)?; + Ok(resp.handle) + } + + /// This command causes all context associated with a loaded object, sequence object, or + /// session to be removed from TPM memory. + /// flushHandle: The handle of the item to flush + /// NOTE This is a use of a handle as a parameter. + pub fn FlushContext( + &mut self, + flushHandle: &TPM_HANDLE, + ) -> Result<(), TpmError> { + let req = TPM2_FlushContext_REQUEST::new( + flushHandle, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::FlushContext, req, &mut resp)?; + Ok(()) + } + + /// This command allows certain Transient Objects to be made persistent or a persistent object + /// to be evicted. + /// auth: TPM_RH_OWNER or TPM_RH_PLATFORM+{PP} + /// Auth Handle: 1 + /// Auth Role: USER + /// objectHandle: The handle of a loaded object + /// Auth Index: None + /// persistentHandle: If objectHandle is a transient object handle, then this is the + /// persistent handle for the object + /// if objectHandle is a persistent object handle, then it shall be the same value as + /// persistentHandle + pub fn EvictControl( + &mut self, + auth: &TPM_HANDLE, + objectHandle: &TPM_HANDLE, + persistentHandle: &TPM_HANDLE, + ) -> Result<(), TpmError> { + let req = TPM2_EvictControl_REQUEST::new( + auth, + objectHandle, + persistentHandle, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::EvictControl, req, &mut resp)?; + Ok(()) + } + + /// This command reads the current TPMS_TIME_INFO structure that contains the current setting + /// of Time, Clock, resetCount, and restartCount. + /// currentTime - This structure is used in, e.g., the TPM2_GetTime() attestation and + /// TPM2_ReadClock(). + pub fn ReadClock( + &mut self, + ) -> Result { + let req = TPM2_ReadClock_REQUEST::default(); + + let mut resp = ReadClockResponse::default(); + self.dispatch(TPM_CC::ReadClock, req, &mut resp)?; + Ok(resp.currentTime) + } + + /// This command is used to advance the value of the TPMs Clock. The command will fail if + /// newTime is less than the current value of Clock or if the new time is greater than + /// FFFF00000000000016. If both of these checks succeed, Clock is set to newTime. If either of + /// these checks fails, the TPM shall return TPM_RC_VALUE and make no change to Clock. + /// auth: TPM_RH_OWNER or TPM_RH_PLATFORM+{PP} + /// Auth Handle: 1 + /// Auth Role: USER + /// newTime: New Clock setting in milliseconds + pub fn ClockSet( + &mut self, + auth: &TPM_HANDLE, + newTime: u64, + ) -> Result<(), TpmError> { + let req = TPM2_ClockSet_REQUEST::new( + auth, + newTime, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::ClockSet, req, &mut resp)?; + Ok(()) + } + + /// This command adjusts the rate of advance of Clock and Time to provide a better + /// approximation to real time. + /// auth: TPM_RH_OWNER or TPM_RH_PLATFORM+{PP} + /// Auth Handle: 1 + /// Auth Role: USER + /// rateAdjust: Adjustment to current Clock update rate + pub fn ClockRateAdjust( + &mut self, + auth: &TPM_HANDLE, + rateAdjust: TPM_CLOCK_ADJUST, + ) -> Result<(), TpmError> { + let req = TPM2_ClockRateAdjust_REQUEST::new( + auth, + rateAdjust, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::ClockRateAdjust, req, &mut resp)?; + Ok(()) + } + + /// This command returns various information regarding the TPM and its current state. + /// capability: Group selection; determines the format of the response + /// property: Further definition of information + /// propertyCount: Number of properties of the indicated type to return + /// moreData - Flag to indicate if there are more values of this type + /// capabilityData - The capability data + pub fn GetCapability( + &mut self, + capability: TPM_CAP, + property: u32, + propertyCount: u32, + ) -> Result { + let req = TPM2_GetCapability_REQUEST::new( + capability, + property, + propertyCount, + ); + + let mut resp = GetCapabilityResponse::default(); + self.dispatch(TPM_CC::GetCapability, req, &mut resp)?; + Ok(resp) + } + + /// This command is used to check to see if specific combinations of algorithm parameters are supported. + /// parameters: Algorithm parameters to be validated + /// One of: TPMS_KEYEDHASH_PARMS, TPMS_SYMCIPHER_PARMS, TPMS_RSA_PARMS, TPMS_ECC_PARMS, + /// TPMS_ASYM_PARMS. + pub fn TestParms( + &mut self, + parameters: &Option, + ) -> Result<(), TpmError> { + let req = TPM2_TestParms_REQUEST::new( + parameters, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::TestParms, req, &mut resp)?; + Ok(()) + } + + /// This command defines the attributes of an NV Index and causes the TPM to reserve space to + /// hold the data associated with the NV Index. If a definition already exists at the NV + /// Index, the TPM will return TPM_RC_NV_DEFINED. + /// authHandle: TPM_RH_OWNER or TPM_RH_PLATFORM+{PP} + /// Auth Index: 1 + /// Auth Role: USER + /// auth: The authorization value + /// publicInfo: The public parameters of the NV area + pub fn NV_DefineSpace( + &mut self, + authHandle: &TPM_HANDLE, + auth: &Vec, + publicInfo: &TPMS_NV_PUBLIC, + ) -> Result<(), TpmError> { + let req = TPM2_NV_DefineSpace_REQUEST::new( + authHandle, + auth, + publicInfo, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::NV_DefineSpace, req, &mut resp)?; + Ok(()) + } + + /// This command removes an Index from the TPM. + /// authHandle: TPM_RH_OWNER or TPM_RH_PLATFORM+{PP} + /// Auth Index: 1 + /// Auth Role: USER + /// nvIndex: The NV Index to remove from NV space + /// Auth Index: None + pub fn NV_UndefineSpace( + &mut self, + authHandle: &TPM_HANDLE, + nvIndex: &TPM_HANDLE, + ) -> Result<(), TpmError> { + let req = TPM2_NV_UndefineSpace_REQUEST::new( + authHandle, + nvIndex, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::NV_UndefineSpace, req, &mut resp)?; + Ok(()) + } + + /// This command allows removal of a platform-created NV Index that has TPMA_NV_POLICY_DELETE SET. + /// nvIndex: Index to be deleted + /// Auth Index: 1 + /// Auth Role: ADMIN + /// platform: TPM_RH_PLATFORM + {PP} + /// Auth Index: 2 + /// Auth Role: USER + pub fn NV_UndefineSpaceSpecial( + &mut self, + nvIndex: &TPM_HANDLE, + platform: &TPM_HANDLE, + ) -> Result<(), TpmError> { + let req = TPM2_NV_UndefineSpaceSpecial_REQUEST::new( + nvIndex, + platform, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::NV_UndefineSpaceSpecial, req, &mut resp)?; + Ok(()) + } + + /// This command is used to read the public area and Name of an NV Index. The public area of + /// an Index is not privacy-sensitive and no authorization is required to read this data. + /// nvIndex: The NV Index + /// Auth Index: None + /// nvPublic - The public area of the NV Index + /// nvName - The Name of the nvIndex + pub fn NV_ReadPublic( + &mut self, + nvIndex: &TPM_HANDLE, + ) -> Result { + let req = TPM2_NV_ReadPublic_REQUEST::new( + nvIndex, + ); + + let mut resp = NV_ReadPublicResponse::default(); + self.dispatch(TPM_CC::NV_ReadPublic, req, &mut resp)?; + Ok(resp) + } + + /// This command writes a value to an area in NV memory that was previously defined by + /// TPM2_NV_DefineSpace(). + /// authHandle: Handle indicating the source of the authorization value + /// Auth Index: 1 + /// Auth Role: USER + /// nvIndex: The NV Index of the area to write + /// Auth Index: None + /// data: The data to write + /// offset: The octet offset into the NV Area + pub fn NV_Write( + &mut self, + authHandle: &TPM_HANDLE, + nvIndex: &TPM_HANDLE, + data: &Vec, + offset: u16, + ) -> Result<(), TpmError> { + let req = TPM2_NV_Write_REQUEST::new( + authHandle, + nvIndex, + data, + offset, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::NV_Write, req, &mut resp)?; + Ok(()) + } + + /// This command is used to increment the value in an NV Index that has the TPM_NT_COUNTER + /// attribute. The data value of the NV Index is incremented by one. + /// authHandle: Handle indicating the source of the authorization value + /// Auth Index: 1 + /// Auth Role: USER + /// nvIndex: The NV Index to increment + /// Auth Index: None + pub fn NV_Increment( + &mut self, + authHandle: &TPM_HANDLE, + nvIndex: &TPM_HANDLE, + ) -> Result<(), TpmError> { + let req = TPM2_NV_Increment_REQUEST::new( + authHandle, + nvIndex, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::NV_Increment, req, &mut resp)?; + Ok(()) + } + + /// This command extends a value to an area in NV memory that was previously defined by + /// TPM2_NV_DefineSpace. + /// authHandle: Handle indicating the source of the authorization value + /// Auth Index: 1 + /// Auth Role: USER + /// nvIndex: The NV Index to extend + /// Auth Index: None + /// data: The data to extend + pub fn NV_Extend( + &mut self, + authHandle: &TPM_HANDLE, + nvIndex: &TPM_HANDLE, + data: &Vec, + ) -> Result<(), TpmError> { + let req = TPM2_NV_Extend_REQUEST::new( + authHandle, + nvIndex, + data, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::NV_Extend, req, &mut resp)?; + Ok(()) + } + + /// This command is used to SET bits in an NV Index that was created as a bit field. Any + /// number of bits from 0 to 64 may be SET. The contents of bits are ORed with the current + /// contents of the NV Index. + /// authHandle: Handle indicating the source of the authorization value + /// Auth Index: 1 + /// Auth Role: USER + /// nvIndex: NV Index of the area in which the bit is to be set + /// Auth Index: None + /// bits: The data to OR with the current contents + pub fn NV_SetBits( + &mut self, + authHandle: &TPM_HANDLE, + nvIndex: &TPM_HANDLE, + bits: u64, + ) -> Result<(), TpmError> { + let req = TPM2_NV_SetBits_REQUEST::new( + authHandle, + nvIndex, + bits, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::NV_SetBits, req, &mut resp)?; + Ok(()) + } + + /// If the TPMA_NV_WRITEDEFINE or TPMA_NV_WRITE_STCLEAR attributes of an NV location are SET, + /// then this command may be used to inhibit further writes of the NV Index. + /// authHandle: Handle indicating the source of the authorization value + /// Auth Index: 1 + /// Auth Role: USER + /// nvIndex: The NV Index of the area to lock + /// Auth Index: None + pub fn NV_WriteLock( + &mut self, + authHandle: &TPM_HANDLE, + nvIndex: &TPM_HANDLE, + ) -> Result<(), TpmError> { + let req = TPM2_NV_WriteLock_REQUEST::new( + authHandle, + nvIndex, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::NV_WriteLock, req, &mut resp)?; + Ok(()) + } + + /// The command will SET TPMA_NV_WRITELOCKED for all indexes that have their + /// TPMA_NV_GLOBALLOCK attribute SET. + /// authHandle: TPM_RH_OWNER or TPM_RH_PLATFORM+{PP} + /// Auth Index: 1 + /// Auth Role: USER + pub fn NV_GlobalWriteLock( + &mut self, + authHandle: &TPM_HANDLE, + ) -> Result<(), TpmError> { + let req = TPM2_NV_GlobalWriteLock_REQUEST::new( + authHandle, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::NV_GlobalWriteLock, req, &mut resp)?; + Ok(()) + } + + /// This command reads a value from an area in NV memory previously defined by TPM2_NV_DefineSpace(). + /// authHandle: The handle indicating the source of the authorization value + /// Auth Index: 1 + /// Auth Role: USER + /// nvIndex: The NV Index to be read + /// Auth Index: None + /// size: Number of octets to read + /// offset: Octet offset into the NV area + /// This value shall be less than or equal to the size of the nvIndex data. + /// data - The data read + pub fn NV_Read( + &mut self, + authHandle: &TPM_HANDLE, + nvIndex: &TPM_HANDLE, + size: u16, + offset: u16, + ) -> Result, TpmError> { + let req = TPM2_NV_Read_REQUEST::new( + authHandle, + nvIndex, + size, + offset, + ); + + let mut resp = NV_ReadResponse::default(); + self.dispatch(TPM_CC::NV_Read, req, &mut resp)?; + Ok(resp.data) + } + + /// If TPMA_NV_READ_STCLEAR is SET in an Index, then this command may be used to prevent + /// further reads of the NV Index until the next TPM2_Startup (TPM_SU_CLEAR). + /// authHandle: The handle indicating the source of the authorization value + /// Auth Index: 1 + /// Auth Role: USER + /// nvIndex: The NV Index to be locked + /// Auth Index: None + pub fn NV_ReadLock( + &mut self, + authHandle: &TPM_HANDLE, + nvIndex: &TPM_HANDLE, + ) -> Result<(), TpmError> { + let req = TPM2_NV_ReadLock_REQUEST::new( + authHandle, + nvIndex, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::NV_ReadLock, req, &mut resp)?; + Ok(()) + } + + /// This command allows the authorization secret for an NV Index to be changed. + /// nvIndex: Handle of the entity + /// Auth Index: 1 + /// Auth Role: ADMIN + /// newAuth: New authorization value + pub fn NV_ChangeAuth( + &mut self, + nvIndex: &TPM_HANDLE, + newAuth: &Vec, + ) -> Result<(), TpmError> { + let req = TPM2_NV_ChangeAuth_REQUEST::new( + nvIndex, + newAuth, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::NV_ChangeAuth, req, &mut resp)?; + Ok(()) + } + + /// The purpose of this command is to certify the contents of an NV Index or portion of an NV Index. + /// signHandle: Handle of the key used to sign the attestation structure + /// Auth Index: 1 + /// Auth Role: USER + /// authHandle: Handle indicating the source of the authorization value for the NV Index + /// Auth Index: 2 + /// Auth Role: USER + /// nvIndex: Index for the area to be certified + /// Auth Index: None + /// qualifyingData: User-provided qualifying data + /// inScheme: Signing scheme to use if the scheme for signHandle is TPM_ALG_NULL + /// One of: TPMS_SIG_SCHEME_RSASSA, TPMS_SIG_SCHEME_RSAPSS, TPMS_SIG_SCHEME_ECDSA, + /// TPMS_SIG_SCHEME_ECDAA, TPMS_SIG_SCHEME_SM2, TPMS_SIG_SCHEME_ECSCHNORR, + /// TPMS_SCHEME_HMAC, TPMS_SCHEME_HASH, TPMS_NULL_SIG_SCHEME. + /// size: Number of octets to certify + /// offset: Octet offset into the NV area + /// This value shall be less than or equal to the size of the nvIndex data. + /// certifyInfo - The structure that was signed + /// signature - The asymmetric signature over certifyInfo using the key referenced by signHandle + pub fn NV_Certify( + &mut self, + signHandle: &TPM_HANDLE, + authHandle: &TPM_HANDLE, + nvIndex: &TPM_HANDLE, + qualifyingData: &Vec, + inScheme: &Option, + size: u16, + offset: u16, + ) -> Result { + let req = TPM2_NV_Certify_REQUEST::new( + signHandle, + authHandle, + nvIndex, + qualifyingData, + inScheme, + size, + offset, + ); + + let mut resp = NV_CertifyResponse::default(); + self.dispatch(TPM_CC::NV_Certify, req, &mut resp)?; + Ok(resp) + } + + /// The purpose of this command is to obtain information about an Attached Component + /// referenced by an AC handle. + /// ac: Handle indicating the Attached Component + /// Auth Index: None + /// capability: Starting info type + /// count: Maximum number of values to return + /// moreData - Flag to indicate whether there are more values + /// capabilitiesData - List of capabilities + pub fn AC_GetCapability( + &mut self, + ac: &TPM_HANDLE, + capability: TPM_AT, + count: u32, + ) -> Result { + let req = TPM2_AC_GetCapability_REQUEST::new( + ac, + capability, + count, + ); + + let mut resp = AC_GetCapabilityResponse::default(); + self.dispatch(TPM_CC::AC_GetCapability, req, &mut resp)?; + Ok(resp) + } + + /// The purpose of this command is to send (copy) a loaded object from the TPM to an Attached Component. + /// sendObject: Handle of the object being sent to ac + /// Auth Index: 1 + /// Auth Role: DUP + /// authHandle: The handle indicating the source of the authorization value + /// Auth Index: 2 + /// Auth Role: USER + /// ac: Handle indicating the Attached Component to which the object will be sent + /// Auth Index: None + /// acDataIn: Optional non sensitive information related to the object + /// acDataOut - May include AC specific data or information about an error. + pub fn AC_Send( + &mut self, + sendObject: &TPM_HANDLE, + authHandle: &TPM_HANDLE, + ac: &TPM_HANDLE, + acDataIn: &Vec, + ) -> Result { + let req = TPM2_AC_Send_REQUEST::new( + sendObject, + authHandle, + ac, + acDataIn, + ); + + let mut resp = AC_SendResponse::default(); + self.dispatch(TPM_CC::AC_Send, req, &mut resp)?; + Ok(resp.acDataOut) + } + + /// This command allows qualification of the sending (copying) of an Object to an Attached + /// Component (AC). Qualification includes selection of the receiving AC and the method of + /// authentication for the AC, and, in certain circumstances, the Object to be sent may be specified. + /// policySession: Handle for the policy session being extended + /// Auth Index: None + /// objectName: The Name of the Object to be sent + /// authHandleName: The Name associated with authHandle used in the TPM2_AC_Send() command + /// acName: The Name of the Attached Component to which the Object will be sent + /// includeObject: If SET, objectName will be included in the value in policySessionpolicyDigest + pub fn Policy_AC_SendSelect( + &mut self, + policySession: &TPM_HANDLE, + objectName: &Vec, + authHandleName: &Vec, + acName: &Vec, + includeObject: u8, + ) -> Result<(), TpmError> { + let req = TPM2_Policy_AC_SendSelect_REQUEST::new( + policySession, + objectName, + authHandleName, + acName, + includeObject, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::Policy_AC_SendSelect, req, &mut resp)?; + Ok(()) + } + + /// This command is used to set the time remaining before an Authenticated Countdown Timer + /// (ACT) expires. + /// actHandle: Handle of the selected ACT + /// Auth Index: 1 + /// Auth Role: USER + /// startTimeout: The start timeout value for the ACT in seconds + pub fn ACT_SetTimeout( + &mut self, + actHandle: &TPM_HANDLE, + startTimeout: u32, + ) -> Result<(), TpmError> { + let req = TPM2_ACT_SetTimeout_REQUEST::new( + actHandle, + startTimeout, + ); + + let mut resp = EmptyTpmResponse::default(); + self.dispatch(TPM_CC::ACT_SetTimeout, req, &mut resp)?; + Ok(()) + } + + /// This is a placeholder to allow testing of the dispatch code. + /// inputData: Dummy data + /// outputData - Dummy data + pub fn Vendor_TCG_Test( + &mut self, + inputData: &Vec, + ) -> Result, TpmError> { + let req = TPM2_Vendor_TCG_Test_REQUEST::new( + inputData, + ); + + let mut resp = Vendor_TCG_TestResponse::default(); + self.dispatch(TPM_CC::Vendor_TCG_Test, req, &mut resp)?; + Ok(resp.outputData) + } + +} + +/// Asynchronous TPM2 command methods +pub struct AsyncMethods<'a> { + tpm: &'a mut Tpm2, +} + +impl<'a> AsyncMethods<'a> { + /// TPM2_Startup() is always preceded by _TPM_Init, which is the physical indication that TPM + /// initialization is necessary because of a system-wide reset. TPM2_Startup() is only valid + /// after _TPM_Init. Additional TPM2_Startup() commands are not allowed after it has completed + /// successfully. If a TPM requires TPM2_Startup() and another command is received, or if the + /// TPM receives TPM2_Startup() when it is not required, the TPM shall return TPM_RC_INITIALIZE. + /// startupType: TPM_SU_CLEAR or TPM_SU_STATE + pub fn Startup_async( + &mut self, + startupType: TPM_SU, + ) -> Result<(), TpmError> { + let req = TPM2_Startup_REQUEST::new( + startupType, + ); + + self.tpm.dispatch_command(TPM_CC::Startup, &req)?; + Ok(()) + } + + /// This command is used to prepare the TPM for a power cycle. The shutdownType parameter + /// indicates how the subsequent TPM2_Startup() will be processed. + /// shutdownType: TPM_SU_CLEAR or TPM_SU_STATE + pub fn Shutdown_async( + &mut self, + shutdownType: TPM_SU, + ) -> Result<(), TpmError> { + let req = TPM2_Shutdown_REQUEST::new( + shutdownType, + ); + + self.tpm.dispatch_command(TPM_CC::Shutdown, &req)?; + Ok(()) + } + + /// This command causes the TPM to perform a test of its capabilities. If the fullTest is YES, + /// the TPM will test all functions. If fullTest = NO, the TPM will only test those functions + /// that have not previously been tested. + /// fullTest: YES if full test to be performed + /// NO if only test of untested functions required + pub fn SelfTest_async( + &mut self, + fullTest: u8, + ) -> Result<(), TpmError> { + let req = TPM2_SelfTest_REQUEST::new( + fullTest, + ); + + self.tpm.dispatch_command(TPM_CC::SelfTest, &req)?; + Ok(()) + } + + /// This command causes the TPM to perform a test of the selected algorithms. + /// toTest: List of algorithms that should be tested + /// toDoList - List of algorithms that need testing + pub fn IncrementalSelfTest_async( + &mut self, + toTest: &Vec, + ) -> Result<(), TpmError> { + let req = TPM2_IncrementalSelfTest_REQUEST::new( + toTest, + ); + + self.tpm.dispatch_command(TPM_CC::IncrementalSelfTest, &req)?; + Ok(()) + } + + /// This command returns manufacturer-specific information regarding the results of a + /// self-test and an indication of the test status. + /// outData - Test result data + /// contains manufacturer-specific information + /// testResult - TBD + pub fn GetTestResult_async( + &mut self, + ) -> Result<(), TpmError> { + let req = TPM2_GetTestResult_REQUEST::default(); + + self.tpm.dispatch_command(TPM_CC::GetTestResult, &req)?; + Ok(()) + } + + /// This command is used to start an authorization session using alternative methods of + /// establishing the session key (sessionKey). The session key is then used to derive values + /// used for authorization and for encrypting parameters. + /// tpmKey: Handle of a loaded decrypt key used to encrypt salt + /// may be TPM_RH_NULL + /// Auth Index: None + /// bind: Entity providing the authValue + /// may be TPM_RH_NULL + /// Auth Index: None + /// nonceCaller: Initial nonceCaller, sets nonceTPM size for the session + /// shall be at least 16 octets + /// encryptedSalt: Value encrypted according to the type of tpmKey + /// If tpmKey is TPM_RH_NULL, this shall be the Empty Buffer. + /// sessionType: Indicates the type of the session; simple HMAC or policy (including a trial policy) + /// symmetric: The algorithm and key size for parameter encryption + /// may select TPM_ALG_NULL + /// authHash: Hash algorithm to use for the session + /// Shall be a hash algorithm supported by the TPM and not TPM_ALG_NULL + /// handle - Handle for the newly created session + /// nonceTPM - The initial nonce from the TPM, used in the computation of the sessionKey + pub fn StartAuthSession_async( + &mut self, + tpmKey: &TPM_HANDLE, + bind: &TPM_HANDLE, + nonceCaller: &Vec, + encryptedSalt: &Vec, + sessionType: TPM_SE, + symmetric: &TPMT_SYM_DEF, + authHash: TPM_ALG_ID, + ) -> Result<(), TpmError> { + let req = TPM2_StartAuthSession_REQUEST::new( + tpmKey, + bind, + nonceCaller, + encryptedSalt, + sessionType, + symmetric, + authHash, + ); + + self.tpm.dispatch_command(TPM_CC::StartAuthSession, &req)?; + Ok(()) + } + + /// This command allows a policy authorization session to be returned to its initial state. + /// This command is used after the TPM returns TPM_RC_PCR_CHANGED. That response code + /// indicates that a policy will fail because the PCR have changed after TPM2_PolicyPCR() was + /// executed. Restarting the session allows the authorizations to be replayed because the + /// session restarts with the same nonceTPM. If the PCR are valid for the policy, the policy + /// may then succeed. + /// sessionHandle: The handle for the policy session + pub fn PolicyRestart_async( + &mut self, + sessionHandle: &TPM_HANDLE, + ) -> Result<(), TpmError> { + let req = TPM2_PolicyRestart_REQUEST::new( + sessionHandle, + ); + + self.tpm.dispatch_command(TPM_CC::PolicyRestart, &req)?; + Ok(()) + } + + /// This command is used to create an object that can be loaded into a TPM using TPM2_Load(). + /// If the command completes successfully, the TPM will create the new object and return the + /// objects creation data (creationData), its public area (outPublic), and its encrypted + /// sensitive area (outPrivate). Preservation of the returned data is the responsibility of + /// the caller. The object will need to be loaded (TPM2_Load()) before it may be used. The + /// only difference between the inPublic TPMT_PUBLIC template and the outPublic TPMT_PUBLIC + /// object is in the unique field. + /// parentHandle: Handle of parent for new object + /// Auth Index: 1 + /// Auth Role: USER + /// inSensitive: The sensitive data + /// inPublic: The public template + /// outsideInfo: Data that will be included in the creation data for this object to provide + /// permanent, verifiable linkage between this object and some object owner data + /// creationPCR: PCR that will be used in creation data + /// outPrivate - The private portion of the object + /// outPublic - The public portion of the created object + /// creationData - Contains a TPMS_CREATION_DATA + /// creationHash - Digest of creationData using nameAlg of outPublic + /// creationTicket - Ticket used by TPM2_CertifyCreation() to validate that the creation + /// data was produced by the TPM + pub fn Create_async( + &mut self, + parentHandle: &TPM_HANDLE, + inSensitive: &TPMS_SENSITIVE_CREATE, + inPublic: &TPMT_PUBLIC, + outsideInfo: &Vec, + creationPCR: &Vec, + ) -> Result<(), TpmError> { + let req = TPM2_Create_REQUEST::new( + parentHandle, + inSensitive, + inPublic, + outsideInfo, + creationPCR, + ); + + self.tpm.dispatch_command(TPM_CC::Create, &req)?; + Ok(()) + } + + /// This command is used to load objects into the TPM. This command is used when both a + /// TPM2B_PUBLIC and TPM2B_PRIVATE are to be loaded. If only a TPM2B_PUBLIC is to be loaded, + /// the TPM2_LoadExternal command is used. + /// parentHandle: TPM handle of parent key; shall not be a reserved handle + /// Auth Index: 1 + /// Auth Role: USER + /// inPrivate: The private portion of the object + /// inPublic: The public portion of the object + /// handle - Handle of type TPM_HT_TRANSIENT for the loaded object + /// name - Name of the loaded object + pub fn Load_async( + &mut self, + parentHandle: &TPM_HANDLE, + inPrivate: &TPM2B_PRIVATE, + inPublic: &TPMT_PUBLIC, + ) -> Result<(), TpmError> { + let req = TPM2_Load_REQUEST::new( + parentHandle, + inPrivate, + inPublic, + ); + + self.tpm.dispatch_command(TPM_CC::Load, &req)?; + Ok(()) + } + + /// This command is used to load an object that is not a Protected Object into the TPM. The + /// command allows loading of a public area or both a public and sensitive area. + /// inPrivate: The sensitive portion of the object (optional) + /// inPublic: The public portion of the object + /// hierarchy: Hierarchy with which the object area is associated + /// handle - Handle of type TPM_HT_TRANSIENT for the loaded object + /// name - Name of the loaded object + pub fn LoadExternal_async( + &mut self, + inPrivate: &TPMT_SENSITIVE, + inPublic: &TPMT_PUBLIC, + hierarchy: &TPM_HANDLE, + ) -> Result<(), TpmError> { + let req = TPM2_LoadExternal_REQUEST::new( + inPrivate, + inPublic, + hierarchy, + ); + + self.tpm.dispatch_command(TPM_CC::LoadExternal, &req)?; + Ok(()) + } + + /// This command allows access to the public area of a loaded object. + /// objectHandle: TPM handle of an object + /// Auth Index: None + /// outPublic - Structure containing the public area of an object + /// name - Name of the object + /// qualifiedName - The Qualified Name of the object + pub fn ReadPublic_async( + &mut self, + objectHandle: &TPM_HANDLE, + ) -> Result<(), TpmError> { + let req = TPM2_ReadPublic_REQUEST::new( + objectHandle, + ); + + self.tpm.dispatch_command(TPM_CC::ReadPublic, &req)?; + Ok(()) + } + + /// This command enables the association of a credential with an object in a way that ensures + /// that the TPM has validated the parameters of the credentialed object. + /// activateHandle: Handle of the object associated with certificate in credentialBlob + /// Auth Index: 1 + /// Auth Role: ADMIN + /// keyHandle: Loaded key used to decrypt the TPMS_SENSITIVE in credentialBlob + /// Auth Index: 2 + /// Auth Role: USER + /// credentialBlob: The credential + /// secret: KeyHandle algorithm-dependent encrypted seed that protects credentialBlob + /// certInfo - The decrypted certificate information + /// the data should be no larger than the size of the digest of the nameAlg + /// associated with keyHandle + pub fn ActivateCredential_async( + &mut self, + activateHandle: &TPM_HANDLE, + keyHandle: &TPM_HANDLE, + credentialBlob: &TPMS_ID_OBJECT, + secret: &Vec, + ) -> Result<(), TpmError> { + let req = TPM2_ActivateCredential_REQUEST::new( + activateHandle, + keyHandle, + credentialBlob, + secret, + ); + + self.tpm.dispatch_command(TPM_CC::ActivateCredential, &req)?; + Ok(()) + } + + /// This command allows the TPM to perform the actions required of a Certificate Authority + /// (CA) in creating a TPM2B_ID_OBJECT containing an activation credential. + /// handle: Loaded public area, used to encrypt the sensitive area containing the credential key + /// Auth Index: None + /// credential: The credential information + /// objectName: Name of the object to which the credential applies + /// credentialBlob - The credential + /// secret - Handle algorithm-dependent data that wraps the key that encrypts credentialBlob + pub fn MakeCredential_async( + &mut self, + handle: &TPM_HANDLE, + credential: &Vec, + objectName: &Vec, + ) -> Result<(), TpmError> { + let req = TPM2_MakeCredential_REQUEST::new( + handle, + credential, + objectName, + ); + + self.tpm.dispatch_command(TPM_CC::MakeCredential, &req)?; + Ok(()) + } + + /// This command returns the data in a loaded Sealed Data Object. + /// itemHandle: Handle of a loaded data object + /// Auth Index: 1 + /// Auth Role: USER + /// outData - Unsealed data + /// Size of outData is limited to be no more than 128 octets. + pub fn Unseal_async( + &mut self, + itemHandle: &TPM_HANDLE, + ) -> Result<(), TpmError> { + let req = TPM2_Unseal_REQUEST::new( + itemHandle, + ); + + self.tpm.dispatch_command(TPM_CC::Unseal, &req)?; + Ok(()) + } + + /// This command is used to change the authorization secret for a TPM-resident object. + /// objectHandle: Handle of the object + /// Auth Index: 1 + /// Auth Role: ADMIN + /// parentHandle: Handle of the parent + /// Auth Index: None + /// newAuth: New authorization value + /// outPrivate - Private area containing the new authorization value + pub fn ObjectChangeAuth_async( + &mut self, + objectHandle: &TPM_HANDLE, + parentHandle: &TPM_HANDLE, + newAuth: &Vec, + ) -> Result<(), TpmError> { + let req = TPM2_ObjectChangeAuth_REQUEST::new( + objectHandle, + parentHandle, + newAuth, + ); + + self.tpm.dispatch_command(TPM_CC::ObjectChangeAuth, &req)?; + Ok(()) + } + + /// This command creates an object and loads it in the TPM. This command allows creation of + /// any type of object (Primary, Ordinary, or Derived) depending on the type of parentHandle. + /// If parentHandle references a Primary Seed, then a Primary Object is created; if + /// parentHandle references a Storage Parent, then an Ordinary Object is created; and if + /// parentHandle references a Derivation Parent, then a Derived Object is generated. + /// parentHandle: Handle of a transient storage key, a persistent storage key, + /// TPM_RH_ENDORSEMENT, TPM_RH_OWNER, TPM_RH_PLATFORM+{PP}, or TPM_RH_NULL + /// Auth Index: 1 + /// Auth Role: USER + /// inSensitive: The sensitive data, see TPM 2.0 Part 1 Sensitive Values + /// inPublic: The public template + /// handle - Handle of type TPM_HT_TRANSIENT for created object + /// outPrivate - The sensitive area of the object (optional) + /// outPublic - The public portion of the created object + /// name - The name of the created object + pub fn CreateLoaded_async( + &mut self, + parentHandle: &TPM_HANDLE, + inSensitive: &TPMS_SENSITIVE_CREATE, + inPublic: &Vec, + ) -> Result<(), TpmError> { + let req = TPM2_CreateLoaded_REQUEST::new( + parentHandle, + inSensitive, + inPublic, + ); + + self.tpm.dispatch_command(TPM_CC::CreateLoaded, &req)?; + Ok(()) + } + + /// This command duplicates a loaded object so that it may be used in a different hierarchy. + /// The new parent key for the duplicate may be on the same or different TPM or TPM_RH_NULL. + /// Only the public area of newParentHandle is required to be loaded. + /// objectHandle: Loaded object to duplicate + /// Auth Index: 1 + /// Auth Role: DUP + /// newParentHandle: Shall reference the public area of an asymmetric key + /// Auth Index: None + /// encryptionKeyIn: Optional symmetric encryption key + /// The size for this key is set to zero when the TPM is to generate the key. This + /// parameter may be encrypted. + /// symmetricAlg: Definition for the symmetric algorithm to be used for the inner wrapper + /// may be TPM_ALG_NULL if no inner wrapper is applied + /// encryptionKeyOut - If the caller provided an encryption key or if symmetricAlg was + /// TPM_ALG_NULL, then this will be the Empty Buffer; otherwise, it + /// shall contain the TPM-generated, symmetric encryption key for the + /// inner wrapper. + /// duplicate - Private area that may be encrypted by encryptionKeyIn; and may be doubly encrypted + /// outSymSeed - Seed protected by the asymmetric algorithms of new parent (NP) + pub fn Duplicate_async( + &mut self, + objectHandle: &TPM_HANDLE, + newParentHandle: &TPM_HANDLE, + encryptionKeyIn: &Vec, + symmetricAlg: &TPMT_SYM_DEF_OBJECT, + ) -> Result<(), TpmError> { + let req = TPM2_Duplicate_REQUEST::new( + objectHandle, + newParentHandle, + encryptionKeyIn, + symmetricAlg, + ); + + self.tpm.dispatch_command(TPM_CC::Duplicate, &req)?; + Ok(()) + } + + /// This command allows the TPM to serve in the role as a Duplication Authority. If proper + /// authorization for use of the oldParent is provided, then an HMAC key and a symmetric key + /// are recovered from inSymSeed and used to integrity check and decrypt inDuplicate. A new + /// protection seed value is generated according to the methods appropriate for newParent and + /// the blob is re-encrypted and a new integrity value is computed. The re-encrypted blob is + /// returned in outDuplicate and the symmetric key returned in outSymKey. + /// oldParent: Parent of object + /// Auth Index: 1 + /// Auth Role: User + /// newParent: New parent of the object + /// Auth Index: None + /// inDuplicate: An object encrypted using symmetric key derived from inSymSeed + /// name: The Name of the object being rewrapped + /// inSymSeed: The seed for the symmetric key and HMAC key + /// needs oldParent private key to recover the seed and generate the symmetric key + /// outDuplicate - An object encrypted using symmetric key derived from outSymSeed + /// outSymSeed - Seed for a symmetric key protected by newParent asymmetric key + pub fn Rewrap_async( + &mut self, + oldParent: &TPM_HANDLE, + newParent: &TPM_HANDLE, + inDuplicate: &TPM2B_PRIVATE, + name: &Vec, + inSymSeed: &Vec, + ) -> Result<(), TpmError> { + let req = TPM2_Rewrap_REQUEST::new( + oldParent, + newParent, + inDuplicate, + name, + inSymSeed, + ); + + self.tpm.dispatch_command(TPM_CC::Rewrap, &req)?; + Ok(()) + } + + /// This command allows an object to be encrypted using the symmetric encryption values of a + /// Storage Key. After encryption, the object may be loaded and used in the new hierarchy. The + /// imported object (duplicate) may be singly encrypted, multiply encrypted, or unencrypted. + /// parentHandle: The handle of the new parent for the object + /// Auth Index: 1 + /// Auth Role: USER + /// encryptionKey: The optional symmetric encryption key used as the inner wrapper for duplicate + /// If symmetricAlg is TPM_ALG_NULL, then this parameter shall be the Empty Buffer. + /// objectPublic: The public area of the object to be imported + /// This is provided so that the integrity value for duplicate and the object + /// attributes can be checked. + /// NOTE Even if the integrity value of the object is not checked on input, the object + /// Name is required to create the integrity value for the imported object. + /// duplicate: The symmetrically encrypted duplicate object that may contain an inner + /// symmetric wrapper + /// inSymSeed: The seed for the symmetric key and HMAC key + /// inSymSeed is encrypted/encoded using the algorithms of newParent. + /// symmetricAlg: Definition for the symmetric algorithm to use for the inner wrapper + /// If this algorithm is TPM_ALG_NULL, no inner wrapper is present and encryptionKey + /// shall be the Empty Buffer. + /// outPrivate - The sensitive area encrypted with the symmetric key of parentHandle + pub fn Import_async( + &mut self, + parentHandle: &TPM_HANDLE, + encryptionKey: &Vec, + objectPublic: &TPMT_PUBLIC, + duplicate: &TPM2B_PRIVATE, + inSymSeed: &Vec, + symmetricAlg: &TPMT_SYM_DEF_OBJECT, + ) -> Result<(), TpmError> { + let req = TPM2_Import_REQUEST::new( + parentHandle, + encryptionKey, + objectPublic, + duplicate, + inSymSeed, + symmetricAlg, + ); + + self.tpm.dispatch_command(TPM_CC::Import, &req)?; + Ok(()) + } + + /// This command performs RSA encryption using the indicated padding scheme according to IETF + /// RFC 8017. If the scheme of keyHandle is TPM_ALG_NULL, then the caller may use inScheme to + /// specify the padding scheme. If scheme of keyHandle is not TPM_ALG_NULL, then inScheme + /// shall either be TPM_ALG_NULL or be the same as scheme (TPM_RC_SCHEME). + /// keyHandle: Reference to public portion of RSA key to use for encryption + /// Auth Index: None + /// message: Message to be encrypted + /// NOTE 1 The data type was chosen because it limits the overall size of the input to + /// no greater than the size of the largest RSA public key. This may be larger than + /// allowed for keyHandle. + /// inScheme: The padding scheme to use if scheme associated with keyHandle is TPM_ALG_NULL + /// One of: TPMS_KEY_SCHEME_ECDH, TPMS_KEY_SCHEME_ECMQV, TPMS_SIG_SCHEME_RSASSA, + /// TPMS_SIG_SCHEME_RSAPSS, TPMS_SIG_SCHEME_ECDSA, TPMS_SIG_SCHEME_ECDAA, + /// TPMS_SIG_SCHEME_SM2, TPMS_SIG_SCHEME_ECSCHNORR, TPMS_ENC_SCHEME_RSAES, + /// TPMS_ENC_SCHEME_OAEP, TPMS_SCHEME_HASH, TPMS_NULL_ASYM_SCHEME. + /// label: Optional label L to be associated with the message + /// Size of the buffer is zero if no label is present + /// NOTE 2 See description of label above. + /// outData - Encrypted output + pub fn RSA_Encrypt_async( + &mut self, + keyHandle: &TPM_HANDLE, + message: &Vec, + inScheme: &Option, + label: &Vec, + ) -> Result<(), TpmError> { + let req = TPM2_RSA_Encrypt_REQUEST::new( + keyHandle, + message, + inScheme, + label, + ); + + self.tpm.dispatch_command(TPM_CC::RSA_Encrypt, &req)?; + Ok(()) + } + + /// This command performs RSA decryption using the indicated padding scheme according to IETF + /// RFC 8017 ((PKCS#1). + /// keyHandle: RSA key to use for decryption + /// Auth Index: 1 + /// Auth Role: USER + /// cipherText: Cipher text to be decrypted + /// NOTE An encrypted RSA data block is the size of the public modulus. + /// inScheme: The padding scheme to use if scheme associated with keyHandle is TPM_ALG_NULL + /// One of: TPMS_KEY_SCHEME_ECDH, TPMS_KEY_SCHEME_ECMQV, TPMS_SIG_SCHEME_RSASSA, + /// TPMS_SIG_SCHEME_RSAPSS, TPMS_SIG_SCHEME_ECDSA, TPMS_SIG_SCHEME_ECDAA, + /// TPMS_SIG_SCHEME_SM2, TPMS_SIG_SCHEME_ECSCHNORR, TPMS_ENC_SCHEME_RSAES, + /// TPMS_ENC_SCHEME_OAEP, TPMS_SCHEME_HASH, TPMS_NULL_ASYM_SCHEME. + /// label: Label whose association with the message is to be verified + /// message - Decrypted output + pub fn RSA_Decrypt_async( + &mut self, + keyHandle: &TPM_HANDLE, + cipherText: &Vec, + inScheme: &Option, + label: &Vec, + ) -> Result<(), TpmError> { + let req = TPM2_RSA_Decrypt_REQUEST::new( + keyHandle, + cipherText, + inScheme, + label, + ); + + self.tpm.dispatch_command(TPM_CC::RSA_Decrypt, &req)?; + Ok(()) + } + + /// This command uses the TPM to generate an ephemeral key pair (de, Qe where Qe [de]G). It + /// uses the private ephemeral key and a loaded public key (QS) to compute the shared secret + /// value (P [hde]QS). + /// keyHandle: Handle of a loaded ECC key public area. + /// Auth Index: None + /// zPoint - Results of P h[de]Qs + /// pubPoint - Generated ephemeral public point (Qe) + pub fn ECDH_KeyGen_async( + &mut self, + keyHandle: &TPM_HANDLE, + ) -> Result<(), TpmError> { + let req = TPM2_ECDH_KeyGen_REQUEST::new( + keyHandle, + ); + + self.tpm.dispatch_command(TPM_CC::ECDH_KeyGen, &req)?; + Ok(()) + } + + /// This command uses the TPM to recover the Z value from a public point (QB) and a private + /// key (ds). It will perform the multiplication of the provided inPoint (QB) with the private + /// key (ds) and return the coordinates of the resultant point (Z = (xZ , yZ) [hds]QB; where h + /// is the cofactor of the curve). + /// keyHandle: Handle of a loaded ECC key + /// Auth Index: 1 + /// Auth Role: USER + /// inPoint: A public key + /// outPoint - X and Y coordinates of the product of the multiplication Z = (xZ , yZ) [hdS]QB + pub fn ECDH_ZGen_async( + &mut self, + keyHandle: &TPM_HANDLE, + inPoint: &TPMS_ECC_POINT, + ) -> Result<(), TpmError> { + let req = TPM2_ECDH_ZGen_REQUEST::new( + keyHandle, + inPoint, + ); + + self.tpm.dispatch_command(TPM_CC::ECDH_ZGen, &req)?; + Ok(()) + } + + /// This command returns the parameters of an ECC curve identified by its TCG-assigned curveID. + /// curveID: Parameter set selector + /// parameters - ECC parameters for the selected curve + pub fn ECC_Parameters_async( + &mut self, + curveID: TPM_ECC_CURVE, + ) -> Result<(), TpmError> { + let req = TPM2_ECC_Parameters_REQUEST::new( + curveID, + ); + + self.tpm.dispatch_command(TPM_CC::ECC_Parameters, &req)?; + Ok(()) + } + + /// This command supports two-phase key exchange protocols. The command is used in combination + /// with TPM2_EC_Ephemeral(). TPM2_EC_Ephemeral() generates an ephemeral key and returns the + /// public point of that ephemeral key along with a numeric value that allows the TPM to + /// regenerate the associated private key. + /// keyA: Handle of an unrestricted decryption key ECC + /// The private key referenced by this handle is used as dS,A + /// Auth Index: 1 + /// Auth Role: USER + /// inQsB: Other partys static public key (Qs,B = (Xs,B, Ys,B)) + /// inQeB: Other party's ephemeral public key (Qe,B = (Xe,B, Ye,B)) + /// inScheme: The key exchange scheme + /// counter: Value returned by TPM2_EC_Ephemeral() + /// outZ1 - X and Y coordinates of the computed value (scheme dependent) + /// outZ2 - X and Y coordinates of the second computed value (scheme dependent) + pub fn ZGen_2Phase_async( + &mut self, + keyA: &TPM_HANDLE, + inQsB: &TPMS_ECC_POINT, + inQeB: &TPMS_ECC_POINT, + inScheme: TPM_ALG_ID, + counter: u16, + ) -> Result<(), TpmError> { + let req = TPM2_ZGen_2Phase_REQUEST::new( + keyA, + inQsB, + inQeB, + inScheme, + counter, + ); + + self.tpm.dispatch_command(TPM_CC::ZGen_2Phase, &req)?; + Ok(()) + } + + /// This command performs ECC encryption as described in Part 1, Annex D. + /// keyHandle: Reference to public portion of ECC key to use for encryption + /// Auth Index: None + /// plainText: Plaintext to be encrypted + /// inScheme: The KDF to use if scheme associated with keyHandle is TPM_ALG_NULL + /// One of: TPMS_KDF_SCHEME_MGF1, TPMS_KDF_SCHEME_KDF1_SP800_56A, TPMS_KDF_SCHEME_KDF2, + /// TPMS_KDF_SCHEME_KDF1_SP800_108, TPMS_SCHEME_HASH, TPMS_NULL_KDF_SCHEME. + /// C1 - The public ephemeral key used for ECDH + /// C2 - The data block produced by the XOR process + /// C3 - The integrity value + pub fn ECC_Encrypt_async( + &mut self, + keyHandle: &TPM_HANDLE, + plainText: &Vec, + inScheme: &Option, + ) -> Result<(), TpmError> { + let req = TPM2_ECC_Encrypt_REQUEST::new( + keyHandle, + plainText, + inScheme, + ); + + self.tpm.dispatch_command(TPM_CC::ECC_Encrypt, &req)?; + Ok(()) + } + + /// This command performs ECC decryption. + /// keyHandle: ECC key to use for decryption + /// Auth Index: 1 + /// Auth Role: USER + /// C1: The public ephemeral key used for ECDH + /// C2: The data block produced by the XOR process + /// C3: The integrity value + /// inScheme: The KDF to use if scheme associated with keyHandle is TPM_ALG_NULL + /// One of: TPMS_KDF_SCHEME_MGF1, TPMS_KDF_SCHEME_KDF1_SP800_56A, TPMS_KDF_SCHEME_KDF2, + /// TPMS_KDF_SCHEME_KDF1_SP800_108, TPMS_SCHEME_HASH, TPMS_NULL_KDF_SCHEME. + /// plainText - Decrypted output + pub fn ECC_Decrypt_async( + &mut self, + keyHandle: &TPM_HANDLE, + C1: &TPMS_ECC_POINT, + C2: &Vec, + C3: &Vec, + inScheme: &Option, + ) -> Result<(), TpmError> { + let req = TPM2_ECC_Decrypt_REQUEST::new( + keyHandle, + C1, + C2, + C3, + inScheme, + ); + + self.tpm.dispatch_command(TPM_CC::ECC_Decrypt, &req)?; + Ok(()) + } + + /// NOTE 1 This command is deprecated, and TPM2_EncryptDecrypt2() is preferred. This should be + /// reflected in platform-specific specifications. + /// keyHandle: The symmetric key used for the operation + /// Auth Index: 1 + /// Auth Role: USER + /// decrypt: If YES, then the operation is decryption; if NO, the operation is encryption + /// mode: Symmetric encryption/decryption mode + /// this field shall match the default mode of the key or be TPM_ALG_NULL. + /// ivIn: An initial value as required by the algorithm + /// inData: The data to be encrypted/decrypted + /// outData - Encrypted or decrypted output + /// ivOut - Chaining value to use for IV in next round + pub fn EncryptDecrypt_async( + &mut self, + keyHandle: &TPM_HANDLE, + decrypt: u8, + mode: TPM_ALG_ID, + ivIn: &Vec, + inData: &Vec, + ) -> Result<(), TpmError> { + let req = TPM2_EncryptDecrypt_REQUEST::new( + keyHandle, + decrypt, + mode, + ivIn, + inData, + ); + + self.tpm.dispatch_command(TPM_CC::EncryptDecrypt, &req)?; + Ok(()) + } + + /// This command is identical to TPM2_EncryptDecrypt(), except that the inData parameter is + /// the first parameter. This permits inData to be parameter encrypted. + /// keyHandle: The symmetric key used for the operation + /// Auth Index: 1 + /// Auth Role: USER + /// inData: The data to be encrypted/decrypted + /// decrypt: If YES, then the operation is decryption; if NO, the operation is encryption + /// mode: Symmetric mode + /// this field shall match the default mode of the key or be TPM_ALG_NULL. + /// ivIn: An initial value as required by the algorithm + /// outData - Encrypted or decrypted output + /// ivOut - Chaining value to use for IV in next round + pub fn EncryptDecrypt2_async( + &mut self, + keyHandle: &TPM_HANDLE, + inData: &Vec, + decrypt: u8, + mode: TPM_ALG_ID, + ivIn: &Vec, + ) -> Result<(), TpmError> { + let req = TPM2_EncryptDecrypt2_REQUEST::new( + keyHandle, + inData, + decrypt, + mode, + ivIn, + ); + + self.tpm.dispatch_command(TPM_CC::EncryptDecrypt2, &req)?; + Ok(()) + } + + /// This command performs a hash operation on a data buffer and returns the results. + /// data: Data to be hashed + /// hashAlg: Algorithm for the hash being computed shall not be TPM_ALG_NULL + /// hierarchy: Hierarchy to use for the ticket (TPM_RH_NULL allowed) + /// outHash - Results + /// validation - Ticket indicating that the sequence of octets used to compute outDigest + /// did not start with TPM_GENERATED_VALUE + /// will be a NULL ticket if the digest may not be signed with a restricted key + pub fn Hash_async( + &mut self, + data: &Vec, + hashAlg: TPM_ALG_ID, + hierarchy: &TPM_HANDLE, + ) -> Result<(), TpmError> { + let req = TPM2_Hash_REQUEST::new( + data, + hashAlg, + hierarchy, + ); + + self.tpm.dispatch_command(TPM_CC::Hash, &req)?; + Ok(()) + } + + /// This command performs an HMAC on the supplied data using the indicated hash algorithm. + /// handle: Handle for the symmetric signing key providing the HMAC key + /// Auth Index: 1 + /// Auth Role: USER + /// buffer: HMAC data + /// hashAlg: Algorithm to use for HMAC + /// outHMAC - The returned HMAC in a sized buffer + pub fn HMAC_async( + &mut self, + handle: &TPM_HANDLE, + buffer: &Vec, + hashAlg: TPM_ALG_ID, + ) -> Result<(), TpmError> { + let req = TPM2_HMAC_REQUEST::new( + handle, + buffer, + hashAlg, + ); + + self.tpm.dispatch_command(TPM_CC::HMAC, &req)?; + Ok(()) + } + + /// This command performs an HMAC or a block cipher MAC on the supplied data using the + /// indicated algorithm. + /// handle: Handle for the symmetric signing key providing the MAC key + /// Auth Index: 1 + /// Auth Role: USER + /// buffer: MAC data + /// inScheme: Algorithm to use for MAC + /// outMAC - The returned MAC in a sized buffer + pub fn MAC_async( + &mut self, + handle: &TPM_HANDLE, + buffer: &Vec, + inScheme: TPM_ALG_ID, + ) -> Result<(), TpmError> { + let req = TPM2_MAC_REQUEST::new( + handle, + buffer, + inScheme, + ); + + self.tpm.dispatch_command(TPM_CC::MAC, &req)?; + Ok(()) + } + + /// This command returns the next bytesRequested octets from the random number generator (RNG). + /// bytesRequested: Number of octets to return + /// randomBytes - The random octets + pub fn GetRandom_async( + &mut self, + bytesRequested: u16, + ) -> Result<(), TpmError> { + let req = TPM2_GetRandom_REQUEST::new( + bytesRequested, + ); + + self.tpm.dispatch_command(TPM_CC::GetRandom, &req)?; + Ok(()) + } + + /// This command is used to add "additional information" to the RNG state. + /// inData: Additional information + pub fn StirRandom_async( + &mut self, + inData: &Vec, + ) -> Result<(), TpmError> { + let req = TPM2_StirRandom_REQUEST::new( + inData, + ); + + self.tpm.dispatch_command(TPM_CC::StirRandom, &req)?; + Ok(()) + } + + /// This command starts an HMAC sequence. The TPM will create and initialize an HMAC sequence + /// structure, assign a handle to the sequence, and set the authValue of the sequence object + /// to the value in auth. + /// handle: Handle of an HMAC key + /// Auth Index: 1 + /// Auth Role: USER + /// auth: Authorization value for subsequent use of the sequence + /// hashAlg: The hash algorithm to use for the HMAC + /// handle - A handle to reference the sequence + pub fn HMAC_Start_async( + &mut self, + handle: &TPM_HANDLE, + auth: &Vec, + hashAlg: TPM_ALG_ID, + ) -> Result<(), TpmError> { + let req = TPM2_HMAC_Start_REQUEST::new( + handle, + auth, + hashAlg, + ); + + self.tpm.dispatch_command(TPM_CC::HMAC_Start, &req)?; + Ok(()) + } + + /// This command starts a MAC sequence. The TPM will create and initialize a MAC sequence + /// structure, assign a handle to the sequence, and set the authValue of the sequence object + /// to the value in auth. + /// handle: Handle of a MAC key + /// Auth Index: 1 + /// Auth Role: USER + /// auth: Authorization value for subsequent use of the sequence + /// inScheme: The algorithm to use for the MAC + /// handle - A handle to reference the sequence + pub fn MAC_Start_async( + &mut self, + handle: &TPM_HANDLE, + auth: &Vec, + inScheme: TPM_ALG_ID, + ) -> Result<(), TpmError> { + let req = TPM2_MAC_Start_REQUEST::new( + handle, + auth, + inScheme, + ); + + self.tpm.dispatch_command(TPM_CC::MAC_Start, &req)?; + Ok(()) + } + + /// This command starts a hash or an Event Sequence. If hashAlg is an implemented hash, then a + /// hash sequence is started. If hashAlg is TPM_ALG_NULL, then an Event Sequence is started. + /// If hashAlg is neither an implemented algorithm nor TPM_ALG_NULL, then the TPM shall return + /// TPM_RC_HASH. + /// auth: Authorization value for subsequent use of the sequence + /// hashAlg: The hash algorithm to use for the hash sequence + /// An Event Sequence starts if this is TPM_ALG_NULL. + /// handle - A handle to reference the sequence + pub fn HashSequenceStart_async( + &mut self, + auth: &Vec, + hashAlg: TPM_ALG_ID, + ) -> Result<(), TpmError> { + let req = TPM2_HashSequenceStart_REQUEST::new( + auth, + hashAlg, + ); + + self.tpm.dispatch_command(TPM_CC::HashSequenceStart, &req)?; + Ok(()) + } + + /// This command is used to add data to a hash or HMAC sequence. The amount of data in buffer + /// may be any size up to the limits of the TPM. + /// sequenceHandle: Handle for the sequence object + /// Auth Index: 1 + /// Auth Role: USER + /// buffer: Data to be added to hash + pub fn SequenceUpdate_async( + &mut self, + sequenceHandle: &TPM_HANDLE, + buffer: &Vec, + ) -> Result<(), TpmError> { + let req = TPM2_SequenceUpdate_REQUEST::new( + sequenceHandle, + buffer, + ); + + self.tpm.dispatch_command(TPM_CC::SequenceUpdate, &req)?; + Ok(()) + } + + /// This command adds the last part of data, if any, to a hash/HMAC sequence and returns the result. + /// sequenceHandle: Authorization for the sequence + /// Auth Index: 1 + /// Auth Role: USER + /// buffer: Data to be added to the hash/HMAC + /// hierarchy: Hierarchy of the ticket for a hash + /// result - The returned HMAC or digest in a sized buffer + /// validation - Ticket indicating that the sequence of octets used to compute outDigest + /// did not start with TPM_GENERATED_VALUE + /// This is a NULL Ticket when the sequence is HMAC. + pub fn SequenceComplete_async( + &mut self, + sequenceHandle: &TPM_HANDLE, + buffer: &Vec, + hierarchy: &TPM_HANDLE, + ) -> Result<(), TpmError> { + let req = TPM2_SequenceComplete_REQUEST::new( + sequenceHandle, + buffer, + hierarchy, + ); + + self.tpm.dispatch_command(TPM_CC::SequenceComplete, &req)?; + Ok(()) + } + + /// This command adds the last part of data, if any, to an Event Sequence and returns the + /// result in a digest list. If pcrHandle references a PCR and not TPM_RH_NULL, then the + /// returned digest list is processed in the same manner as the digest list input parameter to + /// TPM2_PCR_Extend(). That is, if a bank contains a PCR associated with pcrHandle, it is + /// extended with the associated digest value from the list. + /// pcrHandle: PCR to be extended with the Event data + /// Auth Index: 1 + /// Auth Role: USER + /// sequenceHandle: Authorization for the sequence + /// Auth Index: 2 + /// Auth Role: USER + /// buffer: Data to be added to the Event + /// results - List of digests computed for the PCR + pub fn EventSequenceComplete_async( + &mut self, + pcrHandle: &TPM_HANDLE, + sequenceHandle: &TPM_HANDLE, + buffer: &Vec, + ) -> Result<(), TpmError> { + let req = TPM2_EventSequenceComplete_REQUEST::new( + pcrHandle, + sequenceHandle, + buffer, + ); + + self.tpm.dispatch_command(TPM_CC::EventSequenceComplete, &req)?; + Ok(()) + } + + /// The purpose of this command is to prove that an object with a specific Name is loaded in + /// the TPM. By certifying that the object is loaded, the TPM warrants that a public area with + /// a given Name is self-consistent and associated with a valid sensitive area. If a relying + /// party has a public area that has the same Name as a Name certified with this command, then + /// the values in that public area are correct. + /// objectHandle: Handle of the object to be certified + /// Auth Index: 1 + /// Auth Role: ADMIN + /// signHandle: Handle of the key used to sign the attestation structure + /// Auth Index: 2 + /// Auth Role: USER + /// qualifyingData: User provided qualifying data + /// inScheme: Signing scheme to use if the scheme for signHandle is TPM_ALG_NULL + /// One of: TPMS_SIG_SCHEME_RSASSA, TPMS_SIG_SCHEME_RSAPSS, TPMS_SIG_SCHEME_ECDSA, + /// TPMS_SIG_SCHEME_ECDAA, TPMS_SIG_SCHEME_SM2, TPMS_SIG_SCHEME_ECSCHNORR, + /// TPMS_SCHEME_HMAC, TPMS_SCHEME_HASH, TPMS_NULL_SIG_SCHEME. + /// certifyInfo - The structure that was signed + /// signature - The asymmetric signature over certifyInfo using the key referenced by signHandle + pub fn Certify_async( + &mut self, + objectHandle: &TPM_HANDLE, + signHandle: &TPM_HANDLE, + qualifyingData: &Vec, + inScheme: &Option, + ) -> Result<(), TpmError> { + let req = TPM2_Certify_REQUEST::new( + objectHandle, + signHandle, + qualifyingData, + inScheme, + ); + + self.tpm.dispatch_command(TPM_CC::Certify, &req)?; + Ok(()) + } + + /// This command is used to prove the association between an object and its creation data. The + /// TPM will validate that the ticket was produced by the TPM and that the ticket validates + /// the association between a loaded public area and the provided hash of the creation data + /// (creationHash). + /// signHandle: Handle of the key that will sign the attestation block + /// Auth Index: 1 + /// Auth Role: USER + /// objectHandle: The object associated with the creation data + /// Auth Index: None + /// qualifyingData: User-provided qualifying data + /// creationHash: Hash of the creation data produced by TPM2_Create() or TPM2_CreatePrimary() + /// inScheme: Signing scheme to use if the scheme for signHandle is TPM_ALG_NULL + /// One of: TPMS_SIG_SCHEME_RSASSA, TPMS_SIG_SCHEME_RSAPSS, TPMS_SIG_SCHEME_ECDSA, + /// TPMS_SIG_SCHEME_ECDAA, TPMS_SIG_SCHEME_SM2, TPMS_SIG_SCHEME_ECSCHNORR, + /// TPMS_SCHEME_HMAC, TPMS_SCHEME_HASH, TPMS_NULL_SIG_SCHEME. + /// creationTicket: Ticket produced by TPM2_Create() or TPM2_CreatePrimary() + /// certifyInfo - The structure that was signed + /// signature - The signature over certifyInfo + pub fn CertifyCreation_async( + &mut self, + signHandle: &TPM_HANDLE, + objectHandle: &TPM_HANDLE, + qualifyingData: &Vec, + creationHash: &Vec, + inScheme: &Option, + creationTicket: &TPMT_TK_CREATION, + ) -> Result<(), TpmError> { + let req = TPM2_CertifyCreation_REQUEST::new( + signHandle, + objectHandle, + qualifyingData, + creationHash, + inScheme, + creationTicket, + ); + + self.tpm.dispatch_command(TPM_CC::CertifyCreation, &req)?; + Ok(()) + } + + /// This command is used to quote PCR values. + /// signHandle: Handle of key that will perform signature + /// Auth Index: 1 + /// Auth Role: USER + /// qualifyingData: Data supplied by the caller + /// inScheme: Signing scheme to use if the scheme for signHandle is TPM_ALG_NULL + /// One of: TPMS_SIG_SCHEME_RSASSA, TPMS_SIG_SCHEME_RSAPSS, TPMS_SIG_SCHEME_ECDSA, + /// TPMS_SIG_SCHEME_ECDAA, TPMS_SIG_SCHEME_SM2, TPMS_SIG_SCHEME_ECSCHNORR, + /// TPMS_SCHEME_HMAC, TPMS_SCHEME_HASH, TPMS_NULL_SIG_SCHEME. + /// PCRselect: PCR set to quote + /// quoted - The quoted information + /// signature - The signature over quoted + pub fn Quote_async( + &mut self, + signHandle: &TPM_HANDLE, + qualifyingData: &Vec, + inScheme: &Option, + PCRselect: &Vec, + ) -> Result<(), TpmError> { + let req = TPM2_Quote_REQUEST::new( + signHandle, + qualifyingData, + inScheme, + PCRselect, + ); + + self.tpm.dispatch_command(TPM_CC::Quote, &req)?; + Ok(()) + } + + /// This command returns a digital signature of the audit session digest. + /// privacyAdminHandle: Handle of the privacy administrator (TPM_RH_ENDORSEMENT) + /// Auth Index: 1 + /// Auth Role: USER + /// signHandle: Handle of the signing key + /// Auth Index: 2 + /// Auth Role: USER + /// sessionHandle: Handle of the audit session + /// Auth Index: None + /// qualifyingData: User-provided qualifying data may be zero-length + /// inScheme: Signing scheme to use if the scheme for signHandle is TPM_ALG_NULL + /// One of: TPMS_SIG_SCHEME_RSASSA, TPMS_SIG_SCHEME_RSAPSS, TPMS_SIG_SCHEME_ECDSA, + /// TPMS_SIG_SCHEME_ECDAA, TPMS_SIG_SCHEME_SM2, TPMS_SIG_SCHEME_ECSCHNORR, + /// TPMS_SCHEME_HMAC, TPMS_SCHEME_HASH, TPMS_NULL_SIG_SCHEME. + /// auditInfo - The audit information that was signed + /// signature - The signature over auditInfo + pub fn GetSessionAuditDigest_async( + &mut self, + privacyAdminHandle: &TPM_HANDLE, + signHandle: &TPM_HANDLE, + sessionHandle: &TPM_HANDLE, + qualifyingData: &Vec, + inScheme: &Option, + ) -> Result<(), TpmError> { + let req = TPM2_GetSessionAuditDigest_REQUEST::new( + privacyAdminHandle, + signHandle, + sessionHandle, + qualifyingData, + inScheme, + ); + + self.tpm.dispatch_command(TPM_CC::GetSessionAuditDigest, &req)?; + Ok(()) + } + + /// This command returns the current value of the command audit digest, a digest of the + /// commands being audited, and the audit hash algorithm. These values are placed in an + /// attestation structure and signed with the key referenced by signHandle. + /// privacyHandle: Handle of the privacy administrator (TPM_RH_ENDORSEMENT) + /// Auth Index: 1 + /// Auth Role: USER + /// signHandle: The handle of the signing key + /// Auth Index: 2 + /// Auth Role: USER + /// qualifyingData: Other data to associate with this audit digest + /// inScheme: Signing scheme to use if the scheme for signHandle is TPM_ALG_NULL + /// One of: TPMS_SIG_SCHEME_RSASSA, TPMS_SIG_SCHEME_RSAPSS, TPMS_SIG_SCHEME_ECDSA, + /// TPMS_SIG_SCHEME_ECDAA, TPMS_SIG_SCHEME_SM2, TPMS_SIG_SCHEME_ECSCHNORR, + /// TPMS_SCHEME_HMAC, TPMS_SCHEME_HASH, TPMS_NULL_SIG_SCHEME. + /// auditInfo - The auditInfo that was signed + /// signature - The signature over auditInfo + pub fn GetCommandAuditDigest_async( + &mut self, + privacyHandle: &TPM_HANDLE, + signHandle: &TPM_HANDLE, + qualifyingData: &Vec, + inScheme: &Option, + ) -> Result<(), TpmError> { + let req = TPM2_GetCommandAuditDigest_REQUEST::new( + privacyHandle, + signHandle, + qualifyingData, + inScheme, + ); + + self.tpm.dispatch_command(TPM_CC::GetCommandAuditDigest, &req)?; + Ok(()) + } + + /// This command returns the current values of Time and Clock. + /// privacyAdminHandle: Handle of the privacy administrator (TPM_RH_ENDORSEMENT) + /// Auth Index: 1 + /// Auth Role: USER + /// signHandle: The keyHandle identifier of a loaded key that can perform digital signatures + /// Auth Index: 2 + /// Auth Role: USER + /// qualifyingData: Data to tick stamp + /// inScheme: Signing scheme to use if the scheme for signHandle is TPM_ALG_NULL + /// One of: TPMS_SIG_SCHEME_RSASSA, TPMS_SIG_SCHEME_RSAPSS, TPMS_SIG_SCHEME_ECDSA, + /// TPMS_SIG_SCHEME_ECDAA, TPMS_SIG_SCHEME_SM2, TPMS_SIG_SCHEME_ECSCHNORR, + /// TPMS_SCHEME_HMAC, TPMS_SCHEME_HASH, TPMS_NULL_SIG_SCHEME. + /// timeInfo - Standard TPM-generated attestation block + /// signature - The signature over timeInfo + pub fn GetTime_async( + &mut self, + privacyAdminHandle: &TPM_HANDLE, + signHandle: &TPM_HANDLE, + qualifyingData: &Vec, + inScheme: &Option, + ) -> Result<(), TpmError> { + let req = TPM2_GetTime_REQUEST::new( + privacyAdminHandle, + signHandle, + qualifyingData, + inScheme, + ); + + self.tpm.dispatch_command(TPM_CC::GetTime, &req)?; + Ok(()) + } + + /// The purpose of this command is to generate an X.509 certificate that proves an object with + /// a specific public key and attributes is loaded in the TPM. In contrast to TPM2_Certify, + /// which uses a TCG-defined data structure to convey attestation information, + /// TPM2_CertifyX509 encodes the attestation information in a DER-encoded X.509 certificate + /// that is compliant with RFC5280 Internet X.509 Public Key Infrastructure Certificate and + /// Certificate Revocation List (CRL) Profile. + /// objectHandle: Handle of the object to be certified + /// Auth Index: 1 + /// Auth Role: ADMIN + /// signHandle: Handle of the key used to sign the attestation structure + /// Auth Index: 2 + /// Auth Role: USER + /// reserved: Shall be an Empty Buffer + /// inScheme: Signing scheme to use if the scheme for signHandle is TPM_ALG_NULL + /// One of: TPMS_SIG_SCHEME_RSASSA, TPMS_SIG_SCHEME_RSAPSS, TPMS_SIG_SCHEME_ECDSA, + /// TPMS_SIG_SCHEME_ECDAA, TPMS_SIG_SCHEME_SM2, TPMS_SIG_SCHEME_ECSCHNORR, + /// TPMS_SCHEME_HMAC, TPMS_SCHEME_HASH, TPMS_NULL_SIG_SCHEME. + /// partialCertificate: A DER encoded partial certificate + /// addedToCertificate - A DER encoded SEQUENCE containing the DER encoded fields added to + /// partialCertificate to make it a complete RFC5280 TBSCertificate. + /// tbsDigest - The digest that was signed + /// signature - The signature over tbsDigest + pub fn CertifyX509_async( + &mut self, + objectHandle: &TPM_HANDLE, + signHandle: &TPM_HANDLE, + reserved: &Vec, + inScheme: &Option, + partialCertificate: &Vec, + ) -> Result<(), TpmError> { + let req = TPM2_CertifyX509_REQUEST::new( + objectHandle, + signHandle, + reserved, + inScheme, + partialCertificate, + ); + + self.tpm.dispatch_command(TPM_CC::CertifyX509, &req)?; + Ok(()) + } + + /// TPM2_Commit() performs the first part of an ECC anonymous signing operation. The TPM will + /// perform the point multiplications on the provided points and return intermediate signing + /// values. The signHandle parameter shall refer to an ECC key and the signing scheme must be + /// anonymous (TPM_RC_SCHEME). + /// signHandle: Handle of the key that will be used in the signing operation + /// Auth Index: 1 + /// Auth Role: USER + /// P1: A point (M) on the curve used by signHandle + /// s2: Octet array used to derive x-coordinate of a base point + /// y2: Y coordinate of the point associated with s2 + /// K - ECC point K [ds](x2, y2) + /// L - ECC point L [r](x2, y2) + /// E - ECC point E [r]P1 + /// counter - Least-significant 16 bits of commitCount + pub fn Commit_async( + &mut self, + signHandle: &TPM_HANDLE, + P1: &TPMS_ECC_POINT, + s2: &Vec, + y2: &Vec, + ) -> Result<(), TpmError> { + let req = TPM2_Commit_REQUEST::new( + signHandle, + P1, + s2, + y2, + ); + + self.tpm.dispatch_command(TPM_CC::Commit, &req)?; + Ok(()) + } + + /// TPM2_EC_Ephemeral() creates an ephemeral key for use in a two-phase key exchange protocol. + /// curveID: The curve for the computed ephemeral point + /// Q - Ephemeral public key Q [r]G + /// counter - Least-significant 16 bits of commitCount + pub fn EC_Ephemeral_async( + &mut self, + curveID: TPM_ECC_CURVE, + ) -> Result<(), TpmError> { + let req = TPM2_EC_Ephemeral_REQUEST::new( + curveID, + ); + + self.tpm.dispatch_command(TPM_CC::EC_Ephemeral, &req)?; + Ok(()) + } + + /// This command uses loaded keys to validate a signature on a message with the message digest + /// passed to the TPM. + /// keyHandle: Handle of public key that will be used in the validation + /// Auth Index: None + /// digest: Digest of the signed message + /// signature: Signature to be tested + /// One of: TPMS_SIGNATURE_RSASSA, TPMS_SIGNATURE_RSAPSS, TPMS_SIGNATURE_ECDSA, + /// TPMS_SIGNATURE_ECDAA, TPMS_SIGNATURE_SM2, TPMS_SIGNATURE_ECSCHNORR, TPMT_HA, + /// TPMS_SCHEME_HASH, TPMS_NULL_SIGNATURE. + /// validation - This ticket is produced by TPM2_VerifySignature(). This formulation is + /// used for multiple ticket uses. The ticket provides evidence that the TPM + /// has validated that a digest was signed by a key with the Name of keyName. + /// The ticket is computed by + pub fn VerifySignature_async( + &mut self, + keyHandle: &TPM_HANDLE, + digest: &Vec, + signature: &Option, + ) -> Result<(), TpmError> { + let req = TPM2_VerifySignature_REQUEST::new( + keyHandle, + digest, + signature, + ); + + self.tpm.dispatch_command(TPM_CC::VerifySignature, &req)?; + Ok(()) + } + + /// This command causes the TPM to sign an externally provided hash with the specified + /// symmetric or asymmetric signing key. + /// keyHandle: Handle of key that will perform signing + /// Auth Index: 1 + /// Auth Role: USER + /// digest: Digest to be signed + /// inScheme: Signing scheme to use if the scheme for keyHandle is TPM_ALG_NULL + /// One of: TPMS_SIG_SCHEME_RSASSA, TPMS_SIG_SCHEME_RSAPSS, TPMS_SIG_SCHEME_ECDSA, + /// TPMS_SIG_SCHEME_ECDAA, TPMS_SIG_SCHEME_SM2, TPMS_SIG_SCHEME_ECSCHNORR, + /// TPMS_SCHEME_HMAC, TPMS_SCHEME_HASH, TPMS_NULL_SIG_SCHEME. + /// validation: Proof that digest was created by the TPM + /// If keyHandle is not a restricted signing key, then this may be a NULL Ticket with + /// tag = TPM_ST_CHECKHASH. + /// signature - The signature + pub fn Sign_async( + &mut self, + keyHandle: &TPM_HANDLE, + digest: &Vec, + inScheme: &Option, + validation: &TPMT_TK_HASHCHECK, + ) -> Result<(), TpmError> { + let req = TPM2_Sign_REQUEST::new( + keyHandle, + digest, + inScheme, + validation, + ); + + self.tpm.dispatch_command(TPM_CC::Sign, &req)?; + Ok(()) + } + + /// This command may be used by the Privacy Administrator or platform to change the audit + /// status of a command or to set the hash algorithm used for the audit digest, but not both + /// at the same time. + /// auth: TPM_RH_OWNER or TPM_RH_PLATFORM+{PP} + /// Auth Index: 1 + /// Auth Role: USER + /// auditAlg: Hash algorithm for the audit digest; if TPM_ALG_NULL, then the hash is not changed + /// setList: List of commands that will be added to those that will be audited + /// clearList: List of commands that will no longer be audited + pub fn SetCommandCodeAuditStatus_async( + &mut self, + auth: &TPM_HANDLE, + auditAlg: TPM_ALG_ID, + setList: &Vec, + clearList: &Vec, + ) -> Result<(), TpmError> { + let req = TPM2_SetCommandCodeAuditStatus_REQUEST::new( + auth, + auditAlg, + setList, + clearList, + ); + + self.tpm.dispatch_command(TPM_CC::SetCommandCodeAuditStatus, &req)?; + Ok(()) + } + + /// This command is used to cause an update to the indicated PCR. The digests parameter + /// contains one or more tagged digest values identified by an algorithm ID. For each digest, + /// the PCR associated with pcrHandle is Extended into the bank identified by the tag (hashAlg). + /// pcrHandle: Handle of the PCR + /// Auth Handle: 1 + /// Auth Role: USER + /// digests: List of tagged digest values to be extended + pub fn PCR_Extend_async( + &mut self, + pcrHandle: &TPM_HANDLE, + digests: &Vec, + ) -> Result<(), TpmError> { + let req = TPM2_PCR_Extend_REQUEST::new( + pcrHandle, + digests, + ); + + self.tpm.dispatch_command(TPM_CC::PCR_Extend, &req)?; + Ok(()) + } + + /// This command is used to cause an update to the indicated PCR. + /// pcrHandle: Handle of the PCR + /// Auth Handle: 1 + /// Auth Role: USER + /// eventData: Event data in sized buffer + /// digests - Table 80 shows the basic hash-agile structure used in this specification. To + /// handle hash agility, this structure uses the hashAlg parameter to indicate + /// the algorithm used to compute the digest and, by implication, the size of + /// the digest. + pub fn PCR_Event_async( + &mut self, + pcrHandle: &TPM_HANDLE, + eventData: &Vec, + ) -> Result<(), TpmError> { + let req = TPM2_PCR_Event_REQUEST::new( + pcrHandle, + eventData, + ); + + self.tpm.dispatch_command(TPM_CC::PCR_Event, &req)?; + Ok(()) + } + + /// This command returns the values of all PCR specified in pcrSelectionIn. + /// pcrSelectionIn: The selection of PCR to read + /// pcrUpdateCounter - The current value of the PCR update counter + /// pcrSelectionOut - The PCR in the returned list + /// pcrValues - The contents of the PCR indicated in pcrSelectOut-˃ pcrSelection[] as + /// tagged digests + pub fn PCR_Read_async( + &mut self, + pcrSelectionIn: &Vec, + ) -> Result<(), TpmError> { + let req = TPM2_PCR_Read_REQUEST::new( + pcrSelectionIn, + ); + + self.tpm.dispatch_command(TPM_CC::PCR_Read, &req)?; + Ok(()) + } + + /// This command is used to set the desired PCR allocation of PCR and algorithms. This command + /// requires Platform Authorization. + /// authHandle: TPM_RH_PLATFORM+{PP} + /// Auth Index: 1 + /// Auth Role: USER + /// pcrAllocation: The requested allocation + /// allocationSuccess - YES if the allocation succeeded + /// maxPCR - Maximum number of PCR that may be in a bank + /// sizeNeeded - Number of octets required to satisfy the request + /// sizeAvailable - Number of octets available. Computed before the allocation. + pub fn PCR_Allocate_async( + &mut self, + authHandle: &TPM_HANDLE, + pcrAllocation: &Vec, + ) -> Result<(), TpmError> { + let req = TPM2_PCR_Allocate_REQUEST::new( + authHandle, + pcrAllocation, + ); + + self.tpm.dispatch_command(TPM_CC::PCR_Allocate, &req)?; + Ok(()) + } + + /// This command is used to associate a policy with a PCR or group of PCR. The policy + /// determines the conditions under which a PCR may be extended or reset. + /// authHandle: TPM_RH_PLATFORM+{PP} + /// Auth Index: 1 + /// Auth Role: USER + /// authPolicy: The desired authPolicy + /// hashAlg: The hash algorithm of the policy + /// pcrNum: The PCR for which the policy is to be set + pub fn PCR_SetAuthPolicy_async( + &mut self, + authHandle: &TPM_HANDLE, + authPolicy: &Vec, + hashAlg: TPM_ALG_ID, + pcrNum: &TPM_HANDLE, + ) -> Result<(), TpmError> { + let req = TPM2_PCR_SetAuthPolicy_REQUEST::new( + authHandle, + authPolicy, + hashAlg, + pcrNum, + ); + + self.tpm.dispatch_command(TPM_CC::PCR_SetAuthPolicy, &req)?; + Ok(()) + } + + /// This command changes the authValue of a PCR or group of PCR. + /// pcrHandle: Handle for a PCR that may have an authorization value set + /// Auth Index: 1 + /// Auth Role: USER + /// auth: The desired authorization value + pub fn PCR_SetAuthValue_async( + &mut self, + pcrHandle: &TPM_HANDLE, + auth: &Vec, + ) -> Result<(), TpmError> { + let req = TPM2_PCR_SetAuthValue_REQUEST::new( + pcrHandle, + auth, + ); + + self.tpm.dispatch_command(TPM_CC::PCR_SetAuthValue, &req)?; + Ok(()) + } + + /// If the attribute of a PCR allows the PCR to be reset and proper authorization is provided, + /// then this command may be used to set the PCR in all banks to zero. The attributes of the + /// PCR may restrict the locality that can perform the reset operation. + /// pcrHandle: The PCR to reset + /// Auth Index: 1 + /// Auth Role: USER + pub fn PCR_Reset_async( + &mut self, + pcrHandle: &TPM_HANDLE, + ) -> Result<(), TpmError> { + let req = TPM2_PCR_Reset_REQUEST::new( + pcrHandle, + ); + + self.tpm.dispatch_command(TPM_CC::PCR_Reset, &req)?; + Ok(()) + } + + /// This command includes a signed authorization in a policy. The command ties the policy to a + /// signing key by including the Name of the signing key in the policyDigest + /// authObject: Handle for a key that will validate the signature + /// Auth Index: None + /// policySession: Handle for the policy session being extended + /// Auth Index: None + /// nonceTPM: The policy nonce for the session + /// This can be the Empty Buffer. + /// cpHashA: Digest of the command parameters to which this authorization is limited + /// This is not the cpHash for this command but the cpHash for the command to which + /// this policy session will be applied. If it is not limited, the parameter will be + /// the Empty Buffer. + /// policyRef: A reference to a policy relating to the authorization may be the Empty Buffer + /// Size is limited to be no larger than the nonce size supported on the TPM. + /// expiration: Time when authorization will expire, measured in seconds from the time that + /// nonceTPM was generated + /// If expiration is non-negative, a NULL Ticket is returned. See 23.2.5. + /// auth: Signed authorization (not optional) + /// One of: TPMS_SIGNATURE_RSASSA, TPMS_SIGNATURE_RSAPSS, TPMS_SIGNATURE_ECDSA, + /// TPMS_SIGNATURE_ECDAA, TPMS_SIGNATURE_SM2, TPMS_SIGNATURE_ECSCHNORR, TPMT_HA, + /// TPMS_SCHEME_HASH, TPMS_NULL_SIGNATURE. + /// timeout - Implementation-specific time value, used to indicate to the TPM when the + /// ticket expires + /// NOTE If policyTicket is a NULL Ticket, then this shall be the Empty Buffer. + /// policyTicket - Produced if the command succeeds and expiration in the command was + /// non-zero; this ticket will use the TPMT_ST_AUTH_SIGNED structure tag. + /// See 23.2.5 + pub fn PolicySigned_async( + &mut self, + authObject: &TPM_HANDLE, + policySession: &TPM_HANDLE, + nonceTPM: &Vec, + cpHashA: &Vec, + policyRef: &Vec, + expiration: i32, + auth: &Option, + ) -> Result<(), TpmError> { + let req = TPM2_PolicySigned_REQUEST::new( + authObject, + policySession, + nonceTPM, + cpHashA, + policyRef, + expiration, + auth, + ); + + self.tpm.dispatch_command(TPM_CC::PolicySigned, &req)?; + Ok(()) + } + + /// This command includes a secret-based authorization to a policy. The caller proves + /// knowledge of the secret value using an authorization session using the authValue + /// associated with authHandle. A password session, an HMAC session, or a policy session + /// containing TPM2_PolicyAuthValue() or TPM2_PolicyPassword() will satisfy this requirement. + /// authHandle: Handle for an entity providing the authorization + /// Auth Index: 1 + /// Auth Role: USER + /// policySession: Handle for the policy session being extended + /// Auth Index: None + /// nonceTPM: The policy nonce for the session + /// This can be the Empty Buffer. + /// cpHashA: Digest of the command parameters to which this authorization is limited + /// This not the cpHash for this command but the cpHash for the command to which this + /// policy session will be applied. If it is not limited, the parameter will be the + /// Empty Buffer. + /// policyRef: A reference to a policy relating to the authorization may be the Empty Buffer + /// Size is limited to be no larger than the nonce size supported on the TPM. + /// expiration: Time when authorization will expire, measured in seconds from the time that + /// nonceTPM was generated + /// If expiration is non-negative, a NULL Ticket is returned. See 23.2.5. + /// timeout - Implementation-specific time value used to indicate to the TPM when the + /// ticket expires + /// policyTicket - Produced if the command succeeds and expiration in the command was + /// non-zero ( See 23.2.5). This ticket will use the TPMT_ST_AUTH_SECRET + /// structure tag + pub fn PolicySecret_async( + &mut self, + authHandle: &TPM_HANDLE, + policySession: &TPM_HANDLE, + nonceTPM: &Vec, + cpHashA: &Vec, + policyRef: &Vec, + expiration: i32, + ) -> Result<(), TpmError> { + let req = TPM2_PolicySecret_REQUEST::new( + authHandle, + policySession, + nonceTPM, + cpHashA, + policyRef, + expiration, + ); + + self.tpm.dispatch_command(TPM_CC::PolicySecret, &req)?; + Ok(()) + } + + /// This command is similar to TPM2_PolicySigned() except that it takes a ticket instead of a + /// signed authorization. The ticket represents a validated authorization that had an + /// expiration time associated with it. + /// policySession: Handle for the policy session being extended + /// Auth Index: None + /// timeout: Time when authorization will expire + /// The contents are TPM specific. This shall be the value returned when ticket was produced. + /// cpHashA: Digest of the command parameters to which this authorization is limited + /// If it is not limited, the parameter will be the Empty Buffer. + /// policyRef: Reference to a qualifier for the policy may be the Empty Buffer + /// authName: Name of the object that provided the authorization + /// ticket: An authorization ticket returned by the TPM in response to a TPM2_PolicySigned() + /// or TPM2_PolicySecret() + pub fn PolicyTicket_async( + &mut self, + policySession: &TPM_HANDLE, + timeout: &Vec, + cpHashA: &Vec, + policyRef: &Vec, + authName: &Vec, + ticket: &TPMT_TK_AUTH, + ) -> Result<(), TpmError> { + let req = TPM2_PolicyTicket_REQUEST::new( + policySession, + timeout, + cpHashA, + policyRef, + authName, + ticket, + ); + + self.tpm.dispatch_command(TPM_CC::PolicyTicket, &req)?; + Ok(()) + } + + /// This command allows options in authorizations without requiring that the TPM evaluate all + /// of the options. If a policy may be satisfied by different sets of conditions, the TPM need + /// only evaluate one set that satisfies the policy. This command will indicate that one of + /// the required sets of conditions has been satisfied. + /// policySession: Handle for the policy session being extended + /// Auth Index: None + /// pHashList: The list of hashes to check for a match + pub fn PolicyOR_async( + &mut self, + policySession: &TPM_HANDLE, + pHashList: &Vec, + ) -> Result<(), TpmError> { + let req = TPM2_PolicyOR_REQUEST::new( + policySession, + pHashList, + ); + + self.tpm.dispatch_command(TPM_CC::PolicyOR, &req)?; + Ok(()) + } + + /// This command is used to cause conditional gating of a policy based on PCR. This command + /// together with TPM2_PolicyOR() allows one group of authorizations to occur when PCR are in + /// one state and a different set of authorizations when the PCR are in a different state. + /// policySession: Handle for the policy session being extended + /// Auth Index: None + /// pcrDigest: Expected digest value of the selected PCR using the hash algorithm of the + /// session; may be zero length + /// pcrs: The PCR to include in the check digest + pub fn PolicyPCR_async( + &mut self, + policySession: &TPM_HANDLE, + pcrDigest: &Vec, + pcrs: &Vec, + ) -> Result<(), TpmError> { + let req = TPM2_PolicyPCR_REQUEST::new( + policySession, + pcrDigest, + pcrs, + ); + + self.tpm.dispatch_command(TPM_CC::PolicyPCR, &req)?; + Ok(()) + } + + /// This command indicates that the authorization will be limited to a specific locality. + /// policySession: Handle for the policy session being extended + /// Auth Index: None + /// locality: The allowed localities for the policy + pub fn PolicyLocality_async( + &mut self, + policySession: &TPM_HANDLE, + locality: TPMA_LOCALITY, + ) -> Result<(), TpmError> { + let req = TPM2_PolicyLocality_REQUEST::new( + policySession, + locality, + ); + + self.tpm.dispatch_command(TPM_CC::PolicyLocality, &req)?; + Ok(()) + } + + /// This command is used to cause conditional gating of a policy based on the contents of an + /// NV Index. It is an immediate assertion. The NV index is validated during the + /// TPM2_PolicyNV() command, not when the session is used for authorization. + /// authHandle: Handle indicating the source of the authorization value + /// Auth Index: 1 + /// Auth Role: USER + /// nvIndex: The NV Index of the area to read + /// Auth Index: None + /// policySession: Handle for the policy session being extended + /// Auth Index: None + /// operandB: The second operand + /// offset: The octet offset in the NV Index for the start of operand A + /// operation: The comparison to make + pub fn PolicyNV_async( + &mut self, + authHandle: &TPM_HANDLE, + nvIndex: &TPM_HANDLE, + policySession: &TPM_HANDLE, + operandB: &Vec, + offset: u16, + operation: TPM_EO, + ) -> Result<(), TpmError> { + let req = TPM2_PolicyNV_REQUEST::new( + authHandle, + nvIndex, + policySession, + operandB, + offset, + operation, + ); + + self.tpm.dispatch_command(TPM_CC::PolicyNV, &req)?; + Ok(()) + } + + /// This command is used to cause conditional gating of a policy based on the contents of the + /// TPMS_TIME_INFO structure. + /// policySession: Handle for the policy session being extended + /// Auth Index: None + /// operandB: The second operand + /// offset: The octet offset in the TPMS_TIME_INFO structure for the start of operand A + /// operation: The comparison to make + pub fn PolicyCounterTimer_async( + &mut self, + policySession: &TPM_HANDLE, + operandB: &Vec, + offset: u16, + operation: TPM_EO, + ) -> Result<(), TpmError> { + let req = TPM2_PolicyCounterTimer_REQUEST::new( + policySession, + operandB, + offset, + operation, + ); + + self.tpm.dispatch_command(TPM_CC::PolicyCounterTimer, &req)?; + Ok(()) + } + + /// This command indicates that the authorization will be limited to a specific command code. + /// policySession: Handle for the policy session being extended + /// Auth Index: None + /// code: The allowed commandCode + pub fn PolicyCommandCode_async( + &mut self, + policySession: &TPM_HANDLE, + code: TPM_CC, + ) -> Result<(), TpmError> { + let req = TPM2_PolicyCommandCode_REQUEST::new( + policySession, + code, + ); + + self.tpm.dispatch_command(TPM_CC::PolicyCommandCode, &req)?; + Ok(()) + } + + /// This command indicates that physical presence will need to be asserted at the time the + /// authorization is performed. + /// policySession: Handle for the policy session being extended + /// Auth Index: None + pub fn PolicyPhysicalPresence_async( + &mut self, + policySession: &TPM_HANDLE, + ) -> Result<(), TpmError> { + let req = TPM2_PolicyPhysicalPresence_REQUEST::new( + policySession, + ); + + self.tpm.dispatch_command(TPM_CC::PolicyPhysicalPresence, &req)?; + Ok(()) + } + + /// This command is used to allow a policy to be bound to a specific command and command parameters. + /// policySession: Handle for the policy session being extended + /// Auth Index: None + /// cpHashA: The cpHash added to the policy + pub fn PolicyCpHash_async( + &mut self, + policySession: &TPM_HANDLE, + cpHashA: &Vec, + ) -> Result<(), TpmError> { + let req = TPM2_PolicyCpHash_REQUEST::new( + policySession, + cpHashA, + ); + + self.tpm.dispatch_command(TPM_CC::PolicyCpHash, &req)?; + Ok(()) + } + + /// This command allows a policy to be bound to a specific set of TPM entities without being + /// bound to the parameters of the command. This is most useful for commands such as + /// TPM2_Duplicate() and for TPM2_PCR_Event() when the referenced PCR requires a policy. + /// policySession: Handle for the policy session being extended + /// Auth Index: None + /// nameHash: The digest to be added to the policy + pub fn PolicyNameHash_async( + &mut self, + policySession: &TPM_HANDLE, + nameHash: &Vec, + ) -> Result<(), TpmError> { + let req = TPM2_PolicyNameHash_REQUEST::new( + policySession, + nameHash, + ); + + self.tpm.dispatch_command(TPM_CC::PolicyNameHash, &req)?; + Ok(()) + } + + /// This command allows qualification of duplication to allow duplication to a selected new parent. + /// policySession: Handle for the policy session being extended + /// Auth Index: None + /// objectName: The Name of the object to be duplicated + /// newParentName: The Name of the new parent + /// includeObject: If YES, the objectName will be included in the value in policySessionpolicyDigest + pub fn PolicyDuplicationSelect_async( + &mut self, + policySession: &TPM_HANDLE, + objectName: &Vec, + newParentName: &Vec, + includeObject: u8, + ) -> Result<(), TpmError> { + let req = TPM2_PolicyDuplicationSelect_REQUEST::new( + policySession, + objectName, + newParentName, + includeObject, + ); + + self.tpm.dispatch_command(TPM_CC::PolicyDuplicationSelect, &req)?; + Ok(()) + } + + /// This command allows policies to change. If a policy were static, then it would be + /// difficult to add users to a policy. This command lets a policy authority sign a new policy + /// so that it may be used in an existing policy. + /// policySession: Handle for the policy session being extended + /// Auth Index: None + /// approvedPolicy: Digest of the policy being approved + /// policyRef: A policy qualifier + /// keySign: Name of a key that can sign a policy addition + /// checkTicket: Ticket validating that approvedPolicy and policyRef were signed by keySign + pub fn PolicyAuthorize_async( + &mut self, + policySession: &TPM_HANDLE, + approvedPolicy: &Vec, + policyRef: &Vec, + keySign: &Vec, + checkTicket: &TPMT_TK_VERIFIED, + ) -> Result<(), TpmError> { + let req = TPM2_PolicyAuthorize_REQUEST::new( + policySession, + approvedPolicy, + policyRef, + keySign, + checkTicket, + ); + + self.tpm.dispatch_command(TPM_CC::PolicyAuthorize, &req)?; + Ok(()) + } + + /// This command allows a policy to be bound to the authorization value of the authorized entity. + /// policySession: Handle for the policy session being extended + /// Auth Index: None + pub fn PolicyAuthValue_async( + &mut self, + policySession: &TPM_HANDLE, + ) -> Result<(), TpmError> { + let req = TPM2_PolicyAuthValue_REQUEST::new( + policySession, + ); + + self.tpm.dispatch_command(TPM_CC::PolicyAuthValue, &req)?; + Ok(()) + } + + /// This command allows a policy to be bound to the authorization value of the authorized object. + /// policySession: Handle for the policy session being extended + /// Auth Index: None + pub fn PolicyPassword_async( + &mut self, + policySession: &TPM_HANDLE, + ) -> Result<(), TpmError> { + let req = TPM2_PolicyPassword_REQUEST::new( + policySession, + ); + + self.tpm.dispatch_command(TPM_CC::PolicyPassword, &req)?; + Ok(()) + } + + /// This command returns the current policyDigest of the session. This command allows the TPM + /// to be used to perform the actions required to pre-compute the authPolicy for an object. + /// policySession: Handle for the policy session + /// Auth Index: None + /// policyDigest - The current value of the policySessionpolicyDigest + pub fn PolicyGetDigest_async( + &mut self, + policySession: &TPM_HANDLE, + ) -> Result<(), TpmError> { + let req = TPM2_PolicyGetDigest_REQUEST::new( + policySession, + ); + + self.tpm.dispatch_command(TPM_CC::PolicyGetDigest, &req)?; + Ok(()) + } + + /// This command allows a policy to be bound to the TPMA_NV_WRITTEN attributes. This is a + /// deferred assertion. Values are stored in the policy session context and checked when the + /// policy is used for authorization. + /// policySession: Handle for the policy session being extended + /// Auth Index: None + /// writtenSet: YES if NV Index is required to have been written + /// NO if NV Index is required not to have been written + pub fn PolicyNvWritten_async( + &mut self, + policySession: &TPM_HANDLE, + writtenSet: u8, + ) -> Result<(), TpmError> { + let req = TPM2_PolicyNvWritten_REQUEST::new( + policySession, + writtenSet, + ); + + self.tpm.dispatch_command(TPM_CC::PolicyNvWritten, &req)?; + Ok(()) + } + + /// This command allows a policy to be bound to a specific creation template. This is most + /// useful for an object creation command such as TPM2_Create(), TPM2_CreatePrimary(), or + /// TPM2_CreateLoaded(). + /// policySession: Handle for the policy session being extended + /// Auth Index: None + /// templateHash: The digest to be added to the policy + pub fn PolicyTemplate_async( + &mut self, + policySession: &TPM_HANDLE, + templateHash: &Vec, + ) -> Result<(), TpmError> { + let req = TPM2_PolicyTemplate_REQUEST::new( + policySession, + templateHash, + ); + + self.tpm.dispatch_command(TPM_CC::PolicyTemplate, &req)?; + Ok(()) + } + + /// This command provides a capability that is the equivalent of a revocable policy. With + /// TPM2_PolicyAuthorize(), the authorization ticket never expires, so the authorization may + /// not be withdrawn. With this command, the approved policy is kept in an NV Index location + /// so that the policy may be changed as needed to render the old policy unusable. + /// authHandle: Handle indicating the source of the authorization value + /// Auth Index: 1 + /// Auth Role: USER + /// nvIndex: The NV Index of the area to read + /// Auth Index: None + /// policySession: Handle for the policy session being extended + /// Auth Index: None + pub fn PolicyAuthorizeNV_async( + &mut self, + authHandle: &TPM_HANDLE, + nvIndex: &TPM_HANDLE, + policySession: &TPM_HANDLE, + ) -> Result<(), TpmError> { + let req = TPM2_PolicyAuthorizeNV_REQUEST::new( + authHandle, + nvIndex, + policySession, + ); + + self.tpm.dispatch_command(TPM_CC::PolicyAuthorizeNV, &req)?; + Ok(()) + } + + /// This command is used to create a Primary Object under one of the Primary Seeds or a + /// Temporary Object under TPM_RH_NULL. The command uses a TPM2B_PUBLIC as a template for the + /// object to be created. The size of the unique field shall not be checked for consistency + /// with the other object parameters. The command will create and load a Primary Object. The + /// sensitive area is not returned. + /// primaryHandle: TPM_RH_ENDORSEMENT, TPM_RH_OWNER, TPM_RH_PLATFORM+{PP}, or TPM_RH_NULL + /// Auth Index: 1 + /// Auth Role: USER + /// inSensitive: The sensitive data, see TPM 2.0 Part 1 Sensitive Values + /// inPublic: The public template + /// outsideInfo: Data that will be included in the creation data for this object to provide + /// permanent, verifiable linkage between this object and some object owner data + /// creationPCR: PCR that will be used in creation data + /// handle - Handle of type TPM_HT_TRANSIENT for created Primary Object + /// outPublic - The public portion of the created object + /// creationData - Contains a TPMT_CREATION_DATA + /// creationHash - Digest of creationData using nameAlg of outPublic + /// creationTicket - Ticket used by TPM2_CertifyCreation() to validate that the creation + /// data was produced by the TPM + /// name - The name of the created object + pub fn CreatePrimary_async( + &mut self, + primaryHandle: &TPM_HANDLE, + inSensitive: &TPMS_SENSITIVE_CREATE, + inPublic: &TPMT_PUBLIC, + outsideInfo: &Vec, + creationPCR: &Vec, + ) -> Result<(), TpmError> { + let req = TPM2_CreatePrimary_REQUEST::new( + primaryHandle, + inSensitive, + inPublic, + outsideInfo, + creationPCR, + ); + + self.tpm.dispatch_command(TPM_CC::CreatePrimary, &req)?; + Ok(()) + } + + /// This command enables and disables use of a hierarchy and its associated NV storage. The + /// command allows phEnable, phEnableNV, shEnable, and ehEnable to be changed when the proper + /// authorization is provided. + /// authHandle: TPM_RH_ENDORSEMENT, TPM_RH_OWNER or TPM_RH_PLATFORM+{PP} + /// Auth Index: 1 + /// Auth Role: USER + /// enable: The enable being modified + /// TPM_RH_ENDORSEMENT, TPM_RH_OWNER, TPM_RH_PLATFORM, or TPM_RH_PLATFORM_NV + /// state: YES if the enable should be SET, NO if the enable should be CLEAR + pub fn HierarchyControl_async( + &mut self, + authHandle: &TPM_HANDLE, + enable: &TPM_HANDLE, + state: u8, + ) -> Result<(), TpmError> { + let req = TPM2_HierarchyControl_REQUEST::new( + authHandle, + enable, + state, + ); + + self.tpm.dispatch_command(TPM_CC::HierarchyControl, &req)?; + Ok(()) + } + + /// This command allows setting of the authorization policy for the lockout (lockoutPolicy), + /// the platform hierarchy (platformPolicy), the storage hierarchy (ownerPolicy), and the + /// endorsement hierarchy (endorsementPolicy). On TPMs implementing Authenticated Countdown + /// Timers (ACT), this command may also be used to set the authorization policy for an ACT. + /// authHandle: TPM_RH_LOCKOUT, TPM_RH_ENDORSEMENT, TPM_RH_OWNER, TPMI_RH_ACT or TPM_RH_PLATFORM+{PP} + /// Auth Index: 1 + /// Auth Role: USER + /// authPolicy: An authorization policy digest; may be the Empty Buffer + /// If hashAlg is TPM_ALG_NULL, then this shall be an Empty Buffer. + /// hashAlg: The hash algorithm to use for the policy + /// If the authPolicy is an Empty Buffer, then this field shall be TPM_ALG_NULL. + pub fn SetPrimaryPolicy_async( + &mut self, + authHandle: &TPM_HANDLE, + authPolicy: &Vec, + hashAlg: TPM_ALG_ID, + ) -> Result<(), TpmError> { + let req = TPM2_SetPrimaryPolicy_REQUEST::new( + authHandle, + authPolicy, + hashAlg, + ); + + self.tpm.dispatch_command(TPM_CC::SetPrimaryPolicy, &req)?; + Ok(()) + } + + /// This replaces the current platform primary seed (PPS) with a value from the RNG and sets + /// platformPolicy to the default initialization value (the Empty Buffer). + /// authHandle: TPM_RH_PLATFORM+{PP} + /// Auth Index: 1 + /// Auth Role: USER + pub fn ChangePPS_async( + &mut self, + authHandle: &TPM_HANDLE, + ) -> Result<(), TpmError> { + let req = TPM2_ChangePPS_REQUEST::new( + authHandle, + ); + + self.tpm.dispatch_command(TPM_CC::ChangePPS, &req)?; + Ok(()) + } + + /// This replaces the current endorsement primary seed (EPS) with a value from the RNG and + /// sets the Endorsement hierarchy controls to their default initialization values: ehEnable + /// is SET, endorsementAuth and endorsementPolicy are both set to the Empty Buffer. It will + /// flush any resident objects (transient or persistent) in the Endorsement hierarchy and not + /// allow objects in the hierarchy associated with the previous EPS to be loaded. + /// authHandle: TPM_RH_PLATFORM+{PP} + /// Auth Handle: 1 + /// Auth Role: USER + pub fn ChangeEPS_async( + &mut self, + authHandle: &TPM_HANDLE, + ) -> Result<(), TpmError> { + let req = TPM2_ChangeEPS_REQUEST::new( + authHandle, + ); + + self.tpm.dispatch_command(TPM_CC::ChangeEPS, &req)?; + Ok(()) + } + + /// This command removes all TPM context associated with a specific Owner. + /// authHandle: TPM_RH_LOCKOUT or TPM_RH_PLATFORM+{PP} + /// Auth Handle: 1 + /// Auth Role: USER + pub fn Clear_async( + &mut self, + authHandle: &TPM_HANDLE, + ) -> Result<(), TpmError> { + let req = TPM2_Clear_REQUEST::new( + authHandle, + ); + + self.tpm.dispatch_command(TPM_CC::Clear, &req)?; + Ok(()) + } + + /// TPM2_ClearControl() disables and enables the execution of TPM2_Clear(). + /// auth: TPM_RH_LOCKOUT or TPM_RH_PLATFORM+{PP} + /// Auth Handle: 1 + /// Auth Role: USER + /// disable: YES if the disableOwnerClear flag is to be SET, NO if the flag is to be CLEAR. + pub fn ClearControl_async( + &mut self, + auth: &TPM_HANDLE, + disable: u8, + ) -> Result<(), TpmError> { + let req = TPM2_ClearControl_REQUEST::new( + auth, + disable, + ); + + self.tpm.dispatch_command(TPM_CC::ClearControl, &req)?; + Ok(()) + } + + /// This command allows the authorization secret for a hierarchy or lockout to be changed + /// using the current authorization value as the command authorization. + /// authHandle: TPM_RH_LOCKOUT, TPM_RH_ENDORSEMENT, TPM_RH_OWNER or TPM_RH_PLATFORM+{PP} + /// Auth Index: 1 + /// Auth Role: USER + /// newAuth: New authorization value + pub fn HierarchyChangeAuth_async( + &mut self, + authHandle: &TPM_HANDLE, + newAuth: &Vec, + ) -> Result<(), TpmError> { + let req = TPM2_HierarchyChangeAuth_REQUEST::new( + authHandle, + newAuth, + ); + + self.tpm.dispatch_command(TPM_CC::HierarchyChangeAuth, &req)?; + Ok(()) + } + + /// This command cancels the effect of a TPM lockout due to a number of successive + /// authorization failures. If this command is properly authorized, the lockout counter is set + /// to zero. + /// lockHandle: TPM_RH_LOCKOUT + /// Auth Index: 1 + /// Auth Role: USER + pub fn DictionaryAttackLockReset_async( + &mut self, + lockHandle: &TPM_HANDLE, + ) -> Result<(), TpmError> { + let req = TPM2_DictionaryAttackLockReset_REQUEST::new( + lockHandle, + ); + + self.tpm.dispatch_command(TPM_CC::DictionaryAttackLockReset, &req)?; + Ok(()) + } + + /// This command changes the lockout parameters. + /// lockHandle: TPM_RH_LOCKOUT + /// Auth Index: 1 + /// Auth Role: USER + /// newMaxTries: Count of authorization failures before the lockout is imposed + /// newRecoveryTime: Time in seconds before the authorization failure count is automatically decremented + /// A value of zero indicates that DA protection is disabled. + /// lockoutRecovery: Time in seconds after a lockoutAuth failure before use of lockoutAuth is allowed + /// A value of zero indicates that a reboot is required. + pub fn DictionaryAttackParameters_async( + &mut self, + lockHandle: &TPM_HANDLE, + newMaxTries: u32, + newRecoveryTime: u32, + lockoutRecovery: u32, + ) -> Result<(), TpmError> { + let req = TPM2_DictionaryAttackParameters_REQUEST::new( + lockHandle, + newMaxTries, + newRecoveryTime, + lockoutRecovery, + ); + + self.tpm.dispatch_command(TPM_CC::DictionaryAttackParameters, &req)?; + Ok(()) + } + + /// This command is used to determine which commands require assertion of Physical Presence + /// (PP) in addition to platformAuth/platformPolicy. + /// auth: TPM_RH_PLATFORM+PP + /// Auth Index: 1 + /// Auth Role: USER + Physical Presence + /// setList: List of commands to be added to those that will require that Physical Presence be + /// asserted + /// clearList: List of commands that will no longer require that Physical Presence be asserted + pub fn PP_Commands_async( + &mut self, + auth: &TPM_HANDLE, + setList: &Vec, + clearList: &Vec, + ) -> Result<(), TpmError> { + let req = TPM2_PP_Commands_REQUEST::new( + auth, + setList, + clearList, + ); + + self.tpm.dispatch_command(TPM_CC::PP_Commands, &req)?; + Ok(()) + } + + /// This command allows the platform to change the set of algorithms that are used by the TPM. + /// The algorithmSet setting is a vendor-dependent value. + /// authHandle: TPM_RH_PLATFORM + /// Auth Index: 1 + /// Auth Role: USER + /// algorithmSet: A TPM vendor-dependent value indicating the algorithm set selection + pub fn SetAlgorithmSet_async( + &mut self, + authHandle: &TPM_HANDLE, + algorithmSet: u32, + ) -> Result<(), TpmError> { + let req = TPM2_SetAlgorithmSet_REQUEST::new( + authHandle, + algorithmSet, + ); + + self.tpm.dispatch_command(TPM_CC::SetAlgorithmSet, &req)?; + Ok(()) + } + + /// This command uses platformPolicy and a TPM Vendor Authorization Key to authorize a Field + /// Upgrade Manifest. + /// authorization: TPM_RH_PLATFORM+{PP} + /// Auth Index:1 + /// Auth Role: ADMIN + /// keyHandle: Handle of a public area that contains the TPM Vendor Authorization Key that + /// will be used to validate manifestSignature + /// Auth Index: None + /// fuDigest: Digest of the first block in the field upgrade sequence + /// manifestSignature: Signature over fuDigest using the key associated with keyHandle (not optional) + /// One of: TPMS_SIGNATURE_RSASSA, TPMS_SIGNATURE_RSAPSS, TPMS_SIGNATURE_ECDSA, + /// TPMS_SIGNATURE_ECDAA, TPMS_SIGNATURE_SM2, TPMS_SIGNATURE_ECSCHNORR, TPMT_HA, + /// TPMS_SCHEME_HASH, TPMS_NULL_SIGNATURE. + pub fn FieldUpgradeStart_async( + &mut self, + authorization: &TPM_HANDLE, + keyHandle: &TPM_HANDLE, + fuDigest: &Vec, + manifestSignature: &Option, + ) -> Result<(), TpmError> { + let req = TPM2_FieldUpgradeStart_REQUEST::new( + authorization, + keyHandle, + fuDigest, + manifestSignature, + ); + + self.tpm.dispatch_command(TPM_CC::FieldUpgradeStart, &req)?; + Ok(()) + } + + /// This command will take the actual field upgrade image to be installed on the TPM. The + /// exact format of fuData is vendor-specific. This command is only possible following a + /// successful TPM2_FieldUpgradeStart(). If the TPM has not received a properly authorized + /// TPM2_FieldUpgradeStart(), then the TPM shall return TPM_RC_FIELDUPGRADE. + /// fuData: Field upgrade image data + /// nextDigest - Tagged digest of the next block + /// TPM_ALG_NULL if field update is complete + /// firstDigest - Tagged digest of the first block of the sequence + pub fn FieldUpgradeData_async( + &mut self, + fuData: &Vec, + ) -> Result<(), TpmError> { + let req = TPM2_FieldUpgradeData_REQUEST::new( + fuData, + ); + + self.tpm.dispatch_command(TPM_CC::FieldUpgradeData, &req)?; + Ok(()) + } + + /// This command is used to read a copy of the current firmware installed in the TPM. + /// sequenceNumber: The number of previous calls to this command in this sequence + /// set to 0 on the first call + /// fuData - Field upgrade image data + pub fn FirmwareRead_async( + &mut self, + sequenceNumber: u32, + ) -> Result<(), TpmError> { + let req = TPM2_FirmwareRead_REQUEST::new( + sequenceNumber, + ); + + self.tpm.dispatch_command(TPM_CC::FirmwareRead, &req)?; + Ok(()) + } + + /// This command saves a session context, object context, or sequence object context outside + /// the TPM. + /// saveHandle: Handle of the resource to save + /// Auth Index: None + /// context - This structure is used in TPM2_ContextLoad() and TPM2_ContextSave(). If the + /// values of the TPMS_CONTEXT structure in TPM2_ContextLoad() are not the same + /// as the values when the context was saved (TPM2_ContextSave()), then the TPM + /// shall not load the context. + pub fn ContextSave_async( + &mut self, + saveHandle: &TPM_HANDLE, + ) -> Result<(), TpmError> { + let req = TPM2_ContextSave_REQUEST::new( + saveHandle, + ); + + self.tpm.dispatch_command(TPM_CC::ContextSave, &req)?; + Ok(()) + } + + /// This command is used to reload a context that has been saved by TPM2_ContextSave(). + /// context: The context blob + /// handle - The handle assigned to the resource after it has been successfully loaded + pub fn ContextLoad_async( + &mut self, + context: &TPMS_CONTEXT, + ) -> Result<(), TpmError> { + let req = TPM2_ContextLoad_REQUEST::new( + context, + ); + + self.tpm.dispatch_command(TPM_CC::ContextLoad, &req)?; + Ok(()) + } + + /// This command causes all context associated with a loaded object, sequence object, or + /// session to be removed from TPM memory. + /// flushHandle: The handle of the item to flush + /// NOTE This is a use of a handle as a parameter. + pub fn FlushContext_async( + &mut self, + flushHandle: &TPM_HANDLE, + ) -> Result<(), TpmError> { + let req = TPM2_FlushContext_REQUEST::new( + flushHandle, + ); + + self.tpm.dispatch_command(TPM_CC::FlushContext, &req)?; + Ok(()) + } + + /// This command allows certain Transient Objects to be made persistent or a persistent object + /// to be evicted. + /// auth: TPM_RH_OWNER or TPM_RH_PLATFORM+{PP} + /// Auth Handle: 1 + /// Auth Role: USER + /// objectHandle: The handle of a loaded object + /// Auth Index: None + /// persistentHandle: If objectHandle is a transient object handle, then this is the + /// persistent handle for the object + /// if objectHandle is a persistent object handle, then it shall be the same value as + /// persistentHandle + pub fn EvictControl_async( + &mut self, + auth: &TPM_HANDLE, + objectHandle: &TPM_HANDLE, + persistentHandle: &TPM_HANDLE, + ) -> Result<(), TpmError> { + let req = TPM2_EvictControl_REQUEST::new( + auth, + objectHandle, + persistentHandle, + ); + + self.tpm.dispatch_command(TPM_CC::EvictControl, &req)?; + Ok(()) + } + + /// This command reads the current TPMS_TIME_INFO structure that contains the current setting + /// of Time, Clock, resetCount, and restartCount. + /// currentTime - This structure is used in, e.g., the TPM2_GetTime() attestation and + /// TPM2_ReadClock(). + pub fn ReadClock_async( + &mut self, + ) -> Result<(), TpmError> { + let req = TPM2_ReadClock_REQUEST::default(); + + self.tpm.dispatch_command(TPM_CC::ReadClock, &req)?; + Ok(()) + } + + /// This command is used to advance the value of the TPMs Clock. The command will fail if + /// newTime is less than the current value of Clock or if the new time is greater than + /// FFFF00000000000016. If both of these checks succeed, Clock is set to newTime. If either of + /// these checks fails, the TPM shall return TPM_RC_VALUE and make no change to Clock. + /// auth: TPM_RH_OWNER or TPM_RH_PLATFORM+{PP} + /// Auth Handle: 1 + /// Auth Role: USER + /// newTime: New Clock setting in milliseconds + pub fn ClockSet_async( + &mut self, + auth: &TPM_HANDLE, + newTime: u64, + ) -> Result<(), TpmError> { + let req = TPM2_ClockSet_REQUEST::new( + auth, + newTime, + ); + + self.tpm.dispatch_command(TPM_CC::ClockSet, &req)?; + Ok(()) + } + + /// This command adjusts the rate of advance of Clock and Time to provide a better + /// approximation to real time. + /// auth: TPM_RH_OWNER or TPM_RH_PLATFORM+{PP} + /// Auth Handle: 1 + /// Auth Role: USER + /// rateAdjust: Adjustment to current Clock update rate + pub fn ClockRateAdjust_async( + &mut self, + auth: &TPM_HANDLE, + rateAdjust: TPM_CLOCK_ADJUST, + ) -> Result<(), TpmError> { + let req = TPM2_ClockRateAdjust_REQUEST::new( + auth, + rateAdjust, + ); + + self.tpm.dispatch_command(TPM_CC::ClockRateAdjust, &req)?; + Ok(()) + } + + /// This command returns various information regarding the TPM and its current state. + /// capability: Group selection; determines the format of the response + /// property: Further definition of information + /// propertyCount: Number of properties of the indicated type to return + /// moreData - Flag to indicate if there are more values of this type + /// capabilityData - The capability data + pub fn GetCapability_async( + &mut self, + capability: TPM_CAP, + property: u32, + propertyCount: u32, + ) -> Result<(), TpmError> { + let req = TPM2_GetCapability_REQUEST::new( + capability, + property, + propertyCount, + ); + + self.tpm.dispatch_command(TPM_CC::GetCapability, &req)?; + Ok(()) + } + + /// This command is used to check to see if specific combinations of algorithm parameters are supported. + /// parameters: Algorithm parameters to be validated + /// One of: TPMS_KEYEDHASH_PARMS, TPMS_SYMCIPHER_PARMS, TPMS_RSA_PARMS, TPMS_ECC_PARMS, + /// TPMS_ASYM_PARMS. + pub fn TestParms_async( + &mut self, + parameters: &Option, + ) -> Result<(), TpmError> { + let req = TPM2_TestParms_REQUEST::new( + parameters, + ); + + self.tpm.dispatch_command(TPM_CC::TestParms, &req)?; + Ok(()) + } + + /// This command defines the attributes of an NV Index and causes the TPM to reserve space to + /// hold the data associated with the NV Index. If a definition already exists at the NV + /// Index, the TPM will return TPM_RC_NV_DEFINED. + /// authHandle: TPM_RH_OWNER or TPM_RH_PLATFORM+{PP} + /// Auth Index: 1 + /// Auth Role: USER + /// auth: The authorization value + /// publicInfo: The public parameters of the NV area + pub fn NV_DefineSpace_async( + &mut self, + authHandle: &TPM_HANDLE, + auth: &Vec, + publicInfo: &TPMS_NV_PUBLIC, + ) -> Result<(), TpmError> { + let req = TPM2_NV_DefineSpace_REQUEST::new( + authHandle, + auth, + publicInfo, + ); + + self.tpm.dispatch_command(TPM_CC::NV_DefineSpace, &req)?; + Ok(()) + } + + /// This command removes an Index from the TPM. + /// authHandle: TPM_RH_OWNER or TPM_RH_PLATFORM+{PP} + /// Auth Index: 1 + /// Auth Role: USER + /// nvIndex: The NV Index to remove from NV space + /// Auth Index: None + pub fn NV_UndefineSpace_async( + &mut self, + authHandle: &TPM_HANDLE, + nvIndex: &TPM_HANDLE, + ) -> Result<(), TpmError> { + let req = TPM2_NV_UndefineSpace_REQUEST::new( + authHandle, + nvIndex, + ); + + self.tpm.dispatch_command(TPM_CC::NV_UndefineSpace, &req)?; + Ok(()) + } + + /// This command allows removal of a platform-created NV Index that has TPMA_NV_POLICY_DELETE SET. + /// nvIndex: Index to be deleted + /// Auth Index: 1 + /// Auth Role: ADMIN + /// platform: TPM_RH_PLATFORM + {PP} + /// Auth Index: 2 + /// Auth Role: USER + pub fn NV_UndefineSpaceSpecial_async( + &mut self, + nvIndex: &TPM_HANDLE, + platform: &TPM_HANDLE, + ) -> Result<(), TpmError> { + let req = TPM2_NV_UndefineSpaceSpecial_REQUEST::new( + nvIndex, + platform, + ); + + self.tpm.dispatch_command(TPM_CC::NV_UndefineSpaceSpecial, &req)?; + Ok(()) + } + + /// This command is used to read the public area and Name of an NV Index. The public area of + /// an Index is not privacy-sensitive and no authorization is required to read this data. + /// nvIndex: The NV Index + /// Auth Index: None + /// nvPublic - The public area of the NV Index + /// nvName - The Name of the nvIndex + pub fn NV_ReadPublic_async( + &mut self, + nvIndex: &TPM_HANDLE, + ) -> Result<(), TpmError> { + let req = TPM2_NV_ReadPublic_REQUEST::new( + nvIndex, + ); + + self.tpm.dispatch_command(TPM_CC::NV_ReadPublic, &req)?; + Ok(()) + } + + /// This command writes a value to an area in NV memory that was previously defined by + /// TPM2_NV_DefineSpace(). + /// authHandle: Handle indicating the source of the authorization value + /// Auth Index: 1 + /// Auth Role: USER + /// nvIndex: The NV Index of the area to write + /// Auth Index: None + /// data: The data to write + /// offset: The octet offset into the NV Area + pub fn NV_Write_async( + &mut self, + authHandle: &TPM_HANDLE, + nvIndex: &TPM_HANDLE, + data: &Vec, + offset: u16, + ) -> Result<(), TpmError> { + let req = TPM2_NV_Write_REQUEST::new( + authHandle, + nvIndex, + data, + offset, + ); + + self.tpm.dispatch_command(TPM_CC::NV_Write, &req)?; + Ok(()) + } + + /// This command is used to increment the value in an NV Index that has the TPM_NT_COUNTER + /// attribute. The data value of the NV Index is incremented by one. + /// authHandle: Handle indicating the source of the authorization value + /// Auth Index: 1 + /// Auth Role: USER + /// nvIndex: The NV Index to increment + /// Auth Index: None + pub fn NV_Increment_async( + &mut self, + authHandle: &TPM_HANDLE, + nvIndex: &TPM_HANDLE, + ) -> Result<(), TpmError> { + let req = TPM2_NV_Increment_REQUEST::new( + authHandle, + nvIndex, + ); + + self.tpm.dispatch_command(TPM_CC::NV_Increment, &req)?; + Ok(()) + } + + /// This command extends a value to an area in NV memory that was previously defined by + /// TPM2_NV_DefineSpace. + /// authHandle: Handle indicating the source of the authorization value + /// Auth Index: 1 + /// Auth Role: USER + /// nvIndex: The NV Index to extend + /// Auth Index: None + /// data: The data to extend + pub fn NV_Extend_async( + &mut self, + authHandle: &TPM_HANDLE, + nvIndex: &TPM_HANDLE, + data: &Vec, + ) -> Result<(), TpmError> { + let req = TPM2_NV_Extend_REQUEST::new( + authHandle, + nvIndex, + data, + ); + + self.tpm.dispatch_command(TPM_CC::NV_Extend, &req)?; + Ok(()) + } + + /// This command is used to SET bits in an NV Index that was created as a bit field. Any + /// number of bits from 0 to 64 may be SET. The contents of bits are ORed with the current + /// contents of the NV Index. + /// authHandle: Handle indicating the source of the authorization value + /// Auth Index: 1 + /// Auth Role: USER + /// nvIndex: NV Index of the area in which the bit is to be set + /// Auth Index: None + /// bits: The data to OR with the current contents + pub fn NV_SetBits_async( + &mut self, + authHandle: &TPM_HANDLE, + nvIndex: &TPM_HANDLE, + bits: u64, + ) -> Result<(), TpmError> { + let req = TPM2_NV_SetBits_REQUEST::new( + authHandle, + nvIndex, + bits, + ); + + self.tpm.dispatch_command(TPM_CC::NV_SetBits, &req)?; + Ok(()) + } + + /// If the TPMA_NV_WRITEDEFINE or TPMA_NV_WRITE_STCLEAR attributes of an NV location are SET, + /// then this command may be used to inhibit further writes of the NV Index. + /// authHandle: Handle indicating the source of the authorization value + /// Auth Index: 1 + /// Auth Role: USER + /// nvIndex: The NV Index of the area to lock + /// Auth Index: None + pub fn NV_WriteLock_async( + &mut self, + authHandle: &TPM_HANDLE, + nvIndex: &TPM_HANDLE, + ) -> Result<(), TpmError> { + let req = TPM2_NV_WriteLock_REQUEST::new( + authHandle, + nvIndex, + ); + + self.tpm.dispatch_command(TPM_CC::NV_WriteLock, &req)?; + Ok(()) + } + + /// The command will SET TPMA_NV_WRITELOCKED for all indexes that have their + /// TPMA_NV_GLOBALLOCK attribute SET. + /// authHandle: TPM_RH_OWNER or TPM_RH_PLATFORM+{PP} + /// Auth Index: 1 + /// Auth Role: USER + pub fn NV_GlobalWriteLock_async( + &mut self, + authHandle: &TPM_HANDLE, + ) -> Result<(), TpmError> { + let req = TPM2_NV_GlobalWriteLock_REQUEST::new( + authHandle, + ); + + self.tpm.dispatch_command(TPM_CC::NV_GlobalWriteLock, &req)?; + Ok(()) + } + + /// This command reads a value from an area in NV memory previously defined by TPM2_NV_DefineSpace(). + /// authHandle: The handle indicating the source of the authorization value + /// Auth Index: 1 + /// Auth Role: USER + /// nvIndex: The NV Index to be read + /// Auth Index: None + /// size: Number of octets to read + /// offset: Octet offset into the NV area + /// This value shall be less than or equal to the size of the nvIndex data. + /// data - The data read + pub fn NV_Read_async( + &mut self, + authHandle: &TPM_HANDLE, + nvIndex: &TPM_HANDLE, + size: u16, + offset: u16, + ) -> Result<(), TpmError> { + let req = TPM2_NV_Read_REQUEST::new( + authHandle, + nvIndex, + size, + offset, + ); + + self.tpm.dispatch_command(TPM_CC::NV_Read, &req)?; + Ok(()) + } + + /// If TPMA_NV_READ_STCLEAR is SET in an Index, then this command may be used to prevent + /// further reads of the NV Index until the next TPM2_Startup (TPM_SU_CLEAR). + /// authHandle: The handle indicating the source of the authorization value + /// Auth Index: 1 + /// Auth Role: USER + /// nvIndex: The NV Index to be locked + /// Auth Index: None + pub fn NV_ReadLock_async( + &mut self, + authHandle: &TPM_HANDLE, + nvIndex: &TPM_HANDLE, + ) -> Result<(), TpmError> { + let req = TPM2_NV_ReadLock_REQUEST::new( + authHandle, + nvIndex, + ); + + self.tpm.dispatch_command(TPM_CC::NV_ReadLock, &req)?; + Ok(()) + } + + /// This command allows the authorization secret for an NV Index to be changed. + /// nvIndex: Handle of the entity + /// Auth Index: 1 + /// Auth Role: ADMIN + /// newAuth: New authorization value + pub fn NV_ChangeAuth_async( + &mut self, + nvIndex: &TPM_HANDLE, + newAuth: &Vec, + ) -> Result<(), TpmError> { + let req = TPM2_NV_ChangeAuth_REQUEST::new( + nvIndex, + newAuth, + ); + + self.tpm.dispatch_command(TPM_CC::NV_ChangeAuth, &req)?; + Ok(()) + } + + /// The purpose of this command is to certify the contents of an NV Index or portion of an NV Index. + /// signHandle: Handle of the key used to sign the attestation structure + /// Auth Index: 1 + /// Auth Role: USER + /// authHandle: Handle indicating the source of the authorization value for the NV Index + /// Auth Index: 2 + /// Auth Role: USER + /// nvIndex: Index for the area to be certified + /// Auth Index: None + /// qualifyingData: User-provided qualifying data + /// inScheme: Signing scheme to use if the scheme for signHandle is TPM_ALG_NULL + /// One of: TPMS_SIG_SCHEME_RSASSA, TPMS_SIG_SCHEME_RSAPSS, TPMS_SIG_SCHEME_ECDSA, + /// TPMS_SIG_SCHEME_ECDAA, TPMS_SIG_SCHEME_SM2, TPMS_SIG_SCHEME_ECSCHNORR, + /// TPMS_SCHEME_HMAC, TPMS_SCHEME_HASH, TPMS_NULL_SIG_SCHEME. + /// size: Number of octets to certify + /// offset: Octet offset into the NV area + /// This value shall be less than or equal to the size of the nvIndex data. + /// certifyInfo - The structure that was signed + /// signature - The asymmetric signature over certifyInfo using the key referenced by signHandle + pub fn NV_Certify_async( + &mut self, + signHandle: &TPM_HANDLE, + authHandle: &TPM_HANDLE, + nvIndex: &TPM_HANDLE, + qualifyingData: &Vec, + inScheme: &Option, + size: u16, + offset: u16, + ) -> Result<(), TpmError> { + let req = TPM2_NV_Certify_REQUEST::new( + signHandle, + authHandle, + nvIndex, + qualifyingData, + inScheme, + size, + offset, + ); + + self.tpm.dispatch_command(TPM_CC::NV_Certify, &req)?; + Ok(()) + } + + /// The purpose of this command is to obtain information about an Attached Component + /// referenced by an AC handle. + /// ac: Handle indicating the Attached Component + /// Auth Index: None + /// capability: Starting info type + /// count: Maximum number of values to return + /// moreData - Flag to indicate whether there are more values + /// capabilitiesData - List of capabilities + pub fn AC_GetCapability_async( + &mut self, + ac: &TPM_HANDLE, + capability: TPM_AT, + count: u32, + ) -> Result<(), TpmError> { + let req = TPM2_AC_GetCapability_REQUEST::new( + ac, + capability, + count, + ); + + self.tpm.dispatch_command(TPM_CC::AC_GetCapability, &req)?; + Ok(()) + } + + /// The purpose of this command is to send (copy) a loaded object from the TPM to an Attached Component. + /// sendObject: Handle of the object being sent to ac + /// Auth Index: 1 + /// Auth Role: DUP + /// authHandle: The handle indicating the source of the authorization value + /// Auth Index: 2 + /// Auth Role: USER + /// ac: Handle indicating the Attached Component to which the object will be sent + /// Auth Index: None + /// acDataIn: Optional non sensitive information related to the object + /// acDataOut - May include AC specific data or information about an error. + pub fn AC_Send_async( + &mut self, + sendObject: &TPM_HANDLE, + authHandle: &TPM_HANDLE, + ac: &TPM_HANDLE, + acDataIn: &Vec, + ) -> Result<(), TpmError> { + let req = TPM2_AC_Send_REQUEST::new( + sendObject, + authHandle, + ac, + acDataIn, + ); + + self.tpm.dispatch_command(TPM_CC::AC_Send, &req)?; + Ok(()) + } + + /// This command allows qualification of the sending (copying) of an Object to an Attached + /// Component (AC). Qualification includes selection of the receiving AC and the method of + /// authentication for the AC, and, in certain circumstances, the Object to be sent may be specified. + /// policySession: Handle for the policy session being extended + /// Auth Index: None + /// objectName: The Name of the Object to be sent + /// authHandleName: The Name associated with authHandle used in the TPM2_AC_Send() command + /// acName: The Name of the Attached Component to which the Object will be sent + /// includeObject: If SET, objectName will be included in the value in policySessionpolicyDigest + pub fn Policy_AC_SendSelect_async( + &mut self, + policySession: &TPM_HANDLE, + objectName: &Vec, + authHandleName: &Vec, + acName: &Vec, + includeObject: u8, + ) -> Result<(), TpmError> { + let req = TPM2_Policy_AC_SendSelect_REQUEST::new( + policySession, + objectName, + authHandleName, + acName, + includeObject, + ); + + self.tpm.dispatch_command(TPM_CC::Policy_AC_SendSelect, &req)?; + Ok(()) + } + + /// This command is used to set the time remaining before an Authenticated Countdown Timer + /// (ACT) expires. + /// actHandle: Handle of the selected ACT + /// Auth Index: 1 + /// Auth Role: USER + /// startTimeout: The start timeout value for the ACT in seconds + pub fn ACT_SetTimeout_async( + &mut self, + actHandle: &TPM_HANDLE, + startTimeout: u32, + ) -> Result<(), TpmError> { + let req = TPM2_ACT_SetTimeout_REQUEST::new( + actHandle, + startTimeout, + ); + + self.tpm.dispatch_command(TPM_CC::ACT_SetTimeout, &req)?; + Ok(()) + } + + /// This is a placeholder to allow testing of the dispatch code. + /// inputData: Dummy data + /// outputData - Dummy data + pub fn Vendor_TCG_Test_async( + &mut self, + inputData: &Vec, + ) -> Result<(), TpmError> { + let req = TPM2_Vendor_TCG_Test_REQUEST::new( + inputData, + ); + + self.tpm.dispatch_command(TPM_CC::Vendor_TCG_Test, &req)?; + Ok(()) + } + + /// TPM2_Startup() is always preceded by _TPM_Init, which is the physical indication that TPM + /// initialization is necessary because of a system-wide reset. TPM2_Startup() is only valid + /// after _TPM_Init. Additional TPM2_Startup() commands are not allowed after it has completed + /// successfully. If a TPM requires TPM2_Startup() and another command is received, or if the + /// TPM receives TPM2_Startup() when it is not required, the TPM shall return TPM_RC_INITIALIZE. + pub fn Startup_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::Startup, &mut resp)?; + Ok(()) + } + + /// This command is used to prepare the TPM for a power cycle. The shutdownType parameter + /// indicates how the subsequent TPM2_Startup() will be processed. + pub fn Shutdown_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::Shutdown, &mut resp)?; + Ok(()) + } + + /// This command causes the TPM to perform a test of its capabilities. If the fullTest is YES, + /// the TPM will test all functions. If fullTest = NO, the TPM will only test those functions + /// that have not previously been tested. + pub fn SelfTest_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::SelfTest, &mut resp)?; + Ok(()) + } + + /// This command causes the TPM to perform a test of the selected algorithms. + /// toDoList - List of algorithms that need testing + pub fn IncrementalSelfTest_complete( + &mut self, + ) -> Result, TpmError> { + let mut resp = IncrementalSelfTestResponse::default(); + self.tpm.process_response(TPM_CC::IncrementalSelfTest, &mut resp)?; + Ok(resp.toDoList) + } + + /// This command returns manufacturer-specific information regarding the results of a + /// self-test and an indication of the test status. + /// outData - Test result data + /// contains manufacturer-specific information + /// testResult - TBD + pub fn GetTestResult_complete( + &mut self, + ) -> Result { + let mut resp = GetTestResultResponse::default(); + self.tpm.process_response(TPM_CC::GetTestResult, &mut resp)?; + Ok(resp) + } + + /// This command is used to start an authorization session using alternative methods of + /// establishing the session key (sessionKey). The session key is then used to derive values + /// used for authorization and for encrypting parameters. + /// handle - Handle for the newly created session + /// nonceTPM - The initial nonce from the TPM, used in the computation of the sessionKey + pub fn StartAuthSession_complete( + &mut self, + ) -> Result { + let mut resp = StartAuthSessionResponse::default(); + self.tpm.process_response(TPM_CC::StartAuthSession, &mut resp)?; + Ok(resp) + } + + /// This command allows a policy authorization session to be returned to its initial state. + /// This command is used after the TPM returns TPM_RC_PCR_CHANGED. That response code + /// indicates that a policy will fail because the PCR have changed after TPM2_PolicyPCR() was + /// executed. Restarting the session allows the authorizations to be replayed because the + /// session restarts with the same nonceTPM. If the PCR are valid for the policy, the policy + /// may then succeed. + pub fn PolicyRestart_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::PolicyRestart, &mut resp)?; + Ok(()) + } + + /// This command is used to create an object that can be loaded into a TPM using TPM2_Load(). + /// If the command completes successfully, the TPM will create the new object and return the + /// objects creation data (creationData), its public area (outPublic), and its encrypted + /// sensitive area (outPrivate). Preservation of the returned data is the responsibility of + /// the caller. The object will need to be loaded (TPM2_Load()) before it may be used. The + /// only difference between the inPublic TPMT_PUBLIC template and the outPublic TPMT_PUBLIC + /// object is in the unique field. + /// outPrivate - The private portion of the object + /// outPublic - The public portion of the created object + /// creationData - Contains a TPMS_CREATION_DATA + /// creationHash - Digest of creationData using nameAlg of outPublic + /// creationTicket - Ticket used by TPM2_CertifyCreation() to validate that the creation + /// data was produced by the TPM + pub fn Create_complete( + &mut self, + ) -> Result { + let mut resp = CreateResponse::default(); + self.tpm.process_response(TPM_CC::Create, &mut resp)?; + Ok(resp) + } + + /// This command is used to load objects into the TPM. This command is used when both a + /// TPM2B_PUBLIC and TPM2B_PRIVATE are to be loaded. If only a TPM2B_PUBLIC is to be loaded, + /// the TPM2_LoadExternal command is used. + /// handle - Handle of type TPM_HT_TRANSIENT for the loaded object + /// name - Name of the loaded object + pub fn Load_complete( + &mut self, + ) -> Result { + let mut resp = LoadResponse::default(); + self.tpm.process_response(TPM_CC::Load, &mut resp)?; + Ok(resp) + } + + /// This command is used to load an object that is not a Protected Object into the TPM. The + /// command allows loading of a public area or both a public and sensitive area. + /// handle - Handle of type TPM_HT_TRANSIENT for the loaded object + /// name - Name of the loaded object + pub fn LoadExternal_complete( + &mut self, + ) -> Result { + let mut resp = LoadExternalResponse::default(); + self.tpm.process_response(TPM_CC::LoadExternal, &mut resp)?; + Ok(resp) + } + + /// This command allows access to the public area of a loaded object. + /// outPublic - Structure containing the public area of an object + /// name - Name of the object + /// qualifiedName - The Qualified Name of the object + pub fn ReadPublic_complete( + &mut self, + ) -> Result { + let mut resp = ReadPublicResponse::default(); + self.tpm.process_response(TPM_CC::ReadPublic, &mut resp)?; + Ok(resp) + } + + /// This command enables the association of a credential with an object in a way that ensures + /// that the TPM has validated the parameters of the credentialed object. + /// certInfo - The decrypted certificate information + /// the data should be no larger than the size of the digest of the nameAlg + /// associated with keyHandle + pub fn ActivateCredential_complete( + &mut self, + ) -> Result, TpmError> { + let mut resp = ActivateCredentialResponse::default(); + self.tpm.process_response(TPM_CC::ActivateCredential, &mut resp)?; + Ok(resp.certInfo) + } + + /// This command allows the TPM to perform the actions required of a Certificate Authority + /// (CA) in creating a TPM2B_ID_OBJECT containing an activation credential. + /// credentialBlob - The credential + /// secret - Handle algorithm-dependent data that wraps the key that encrypts credentialBlob + pub fn MakeCredential_complete( + &mut self, + ) -> Result { + let mut resp = MakeCredentialResponse::default(); + self.tpm.process_response(TPM_CC::MakeCredential, &mut resp)?; + Ok(resp) + } + + /// This command returns the data in a loaded Sealed Data Object. + /// outData - Unsealed data + /// Size of outData is limited to be no more than 128 octets. + pub fn Unseal_complete( + &mut self, + ) -> Result, TpmError> { + let mut resp = UnsealResponse::default(); + self.tpm.process_response(TPM_CC::Unseal, &mut resp)?; + Ok(resp.outData) + } + + /// This command is used to change the authorization secret for a TPM-resident object. + /// outPrivate - Private area containing the new authorization value + pub fn ObjectChangeAuth_complete( + &mut self, + ) -> Result { + let mut resp = ObjectChangeAuthResponse::default(); + self.tpm.process_response(TPM_CC::ObjectChangeAuth, &mut resp)?; + Ok(resp.outPrivate) + } + + /// This command creates an object and loads it in the TPM. This command allows creation of + /// any type of object (Primary, Ordinary, or Derived) depending on the type of parentHandle. + /// If parentHandle references a Primary Seed, then a Primary Object is created; if + /// parentHandle references a Storage Parent, then an Ordinary Object is created; and if + /// parentHandle references a Derivation Parent, then a Derived Object is generated. + /// handle - Handle of type TPM_HT_TRANSIENT for created object + /// outPrivate - The sensitive area of the object (optional) + /// outPublic - The public portion of the created object + /// name - The name of the created object + pub fn CreateLoaded_complete( + &mut self, + ) -> Result { + let mut resp = CreateLoadedResponse::default(); + self.tpm.process_response(TPM_CC::CreateLoaded, &mut resp)?; + Ok(resp) + } + + /// This command duplicates a loaded object so that it may be used in a different hierarchy. + /// The new parent key for the duplicate may be on the same or different TPM or TPM_RH_NULL. + /// Only the public area of newParentHandle is required to be loaded. + /// encryptionKeyOut - If the caller provided an encryption key or if symmetricAlg was + /// TPM_ALG_NULL, then this will be the Empty Buffer; otherwise, it + /// shall contain the TPM-generated, symmetric encryption key for the + /// inner wrapper. + /// duplicate - Private area that may be encrypted by encryptionKeyIn; and may be doubly encrypted + /// outSymSeed - Seed protected by the asymmetric algorithms of new parent (NP) + pub fn Duplicate_complete( + &mut self, + ) -> Result { + let mut resp = DuplicateResponse::default(); + self.tpm.process_response(TPM_CC::Duplicate, &mut resp)?; + Ok(resp) + } + + /// This command allows the TPM to serve in the role as a Duplication Authority. If proper + /// authorization for use of the oldParent is provided, then an HMAC key and a symmetric key + /// are recovered from inSymSeed and used to integrity check and decrypt inDuplicate. A new + /// protection seed value is generated according to the methods appropriate for newParent and + /// the blob is re-encrypted and a new integrity value is computed. The re-encrypted blob is + /// returned in outDuplicate and the symmetric key returned in outSymKey. + /// outDuplicate - An object encrypted using symmetric key derived from outSymSeed + /// outSymSeed - Seed for a symmetric key protected by newParent asymmetric key + pub fn Rewrap_complete( + &mut self, + ) -> Result { + let mut resp = RewrapResponse::default(); + self.tpm.process_response(TPM_CC::Rewrap, &mut resp)?; + Ok(resp) + } + + /// This command allows an object to be encrypted using the symmetric encryption values of a + /// Storage Key. After encryption, the object may be loaded and used in the new hierarchy. The + /// imported object (duplicate) may be singly encrypted, multiply encrypted, or unencrypted. + /// outPrivate - The sensitive area encrypted with the symmetric key of parentHandle + pub fn Import_complete( + &mut self, + ) -> Result { + let mut resp = ImportResponse::default(); + self.tpm.process_response(TPM_CC::Import, &mut resp)?; + Ok(resp.outPrivate) + } + + /// This command performs RSA encryption using the indicated padding scheme according to IETF + /// RFC 8017. If the scheme of keyHandle is TPM_ALG_NULL, then the caller may use inScheme to + /// specify the padding scheme. If scheme of keyHandle is not TPM_ALG_NULL, then inScheme + /// shall either be TPM_ALG_NULL or be the same as scheme (TPM_RC_SCHEME). + /// outData - Encrypted output + pub fn RSA_Encrypt_complete( + &mut self, + ) -> Result, TpmError> { + let mut resp = RSA_EncryptResponse::default(); + self.tpm.process_response(TPM_CC::RSA_Encrypt, &mut resp)?; + Ok(resp.outData) + } + + /// This command performs RSA decryption using the indicated padding scheme according to IETF + /// RFC 8017 ((PKCS#1). + /// message - Decrypted output + pub fn RSA_Decrypt_complete( + &mut self, + ) -> Result, TpmError> { + let mut resp = RSA_DecryptResponse::default(); + self.tpm.process_response(TPM_CC::RSA_Decrypt, &mut resp)?; + Ok(resp.message) + } + + /// This command uses the TPM to generate an ephemeral key pair (de, Qe where Qe [de]G). It + /// uses the private ephemeral key and a loaded public key (QS) to compute the shared secret + /// value (P [hde]QS). + /// zPoint - Results of P h[de]Qs + /// pubPoint - Generated ephemeral public point (Qe) + pub fn ECDH_KeyGen_complete( + &mut self, + ) -> Result { + let mut resp = ECDH_KeyGenResponse::default(); + self.tpm.process_response(TPM_CC::ECDH_KeyGen, &mut resp)?; + Ok(resp) + } + + /// This command uses the TPM to recover the Z value from a public point (QB) and a private + /// key (ds). It will perform the multiplication of the provided inPoint (QB) with the private + /// key (ds) and return the coordinates of the resultant point (Z = (xZ , yZ) [hds]QB; where h + /// is the cofactor of the curve). + /// outPoint - X and Y coordinates of the product of the multiplication Z = (xZ , yZ) [hdS]QB + pub fn ECDH_ZGen_complete( + &mut self, + ) -> Result { + let mut resp = ECDH_ZGenResponse::default(); + self.tpm.process_response(TPM_CC::ECDH_ZGen, &mut resp)?; + Ok(resp.outPoint) + } + + /// This command returns the parameters of an ECC curve identified by its TCG-assigned curveID. + /// parameters - ECC parameters for the selected curve + pub fn ECC_Parameters_complete( + &mut self, + ) -> Result { + let mut resp = ECC_ParametersResponse::default(); + self.tpm.process_response(TPM_CC::ECC_Parameters, &mut resp)?; + Ok(resp.parameters) + } + + /// This command supports two-phase key exchange protocols. The command is used in combination + /// with TPM2_EC_Ephemeral(). TPM2_EC_Ephemeral() generates an ephemeral key and returns the + /// public point of that ephemeral key along with a numeric value that allows the TPM to + /// regenerate the associated private key. + /// outZ1 - X and Y coordinates of the computed value (scheme dependent) + /// outZ2 - X and Y coordinates of the second computed value (scheme dependent) + pub fn ZGen_2Phase_complete( + &mut self, + ) -> Result { + let mut resp = ZGen_2PhaseResponse::default(); + self.tpm.process_response(TPM_CC::ZGen_2Phase, &mut resp)?; + Ok(resp) + } + + /// This command performs ECC encryption as described in Part 1, Annex D. + /// C1 - The public ephemeral key used for ECDH + /// C2 - The data block produced by the XOR process + /// C3 - The integrity value + pub fn ECC_Encrypt_complete( + &mut self, + ) -> Result { + let mut resp = ECC_EncryptResponse::default(); + self.tpm.process_response(TPM_CC::ECC_Encrypt, &mut resp)?; + Ok(resp) + } + + /// This command performs ECC decryption. + /// plainText - Decrypted output + pub fn ECC_Decrypt_complete( + &mut self, + ) -> Result, TpmError> { + let mut resp = ECC_DecryptResponse::default(); + self.tpm.process_response(TPM_CC::ECC_Decrypt, &mut resp)?; + Ok(resp.plainText) + } + + /// NOTE 1 This command is deprecated, and TPM2_EncryptDecrypt2() is preferred. This should be + /// reflected in platform-specific specifications. + /// outData - Encrypted or decrypted output + /// ivOut - Chaining value to use for IV in next round + pub fn EncryptDecrypt_complete( + &mut self, + ) -> Result { + let mut resp = EncryptDecryptResponse::default(); + self.tpm.process_response(TPM_CC::EncryptDecrypt, &mut resp)?; + Ok(resp) + } + + /// This command is identical to TPM2_EncryptDecrypt(), except that the inData parameter is + /// the first parameter. This permits inData to be parameter encrypted. + /// outData - Encrypted or decrypted output + /// ivOut - Chaining value to use for IV in next round + pub fn EncryptDecrypt2_complete( + &mut self, + ) -> Result { + let mut resp = EncryptDecrypt2Response::default(); + self.tpm.process_response(TPM_CC::EncryptDecrypt2, &mut resp)?; + Ok(resp) + } + + /// This command performs a hash operation on a data buffer and returns the results. + /// outHash - Results + /// validation - Ticket indicating that the sequence of octets used to compute outDigest + /// did not start with TPM_GENERATED_VALUE + /// will be a NULL ticket if the digest may not be signed with a restricted key + pub fn Hash_complete( + &mut self, + ) -> Result { + let mut resp = HashResponse::default(); + self.tpm.process_response(TPM_CC::Hash, &mut resp)?; + Ok(resp) + } + + /// This command performs an HMAC on the supplied data using the indicated hash algorithm. + /// outHMAC - The returned HMAC in a sized buffer + pub fn HMAC_complete( + &mut self, + ) -> Result, TpmError> { + let mut resp = HMACResponse::default(); + self.tpm.process_response(TPM_CC::HMAC, &mut resp)?; + Ok(resp.outHMAC) + } + + /// This command performs an HMAC or a block cipher MAC on the supplied data using the + /// indicated algorithm. + /// outMAC - The returned MAC in a sized buffer + pub fn MAC_complete( + &mut self, + ) -> Result, TpmError> { + let mut resp = MACResponse::default(); + self.tpm.process_response(TPM_CC::MAC, &mut resp)?; + Ok(resp.outMAC) + } + + /// This command returns the next bytesRequested octets from the random number generator (RNG). + /// randomBytes - The random octets + pub fn GetRandom_complete( + &mut self, + ) -> Result, TpmError> { + let mut resp = GetRandomResponse::default(); + self.tpm.process_response(TPM_CC::GetRandom, &mut resp)?; + Ok(resp.randomBytes) + } + + /// This command is used to add "additional information" to the RNG state. + pub fn StirRandom_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::StirRandom, &mut resp)?; + Ok(()) + } + + /// This command starts an HMAC sequence. The TPM will create and initialize an HMAC sequence + /// structure, assign a handle to the sequence, and set the authValue of the sequence object + /// to the value in auth. + /// handle - A handle to reference the sequence + pub fn HMAC_Start_complete( + &mut self, + ) -> Result { + let mut resp = HMAC_StartResponse::default(); + self.tpm.process_response(TPM_CC::HMAC_Start, &mut resp)?; + Ok(resp.handle) + } + + /// This command starts a MAC sequence. The TPM will create and initialize a MAC sequence + /// structure, assign a handle to the sequence, and set the authValue of the sequence object + /// to the value in auth. + /// handle - A handle to reference the sequence + pub fn MAC_Start_complete( + &mut self, + ) -> Result { + let mut resp = MAC_StartResponse::default(); + self.tpm.process_response(TPM_CC::MAC_Start, &mut resp)?; + Ok(resp.handle) + } + + /// This command starts a hash or an Event Sequence. If hashAlg is an implemented hash, then a + /// hash sequence is started. If hashAlg is TPM_ALG_NULL, then an Event Sequence is started. + /// If hashAlg is neither an implemented algorithm nor TPM_ALG_NULL, then the TPM shall return + /// TPM_RC_HASH. + /// handle - A handle to reference the sequence + pub fn HashSequenceStart_complete( + &mut self, + ) -> Result { + let mut resp = HashSequenceStartResponse::default(); + self.tpm.process_response(TPM_CC::HashSequenceStart, &mut resp)?; + Ok(resp.handle) + } + + /// This command is used to add data to a hash or HMAC sequence. The amount of data in buffer + /// may be any size up to the limits of the TPM. + pub fn SequenceUpdate_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::SequenceUpdate, &mut resp)?; + Ok(()) + } + + /// This command adds the last part of data, if any, to a hash/HMAC sequence and returns the result. + /// result - The returned HMAC or digest in a sized buffer + /// validation - Ticket indicating that the sequence of octets used to compute outDigest + /// did not start with TPM_GENERATED_VALUE + /// This is a NULL Ticket when the sequence is HMAC. + pub fn SequenceComplete_complete( + &mut self, + ) -> Result { + let mut resp = SequenceCompleteResponse::default(); + self.tpm.process_response(TPM_CC::SequenceComplete, &mut resp)?; + Ok(resp) + } + + /// This command adds the last part of data, if any, to an Event Sequence and returns the + /// result in a digest list. If pcrHandle references a PCR and not TPM_RH_NULL, then the + /// returned digest list is processed in the same manner as the digest list input parameter to + /// TPM2_PCR_Extend(). That is, if a bank contains a PCR associated with pcrHandle, it is + /// extended with the associated digest value from the list. + /// results - List of digests computed for the PCR + pub fn EventSequenceComplete_complete( + &mut self, + ) -> Result, TpmError> { + let mut resp = EventSequenceCompleteResponse::default(); + self.tpm.process_response(TPM_CC::EventSequenceComplete, &mut resp)?; + Ok(resp.results) + } + + /// The purpose of this command is to prove that an object with a specific Name is loaded in + /// the TPM. By certifying that the object is loaded, the TPM warrants that a public area with + /// a given Name is self-consistent and associated with a valid sensitive area. If a relying + /// party has a public area that has the same Name as a Name certified with this command, then + /// the values in that public area are correct. + /// certifyInfo - The structure that was signed + /// signature - The asymmetric signature over certifyInfo using the key referenced by signHandle + pub fn Certify_complete( + &mut self, + ) -> Result { + let mut resp = CertifyResponse::default(); + self.tpm.process_response(TPM_CC::Certify, &mut resp)?; + Ok(resp) + } + + /// This command is used to prove the association between an object and its creation data. The + /// TPM will validate that the ticket was produced by the TPM and that the ticket validates + /// the association between a loaded public area and the provided hash of the creation data + /// (creationHash). + /// certifyInfo - The structure that was signed + /// signature - The signature over certifyInfo + pub fn CertifyCreation_complete( + &mut self, + ) -> Result { + let mut resp = CertifyCreationResponse::default(); + self.tpm.process_response(TPM_CC::CertifyCreation, &mut resp)?; + Ok(resp) + } + + /// This command is used to quote PCR values. + /// quoted - The quoted information + /// signature - The signature over quoted + pub fn Quote_complete( + &mut self, + ) -> Result { + let mut resp = QuoteResponse::default(); + self.tpm.process_response(TPM_CC::Quote, &mut resp)?; + Ok(resp) + } + + /// This command returns a digital signature of the audit session digest. + /// auditInfo - The audit information that was signed + /// signature - The signature over auditInfo + pub fn GetSessionAuditDigest_complete( + &mut self, + ) -> Result { + let mut resp = GetSessionAuditDigestResponse::default(); + self.tpm.process_response(TPM_CC::GetSessionAuditDigest, &mut resp)?; + Ok(resp) + } + + /// This command returns the current value of the command audit digest, a digest of the + /// commands being audited, and the audit hash algorithm. These values are placed in an + /// attestation structure and signed with the key referenced by signHandle. + /// auditInfo - The auditInfo that was signed + /// signature - The signature over auditInfo + pub fn GetCommandAuditDigest_complete( + &mut self, + ) -> Result { + let mut resp = GetCommandAuditDigestResponse::default(); + self.tpm.process_response(TPM_CC::GetCommandAuditDigest, &mut resp)?; + Ok(resp) + } + + /// This command returns the current values of Time and Clock. + /// timeInfo - Standard TPM-generated attestation block + /// signature - The signature over timeInfo + pub fn GetTime_complete( + &mut self, + ) -> Result { + let mut resp = GetTimeResponse::default(); + self.tpm.process_response(TPM_CC::GetTime, &mut resp)?; + Ok(resp) + } + + /// The purpose of this command is to generate an X.509 certificate that proves an object with + /// a specific public key and attributes is loaded in the TPM. In contrast to TPM2_Certify, + /// which uses a TCG-defined data structure to convey attestation information, + /// TPM2_CertifyX509 encodes the attestation information in a DER-encoded X.509 certificate + /// that is compliant with RFC5280 Internet X.509 Public Key Infrastructure Certificate and + /// Certificate Revocation List (CRL) Profile. + /// addedToCertificate - A DER encoded SEQUENCE containing the DER encoded fields added to + /// partialCertificate to make it a complete RFC5280 TBSCertificate. + /// tbsDigest - The digest that was signed + /// signature - The signature over tbsDigest + pub fn CertifyX509_complete( + &mut self, + ) -> Result { + let mut resp = CertifyX509Response::default(); + self.tpm.process_response(TPM_CC::CertifyX509, &mut resp)?; + Ok(resp) + } + + /// TPM2_Commit() performs the first part of an ECC anonymous signing operation. The TPM will + /// perform the point multiplications on the provided points and return intermediate signing + /// values. The signHandle parameter shall refer to an ECC key and the signing scheme must be + /// anonymous (TPM_RC_SCHEME). + /// K - ECC point K [ds](x2, y2) + /// L - ECC point L [r](x2, y2) + /// E - ECC point E [r]P1 + /// counter - Least-significant 16 bits of commitCount + pub fn Commit_complete( + &mut self, + ) -> Result { + let mut resp = CommitResponse::default(); + self.tpm.process_response(TPM_CC::Commit, &mut resp)?; + Ok(resp) + } + + /// TPM2_EC_Ephemeral() creates an ephemeral key for use in a two-phase key exchange protocol. + /// Q - Ephemeral public key Q [r]G + /// counter - Least-significant 16 bits of commitCount + pub fn EC_Ephemeral_complete( + &mut self, + ) -> Result { + let mut resp = EC_EphemeralResponse::default(); + self.tpm.process_response(TPM_CC::EC_Ephemeral, &mut resp)?; + Ok(resp) + } + + /// This command uses loaded keys to validate a signature on a message with the message digest + /// passed to the TPM. + /// validation - This ticket is produced by TPM2_VerifySignature(). This formulation is + /// used for multiple ticket uses. The ticket provides evidence that the TPM + /// has validated that a digest was signed by a key with the Name of keyName. + /// The ticket is computed by + pub fn VerifySignature_complete( + &mut self, + ) -> Result { + let mut resp = VerifySignatureResponse::default(); + self.tpm.process_response(TPM_CC::VerifySignature, &mut resp)?; + Ok(resp.validation) + } + + /// This command causes the TPM to sign an externally provided hash with the specified + /// symmetric or asymmetric signing key. + /// signature - The signature + pub fn Sign_complete( + &mut self, + ) -> Result, TpmError> { + let mut resp = SignResponse::default(); + self.tpm.process_response(TPM_CC::Sign, &mut resp)?; + Ok(resp.signature) + } + + /// This command may be used by the Privacy Administrator or platform to change the audit + /// status of a command or to set the hash algorithm used for the audit digest, but not both + /// at the same time. + pub fn SetCommandCodeAuditStatus_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::SetCommandCodeAuditStatus, &mut resp)?; + Ok(()) + } + + /// This command is used to cause an update to the indicated PCR. The digests parameter + /// contains one or more tagged digest values identified by an algorithm ID. For each digest, + /// the PCR associated with pcrHandle is Extended into the bank identified by the tag (hashAlg). + pub fn PCR_Extend_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::PCR_Extend, &mut resp)?; + Ok(()) + } + + /// This command is used to cause an update to the indicated PCR. + /// digests - Table 80 shows the basic hash-agile structure used in this specification. To + /// handle hash agility, this structure uses the hashAlg parameter to indicate + /// the algorithm used to compute the digest and, by implication, the size of + /// the digest. + pub fn PCR_Event_complete( + &mut self, + ) -> Result, TpmError> { + let mut resp = PCR_EventResponse::default(); + self.tpm.process_response(TPM_CC::PCR_Event, &mut resp)?; + Ok(resp.digests) + } + + /// This command returns the values of all PCR specified in pcrSelectionIn. + /// pcrUpdateCounter - The current value of the PCR update counter + /// pcrSelectionOut - The PCR in the returned list + /// pcrValues - The contents of the PCR indicated in pcrSelectOut-˃ pcrSelection[] as + /// tagged digests + pub fn PCR_Read_complete( + &mut self, + ) -> Result { + let mut resp = PCR_ReadResponse::default(); + self.tpm.process_response(TPM_CC::PCR_Read, &mut resp)?; + Ok(resp) + } + + /// This command is used to set the desired PCR allocation of PCR and algorithms. This command + /// requires Platform Authorization. + /// allocationSuccess - YES if the allocation succeeded + /// maxPCR - Maximum number of PCR that may be in a bank + /// sizeNeeded - Number of octets required to satisfy the request + /// sizeAvailable - Number of octets available. Computed before the allocation. + pub fn PCR_Allocate_complete( + &mut self, + ) -> Result { + let mut resp = PCR_AllocateResponse::default(); + self.tpm.process_response(TPM_CC::PCR_Allocate, &mut resp)?; + Ok(resp) + } + + /// This command is used to associate a policy with a PCR or group of PCR. The policy + /// determines the conditions under which a PCR may be extended or reset. + pub fn PCR_SetAuthPolicy_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::PCR_SetAuthPolicy, &mut resp)?; + Ok(()) + } + + /// This command changes the authValue of a PCR or group of PCR. + pub fn PCR_SetAuthValue_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::PCR_SetAuthValue, &mut resp)?; + Ok(()) + } + + /// If the attribute of a PCR allows the PCR to be reset and proper authorization is provided, + /// then this command may be used to set the PCR in all banks to zero. The attributes of the + /// PCR may restrict the locality that can perform the reset operation. + pub fn PCR_Reset_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::PCR_Reset, &mut resp)?; + Ok(()) + } + + /// This command includes a signed authorization in a policy. The command ties the policy to a + /// signing key by including the Name of the signing key in the policyDigest + /// timeout - Implementation-specific time value, used to indicate to the TPM when the + /// ticket expires + /// NOTE If policyTicket is a NULL Ticket, then this shall be the Empty Buffer. + /// policyTicket - Produced if the command succeeds and expiration in the command was + /// non-zero; this ticket will use the TPMT_ST_AUTH_SIGNED structure tag. + /// See 23.2.5 + pub fn PolicySigned_complete( + &mut self, + ) -> Result { + let mut resp = PolicySignedResponse::default(); + self.tpm.process_response(TPM_CC::PolicySigned, &mut resp)?; + Ok(resp) + } + + /// This command includes a secret-based authorization to a policy. The caller proves + /// knowledge of the secret value using an authorization session using the authValue + /// associated with authHandle. A password session, an HMAC session, or a policy session + /// containing TPM2_PolicyAuthValue() or TPM2_PolicyPassword() will satisfy this requirement. + /// timeout - Implementation-specific time value used to indicate to the TPM when the + /// ticket expires + /// policyTicket - Produced if the command succeeds and expiration in the command was + /// non-zero ( See 23.2.5). This ticket will use the TPMT_ST_AUTH_SECRET + /// structure tag + pub fn PolicySecret_complete( + &mut self, + ) -> Result { + let mut resp = PolicySecretResponse::default(); + self.tpm.process_response(TPM_CC::PolicySecret, &mut resp)?; + Ok(resp) + } + + /// This command is similar to TPM2_PolicySigned() except that it takes a ticket instead of a + /// signed authorization. The ticket represents a validated authorization that had an + /// expiration time associated with it. + pub fn PolicyTicket_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::PolicyTicket, &mut resp)?; + Ok(()) + } + + /// This command allows options in authorizations without requiring that the TPM evaluate all + /// of the options. If a policy may be satisfied by different sets of conditions, the TPM need + /// only evaluate one set that satisfies the policy. This command will indicate that one of + /// the required sets of conditions has been satisfied. + pub fn PolicyOR_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::PolicyOR, &mut resp)?; + Ok(()) + } + + /// This command is used to cause conditional gating of a policy based on PCR. This command + /// together with TPM2_PolicyOR() allows one group of authorizations to occur when PCR are in + /// one state and a different set of authorizations when the PCR are in a different state. + pub fn PolicyPCR_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::PolicyPCR, &mut resp)?; + Ok(()) + } + + /// This command indicates that the authorization will be limited to a specific locality. + pub fn PolicyLocality_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::PolicyLocality, &mut resp)?; + Ok(()) + } + + /// This command is used to cause conditional gating of a policy based on the contents of an + /// NV Index. It is an immediate assertion. The NV index is validated during the + /// TPM2_PolicyNV() command, not when the session is used for authorization. + pub fn PolicyNV_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::PolicyNV, &mut resp)?; + Ok(()) + } + + /// This command is used to cause conditional gating of a policy based on the contents of the + /// TPMS_TIME_INFO structure. + pub fn PolicyCounterTimer_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::PolicyCounterTimer, &mut resp)?; + Ok(()) + } + + /// This command indicates that the authorization will be limited to a specific command code. + pub fn PolicyCommandCode_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::PolicyCommandCode, &mut resp)?; + Ok(()) + } + + /// This command indicates that physical presence will need to be asserted at the time the + /// authorization is performed. + pub fn PolicyPhysicalPresence_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::PolicyPhysicalPresence, &mut resp)?; + Ok(()) + } + + /// This command is used to allow a policy to be bound to a specific command and command parameters. + pub fn PolicyCpHash_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::PolicyCpHash, &mut resp)?; + Ok(()) + } + + /// This command allows a policy to be bound to a specific set of TPM entities without being + /// bound to the parameters of the command. This is most useful for commands such as + /// TPM2_Duplicate() and for TPM2_PCR_Event() when the referenced PCR requires a policy. + pub fn PolicyNameHash_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::PolicyNameHash, &mut resp)?; + Ok(()) + } + + /// This command allows qualification of duplication to allow duplication to a selected new parent. + pub fn PolicyDuplicationSelect_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::PolicyDuplicationSelect, &mut resp)?; + Ok(()) + } + + /// This command allows policies to change. If a policy were static, then it would be + /// difficult to add users to a policy. This command lets a policy authority sign a new policy + /// so that it may be used in an existing policy. + pub fn PolicyAuthorize_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::PolicyAuthorize, &mut resp)?; + Ok(()) + } + + /// This command allows a policy to be bound to the authorization value of the authorized entity. + pub fn PolicyAuthValue_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::PolicyAuthValue, &mut resp)?; + Ok(()) + } + + /// This command allows a policy to be bound to the authorization value of the authorized object. + pub fn PolicyPassword_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::PolicyPassword, &mut resp)?; + Ok(()) + } + + /// This command returns the current policyDigest of the session. This command allows the TPM + /// to be used to perform the actions required to pre-compute the authPolicy for an object. + /// policyDigest - The current value of the policySessionpolicyDigest + pub fn PolicyGetDigest_complete( + &mut self, + ) -> Result, TpmError> { + let mut resp = PolicyGetDigestResponse::default(); + self.tpm.process_response(TPM_CC::PolicyGetDigest, &mut resp)?; + Ok(resp.policyDigest) + } + + /// This command allows a policy to be bound to the TPMA_NV_WRITTEN attributes. This is a + /// deferred assertion. Values are stored in the policy session context and checked when the + /// policy is used for authorization. + pub fn PolicyNvWritten_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::PolicyNvWritten, &mut resp)?; + Ok(()) + } + + /// This command allows a policy to be bound to a specific creation template. This is most + /// useful for an object creation command such as TPM2_Create(), TPM2_CreatePrimary(), or + /// TPM2_CreateLoaded(). + pub fn PolicyTemplate_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::PolicyTemplate, &mut resp)?; + Ok(()) + } + + /// This command provides a capability that is the equivalent of a revocable policy. With + /// TPM2_PolicyAuthorize(), the authorization ticket never expires, so the authorization may + /// not be withdrawn. With this command, the approved policy is kept in an NV Index location + /// so that the policy may be changed as needed to render the old policy unusable. + pub fn PolicyAuthorizeNV_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::PolicyAuthorizeNV, &mut resp)?; + Ok(()) + } + + /// This command is used to create a Primary Object under one of the Primary Seeds or a + /// Temporary Object under TPM_RH_NULL. The command uses a TPM2B_PUBLIC as a template for the + /// object to be created. The size of the unique field shall not be checked for consistency + /// with the other object parameters. The command will create and load a Primary Object. The + /// sensitive area is not returned. + /// handle - Handle of type TPM_HT_TRANSIENT for created Primary Object + /// outPublic - The public portion of the created object + /// creationData - Contains a TPMT_CREATION_DATA + /// creationHash - Digest of creationData using nameAlg of outPublic + /// creationTicket - Ticket used by TPM2_CertifyCreation() to validate that the creation + /// data was produced by the TPM + /// name - The name of the created object + pub fn CreatePrimary_complete( + &mut self, + ) -> Result { + let mut resp = CreatePrimaryResponse::default(); + self.tpm.process_response(TPM_CC::CreatePrimary, &mut resp)?; + Ok(resp) + } + + /// This command enables and disables use of a hierarchy and its associated NV storage. The + /// command allows phEnable, phEnableNV, shEnable, and ehEnable to be changed when the proper + /// authorization is provided. + pub fn HierarchyControl_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::HierarchyControl, &mut resp)?; + Ok(()) + } + + /// This command allows setting of the authorization policy for the lockout (lockoutPolicy), + /// the platform hierarchy (platformPolicy), the storage hierarchy (ownerPolicy), and the + /// endorsement hierarchy (endorsementPolicy). On TPMs implementing Authenticated Countdown + /// Timers (ACT), this command may also be used to set the authorization policy for an ACT. + pub fn SetPrimaryPolicy_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::SetPrimaryPolicy, &mut resp)?; + Ok(()) + } + + /// This replaces the current platform primary seed (PPS) with a value from the RNG and sets + /// platformPolicy to the default initialization value (the Empty Buffer). + pub fn ChangePPS_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::ChangePPS, &mut resp)?; + Ok(()) + } + + /// This replaces the current endorsement primary seed (EPS) with a value from the RNG and + /// sets the Endorsement hierarchy controls to their default initialization values: ehEnable + /// is SET, endorsementAuth and endorsementPolicy are both set to the Empty Buffer. It will + /// flush any resident objects (transient or persistent) in the Endorsement hierarchy and not + /// allow objects in the hierarchy associated with the previous EPS to be loaded. + pub fn ChangeEPS_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::ChangeEPS, &mut resp)?; + Ok(()) + } + + /// This command removes all TPM context associated with a specific Owner. + pub fn Clear_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::Clear, &mut resp)?; + Ok(()) + } + + /// TPM2_ClearControl() disables and enables the execution of TPM2_Clear(). + pub fn ClearControl_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::ClearControl, &mut resp)?; + Ok(()) + } + + /// This command allows the authorization secret for a hierarchy or lockout to be changed + /// using the current authorization value as the command authorization. + pub fn HierarchyChangeAuth_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::HierarchyChangeAuth, &mut resp)?; + Ok(()) + } + + /// This command cancels the effect of a TPM lockout due to a number of successive + /// authorization failures. If this command is properly authorized, the lockout counter is set + /// to zero. + pub fn DictionaryAttackLockReset_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::DictionaryAttackLockReset, &mut resp)?; + Ok(()) + } + + /// This command changes the lockout parameters. + pub fn DictionaryAttackParameters_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::DictionaryAttackParameters, &mut resp)?; + Ok(()) + } + + /// This command is used to determine which commands require assertion of Physical Presence + /// (PP) in addition to platformAuth/platformPolicy. + pub fn PP_Commands_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::PP_Commands, &mut resp)?; + Ok(()) + } + + /// This command allows the platform to change the set of algorithms that are used by the TPM. + /// The algorithmSet setting is a vendor-dependent value. + pub fn SetAlgorithmSet_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::SetAlgorithmSet, &mut resp)?; + Ok(()) + } + + /// This command uses platformPolicy and a TPM Vendor Authorization Key to authorize a Field + /// Upgrade Manifest. + pub fn FieldUpgradeStart_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::FieldUpgradeStart, &mut resp)?; + Ok(()) + } + + /// This command will take the actual field upgrade image to be installed on the TPM. The + /// exact format of fuData is vendor-specific. This command is only possible following a + /// successful TPM2_FieldUpgradeStart(). If the TPM has not received a properly authorized + /// TPM2_FieldUpgradeStart(), then the TPM shall return TPM_RC_FIELDUPGRADE. + /// nextDigest - Tagged digest of the next block + /// TPM_ALG_NULL if field update is complete + /// firstDigest - Tagged digest of the first block of the sequence + pub fn FieldUpgradeData_complete( + &mut self, + ) -> Result { + let mut resp = FieldUpgradeDataResponse::default(); + self.tpm.process_response(TPM_CC::FieldUpgradeData, &mut resp)?; + Ok(resp) + } + + /// This command is used to read a copy of the current firmware installed in the TPM. + /// fuData - Field upgrade image data + pub fn FirmwareRead_complete( + &mut self, + ) -> Result, TpmError> { + let mut resp = FirmwareReadResponse::default(); + self.tpm.process_response(TPM_CC::FirmwareRead, &mut resp)?; + Ok(resp.fuData) + } + + /// This command saves a session context, object context, or sequence object context outside + /// the TPM. + /// context - This structure is used in TPM2_ContextLoad() and TPM2_ContextSave(). If the + /// values of the TPMS_CONTEXT structure in TPM2_ContextLoad() are not the same + /// as the values when the context was saved (TPM2_ContextSave()), then the TPM + /// shall not load the context. + pub fn ContextSave_complete( + &mut self, + ) -> Result { + let mut resp = ContextSaveResponse::default(); + self.tpm.process_response(TPM_CC::ContextSave, &mut resp)?; + Ok(resp.context) + } + + /// This command is used to reload a context that has been saved by TPM2_ContextSave(). + /// handle - The handle assigned to the resource after it has been successfully loaded + pub fn ContextLoad_complete( + &mut self, + ) -> Result { + let mut resp = ContextLoadResponse::default(); + self.tpm.process_response(TPM_CC::ContextLoad, &mut resp)?; + Ok(resp.handle) + } + + /// This command causes all context associated with a loaded object, sequence object, or + /// session to be removed from TPM memory. + pub fn FlushContext_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::FlushContext, &mut resp)?; + Ok(()) + } + + /// This command allows certain Transient Objects to be made persistent or a persistent object + /// to be evicted. + pub fn EvictControl_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::EvictControl, &mut resp)?; + Ok(()) + } + + /// This command reads the current TPMS_TIME_INFO structure that contains the current setting + /// of Time, Clock, resetCount, and restartCount. + /// currentTime - This structure is used in, e.g., the TPM2_GetTime() attestation and + /// TPM2_ReadClock(). + pub fn ReadClock_complete( + &mut self, + ) -> Result { + let mut resp = ReadClockResponse::default(); + self.tpm.process_response(TPM_CC::ReadClock, &mut resp)?; + Ok(resp.currentTime) + } + + /// This command is used to advance the value of the TPMs Clock. The command will fail if + /// newTime is less than the current value of Clock or if the new time is greater than + /// FFFF00000000000016. If both of these checks succeed, Clock is set to newTime. If either of + /// these checks fails, the TPM shall return TPM_RC_VALUE and make no change to Clock. + pub fn ClockSet_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::ClockSet, &mut resp)?; + Ok(()) + } + + /// This command adjusts the rate of advance of Clock and Time to provide a better + /// approximation to real time. + pub fn ClockRateAdjust_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::ClockRateAdjust, &mut resp)?; + Ok(()) + } + + /// This command returns various information regarding the TPM and its current state. + /// moreData - Flag to indicate if there are more values of this type + /// capabilityData - The capability data + pub fn GetCapability_complete( + &mut self, + ) -> Result { + let mut resp = GetCapabilityResponse::default(); + self.tpm.process_response(TPM_CC::GetCapability, &mut resp)?; + Ok(resp) + } + + /// This command is used to check to see if specific combinations of algorithm parameters are supported. + pub fn TestParms_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::TestParms, &mut resp)?; + Ok(()) + } + + /// This command defines the attributes of an NV Index and causes the TPM to reserve space to + /// hold the data associated with the NV Index. If a definition already exists at the NV + /// Index, the TPM will return TPM_RC_NV_DEFINED. + pub fn NV_DefineSpace_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::NV_DefineSpace, &mut resp)?; + Ok(()) + } + + /// This command removes an Index from the TPM. + pub fn NV_UndefineSpace_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::NV_UndefineSpace, &mut resp)?; + Ok(()) + } + + /// This command allows removal of a platform-created NV Index that has TPMA_NV_POLICY_DELETE SET. + pub fn NV_UndefineSpaceSpecial_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::NV_UndefineSpaceSpecial, &mut resp)?; + Ok(()) + } + + /// This command is used to read the public area and Name of an NV Index. The public area of + /// an Index is not privacy-sensitive and no authorization is required to read this data. + /// nvPublic - The public area of the NV Index + /// nvName - The Name of the nvIndex + pub fn NV_ReadPublic_complete( + &mut self, + ) -> Result { + let mut resp = NV_ReadPublicResponse::default(); + self.tpm.process_response(TPM_CC::NV_ReadPublic, &mut resp)?; + Ok(resp) + } + + /// This command writes a value to an area in NV memory that was previously defined by + /// TPM2_NV_DefineSpace(). + pub fn NV_Write_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::NV_Write, &mut resp)?; + Ok(()) + } + + /// This command is used to increment the value in an NV Index that has the TPM_NT_COUNTER + /// attribute. The data value of the NV Index is incremented by one. + pub fn NV_Increment_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::NV_Increment, &mut resp)?; + Ok(()) + } + + /// This command extends a value to an area in NV memory that was previously defined by + /// TPM2_NV_DefineSpace. + pub fn NV_Extend_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::NV_Extend, &mut resp)?; + Ok(()) + } + + /// This command is used to SET bits in an NV Index that was created as a bit field. Any + /// number of bits from 0 to 64 may be SET. The contents of bits are ORed with the current + /// contents of the NV Index. + pub fn NV_SetBits_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::NV_SetBits, &mut resp)?; + Ok(()) + } + + /// If the TPMA_NV_WRITEDEFINE or TPMA_NV_WRITE_STCLEAR attributes of an NV location are SET, + /// then this command may be used to inhibit further writes of the NV Index. + pub fn NV_WriteLock_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::NV_WriteLock, &mut resp)?; + Ok(()) + } + + /// The command will SET TPMA_NV_WRITELOCKED for all indexes that have their + /// TPMA_NV_GLOBALLOCK attribute SET. + pub fn NV_GlobalWriteLock_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::NV_GlobalWriteLock, &mut resp)?; + Ok(()) + } + + /// This command reads a value from an area in NV memory previously defined by TPM2_NV_DefineSpace(). + /// data - The data read + pub fn NV_Read_complete( + &mut self, + ) -> Result, TpmError> { + let mut resp = NV_ReadResponse::default(); + self.tpm.process_response(TPM_CC::NV_Read, &mut resp)?; + Ok(resp.data) + } + + /// If TPMA_NV_READ_STCLEAR is SET in an Index, then this command may be used to prevent + /// further reads of the NV Index until the next TPM2_Startup (TPM_SU_CLEAR). + pub fn NV_ReadLock_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::NV_ReadLock, &mut resp)?; + Ok(()) + } + + /// This command allows the authorization secret for an NV Index to be changed. + pub fn NV_ChangeAuth_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::NV_ChangeAuth, &mut resp)?; + Ok(()) + } + + /// The purpose of this command is to certify the contents of an NV Index or portion of an NV Index. + /// certifyInfo - The structure that was signed + /// signature - The asymmetric signature over certifyInfo using the key referenced by signHandle + pub fn NV_Certify_complete( + &mut self, + ) -> Result { + let mut resp = NV_CertifyResponse::default(); + self.tpm.process_response(TPM_CC::NV_Certify, &mut resp)?; + Ok(resp) + } + + /// The purpose of this command is to obtain information about an Attached Component + /// referenced by an AC handle. + /// moreData - Flag to indicate whether there are more values + /// capabilitiesData - List of capabilities + pub fn AC_GetCapability_complete( + &mut self, + ) -> Result { + let mut resp = AC_GetCapabilityResponse::default(); + self.tpm.process_response(TPM_CC::AC_GetCapability, &mut resp)?; + Ok(resp) + } + + /// The purpose of this command is to send (copy) a loaded object from the TPM to an Attached Component. + /// acDataOut - May include AC specific data or information about an error. + pub fn AC_Send_complete( + &mut self, + ) -> Result { + let mut resp = AC_SendResponse::default(); + self.tpm.process_response(TPM_CC::AC_Send, &mut resp)?; + Ok(resp.acDataOut) + } + + /// This command allows qualification of the sending (copying) of an Object to an Attached + /// Component (AC). Qualification includes selection of the receiving AC and the method of + /// authentication for the AC, and, in certain circumstances, the Object to be sent may be specified. + pub fn Policy_AC_SendSelect_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::Policy_AC_SendSelect, &mut resp)?; + Ok(()) + } + + /// This command is used to set the time remaining before an Authenticated Countdown Timer + /// (ACT) expires. + pub fn ACT_SetTimeout_complete( + &mut self, + ) -> Result<(), TpmError> { + let mut resp = EmptyTpmResponse::default(); + self.tpm.process_response(TPM_CC::ACT_SetTimeout, &mut resp)?; + Ok(()) + } + + /// This is a placeholder to allow testing of the dispatch code. + /// outputData - Dummy data + pub fn Vendor_TCG_Test_complete( + &mut self, + ) -> Result, TpmError> { + let mut resp = Vendor_TCG_TestResponse::default(); + self.tpm.process_response(TPM_CC::Vendor_TCG_Test, &mut resp)?; + Ok(resp.outputData) + } + +} + diff --git a/TSS.Rust/src/tpm2_helpers.rs b/TSS.Rust/src/tpm2_helpers.rs new file mode 100644 index 00000000..34904e5d --- /dev/null +++ b/TSS.Rust/src/tpm2_helpers.rs @@ -0,0 +1,55 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See the LICENSE file in the project root for full license information. + */ + +use crate::{tpm_buffer::TpmBuffer, tpm_types::ENUM_TO_STR_MAP}; + +/// Convert a numeric enum value to its string representation +/// +/// # Arguments +/// +/// * `enum_val` - The numeric value of the enum +/// * `enum_id` - The identifier of the enum type +/// +/// # Returns +/// +/// The string representation of the enum value, or a formatted string of OR'd values +pub fn enum_to_str(enum_val: u64, enum_id: std::any::TypeId) -> String { + let mut res = String::new(); + + // Try to find the exact enum value in the map + if let Some(enum_map) = ENUM_TO_STR_MAP.get(&enum_id) { + if let Some(name) = enum_map.get(&enum_val) { + return name.to_string(); + } + + // If not found as an exact match, try to decompose as bit flags + let mut cur_bit: u64 = 1; + let mut found_bits: u64 = 0; + + while (found_bits != enum_val) { + if (cur_bit & enum_val) != 0 { + found_bits |= cur_bit; + + if !res.is_empty() { + res.push_str(" | "); + } + + if let Some(bit_name) = enum_map.get(&cur_bit) { + res.push_str(bit_name); + } + } + + cur_bit <<= 1; + } + } + + res // Return empty string if enum ID is not found +} + +pub fn int_to_tpm>(val: T) -> Vec { + let mut buffer = TpmBuffer::new(None); + buffer.write_num(val.into(), std::mem::size_of::().into()); + buffer.trim().to_vec() +} \ No newline at end of file diff --git a/TSS.Rust/src/tpm2_impl.rs b/TSS.Rust/src/tpm2_impl.rs new file mode 100644 index 00000000..74936a83 --- /dev/null +++ b/TSS.Rust/src/tpm2_impl.rs @@ -0,0 +1,1309 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See the LICENSE file in the project root for full license information. + */ + +use crate::auth_session::Session; +use crate::crypto::Crypto; +use crate::device::TpmDevice; +use crate::error::TpmError; +use crate::tpm_buffer::{TpmBuffer, TpmMarshaller}; +use crate::tpm_structure::{CmdStructure, ReqStructure, RespStructure, TpmEnum}; +use crate::tpm_types::{ + TPMA_SESSION, TPMS_AUTH_COMMAND, TPMS_AUTH_RESPONSE, TPMT_HA, TPMT_SYM_DEF, TPM_ALG_ID, + TPM_CC, TPM_HANDLE, TPM_HT, TPM_RC, TPM_RH, TPM_SE, TPM_ST, +}; + +/// A TPM error with associated command and context information +#[derive(Debug, Clone)] +pub struct TpmCommandError { + /// Response code returned by the TPM + pub response_code: TPM_RC, + /// Command code that triggered the error + pub command_code: TPM_CC, + /// Description of the error + pub message: String, +} + +impl std::fmt::Display for TpmCommandError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "TPM command {:?} failed with response code {:?}: {}", + self.command_code, self.response_code, self.message + ) + } +} + +impl std::error::Error for TpmCommandError {} + +impl From for TpmError { + fn from(err: TpmCommandError) -> Self { + TpmError::GenericError(err.to_string()) + } +} + +/// Base implementation for TPM operations +pub struct Tpm2 { + /// The TPM device used for communication + device: Box, + + /// Response code returned by the last executed command + last_response_code: TPM_RC, + + /// Error object (may be None) generated during the last TPM command execution + last_error: Option, + + /// TPM sessions associated with the next command + sessions: Option>, + + /// Controls whether exceptions are enabled + exceptions_enabled: bool, + + /// Suppresses exceptions in response to the next command failure, when exceptions are enabled + errors_allowed: bool, + + /// Command code for the current operation (for error reporting) + current_cmd_code: Option, + + /// Session tag for the current operation + current_session_tag: Option, + + /// Handle for pending TPM commands + pending_command: Option, + + /// Input handles for current command + in_handles: Vec, + + /// Auth value for objects + object_in_auth: Vec, + + /// Name for objects + object_in_name: Vec, + + /// Admin authorization handles with auth values + admin_platform: TPM_HANDLE, + admin_owner: TPM_HANDLE, + admin_endorsement: TPM_HANDLE, + admin_lockout: TPM_HANDLE, + + /// CpHash for parameter encryption + cp_hash: Option, + + /// Command audit hash + command_audit_hash: TPMT_HA, + + /// Audit command flag + audit_command: bool, + + /// Audit CpHash + audit_cp_hash: TPMT_HA, + + /// Encryption session + enc_session: Option, + + /// Decryption session + dec_session: Option, + + /// Nonces for TPM parameter encryption/decryption + nonce_tpm_dec: Vec, + nonce_tpm_enc: Vec, + + /// Command buffer for last command + last_command_buf: Vec, + + /// Last command's serialized parameters (before handles) + last_cmd_params: Vec, + + /// Sessions updated after the last command (preserved for continueSession) + completed_sessions: Option>, +} + +impl Tpm2 { + /// Creates a new Tpm2 with the specified device + pub fn new(device: Box) -> Self { + Tpm2 { + device, + last_response_code: TPM_RC::SUCCESS, + last_error: None, + sessions: None, + exceptions_enabled: false, + errors_allowed: true, + current_cmd_code: None, + current_session_tag: None, + pending_command: None, + in_handles: Vec::new(), + object_in_auth: Vec::new(), + object_in_name: Vec::new(), + admin_platform: TPM_HANDLE::new(0), + admin_owner: TPM_HANDLE::new(0), + admin_endorsement: TPM_HANDLE::new(0), + admin_lockout: TPM_HANDLE::new(0), + cp_hash: None, + command_audit_hash: TPMT_HA::default(), + audit_command: false, + audit_cp_hash: TPMT_HA::default(), + enc_session: None, + dec_session: None, + nonce_tpm_dec: Vec::new(), + nonce_tpm_enc: Vec::new(), + last_command_buf: Vec::new(), + last_cmd_params: Vec::new(), + completed_sessions: None, + } + } + + /// Checks whether the response code is generated by the TSS.Rust implementation + fn is_comm_medium_error(code: TPM_RC) -> bool { + // Check if error is in the TSS communication layer rather than TPM itself + (code.get_value()) & 0xFFFF0000 == 0x80280000 + } + + /// Cleans the raw response code from the TPM + fn response_code_from_tpm_error(raw_response: TPM_RC) -> TPM_RC { + if Self::is_comm_medium_error(raw_response) { + return raw_response; + } + + let raw_response_u32 = raw_response.get_value(); + let is_fmt = (raw_response_u32 & TPM_RC::RC_FMT1.get_value()) != 0; + + + let mask: u32 = if is_fmt { 0xBF } else { 0x97F }; + + TPM_RC { 0: (raw_response_u32 & mask) } + } + + /// Send a TPM command to the underlying TPM device. + pub fn dispatch( + &mut self, + cmd_code: TPM_CC, + req: R, + resp: &mut S, + ) -> Result<(), TpmError> { + loop { + let process_phase_two = match self.dispatch_command(cmd_code, &req) { + Ok(v) => v, + Err(e) => { + self.current_cmd_code = None; + return Err(e); + } + }; + match self.process_response(cmd_code, resp) { + Ok(done) => { + if !process_phase_two || done { + break; + } + } + Err(e) => { + self.current_cmd_code = None; + return Err(e); + } + } + std::thread::sleep(std::time::Duration::from_millis(1000)); + } + + Ok(()) + } + + /// Internal method to dispatch a command to the TPM + pub fn dispatch_command( + &mut self, + cmd_code: TPM_CC, + req: &R, + ) -> Result<(bool), TpmError> { + if self.current_cmd_code.is_some() { + return Err(TpmError::GenericError( + "Pending async command must be completed before issuing the next command." + .to_string(), + )); + } + + if self.audit_command && self.command_audit_hash.hashAlg == TPM_ALG_ID::NULL { + return Err(TpmError::GenericError( + "Command audit is not enabled".to_string(), + )); + } + + self.current_cmd_code = Some(cmd_code); + + // Determine session tag based on whether we need authorization + let num_auth_handles = req.num_auth_handles(); + let has_sessions = num_auth_handles > 0 || self.sessions.is_some(); + self.current_session_tag = if has_sessions { + Some(TPM_ST::SESSIONS) + } else { + Some(TPM_ST::NO_SESSIONS) + }; + + let mut cmd_buf = TpmBuffer::new(None); + + // Create command buffer header + cmd_buf.writeShort(self.current_session_tag.unwrap().get_value() as u16); + cmd_buf.writeInt(0); // to be filled in later + cmd_buf.writeInt(cmd_code.get_value()); + + // Marshal handles + self.in_handles = req.get_handles(); + // Set auth values for well-known admin handles (OWNER, LOCKOUT, ENDORSEMENT, PLATFORM) + for h in self.in_handles.iter_mut() { + Self::set_rh_auth_value_static(h, &self.admin_owner, &self.admin_endorsement, &self.admin_platform, &self.admin_lockout); + } + for handle in self.in_handles.iter() { + handle.toTpm(&mut cmd_buf)?; + } + + // Marshal command parameters to a separate buffer + let mut param_buf = TpmBuffer::new(None); + req.toTpm(&mut param_buf)?; + param_buf.trim(); + self.last_cmd_params = param_buf.buffer().clone(); + + // Process authorization sessions if present + let mut cp_hash_data = Vec::new(); + + if has_sessions { + // We do not know the size of the authorization area yet. + // Remember the place to marshal it, ... + let auth_size_pos = cmd_buf.current_pos(); + // ... and marshal a placeholder 0 value for now. + cmd_buf.writeInt(0); + + // If not all required sessions were provided explicitly, create the necessary + // number of password sessions with auth values from the corresponding TPM_HANDLE objects. + if let Some(ref mut sessions) = self.sessions { + // Ensure we have enough sessions + if sessions.len() < num_auth_handles as usize { + for _ in sessions.len()..(num_auth_handles as usize) { + sessions.push(Session::pw(None)); + } + } + + // Roll nonces + self.roll_nonces(); + + // Prepare parameter encryption sessions + self.prepare_param_encryption_sessions(); + + // Do parameter encryption if needed + self.do_param_encryption(req, &mut param_buf, 0, true)?; + + // Process authorization sessions and get cpHash data + cp_hash_data = self.process_auth_sessions( + &mut cmd_buf, + cmd_code, + num_auth_handles, + ¶m_buf.buffer(), + )?; + } else { + // Create all password sessions with auth from the corresponding handles + let mut new_sessions = Vec::with_capacity(num_auth_handles as usize); + for i in 0..num_auth_handles as usize { + let auth = if i < self.in_handles.len() { + Some(self.in_handles[i].auth_value.clone()) + } else { + None + }; + new_sessions.push(Session::pw(auth)); + } + + // Marshal sessions to command buffer + for sess in new_sessions.iter() { + sess.sess_in.toTpm(&mut cmd_buf)?; + } + + self.sessions = Some(new_sessions); + } + + // Update the auth area size + cmd_buf.write_num_at_pos( + (cmd_buf.current_pos() - auth_size_pos - 4) as u64, + auth_size_pos, + 4, + ); + } + + // Write marshaled command params to the command buffer + cmd_buf.writeByteBuf(¶m_buf.buffer()); + + // Fill in command buffer size in the command header + cmd_buf.write_num_at_pos(cmd_buf.current_pos() as u64, 2, 4); + cmd_buf.trim(); + + // Handle CpHash and Audit processing + if self.cp_hash.is_some() || self.audit_command { + if cp_hash_data.is_empty() { + cp_hash_data = self.get_cp_hash_data(cmd_code, ¶m_buf.buffer())?; + } + + if let Some(ref mut cp_hash) = self.cp_hash { + cp_hash.digest = Crypto::hash(cp_hash.hashAlg, &cp_hash_data)?; + self.clear_invocation_state(); + self.sessions = None; + self.cp_hash = None; + return Ok(false); + } + + if self.audit_command { + self.audit_cp_hash.digest = + Crypto::hash(self.command_audit_hash.hashAlg, &cp_hash_data)?; + } + } + + // Dispatch command to the device + self.last_command_buf = cmd_buf.trim().to_vec(); + self.device.dispatch_command(&self.last_command_buf)?; + + // Update request handles based on command + self.update_request_handles(cmd_code)?; + + // Set pending command + self.pending_command = Some(cmd_code); + + Ok(true) + } + + /// Process the TPM response and update the response structure + pub fn process_response( + &mut self, + cmd_code: TPM_CC, + resp_struct: &mut T, + ) -> Result<(bool), TpmError> { + if self.pending_command.is_none() { + return Err(TpmError::GenericError( + "Async command completion with no outstanding command".to_string(), + )); + } + + if self.pending_command.unwrap() != cmd_code { + return Err(TpmError::GenericError( + "Async command completion does not match command being processed".to_string(), + )); + } + + if self.audit_command && self.command_audit_hash.hashAlg == TPM_ALG_ID::NULL { + return Err(TpmError::GenericError( + "Command audit is not enabled".to_string(), + )); + } + + self.pending_command = None; + + // Get response from the TPM device + let raw_resp_buf = self.device.get_response()?; + + if raw_resp_buf.len() < 10 { + return Err(TpmError::GenericError(format!( + "Too short TPM response of {} B received", + raw_resp_buf.len() + ))); + } + + let mut resp_buf = TpmBuffer::from(&raw_resp_buf); + + // Read the response header + let resp_tag = TPM_ST::try_from(resp_buf.readShort())?; + let resp_size = resp_buf.readInt(); + let resp_code = TPM_RC::try_from(resp_buf.readInt())?; + + let act_resp_size = resp_buf.size(); + if resp_size as usize != act_resp_size { + return Err(TpmError::GenericError(format!( + "Inconsistent TPM response buffer: {} B reported, {} B received", + resp_size, act_resp_size + ))); + } + + if resp_code == TPM_RC::RETRY { + return Ok(false); + } + + // Clean and store the response code + self.last_response_code = Self::response_code_from_tpm_error(resp_code); + + // Figure out our reaction to the received response. This logic depends on: + // errors_allowed - no exception, regardless of success or failure + + // Store a copy of audit command flag before clearing invocation state + let audit_command = self.audit_command; + + // Handle errors and clean up invocation state + if resp_code != TPM_RC::SUCCESS { + self.clear_invocation_state(); + self.sessions = None; + + // Return error + return Err(TpmError::GenericError(format!( + "TPM Error - TPM_RC::{:?}", + self.last_response_code + ))); + } + + // A check for the session tag consistency across the command invocation + let sess_tag = self.current_session_tag.unwrap_or(TPM_ST::NULL); + if resp_tag != sess_tag { + self.clear_invocation_state(); + self.sessions = None; + return Err(TpmError::GenericError( + "Wrong response session tag".to_string(), + )); + } + + // + // The command succeeded, so we can process the response buffer + // + + // Get the handles if any + if resp_struct.num_handles() > 0 { + let handle_val = resp_buf.readInt(); + resp_struct.set_handle(&TPM_HANDLE::new(handle_val)); + } + + let resp_params_pos: usize; + let resp_params_size: usize; + let mut rp_ready = false; + + // If there are no sessions then response parameters take up the remaining part + // of the response buffer. Otherwise the response parameters area is preceded with + // its size, and followed by the session area. + if sess_tag == TPM_ST::SESSIONS { + resp_params_size = resp_buf.readInt() as usize; + resp_params_pos = resp_buf.current_pos(); + + // Process response sessions, including verification of response HMACs + rp_ready = match self.process_resp_sessions( + &mut resp_buf, + cmd_code, + resp_params_pos, + resp_params_size, + ) { + Ok(ready) => ready, + Err(e) => { + self.clear_invocation_state(); + self.sessions = None; + return Err(e); + } + }; + } else { + resp_params_pos = resp_buf.current_pos(); + resp_params_size = resp_buf.size() - resp_params_pos; + } + + // Update enc_session/dec_session nonces from the processed sessions + if let Some(ref sessions) = self.sessions { + if let Some(ref mut enc) = self.enc_session { + for s in sessions.iter() { + if s.sess_in.sessionHandle.handle == enc.sess_in.sessionHandle.handle { + enc.sess_out.nonce = s.sess_out.nonce.clone(); + enc.sess_in.nonce = s.sess_in.nonce.clone(); + break; + } + } + } + if let Some(ref mut dec) = self.dec_session { + for s in sessions.iter() { + if s.sess_in.sessionHandle.handle == dec.sess_in.sessionHandle.handle { + dec.sess_out.nonce = s.sess_out.nonce.clone(); + dec.sess_in.nonce = s.sess_in.nonce.clone(); + break; + } + } + } + } + + // Handle audit processing + if audit_command { + let rp_hash = self.get_rp_hash( + self.command_audit_hash.hashAlg, + &mut resp_buf, + cmd_code, + resp_params_pos, + resp_params_size, + rp_ready, + )?; + + // Extend audit digest: CommandAuditHash = H(CommandAuditHash || cpHash || rpHash) + let hash_alg = self.command_audit_hash.hashAlg; + let mut extend_data = Vec::new(); + extend_data.extend_from_slice(&self.command_audit_hash.digest); + extend_data.extend_from_slice(&self.audit_cp_hash.digest); + extend_data.extend_from_slice(&rp_hash); + if let Ok(new_digest) = Crypto::hash(hash_alg, &extend_data) { + self.command_audit_hash.digest = new_digest; + } + } + + // Parameter decryption (if necessary) + if let Err(e) = self.do_param_encryption(resp_struct, &mut resp_buf, resp_params_pos, false) + { + self.clear_invocation_state(); + self.sessions = None; + return Err(e); + } + // Clear encryption session state after use + self.enc_session = None; + self.dec_session = None; + + // Reset position to start of parameters area and unmarshall + resp_buf.set_current_pos(resp_params_pos); + resp_struct.initFromTpm(&mut resp_buf)?; + + // Validate that we read the exact number of bytes expected + if resp_buf.current_pos() != resp_params_pos + resp_params_size { + self.clear_invocation_state(); + self.sessions = None; + return Err(TpmError::GenericError( + "Bad response parameters area".to_string(), + )); + } + + // Update response handle with name and auth value + if let Err(e) = self.update_resp_handle(cmd_code, resp_struct) { + self.clear_invocation_state(); + self.sessions = None; + return Err(e); + } + + // Complete post-command handle updates (e.g., HierarchyChangeAuth auth tracking) + if let Err(e) = self.complete_update_request_handles(cmd_code) { + self.clear_invocation_state(); + self.sessions = None; + return Err(e); + } + + // Preserve sessions with continueSession for reuse, otherwise clear + self.completed_sessions = self.sessions.take(); + self.clear_invocation_state(); + + Ok(true) + } +} + +impl Tpm2 { + pub fn last_response_code(&self) -> TPM_RC { + self.last_response_code + } + + pub fn last_error(&self) -> Option { + self.last_error.clone() + } + + pub fn allow_errors(&mut self) -> &mut Self { + self.errors_allowed = true; + self + } + + pub fn enable_exceptions(&mut self, enable: bool) { + self.exceptions_enabled = enable; + self.errors_allowed = !enable; + } + + pub fn with_session(&mut self, session: Session) -> &mut Self { + self.sessions = Some(vec![session]); + self + } + + pub fn with_sessions(&mut self, sessions: Vec) -> &mut Self { + self.sessions = Some(sessions); + self + } + + /// Get the updated session after the last command completed. + /// This is needed when reusing HMAC/policy sessions across commands, + /// since the TPM updates nonces after each command. + pub fn last_sessions(&self) -> Option<&Vec> { + self.completed_sessions.as_ref() + } + + /// Get the first updated session from the last completed command. + /// Convenience method for the common single-session case. + pub fn last_session(&self) -> Option { + self.completed_sessions.as_ref() + .and_then(|s| s.first().cloned()) + } + + pub fn connect(&mut self) -> Result<(), TpmError> { + self.device.connect()?; + self.last_response_code = TPM_RC::SUCCESS; + Ok(()) + } + + pub fn close(&mut self) { + self.device.close(); + } +} + +/// High-level convenience methods for session management and common patterns. +impl Tpm2 { + /// Start a simple HMAC or policy auth session (no salt, no binding). + pub fn start_auth_session( + &mut self, + session_type: TPM_SE, + auth_hash: TPM_ALG_ID, + ) -> Result { + self.start_auth_session_full( + session_type, + auth_hash, + TPMA_SESSION::continueSession, + TPMT_SYM_DEF::default(), + ) + } + + /// Start an auth session with explicit attributes and symmetric definition. + pub fn start_auth_session_full( + &mut self, + session_type: TPM_SE, + auth_hash: TPM_ALG_ID, + attributes: TPMA_SESSION, + symmetric: TPMT_SYM_DEF, + ) -> Result { + let null_handle = TPM_HANDLE::new(TPM_RH::NULL.get_value()); + + self.start_auth_session_ex( + &null_handle, // tpmKey (no salt) + &null_handle, // bind (no binding) + session_type, + auth_hash, + attributes, + symmetric, + &[], // no salt + ) + } + + /// Start an auth session with full control (salt key, bind object, etc.). + pub fn start_auth_session_ex( + &mut self, + tpm_key: &TPM_HANDLE, + bind: &TPM_HANDLE, + session_type: TPM_SE, + auth_hash: TPM_ALG_ID, + attributes: TPMA_SESSION, + symmetric: TPMT_SYM_DEF, + salt: &[u8], + ) -> Result { + let nonce_size = Crypto::digestSize(auth_hash); + let nonce_caller = Crypto::get_random(nonce_size); + + // For salted sessions, encrypt the salt to the tpmKey's public area + let encrypted_salt = if !salt.is_empty() { + let pub_info = self.ReadPublic(tpm_key)?; + pub_info.outPublic.encrypt_session_salt(salt)? + } else { + Vec::new() + }; + + let resp = self.StartAuthSession( + tpm_key, + bind, + &nonce_caller, + &encrypted_salt, + session_type, + &symmetric, + auth_hash, + )?; + + Session::from_tpm_response( + resp.handle, + session_type, + auth_hash, + nonce_caller, + resp.nonceTPM, + attributes, + symmetric, + salt, + bind, + ) + } + + /// Set a session on this Tpm2 for the next command. + pub fn set_sessions(&mut self, sessions: Vec) { + self.sessions = Some(sessions); + } +} + +impl Tpm2 { + // Additional helper methods to support the dispatch_command and process_response implementations + + /// Roll nonces for all non-PWAP sessions + fn roll_nonces(&mut self) { + if let Some(ref mut sessions) = self.sessions { + for session in sessions.iter_mut() { + if !session.is_pwap() { + let nonce_size = session.sess_out.nonce.len(); + session.sess_in.nonce = Crypto::get_random(nonce_size.max(16)); + } + } + } + } + + /// Clear the current invocation state + fn clear_invocation_state(&mut self) { + self.current_cmd_code = None; + self.current_session_tag = None; + // Clear other command-specific state + } + + /// Set the auth value for an admin hierarchy handle. + /// Use this when the TPM's hierarchy auth was set externally (e.g., recovering from a + /// previous run that changed auth but failed to reset it). + pub fn set_admin_auth(&mut self, hierarchy: TPM_RH, auth: &[u8]) { + let val = hierarchy.get_value(); + if val == TPM_RH::OWNER.get_value() { + self.admin_owner.set_auth(auth); + } else if val == TPM_RH::ENDORSEMENT.get_value() { + self.admin_endorsement.set_auth(auth); + } else if val == TPM_RH::PLATFORM.get_value() { + self.admin_platform.set_auth(auth); + } else if val == TPM_RH::LOCKOUT.get_value() { + self.admin_lockout.set_auth(auth); + } + } + + /// Set auth values for well-known admin handles (avoids borrow issues) + fn set_rh_auth_value_static(h: &mut TPM_HANDLE, admin_owner: &TPM_HANDLE, admin_endorsement: &TPM_HANDLE, admin_platform: &TPM_HANDLE, admin_lockout: &TPM_HANDLE) { + match h.handle { + val if val == TPM_RH::OWNER.get_value() => h.set_auth(&admin_owner.auth_value), + val if val == TPM_RH::ENDORSEMENT.get_value() => { + h.set_auth(&admin_endorsement.auth_value) + } + val if val == TPM_RH::PLATFORM.get_value() => { + h.set_auth(&admin_platform.auth_value) + } + val if val == TPM_RH::LOCKOUT.get_value() => h.set_auth(&admin_lockout.auth_value), + _ => {} // No auth value change needed + } + } + + /// Get CpHash data for parameter encryption + fn get_cp_hash_data(&self, cmd_code: TPM_CC, cmd_params: &[u8]) -> Result, TpmError> { + let mut buf = TpmBuffer::new(None); + buf.writeInt(cmd_code.get_value()); + + for h in self.in_handles.iter() { + let name = h.get_name()?; + buf.writeByteBuf(&name); + } + + buf.writeByteBuf(&cmd_params.to_vec()); + Ok(buf.buffer().clone()) + } + + /// Process authorization sessions for a command + fn process_auth_sessions( + &mut self, + cmd_buf: &mut TpmBuffer, + cmd_code: TPM_CC, + num_auth_handles: u16, + cmd_params: &[u8], + ) -> Result, TpmError> { + let mut needs_hmac = false; + + if let Some(ref sessions) = self.sessions { + for session in sessions.iter() { + if !session.is_pwap() { + needs_hmac = true; + break; + } + } + } + + // Compute CpHash if needed for HMAC sessions + let cp_hash_data = if needs_hmac { + self.get_cp_hash_data(cmd_code, cmd_params)? + } else { + Vec::new() + }; + + if let Some(ref mut sessions) = self.sessions { + for (i, session) in sessions.iter().enumerate() { + let mut auth_cmd = TPMS_AUTH_COMMAND::default(); + + // If it's a PWAP session, handling is simple + if session.is_pwap() { + auth_cmd.sessionHandle = TPM_HANDLE::new(TPM_RH::PW.get_value()); + auth_cmd.nonce = Vec::new(); + + if i < self.in_handles.len() { + auth_cmd.hmac = self.in_handles[i].auth_value.clone(); + } + + auth_cmd.sessionAttributes = TPMA_SESSION::continueSession; + auth_cmd.toTpm(cmd_buf)?; + continue; + } + + // For non-PWAP sessions, we need more complex processing + let mut h_copy = None; + + if i < num_auth_handles as usize { + if i < self.in_handles.len() { + // Set appropriate auth value on handle + h_copy = Some(self.in_handles[i].clone()); + } + } + + auth_cmd.nonce = session.sess_in.nonce.clone(); + auth_cmd.sessionHandle = session.sess_in.sessionHandle.clone(); + auth_cmd.sessionAttributes = session.sess_in.sessionAttributes; + + if session.session_type == TPM_SE::HMAC || session.needs_hmac { + // Calculate HMAC based on CpHash + let cp_hash = Crypto::hash(session.get_hash_alg(), &cp_hash_data)?; + auth_cmd.hmac = session.get_auth_hmac( + cp_hash, + true, + &self.nonce_tpm_dec, + &self.nonce_tpm_enc, + h_copy.as_ref(), + )?; + } else if session.needs_password { + auth_cmd.hmac = self.in_handles[i].auth_value.clone(); + } + + auth_cmd.toTpm(cmd_buf)?; + } + } + + Ok(cp_hash_data) + } + + /// Prepare parameter encryption sessions + fn prepare_param_encryption_sessions(&mut self) { + self.enc_session = None; + self.dec_session = None; + self.nonce_tpm_dec.clear(); + self.nonce_tpm_enc.clear(); + + if let Some(ref sessions) = self.sessions { + for session in sessions.iter() { + if session.is_pwap() { + continue; + } + + // Check for decrypt attribute + if (session.sess_in.sessionAttributes.get_value() + & TPMA_SESSION::decrypt.get_value()) + != 0 + { + self.dec_session = Some(session.clone()); + } + + // Check for encrypt attribute + if (session.sess_in.sessionAttributes.get_value() + & TPMA_SESSION::encrypt.get_value()) + != 0 + { + self.enc_session = Some(session.clone()); + } + } + + // Store nonces for the first session to prevent tampering + if let Some(ref sessions_vec) = self.sessions { + if !sessions_vec.is_empty() { + let first_session = &sessions_vec[0]; + + // If first session is followed by decrypt session + if let Some(ref dec) = self.dec_session { + if dec.sess_in.sessionHandle.handle + != first_session.sess_in.sessionHandle.handle + { + self.nonce_tpm_dec = dec.sess_out.nonce.clone(); + } + } + + // If first session is followed by encrypt session (and it's not the decrypt session) + if let Some(ref enc) = self.enc_session { + if enc.sess_in.sessionHandle.handle + != first_session.sess_in.sessionHandle.handle + && (self.dec_session.is_none() + || enc.sess_in.sessionHandle.handle + != self + .dec_session + .as_ref() + .unwrap() + .sess_in + .sessionHandle + .handle) + { + self.nonce_tpm_enc = enc.sess_out.nonce.clone(); + } + } + } + } + } + } + + /// Process parameter encryption/decryption + fn do_param_encryption( + &self, + cmd: &T, + param_buf: &mut TpmBuffer, + start_pos: usize, + is_request: bool, + ) -> Result<(), TpmError> { + let xcrypt_sess = if is_request { + if self.dec_session.is_none() { + return Ok(()); + } + self.dec_session.as_ref() + } else { + if self.enc_session.is_none() { + return Ok(()); + } + self.enc_session.as_ref() + }; + + let sess = xcrypt_sess.unwrap(); + let sei = cmd.sess_enc_info(); + if sei.size_len == 0 || sei.val_len == 0 { + return Ok(()); + } + + let orig_cur_pos = param_buf.current_pos(); + param_buf.set_current_pos(start_pos); + + // Read the size of the first parameter (TPM2B prefix) + let arr_size = param_buf.read_num(sei.size_len as usize) as usize; + let arr_pos = param_buf.current_pos(); + + if arr_size == 0 { + param_buf.set_current_pos(orig_cur_pos); + return Ok(()); + } + + // Read the data to encrypt/decrypt + let to_xcrypt = param_buf.readByteBuf(arr_size * sei.val_len as usize); + + // Perform encryption/decryption + let result = sess.param_xcrypt(&to_xcrypt, is_request)?; + + // Write the result back into the buffer + param_buf.set_current_pos(arr_pos); + param_buf.writeByteBuf(&result); + + param_buf.set_current_pos(orig_cur_pos); + + Ok(()) + } + + /// Get RP hash (response parameter hash) + fn get_rp_hash( + &self, + hash_alg: TPM_ALG_ID, + resp_buf: &mut TpmBuffer, + cmd_code: TPM_CC, + resp_params_pos: usize, + resp_params_size: usize, + rp_ready: bool, + ) -> Result, TpmError> { + let rp_header_size = 8; + let rp_hash_data_pos = resp_params_pos - rp_header_size; + + if !rp_ready { + // Create a continuous data area required by rpHash + let orig_cur_pos = resp_buf.current_pos(); + resp_buf.set_current_pos(rp_hash_data_pos); + resp_buf.writeInt(TPM_RC::SUCCESS.get_value()); + resp_buf.writeInt(cmd_code.get_value()); + resp_buf.set_current_pos(orig_cur_pos); + } + + let data_to_hash = &resp_buf.buffer() + [rp_hash_data_pos..(rp_hash_data_pos + rp_header_size + resp_params_size)]; + Crypto::hash(hash_alg, data_to_hash) + } + + /// Process response sessions + fn process_resp_sessions( + &mut self, + resp_buf: &mut TpmBuffer, + cmd_code: TPM_CC, + resp_params_pos: usize, + resp_params_size: usize, + ) -> Result { + let mut rp_ready = false; + resp_buf.set_current_pos(resp_params_pos + resp_params_size); + + // Pre-compute values needed for HMAC verification to avoid borrow conflicts + let nonce_tpm_dec = self.nonce_tpm_dec.clone(); + let nonce_tpm_enc = self.nonce_tpm_enc.clone(); + let in_handles = self.in_handles.clone(); + + if let Some(ref mut sessions) = self.sessions { + for (j, session) in sessions.iter_mut().enumerate() { + let mut auth_response = TPMS_AUTH_RESPONSE::default(); + auth_response.initFromTpm(resp_buf)?; + + if session.is_pwap() { + // PWAP sessions should have empty nonce and hmac + if !auth_response.nonce.is_empty() || !auth_response.hmac.is_empty() { + return Err(TpmError::GenericError( + "Bad value in PWAP session response".to_string(), + )); + } + continue; + } + + // Non-PWAP session handling + let associated_handle = if j < in_handles.len() { + Some(&in_handles[j]) + } else { + None + }; + + // Update session data based on what the TPM just told us + session.sess_out.nonce = auth_response.nonce; + session.sess_out.sessionAttributes = auth_response.sessionAttributes; + // Update command attributes for next use + session.sess_in.sessionAttributes = auth_response.sessionAttributes; + + if session.session_type == TPM_SE::HMAC + || (session.session_type == TPM_SE::POLICY && session.needs_hmac) + { + // Compute rpHash inline to avoid borrow conflict with self + let rp_hash = { + let rp_header_size = 8; + let rp_hash_data_pos = resp_params_pos - rp_header_size; + + if !rp_ready { + let orig_cur_pos = resp_buf.current_pos(); + resp_buf.set_current_pos(rp_hash_data_pos); + resp_buf.writeInt(TPM_RC::SUCCESS.get_value()); + resp_buf.writeInt(cmd_code.get_value()); + resp_buf.set_current_pos(orig_cur_pos); + } + + let data_to_hash = &resp_buf.buffer() + [rp_hash_data_pos..(rp_hash_data_pos + rp_header_size + resp_params_size)]; + Crypto::hash(session.get_hash_alg(), data_to_hash)? + }; + rp_ready = true; + + let expected_hmac = session.get_auth_hmac( + rp_hash, + false, + &nonce_tpm_dec, + &nonce_tpm_enc, + associated_handle, + )?; + + if expected_hmac != auth_response.hmac { + return Err(TpmError::GenericError( + format!("Invalid TPM response HMAC (session {})", j), + )); + } + } + } + } + + if resp_buf.size() - resp_buf.current_pos() != 0 { + return Err(TpmError::GenericError( + "Invalid response buffer: Data beyond the authorization area".to_string(), + )); + } + + Ok(rp_ready) + } + + /// Update request handles based on command + fn update_request_handles( + &mut self, + cmd_code: TPM_CC, + ) -> Result<(), TpmError> { + // Reset state + self.object_in_name.clear(); + + // This function handles updates to handles based on specific commands + match cmd_code { + TPM_CC::HierarchyChangeAuth => { + // Extract newAuth from the serialized parameters (TPM2B: 2-byte size + data) + if self.last_cmd_params.len() >= 2 { + let size = u16::from_be_bytes([self.last_cmd_params[0], self.last_cmd_params[1]]) as usize; + if self.last_cmd_params.len() >= 2 + size { + self.object_in_auth = self.last_cmd_params[2..2 + size].to_vec(); + } + } + Ok(()) + } + TPM_CC::LoadExternal => { + // Store the name for later use + // In a real implementation, calculate the name from the public area + self.object_in_name = vec![]; // Calculate from req + Ok(()) + } + TPM_CC::Load => { + // Store the name for later use + // In a real implementation, calculate the name from the public area + self.object_in_name = vec![]; // Calculate from req + Ok(()) + } + TPM_CC::NV_ChangeAuth => { + // Extract newAuth from the serialized parameters (TPM2B: 2-byte size + data) + if self.last_cmd_params.len() >= 2 { + let size = u16::from_be_bytes([self.last_cmd_params[0], self.last_cmd_params[1]]) as usize; + if self.last_cmd_params.len() >= 2 + size { + self.object_in_auth = self.last_cmd_params[2..2 + size].to_vec(); + } + } + Ok(()) + } + TPM_CC::ObjectChangeAuth => { + // Extract newAuth from the serialized parameters (TPM2B: 2-byte size + data) + if self.last_cmd_params.len() >= 2 { + let size = u16::from_be_bytes([self.last_cmd_params[0], self.last_cmd_params[1]]) as usize; + if self.last_cmd_params.len() >= 2 + size { + self.object_in_auth = self.last_cmd_params[2..2 + size].to_vec(); + } + } + Ok(()) + } + TPM_CC::PCR_SetAuthValue => { + // Store auth value for later use + // In a real implementation, extract the new auth value from the request + self.object_in_auth = vec![]; // Extract from req + Ok(()) + } + TPM_CC::EvictControl => { + // Store name and auth value for later use + if (!self.in_handles.is_empty() + && self.in_handles[1].get_type() != TPM_HT::PERSISTENT) + { + let handle = &self.in_handles[1]; + self.object_in_auth = handle.auth_value.clone(); + self.object_in_name = handle.get_name()?; + } + Ok(()) + } + TPM_CC::Clear => { + // Reset admin auth values + if !self.in_handles.is_empty() { + let mut handle = self.in_handles[0].clone(); + handle.set_auth(&[]); + } + Ok(()) + } + TPM_CC::HashSequenceStart => { + // Extract auth from the serialized parameters (TPM2B: 2-byte size + data) + if self.last_cmd_params.len() >= 2 { + let size = u16::from_be_bytes([self.last_cmd_params[0], self.last_cmd_params[1]]) as usize; + if self.last_cmd_params.len() >= 2 + size { + self.object_in_auth = self.last_cmd_params[2..2 + size].to_vec(); + } + } + Ok(()) + } + _ => Ok(()), + } + } + + /// Complete update of request handles after command success + fn complete_update_request_handles(&mut self, cmd_code: TPM_CC) -> Result<(), TpmError> { + match cmd_code { + TPM_CC::HierarchyChangeAuth => { + // Update the appropriate hierarchy auth value + if !self.in_handles.is_empty() { + match self.in_handles[0].handle { + val if val == TPM_RH::OWNER.get_value() => { + self.admin_owner.set_auth(&self.object_in_auth) + } + val if val == TPM_RH::ENDORSEMENT.get_value() => { + self.admin_endorsement.set_auth(&self.object_in_auth) + } + val if val == TPM_RH::PLATFORM.get_value() => { + self.admin_platform.set_auth(&self.object_in_auth) + } + val if val == TPM_RH::LOCKOUT.get_value() => { + self.admin_lockout.set_auth(&self.object_in_auth) + } + _ => {} + } + + // Update handle auth + self.in_handles[0].set_auth(&self.object_in_auth); + } + Ok(()) + } + TPM_CC::NV_ChangeAuth => { + if !self.in_handles.is_empty() { + self.in_handles[0].set_auth(&self.object_in_auth); + } + Ok(()) + } + TPM_CC::PCR_SetAuthValue => { + if !self.in_handles.is_empty() { + self.in_handles[0].set_auth(&self.object_in_auth); + } + Ok(()) + } + TPM_CC::EvictControl => { + // Update handle auth and name + if self.in_handles.len() >= 2 && self.in_handles[1].get_type() != TPM_HT::PERSISTENT + { + self.in_handles[1].set_auth(&self.object_in_auth); + let _ = self.in_handles[1].set_name(&self.object_in_name.clone()); + } + Ok(()) + } + TPM_CC::Clear => { + // Reset all hierarchy auth values + self.admin_lockout.set_auth(&[]); + self.admin_owner.set_auth(&[]); + self.admin_endorsement.set_auth(&[]); + Ok(()) + } + _ => Ok(()), + } + } + + /// Update response handle with name and auth value + fn update_resp_handle( + &mut self, + cmd_code: TPM_CC, + resp: &mut T, + ) -> Result<(), TpmError> { + match cmd_code { + TPM_CC::Load | TPM_CC::CreatePrimary | TPM_CC::LoadExternal | TPM_CC::CreateLoaded => { + let name = resp.get_resp_name(); + if !name.is_empty() { + let mut handle = resp.get_handle(); + handle.set_name(&name)?; + resp.set_handle(&handle); + } + Ok(()) + } + TPM_CC::HashSequenceStart | TPM_CC::HMAC_Start => { + Ok(()) + } + _ => Ok(()), + } + } +} + +/// Factory function to create a new TPM implementation based on the available platform +pub fn create_tpm() -> Tpm2 { + #[cfg(target_os = "windows")] + { + use crate::device::TpmTbsDevice; + Tpm2::new(Box::new(TpmTbsDevice::new())) + } + #[cfg(not(target_os = "windows"))] + { + use crate::device::{TpmTbsDevice, TpmTcpDevice}; + + // Try to create a TBS device first (for Linux/Unix), falling back to TCP simulator + let mut tbs_device = TpmTbsDevice::new(); + match tbs_device.connect() { + Ok(_) => Tpm2::new(tbs_device), + Err(_) => { + // Fall back to TCP simulator + let tcp_device = TpmTcpDevice::new("127.0.0.1".to_string(), 2321); + Tpm2::new(Box::new(tcp_device)) + } + } + } +} + +/// Factory function to create a TPM implementation with a custom device +pub fn create_tpm_with_device(device: Box) -> Tpm2 { + Tpm2::new(device) +} diff --git a/TSS.Rust/src/tpm_buffer.rs b/TSS.Rust/src/tpm_buffer.rs new file mode 100644 index 00000000..31b1b7eb --- /dev/null +++ b/TSS.Rust/src/tpm_buffer.rs @@ -0,0 +1,373 @@ +// Since all of the functions here are called from auto-generated code that expects a specific names, +// we have to use those names and not the Rust convention of snake_case +#![allow(non_snake_case)] + +use crate::error::TpmError; +use crate::tpm_structure::TpmEnum; + +pub struct SizedStructInfo { + pub start_pos: usize, + pub size: usize, +} + +pub trait TpmMarshaller { + /** Convert this object to its TPM representation and store it in the given marshaling buffer */ + fn toTpm(&self, buf: &mut TpmBuffer) -> Result<(), TpmError>; + + /** Populate this object from the TPM representation in the given marshaling buffer */ + fn initFromTpm(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError>; +} + +pub struct TpmBuffer { + buf: Vec, + pos: usize, + out_of_bounds: bool, + sized_struct_sizes: Vec, +} + +impl TpmBuffer { + /** Constructs output (default) or input marshaling buffer depending on the parameter. */ + pub fn new(capacity_or_src_buf: Option<&TpmBuffer>) -> Self { + match capacity_or_src_buf { + Some(src_buf) => TpmBuffer { + buf: src_buf.buf.clone(), + pos: src_buf.pos, + out_of_bounds: false, + sized_struct_sizes: Vec::new(), + }, + None => TpmBuffer { + buf: Vec::with_capacity(4096), + pos: 0, + out_of_bounds: false, + sized_struct_sizes: Vec::new(), + }, + } + } + + pub fn from(src_buf: &[u8]) -> Self { + TpmBuffer { + buf: src_buf.to_vec(), + pos: 0, + out_of_bounds: false, + sized_struct_sizes: Vec::new(), + } + } + + /** @return Reference to the backing byte buffer */ + pub fn buffer(&self) -> &Vec { + &self.buf + } + + /** @return Size of the backing byte buffer. */ + pub fn size(&self) -> usize { + self.buf.len() + } + + /** @return Current read/write position in the backing byte buffer. */ + pub fn current_pos(&self) -> usize { + self.pos + } + + /** Sets the current read/write position in the backing byte buffer. */ + pub fn set_current_pos(&mut self, new_pos: usize) { + self.pos = new_pos; + self.out_of_bounds = self.size() < new_pos; + } + + /** @return True unless a previous read/write operation caused under/overflow correspondingly. */ + pub fn isOk(&self) -> bool { + !self.out_of_bounds + } + + /** Shrinks the backing byte buffer so that it ends at the current position */ + pub fn trim(&mut self) -> &Vec { + self.buf.truncate(self.pos); + &self.buf + } + + pub fn getCurStuctRemainingSize(&self) -> usize { + if let Some(ssi) = self.sized_struct_sizes.last() { + return ssi.size - (self.pos - ssi.start_pos); + } + 0 + } + + fn check_len(&mut self, len: usize) -> bool { + if self.buf.len() < self.pos + len { + // Grow the buffer if needed on write operations + self.buf.resize(self.pos + len, 0); + } + true + } + + pub fn write_num(&mut self, val: u64, len: usize) { + if !self.check_len(len) { + return; + } + + if len == 8 { + self.buf[self.pos] = ((val >> 56) & 0xFF) as u8; + self.pos += 1; + self.buf[self.pos] = ((val >> 48) & 0xFF) as u8; + self.pos += 1; + self.buf[self.pos] = ((val >> 40) & 0xFF) as u8; + self.pos += 1; + self.buf[self.pos] = ((val >> 32) & 0xFF) as u8; + self.pos += 1; + } + if len >= 4 { + self.buf[self.pos] = ((val >> 24) & 0xFF) as u8; + self.pos += 1; + self.buf[self.pos] = ((val >> 16) & 0xFF) as u8; + self.pos += 1; + } + if len >= 2 { + self.buf[self.pos] = ((val >> 8) & 0xFF) as u8; + self.pos += 1; + } + self.buf[self.pos] = (val & 0xFF) as u8; + self.pos += 1; + } + + pub fn read_num(&mut self, len: usize) -> u64 { + if !self.check_len(len) { + return 0; + } + + let mut res: u64 = 0; + if len == 8 { + res += (self.buf[self.pos] as u64) << 56; + self.pos += 1; + res += (self.buf[self.pos] as u64) << 48; + self.pos += 1; + res += (self.buf[self.pos] as u64) << 40; + self.pos += 1; + res += (self.buf[self.pos] as u64) << 32; + self.pos += 1; + } + if len >= 4 { + res += (self.buf[self.pos] as u64) << 24; + self.pos += 1; + res += (self.buf[self.pos] as u64) << 16; + self.pos += 1; + } + if len >= 2 { + res += (self.buf[self.pos] as u64) << 8; + self.pos += 1; + } + res += (self.buf[self.pos] as u8) as u64; + self.pos += 1; + res + } + + pub fn write_num_at_pos(&mut self, val: u64, pos: usize, len: usize) { + let cur_pos = self.pos; + self.pos = pos; + self.write_num(val, len); + self.pos = cur_pos; + } + + /** Writes the given 8-bit integer to this buffer */ + pub fn writeByte(&mut self, val: u8) { + if self.check_len(1) { + self.buf[self.pos] = val; + self.pos += 1; + } + } + + /** Marshals the given 16-bit integer to this buffer. */ + pub fn writeShort(&mut self, val: u16) { + self.write_num(val as u64, 2); + } + + /** Marshals the given 32-bit integer to this buffer. */ + pub fn writeInt(&mut self, val: u32) { + self.write_num(val as u64, 4); + } + + /** Marshals the given 64-bit integer to this buffer. */ + pub fn writeInt64(&mut self, val: u64) { + self.write_num(val, 8); + } + + /** Reads a byte from this buffer. */ + pub fn readByte(&mut self) -> u8 { + if self.check_len(1) { + let val = self.buf[self.pos]; + self.pos += 1; + return val; + } + 0 + } + + /** Unmarshals a 16-bit integer from this buffer. */ + pub fn readShort(&mut self) -> u16 { + self.read_num(2) as u16 + } + + /** Unmarshals a 32-bit integer from this buffer. */ + pub fn readInt(&mut self) -> u32 { + self.read_num(4) as u32 + } + + /** Unmarshals a 64-bit integer from this buffer. */ + pub fn readInt64(&mut self) -> u64 { + self.read_num(8) + } + + /** Marshalls the given byte buffer with no length prefix. */ + pub fn writeByteBuf(&mut self, data: &Vec) { + let data_size = data.len(); + if data_size == 0 || !self.check_len(data_size) { + return; + } + for i in 0..data_size { + self.buf[self.pos + i] = data[i]; + } + self.pos += data_size; + } + + /** Unmarshalls a byte buffer of the given size (no marshaled length prefix). */ + pub fn readByteBuf(&mut self, size: usize) -> Vec { + if !self.check_len(size) { + return Vec::new().into(); + } + let mut new_buf = Vec::with_capacity(size); + for i in 0..size { + new_buf.push(self.buf[self.pos + i]); + } + self.pos += size; + new_buf + } + + /** Marshalls the given byte buffer with a length prefix. */ + pub fn writeSizedByteBuf(&mut self, data: &Vec, size_len: usize) { + self.write_num(data.len() as u64, size_len); + self.writeByteBuf(data); + } + + /** Unmarshals a byte buffer from its size-prefixed representation in the TPM wire format. */ + pub fn readSizedByteBuf(&mut self, size_len: usize) -> Vec { + let size = self.read_num(size_len) as usize; + self.readByteBuf(size) + } + + pub fn createObj(&mut self) -> Result { + let mut new_obj = T::default(); + new_obj.initFromTpm(self)?; + Ok(new_obj) + } + + pub fn writeSizedObj(&mut self, obj: &T) -> Result<(), TpmError> { + const LEN_SIZE: usize = 2; // Length of the object size is always 2 bytes + if !self.check_len(LEN_SIZE) { + return Ok(()); + } + + // Remember position to marshal the size of the data structure + let size_pos = self.pos; + // Account for the reserved size area + self.pos += LEN_SIZE; + // Marshal the object + obj.toTpm(self)?; + // Calc marshaled object len + let obj_size = self.pos - (size_pos + LEN_SIZE); + // Marshal it in the appropriate position + self.pos = size_pos; + self.writeShort(obj_size as u16); + self.pos += obj_size; + + Ok(()) + } + + pub fn readSizedObj( + &mut self, + obj: &mut T, + ) -> Result<(), TpmError> { + let size = self.readShort(); + if size == 0 { + return Ok(()); + } + + self.sized_struct_sizes.push(SizedStructInfo { + start_pos: self.pos, + size: size as usize, + }); + + obj.initFromTpm(self)?; + + self.sized_struct_sizes.pop(); + Ok(()) + } + + pub fn writeObjArr(&mut self, arr: &[T]) -> Result<(), TpmError> { + self.writeInt(arr.len() as u32); + for elt in arr { + if !self.isOk() { + break; + } + elt.toTpm(self)?; + } + + Ok(()) + } + + pub fn readObjArr( + &mut self, + arr: &mut Vec, + ) -> Result<(), TpmError> { + let len = self.readInt(); + if len == 0 { + return Ok(arr.clear()); + } + + arr.resize_with(len as usize, T::default); + for elt in arr { + if !self.isOk() { + break; + } + elt.initFromTpm(self)?; + } + + Ok(()) + } + + pub fn writeValArr(&mut self, arr: &[T], val_size: usize) + where + T: TpmEnum + Default, + U: Into, + { + // Length of the array size is always 4 bytes + self.writeInt(arr.len() as u32); + for val in arr { + if !self.isOk() { + break; + } + self.write_num(val.get_value().into(), val_size); + } + } + + pub fn readValArr(&mut self, arr: &mut Vec, val_size: usize) -> Result<(), TpmError> + where + T: TpmEnum + Default, + U: Into, + { + // Length of the array size is always 4 bytes + let len = self.readInt(); + if len == 0 { + return Ok(arr.clear()); + } + + arr.resize_with(len as usize, Default::default); + + for elt in arr { + if !self.isOk() { + break; + } + + *elt = T::new_from_trait((self.read_num(val_size) as u32).into())?; + } + + Ok(()) + } +} diff --git a/TSS.Rust/src/tpm_extensions.rs.snips b/TSS.Rust/src/tpm_extensions.rs.snips new file mode 100644 index 00000000..30868a49 --- /dev/null +++ b/TSS.Rust/src/tpm_extensions.rs.snips @@ -0,0 +1,13 @@ +/* + This file contains source-code snippets that the code-generator inserts into the + appropriate Rust type implementation file. Note - only fields are added to the + relevant structs. Extension methods implementations may be found in tpm_type_extensions.rs +*/ + +>> TPM_HANDLE + +/// The authorization value associated with this handle +pub auth_value: Vec, + +/// The name associated with this handle +pub name: Vec, diff --git a/TSS.Rust/src/tpm_structure.rs b/TSS.Rust/src/tpm_structure.rs new file mode 100644 index 00000000..1d23d8f6 --- /dev/null +++ b/TSS.Rust/src/tpm_structure.rs @@ -0,0 +1,109 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See the LICENSE file in the project root for full license information. + */ + +#![allow(unused_variables)] + +//! TPM type definitions + +use crate::error::*; +use crate::tpm_buffer::*; +use crate::tpm_types::*; + +/// Trait for structures that can be marshaled to/from TPM wire format +pub trait TpmStructure: TpmMarshaller { + fn serialize(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError>; + fn deserialize(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError>; + #[allow(non_snake_case)] + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError>; + #[allow(non_snake_case)] + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError>; +} + +/// Common trait for all TPM enumeration types +pub trait TpmEnum { + /// Get the numeric value of the enum + fn get_value(&self) -> T; + /// Create enum from a numeric value + fn try_from_trait(value: u64) -> Result + where + Self: Sized; + fn new_from_trait(value: u64) -> Result + where + Self: Sized; +} + +/// Trait for TPM union types +pub trait TpmUnion: TpmStructure {} + +/// Parameters of the TPM command request data structure field, to which session +/// based encryption can be applied (i.e. the first non-handle field marshaled in size-prefixed +/// form, if any) +pub struct SessEncInfo { + /// Length of the size prefix in bytes. The size prefix contains the number of + /// elements in the sized area filed (normally just bytes). + pub size_len: u16, + + /// Length of an element of the sized area in bytes (in most cases 1) + pub val_len: u16, +} + +/// Base class for custom (not TPM 2.0 spec defined) auto-generated classes +/// representing a TPM command or response parameters and handles, if any. +/// +/// These data structures differ from the spec-defined ones derived directly from +/// the TpmStructure class in that their handle fields are not marshaled by their toTpm() and +/// initFrom() methods, but rather are acceesed and manipulated via an interface defined by +/// this structs and its derivatives ReqStructure and RespStructure. +pub trait CmdStructure: TpmStructure { + /// Number of TPM handles contained (as fields) in this data structure + fn num_handles(&self) -> u16 { + 0 + } + + /// Non-zero size info of the encryptable command/response parameter if session + /// based encryption can be applied to this object (i.e. its first non-handle field is + /// marshaled in size-prefixed form). Otherwise returns zero initialized struct. + fn sess_enc_info(&self) -> SessEncInfo { + SessEncInfo { + size_len: 0, + val_len: 0, + } + } +} + +/// Base class for custom (not TPM 2.0 spec defined) auto-generated data structures +/// representing a TPM command parameters and handles, if any. +pub trait ReqStructure: CmdStructure { + /// A vector of TPM handles contained in this request data structure + fn get_handles(&self) -> Vec; + + /// Number of authorization TPM handles contained in this data structure + fn num_auth_handles(&self) -> u16 { + 0 + } + + /// Serializable method + fn type_name(&self) -> String { + "ReqStructure".to_string() + } +} + +/// Base class for custom (not TPM 2.0 spec defined) auto-generated data structures +/// representing a TPM response parameters and handles, if any. +pub trait RespStructure: CmdStructure { + /// this structure's handle field value + fn get_handle(&self) -> TPM_HANDLE; + + /// Sets this structure's handle field (TPM_HANDLE) if it is present + fn set_handle(&mut self, _handle: &TPM_HANDLE) {} + + /// Returns the name field from the response, if present + fn get_resp_name(&self) -> Vec { Vec::new() } + + /// Serializable method + fn type_name(&self) -> String { + "RespStructure".to_string() + } +} diff --git a/TSS.Rust/src/tpm_type_extensions.rs b/TSS.Rust/src/tpm_type_extensions.rs new file mode 100644 index 00000000..ed444e5e --- /dev/null +++ b/TSS.Rust/src/tpm_type_extensions.rs @@ -0,0 +1,450 @@ +use crate::crypto::Crypto; +use crate::error::TpmError; +use crate::tpm2_helpers::int_to_tpm; +use crate::tpm_buffer::*; +use crate::tpm_structure::TpmEnum; +use crate::tpm_types::CertifyResponse; +use crate::tpm_types::*; +use rsa::{BigUint, RsaPublicKey, RsaPrivateKey, Oaep, Pkcs1v15Sign}; +use rsa::traits::{PublicKeyParts, PrivateKeyParts}; +use rand::rngs::OsRng; +use zeroize::Zeroize; + +/// Activation data returned from create_activation +#[derive(Debug)] +pub struct ActivationData { + pub credential_blob: TPMS_ID_OBJECT, + pub secret: Vec, // Encrypted seed (ENCRYPTED_SECRET) +} + +impl TPMT_PUBLIC { + pub fn get_name(&self) -> Result, TpmError> { + let mut buffer = TpmBuffer::new(None); + self.toTpm(&mut buffer)?; + + let mut pub_hash = Crypto::hash(self.nameAlg, buffer.trim())?; + let hash_alg = int_to_tpm(self.nameAlg.get_value()); + + pub_hash.splice(0..0, hash_alg.iter().cloned()); + + Ok(pub_hash) + } + + pub fn get_signing_hash_alg(&self) -> Result { + let rsa_params = if let Some(TPMU_PUBLIC_PARMS::rsaDetail(rsa_params)) = &self.parameters { + rsa_params + } else { + return Err(TpmError::NotSupported( + "Get signing hash algorithm is only supported for RSA".to_string(), + )); + }; + + let scheme = if let Some(TPMU_ASYM_SCHEME::rsassa(scheme)) = &rsa_params.scheme { + scheme + } else { + return Err(TpmError::NotSupported( + "Get signing hash algorithm is only supported for RSA-SSA".to_string(), + )); + }; + + Ok(scheme.hashAlg) + } + + pub fn validate_certify( + &self, + certified_key: &TPMT_PUBLIC, + nonce: &[u8], + certify_response: &CertifyResponse, + ) -> Result { + let hash_alg = self.get_signing_hash_alg()?; + let attest = &certify_response.certifyInfo; + + if (attest.extraData != nonce) { + return Ok(false); + } + + if (attest.magic != TPM_GENERATED::VALUE) { + return Ok(false); + } + + if let Some(TPMU_ATTEST::certify(quote_info)) = &attest.attested { + if (quote_info.name != certified_key.get_name()?) { + return Ok(false); + } + } else { + return Ok(false); + } + + // And finally, check the signature + let signed_blob = { + let mut buffer = TpmBuffer::new(None); + certify_response.certifyInfo.toTpm(&mut buffer)?; + buffer.trim().to_vec() + }; + + let signed_blob_hash = Crypto::hash(hash_alg, &signed_blob)?; + + Crypto::validate_signature(self, signed_blob_hash, &certify_response.signature) + } + + /// Implements the TPM2_MakeCredential command functionality: + /// 1. Generate random seed + /// 2. RSA-OAEP encrypt seed with label "IDENTITY" + /// 3. Derive symmetric key via KDFa + /// 4. Encrypt credential + create integrity HMAC + pub fn create_activation( + &self, + credential: &[u8], + activated_name: &[u8], + ) -> Result { + // Verify we have an RSA key with correct parameters + let rsa_params = if let Some(TPMU_PUBLIC_PARMS::rsaDetail(params)) = &self.parameters { + params + } else { + return Err(TpmError::NotSupported("Only RSA activation supported".to_string())); + }; + + // Check symmetric definition + let sym_def = &rsa_params.symmetric; + if sym_def.algorithm != TPM_ALG_ID::AES + || sym_def.keyBits != 128 + || sym_def.mode != TPM_ALG_ID::CFB { + return Err(TpmError::NotSupported("Unsupported wrapping scheme".to_string())); + } + + // Generate random 16-byte seed + let mut seed = Crypto::get_random(16); + + // Get RSA public key components for encrypting the seed + let rsa_pub_n = if let Some(TPMU_PUBLIC_ID::rsa(unique)) = &self.unique { + &unique.buffer + } else { + return Err(TpmError::NotSupported("Invalid RSA public key".to_string())); + }; + + let rsa_public_key = RsaPublicKey::new( + BigUint::from_bytes_be(rsa_pub_n), + BigUint::from_bytes_be(&[1, 0, 1]) // e = 65537 + ).map_err(|_| TpmError::GenericError("Invalid RSA parameters".to_string()))?; + + // Encrypt seed with label "IDENTITY" using OAEP-SHA1 + let padding = Oaep::new_with_label::("IDENTITY\0"); + let secret = rsa_public_key + .encrypt(&mut OsRng, padding, &seed) + .map_err(|_| TpmError::GenericError("Failed to encrypt seed".to_string()))?; + + // Make the credential blob: + + // 1. Create the symmetric key via KDFa + let mut sym_key = Crypto::kdfa( + self.nameAlg, + &seed, + "STORAGE", + activated_name, + &[], + 128, // 128-bit AES key + )?; + + // 2. Take credential and prepend size + let mut credential_with_size = Vec::with_capacity(2 + credential.len()); + credential_with_size.extend_from_slice(&(credential.len() as u16).to_be_bytes()); + credential_with_size.extend_from_slice(credential); + + // 3. Encrypt the credential + let enc_credential = Crypto::cfb_xcrypt( + true, + &sym_key, + &vec![0u8; 16], // Zero IV + &credential_with_size + )?; + + // 4. Generate the integrity HMAC key + let mut hmac_key = Crypto::kdfa( + self.nameAlg, + &seed, + "INTEGRITY", + &[], + &[], + Crypto::digestSize(self.nameAlg) * 8, + )?; + + // 5. Calculate outer HMAC + let mut to_hmac = Vec::new(); + to_hmac.extend_from_slice(&enc_credential); + to_hmac.extend_from_slice(activated_name); + + let integrity_hmac = Crypto::hmac( + self.nameAlg, + &hmac_key, + &to_hmac + )?; + + // Cleanup sensitive data + seed.zeroize(); + hmac_key.zeroize(); + sym_key.zeroize(); + + Ok(ActivationData { + credential_blob: TPMS_ID_OBJECT::new(&integrity_hmac, &enc_credential), + secret, + }) + } + + // Performs RSA encryption of the given data using the public key + pub fn encrypt( + &self, + data: &[u8], + ) -> Result, TpmError> { + // Verify we have an RSA key with correct parameters + let rsa_params = if let Some(TPMU_PUBLIC_PARMS::rsaDetail(params)) = &self.parameters { + params + } else { + return Err(TpmError::NotSupported("Only RSA encryption supported".to_string())); + }; + + // Check symmetric definition + let sym_def = &rsa_params.symmetric; + if sym_def.algorithm != TPM_ALG_ID::AES + || sym_def.keyBits != 128 + || sym_def.mode != TPM_ALG_ID::CFB { + return Err(TpmError::NotSupported("Unsupported wrapping scheme".to_string())); + } + + // Get RSA public key components + let rsa_pub_n = if let Some(TPMU_PUBLIC_ID::rsa(unique)) = &self.unique { + &unique.buffer + } else { + return Err(TpmError::NotSupported("Invalid RSA public key".to_string())); + }; + + // Create RSA public key (usually e = 65537) + let rsa_public_key = RsaPublicKey::new( + BigUint::from_bytes_be(rsa_pub_n), + BigUint::from_bytes_be(&[1, 0, 1]) // e = 65537 + ).map_err(|_| TpmError::InvalidArraySize("Invalid RSA parameters".to_string()))?; + + // Encrypt the data using OAEP padding with SHA-1 hash function + let padding = Oaep::new_with_label::("IDENTITY\0"); + let encrypted_data = rsa_public_key + .encrypt(&mut OsRng, padding, data) + .map_err(|_| TpmError::GenericError("Failed to encrypt data".to_string()))?; + + Ok(encrypted_data) + } + + /// Encrypt a session salt for use with salted auth sessions. + /// Uses RSA-OAEP with the nameAlg hash and label "SECRET\0". + pub fn encrypt_session_salt(&self, salt: &[u8]) -> Result, TpmError> { + let rsa_pub_n = if let Some(TPMU_PUBLIC_ID::rsa(unique)) = &self.unique { + &unique.buffer + } else { + return Err(TpmError::NotSupported("Only RSA keys can encrypt session salt".to_string())); + }; + + let rsa_public_key = RsaPublicKey::new( + BigUint::from_bytes_be(rsa_pub_n), + BigUint::from_bytes_be(&[1, 0, 1]), + ).map_err(|_| TpmError::InvalidArraySize("Invalid RSA parameters".to_string()))?; + + let padding = match self.nameAlg { + TPM_ALG_ID::SHA1 => Oaep::new_with_label::("SECRET\0"), + TPM_ALG_ID::SHA256 => Oaep::new_with_label::("SECRET\0"), + _ => return Err(TpmError::NotSupported(format!("Unsupported nameAlg for session salt: {:?}", self.nameAlg))), + }; + + rsa_public_key + .encrypt(&mut OsRng, padding, salt) + .map_err(|e| TpmError::GenericError(format!("Failed to encrypt session salt: {}", e))) + } +} + +impl TPMS_PCR_SELECTION { + /// Get a PCR-selection array naming exactly one PCR in one bank + pub fn get_selection_array(hash_alg: TPM_ALG_ID, pcr: u32) -> Vec { + vec![TPMS_PCR_SELECTION::new_from_pcr_u32(hash_alg, pcr)] + } + + /// Create a TPMS_PCR_SELECTION naming a single-PCR + pub fn new_from_pcr_u32(hash_alg: TPM_ALG_ID, pcr: u32) -> Self { + let mut size = 3; + + let pcr_bytes = pcr / 8; + if ((pcr_bytes / 8) + 1) > size { + size = pcr_bytes + 1; + } + + let mut pcr_select = vec![0; size as usize]; + pcr_select[pcr_bytes as usize] = 1 << (pcr % 8); + + TPMS_PCR_SELECTION::new(hash_alg, &pcr_select) + } + + /// Create a TPMS_PCR_SELECTION for a set of PCRs in a single bank + pub fn new_from_pcrs_vec(hash_alg: TPM_ALG_ID, pcrs: &[u32]) -> Self { + let mut pcr_max = *pcrs.iter().max().unwrap_or(&0); + + if (pcr_max < 23) { + pcr_max = 23; + } + + let mut pcr_select = vec![0; (pcr_max / 8 + 1) as usize]; + for pcr in pcrs { + pcr_select[*pcr as usize / 8] |= 1 << (*pcr % 8); + } + + TPMS_PCR_SELECTION::new(hash_alg, &pcr_select) + } +} + +impl TPM_HANDLE { + /// Creates a handle for a persistent object + pub fn persistent(handle_offset: u32) -> Self { + Self::new(((TPM_HT::PERSISTENT.get_value() as u32) << 24) + handle_offset) + } + + /// Creates a handle for a PCR + pub fn pcr(pcr_index: u32) -> Self { + Self::new(pcr_index) + } + + /// Creates a handle for an NV slot + pub fn nv(nv_index: u32) -> Self { + Self::new(((TPM_HT::NV_INDEX.get_value() as u32) << 24) + nv_index) + } + + /// Set the authorization value for this TPM_HANDLE. The default auth-value is NULL + pub fn set_auth(&mut self, auth_val: &[u8]) { + self.auth_value = auth_val.to_vec(); + } + + /// Returns this handle's type + pub fn get_type(&self) -> TPM_HT { + // The handle type is the top byte of the handle value + unsafe { std::mem::transmute((self.handle >> 24) as u8) } + } + + pub fn set_name(&mut self, name: &[u8]) -> Result<(), TpmError> { + let handle_type = self.get_type(); + + if (handle_type == TPM_HT::NV_INDEX + || handle_type == TPM_HT::TRANSIENT + || handle_type == TPM_HT::PERSISTENT + || handle_type == TPM_HT::PERSISTENT) + { + self.name = name.to_vec(); + return Ok(()); + } + + if (name != self.get_name()?) { + return Err(TpmError::GenericError(format!("Setting an invalid name of an entity with the name defined by the handle value, handle type: {}", handle_type))); + } + + Ok(()) + } + + /// Get the TPM name of this handle + pub fn get_name(&self) -> Result, TpmError> { + let handle_type = self.get_type(); + + // Per spec: handles of these types have their handle value as their name + if handle_type == TPM_HT::PCR + || handle_type == TPM_HT::HMAC_SESSION + || handle_type == TPM_HT::POLICY_SESSION + || handle_type == TPM_HT::PERMANENT + { + let mut name = Vec::with_capacity(4); + name.extend_from_slice(&self.handle.to_be_bytes()); + return Ok(name); + } + + if handle_type == TPM_HT::NV_INDEX + || handle_type == TPM_HT::TRANSIENT + || handle_type == TPM_HT::PERSISTENT + { + if (self.name.is_empty()) { + return Err(TpmError::GenericError(format!( + "Name is not set for handle, handle type: {}", + handle_type + ))); + } + return Ok(self.name.clone()); + } + + Err(TpmError::GenericError(format!( + "Unknown handle type, handle type: {}", + handle_type + ))) + } + + /// Get a string representation of this handle + pub fn to_string(&self) -> String { + format!("{}:0x{:x}", self.get_type(), self.handle) + } +} + +impl TSS_KEY { + /// Generate an RSA key pair in software. + /// Populates publicPart.unique with the modulus and privatePart with the first prime (p). + pub fn create_key(&mut self) -> Result<(), TpmError> { + let rsa_params = if let Some(TPMU_PUBLIC_PARMS::rsaDetail(ref params)) = self.publicPart.parameters { + params.clone() + } else { + return Err(TpmError::GenericError("Only RSA key creation is supported".to_string())); + }; + + let key_bits = rsa_params.keyBits as usize; + let priv_key = RsaPrivateKey::new(&mut OsRng, key_bits) + .map_err(|e| TpmError::GenericError(format!("RSA key generation failed: {}", e)))?; + + // Store modulus (n) in publicPart.unique + let n_bytes = priv_key.n().to_bytes_be(); + self.publicPart.unique = Some(TPMU_PUBLIC_ID::rsa(TPM2B_PUBLIC_KEY_RSA { buffer: n_bytes })); + + // Store first prime (p) as privatePart + let primes = priv_key.primes(); + self.privatePart = primes[0].to_bytes_be(); + + Ok(()) + } + + /// Sign a digest using the software key (RSASSA-PKCS1-v1_5). + /// `digest` should be the hash of the data to sign. + /// Returns a TPMT_SIGNATURE with RSASSA scheme. + pub fn sign(&self, digest: &[u8], hash_alg: TPM_ALG_ID) -> Result { + if !matches!(&self.publicPart.parameters, Some(TPMU_PUBLIC_PARMS::rsaDetail(_))) { + return Err(TpmError::GenericError("Only RSA signing is supported".to_string())); + } + + let n_bytes = if let Some(TPMU_PUBLIC_ID::rsa(ref pub_key)) = self.publicPart.unique { + pub_key.buffer.clone() + } else { + return Err(TpmError::GenericError("No public key available".to_string())); + }; + + // Reconstruct RSA private key from modulus + prime p + let n = BigUint::from_bytes_be(&n_bytes); + let p = BigUint::from_bytes_be(&self.privatePart); + let q = &n / &p; + let e = BigUint::from(65537u32); + + let priv_key = RsaPrivateKey::from_p_q(p, q, e) + .map_err(|e| TpmError::GenericError(format!("Failed to reconstruct RSA key: {}", e)))?; + + // Sign with PKCS#1 v1.5 + let scheme = match hash_alg { + TPM_ALG_ID::SHA1 => Pkcs1v15Sign::new::(), + TPM_ALG_ID::SHA256 => Pkcs1v15Sign::new::(), + _ => return Err(TpmError::GenericError(format!("Unsupported hash algorithm for signing: {:?}", hash_alg))), + }; + + let sig_bytes = priv_key.sign(scheme, digest) + .map_err(|e| TpmError::GenericError(format!("RSA signing failed: {}", e)))?; + + Ok(TPMT_SIGNATURE { + signature: Some(TPMU_SIGNATURE::rsassa(TPMS_SIGNATURE_RSASSA { + hash: hash_alg, + sig: sig_bytes, + })), + }) + } +} diff --git a/TSS.Rust/src/tpm_types.rs b/TSS.Rust/src/tpm_types.rs new file mode 100644 index 00000000..814df6f7 --- /dev/null +++ b/TSS.Rust/src/tpm_types.rs @@ -0,0 +1,34775 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See the LICENSE file in the project root for full license information. + */ + +/* + * NOTE: this file is partially auto generated! + * + * All code after the point marked with the '// <>' comment + * is autogenerated from the TPM 2.0 Specification docs. + * + * DO NOT EDIT AUTOGENERATED PART - all manual changes will be lost! + */ + +#![allow( + unused_variables, + non_snake_case, + non_camel_case_types, + non_upper_case_globals, + dead_code +)] + +//! TPM type definitions + +use crate::crypto::Crypto; +use crate::error::*; +use crate::tpm2_helpers::*; +use crate::tpm_buffer::*; +use crate::tpm_structure::*; +use std::collections::HashMap; +use std::fmt; +use std::fmt::Debug; +use derivative::Derivative; + +// <> +// ------------------------------------------------------------------------------------------------ +// DO NOT REMOVE the <> comment! +// DO NOT MODIFY any code below this point - all manual changes will be lost! +// ------------------------------------------------------------------------------------------------ + + +/// Table 2 is the list of algorithms to which the TCG has assigned an algorithm +/// identifier along with its numeric identifier. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub struct TPM_ALG_ID(pub u16); + +impl TPM_ALG_ID { + /// Should not occur + pub const ERROR: Self = Self(0x0); // Original value: 0x0000 + + /// An object type that contains an RSA key + pub const FIRST: Self = Self(0x1); // Original value: 0x0001 + + /// An object type that contains an RSA key + pub const RSA: Self = Self(0x1); // Original value: 0x0001 + + /// Block cipher with various key sizes (Triple Data Encryption Algorithm, commonly called + /// Triple Data Encryption Standard) + pub const TDES: Self = Self(0x3); // Original value: 0x0003 + + /// Hash algorithm producing a 160-bit digest + pub const SHA: Self = Self(0x4); // Original value: 0x0004 + + /// Redefinition for documentation consistency + pub const SHA1: Self = Self(0x4); // Original value: 0x0004 + + /// Hash Message Authentication Code (HMAC) algorithm + pub const HMAC: Self = Self(0x5); // Original value: 0x0005 + + /// Block cipher with various key sizes + pub const AES: Self = Self(0x6); // Original value: 0x0006 + + /// Hash-based mask-generation function + pub const MGF1: Self = Self(0x7); // Original value: 0x0007 + + /// An object type that may use XOR for encryption or an HMAC for signing and may also + /// refer to a data object that is neither signing nor encrypting + pub const KEYEDHASH: Self = Self(0x8); // Original value: 0x0008 + + /// Hash-based stream cipher + pub const XOR: Self = Self(0xA); // Original value: 0x000A + + /// Hash algorithm producing a 256-bit digest + pub const SHA256: Self = Self(0xB); // Original value: 0x000B + + /// Hash algorithm producing a 384-bit digest + pub const SHA384: Self = Self(0xC); // Original value: 0x000C + + /// Hash algorithm producing a 512-bit digest + pub const SHA512: Self = Self(0xD); // Original value: 0x000D + + /// Indication that no algorithm is selected + pub const NULL: Self = Self(0x10); // Original value: 0x0010 + + /// Hash algorithm producing a 256-bit digest + pub const SM3_256: Self = Self(0x12); // Original value: 0x0012 + + /// Symmetric block cipher with 128 bit key + pub const SM4: Self = Self(0x13); // Original value: 0x0013 + + /// A signature algorithm defined in section 8.2 (RSASSA-PKCS1-v1_5) + pub const RSASSA: Self = Self(0x14); // Original value: 0x0014 + + /// A padding algorithm defined in section 7.2 (RSAES-PKCS1-v1_5) + pub const RSAES: Self = Self(0x15); // Original value: 0x0015 + + /// A signature algorithm defined in section 8.1 (RSASSA-PSS) + pub const RSAPSS: Self = Self(0x16); // Original value: 0x0016 + + /// A padding algorithm defined in Section 7.1 (RSAES_OAEP) + pub const OAEP: Self = Self(0x17); // Original value: 0x0017 + + /// Signature algorithm using elliptic curve cryptography (ECC) + pub const ECDSA: Self = Self(0x18); // Original value: 0x0018 + + /// Secret sharing using ECC Based on context, this can be either One-Pass Diffie-Hellman, + /// C(1, 1, ECC CDH) defined in 6.2.2.2 or Full Unified Model C(2, 2, ECC CDH) defined in 6.1.1.2 + pub const ECDH: Self = Self(0x19); // Original value: 0x0019 + + /// Elliptic-curve based, anonymous signing scheme + pub const ECDAA: Self = Self(0x1A); // Original value: 0x001A + + /// Depending on context, either an elliptic-curve-based signature algorithm, encryption + /// algorithm, or key exchange protocol + pub const SM2: Self = Self(0x1B); // Original value: 0x001B + + /// Elliptic-curve based Schnorr signature + pub const ECSCHNORR: Self = Self(0x1C); // Original value: 0x001C + + /// Two-phase elliptic-curve key exchange C(2, 2, ECC MQV) Section 6.1.1.4 + pub const ECMQV: Self = Self(0x1D); // Original value: 0x001D + + /// Concatenation key derivation function (approved alternative 1) Section 5.8.1 + pub const KDF1_SP800_56A: Self = Self(0x20); // Original value: 0x0020 + + /// Key derivation function KDF2 Section 13.2 + pub const KDF2: Self = Self(0x21); // Original value: 0x0021 + + /// A key derivation method SP800-108, Section 5.1 KDF in Counter Mode + pub const KDF1_SP800_108: Self = Self(0x22); // Original value: 0x0022 + + /// Prime field ECC + pub const ECC: Self = Self(0x23); // Original value: 0x0023 + + /// The object type for a symmetric block cipher key + pub const SYMCIPHER: Self = Self(0x25); // Original value: 0x0025 + + /// Symmetric block cipher with various key sizes + pub const CAMELLIA: Self = Self(0x26); // Original value: 0x0026 + + /// Hash algorithm producing a 256-bit digest + pub const SHA3_256: Self = Self(0x27); // Original value: 0x0027 + + /// Hash algorithm producing a 384-bit digest + pub const SHA3_384: Self = Self(0x28); // Original value: 0x0028 + + /// Hash algorithm producing a 512-bit digest + pub const SHA3_512: Self = Self(0x29); // Original value: 0x0029 + pub const CMAC: Self = Self(0x3F); // Original value: 0x003F + + /// Counter mode if implemented, all symmetric block ciphers (S type) implemented shall be + /// capable of using this mode. + pub const CTR: Self = Self(0x40); // Original value: 0x0040 + + /// Output Feedback mode if implemented, all symmetric block ciphers (S type) implemented + /// shall be capable of using this mode. + pub const OFB: Self = Self(0x41); // Original value: 0x0041 + + /// Cipher Block Chaining mode if implemented, all symmetric block ciphers (S type) + /// implemented shall be capable of using this mode. + pub const CBC: Self = Self(0x42); // Original value: 0x0042 + + /// Cipher Feedback mode if implemented, all symmetric block ciphers (S type) implemented + /// shall be capable of using this mode. + pub const CFB: Self = Self(0x43); // Original value: 0x0043 + + /// Electronic Codebook mode if implemented, all implemented symmetric block ciphers (S + /// type) shall be capable of using this mode. + /// NOTE This mode is not recommended for uses unless the key is frequently rotated such + /// as in video codecs + pub const ECB: Self = Self(0x44); // Original value: 0x0044 + pub const LAST: Self = Self(0x44); // Original value: 0x0044 + + /// Phony alg ID to be used for the first union member with no selector + pub const ANY: Self = Self(0x7FFF); + + /// Phony alg ID to be used for the second union member with no selector + pub const ANY2: Self = Self(0x7FFE); + + pub fn try_from(value: u16) -> Result { + match value { + 0 => Ok(Self::ERROR), // Original value: 0x0000 + 1 => Ok(Self::RSA), // Original value: 0x0001 + 3 => Ok(Self::TDES), // Original value: 0x0003 + 4 => Ok(Self::SHA1), // Original value: 0x0004 + 5 => Ok(Self::HMAC), // Original value: 0x0005 + 6 => Ok(Self::AES), // Original value: 0x0006 + 7 => Ok(Self::MGF1), // Original value: 0x0007 + 8 => Ok(Self::KEYEDHASH), // Original value: 0x0008 + 10 => Ok(Self::XOR), // Original value: 0x000A + 11 => Ok(Self::SHA256), // Original value: 0x000B + 12 => Ok(Self::SHA384), // Original value: 0x000C + 13 => Ok(Self::SHA512), // Original value: 0x000D + 16 => Ok(Self::NULL), // Original value: 0x0010 + 18 => Ok(Self::SM3_256), // Original value: 0x0012 + 19 => Ok(Self::SM4), // Original value: 0x0013 + 20 => Ok(Self::RSASSA), // Original value: 0x0014 + 21 => Ok(Self::RSAES), // Original value: 0x0015 + 22 => Ok(Self::RSAPSS), // Original value: 0x0016 + 23 => Ok(Self::OAEP), // Original value: 0x0017 + 24 => Ok(Self::ECDSA), // Original value: 0x0018 + 25 => Ok(Self::ECDH), // Original value: 0x0019 + 26 => Ok(Self::ECDAA), // Original value: 0x001A + 27 => Ok(Self::SM2), // Original value: 0x001B + 28 => Ok(Self::ECSCHNORR), // Original value: 0x001C + 29 => Ok(Self::ECMQV), // Original value: 0x001D + 32 => Ok(Self::KDF1_SP800_56A), // Original value: 0x0020 + 33 => Ok(Self::KDF2), // Original value: 0x0021 + 34 => Ok(Self::KDF1_SP800_108), // Original value: 0x0022 + 35 => Ok(Self::ECC), // Original value: 0x0023 + 37 => Ok(Self::SYMCIPHER), // Original value: 0x0025 + 38 => Ok(Self::CAMELLIA), // Original value: 0x0026 + 39 => Ok(Self::SHA3_256), // Original value: 0x0027 + 40 => Ok(Self::SHA3_384), // Original value: 0x0028 + 41 => Ok(Self::SHA3_512), // Original value: 0x0029 + 63 => Ok(Self::CMAC), // Original value: 0x003F + 64 => Ok(Self::CTR), // Original value: 0x0040 + 65 => Ok(Self::OFB), // Original value: 0x0041 + 66 => Ok(Self::CBC), // Original value: 0x0042 + 67 => Ok(Self::CFB), // Original value: 0x0043 + 68 => Ok(Self::LAST), // Original value: 0x0044 + 32767 => Ok(Self::ANY), // Original value: 0x7FFF + 32766 => Ok(Self::ANY2), // Original value: 0x7FFE + _ => Err(TpmError::InvalidEnumValue), + } + } +} + +impl TpmEnum for TPM_ALG_ID { + fn get_value(&self) -> u16 { + self.0.into() + } + + fn try_from_trait(value: u64) -> Result where Self: Sized { + TPM_ALG_ID::try_from(value as u16) + } + + fn new_from_trait(value: u64) -> Result where Self: Sized { + Ok(TPM_ALG_ID(value as u16)) + } +} + +impl From for u16 { + fn from(value: TPM_ALG_ID) -> Self { + value.0 as u16 + } +} + +impl From for i16 { + fn from(value: TPM_ALG_ID) -> Self { + value.0 as i16 + } +} + +impl fmt::Display for TPM_ALG_ID { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + 0 => write!(f, "ERROR"), + 1 => write!(f, "RSA"), + 3 => write!(f, "TDES"), + 4 => write!(f, "SHA1"), + 5 => write!(f, "HMAC"), + 6 => write!(f, "AES"), + 7 => write!(f, "MGF1"), + 8 => write!(f, "KEYEDHASH"), + 10 => write!(f, "XOR"), + 11 => write!(f, "SHA256"), + 12 => write!(f, "SHA384"), + 13 => write!(f, "SHA512"), + 16 => write!(f, "NULL"), + 18 => write!(f, "SM3_256"), + 19 => write!(f, "SM4"), + 20 => write!(f, "RSASSA"), + 21 => write!(f, "RSAES"), + 22 => write!(f, "RSAPSS"), + 23 => write!(f, "OAEP"), + 24 => write!(f, "ECDSA"), + 25 => write!(f, "ECDH"), + 26 => write!(f, "ECDAA"), + 27 => write!(f, "SM2"), + 28 => write!(f, "ECSCHNORR"), + 29 => write!(f, "ECMQV"), + 32 => write!(f, "KDF1_SP800_56A"), + 33 => write!(f, "KDF2"), + 34 => write!(f, "KDF1_SP800_108"), + 35 => write!(f, "ECC"), + 37 => write!(f, "SYMCIPHER"), + 38 => write!(f, "CAMELLIA"), + 39 => write!(f, "SHA3_256"), + 40 => write!(f, "SHA3_384"), + 41 => write!(f, "SHA3_512"), + 63 => write!(f, "CMAC"), + 64 => write!(f, "CTR"), + 65 => write!(f, "OFB"), + 66 => write!(f, "CBC"), + 67 => write!(f, "CFB"), + 68 => write!(f, "LAST"), + 32767 => write!(f, "ANY"), + 32766 => write!(f, "ANY2"), + _ => write!(f, "{}", enum_to_str(self.0 as u64, std::any::TypeId::of::())), + } + } +} + +/// Table 4 is the list of identifiers for TCG-registered curve ID values for elliptic +/// curve cryptography. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub struct TPM_ECC_CURVE(pub u16); + +impl TPM_ECC_CURVE { + pub const NONE: Self = Self(0x0); // Original value: 0x0000 + pub const NIST_P192: Self = Self(0x1); // Original value: 0x0001 + pub const NIST_P224: Self = Self(0x2); // Original value: 0x0002 + pub const NIST_P256: Self = Self(0x3); // Original value: 0x0003 + pub const NIST_P384: Self = Self(0x4); // Original value: 0x0004 + pub const NIST_P521: Self = Self(0x5); // Original value: 0x0005 + + /// Curve to support ECDAA + pub const BN_P256: Self = Self(0x10); // Original value: 0x0010 + + /// Curve to support ECDAA + pub const BN_P638: Self = Self(0x11); // Original value: 0x0011 + pub const SM2_P256: Self = Self(0x20); // Original value: 0x0020 + pub const TEST_P192: Self = Self(0x21); // Original value: 0x0021 + + pub fn try_from(value: u16) -> Result { + match value { + 0 => Ok(Self::NONE), // Original value: 0x0000 + 1 => Ok(Self::NIST_P192), // Original value: 0x0001 + 2 => Ok(Self::NIST_P224), // Original value: 0x0002 + 3 => Ok(Self::NIST_P256), // Original value: 0x0003 + 4 => Ok(Self::NIST_P384), // Original value: 0x0004 + 5 => Ok(Self::NIST_P521), // Original value: 0x0005 + 16 => Ok(Self::BN_P256), // Original value: 0x0010 + 17 => Ok(Self::BN_P638), // Original value: 0x0011 + 32 => Ok(Self::SM2_P256), // Original value: 0x0020 + 33 => Ok(Self::TEST_P192), // Original value: 0x0021 + _ => Err(TpmError::InvalidEnumValue), + } + } +} + +impl TpmEnum for TPM_ECC_CURVE { + fn get_value(&self) -> u16 { + self.0.into() + } + + fn try_from_trait(value: u64) -> Result where Self: Sized { + TPM_ECC_CURVE::try_from(value as u16) + } + + fn new_from_trait(value: u64) -> Result where Self: Sized { + Ok(TPM_ECC_CURVE(value as u16)) + } +} + +impl From for u16 { + fn from(value: TPM_ECC_CURVE) -> Self { + value.0 as u16 + } +} + +impl From for i16 { + fn from(value: TPM_ECC_CURVE) -> Self { + value.0 as i16 + } +} + +impl fmt::Display for TPM_ECC_CURVE { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + 0 => write!(f, "NONE"), + 1 => write!(f, "NIST_P192"), + 2 => write!(f, "NIST_P224"), + 3 => write!(f, "NIST_P256"), + 4 => write!(f, "NIST_P384"), + 5 => write!(f, "NIST_P521"), + 16 => write!(f, "BN_P256"), + 17 => write!(f, "BN_P638"), + 32 => write!(f, "SM2_P256"), + 33 => write!(f, "TEST_P192"), + _ => write!(f, "{}", enum_to_str(self.0 as u64, std::any::TypeId::of::())), + } + } +} + +/// Table 13 Defines for SHA1 Hash Values +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub struct SHA1(pub u32); + +impl SHA1 { + /// Size of digest in octets + pub const DIGEST_SIZE: Self = Self(0x14); // Original value: 20 + + /// Size of hash block in octets + pub const BLOCK_SIZE: Self = Self(0x40); // Original value: 64 + + pub fn try_from(value: u32) -> Result { + match value { + 20 => Ok(Self::DIGEST_SIZE), // Original value: 20 + 64 => Ok(Self::BLOCK_SIZE), // Original value: 64 + _ => Err(TpmError::InvalidEnumValue), + } + } +} + +impl TpmEnum for SHA1 { + fn get_value(&self) -> u32 { + self.0.into() + } + + fn try_from_trait(value: u64) -> Result where Self: Sized { + SHA1::try_from(value as u32) + } + + fn new_from_trait(value: u64) -> Result where Self: Sized { + Ok(SHA1(value as u32)) + } +} + +impl From for u32 { + fn from(value: SHA1) -> Self { + value.0 as u32 + } +} + +impl From for i32 { + fn from(value: SHA1) -> Self { + value.0 as i32 + } +} + +impl fmt::Display for SHA1 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + 20 => write!(f, "DIGEST_SIZE"), + 64 => write!(f, "BLOCK_SIZE"), + _ => write!(f, "{}", enum_to_str(self.0 as u64, std::any::TypeId::of::())), + } + } +} + +/// Table 14 Defines for SHA256 Hash Values +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub struct SHA256(pub u32); + +impl SHA256 { + /// Size of digest + pub const DIGEST_SIZE: Self = Self(0x20); // Original value: 32 + + /// Size of hash block + pub const BLOCK_SIZE: Self = Self(0x40); // Original value: 64 + + pub fn try_from(value: u32) -> Result { + match value { + 32 => Ok(Self::DIGEST_SIZE), // Original value: 32 + 64 => Ok(Self::BLOCK_SIZE), // Original value: 64 + _ => Err(TpmError::InvalidEnumValue), + } + } +} + +impl TpmEnum for SHA256 { + fn get_value(&self) -> u32 { + self.0.into() + } + + fn try_from_trait(value: u64) -> Result where Self: Sized { + SHA256::try_from(value as u32) + } + + fn new_from_trait(value: u64) -> Result where Self: Sized { + Ok(SHA256(value as u32)) + } +} + +impl From for u32 { + fn from(value: SHA256) -> Self { + value.0 as u32 + } +} + +impl From for i32 { + fn from(value: SHA256) -> Self { + value.0 as i32 + } +} + +impl fmt::Display for SHA256 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + 32 => write!(f, "DIGEST_SIZE"), + 64 => write!(f, "BLOCK_SIZE"), + _ => write!(f, "{}", enum_to_str(self.0 as u64, std::any::TypeId::of::())), + } + } +} + +/// Table 15 Defines for SHA384 Hash Values +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub struct SHA384(pub u32); + +impl SHA384 { + /// Size of digest in octets + pub const DIGEST_SIZE: Self = Self(0x30); // Original value: 48 + + /// Size of hash block in octets + pub const BLOCK_SIZE: Self = Self(0x80); // Original value: 128 + + pub fn try_from(value: u32) -> Result { + match value { + 48 => Ok(Self::DIGEST_SIZE), // Original value: 48 + 128 => Ok(Self::BLOCK_SIZE), // Original value: 128 + _ => Err(TpmError::InvalidEnumValue), + } + } +} + +impl TpmEnum for SHA384 { + fn get_value(&self) -> u32 { + self.0.into() + } + + fn try_from_trait(value: u64) -> Result where Self: Sized { + SHA384::try_from(value as u32) + } + + fn new_from_trait(value: u64) -> Result where Self: Sized { + Ok(SHA384(value as u32)) + } +} + +impl From for u32 { + fn from(value: SHA384) -> Self { + value.0 as u32 + } +} + +impl From for i32 { + fn from(value: SHA384) -> Self { + value.0 as i32 + } +} + +impl fmt::Display for SHA384 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + 48 => write!(f, "DIGEST_SIZE"), + 128 => write!(f, "BLOCK_SIZE"), + _ => write!(f, "{}", enum_to_str(self.0 as u64, std::any::TypeId::of::())), + } + } +} + +/// Table 16 Defines for SHA512 Hash Values +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub struct SHA512(pub u32); + +impl SHA512 { + /// Size of digest in octets + pub const DIGEST_SIZE: Self = Self(0x40); // Original value: 64 + + /// Size of hash block in octets + pub const BLOCK_SIZE: Self = Self(0x80); // Original value: 128 + + pub fn try_from(value: u32) -> Result { + match value { + 64 => Ok(Self::DIGEST_SIZE), // Original value: 64 + 128 => Ok(Self::BLOCK_SIZE), // Original value: 128 + _ => Err(TpmError::InvalidEnumValue), + } + } +} + +impl TpmEnum for SHA512 { + fn get_value(&self) -> u32 { + self.0.into() + } + + fn try_from_trait(value: u64) -> Result where Self: Sized { + SHA512::try_from(value as u32) + } + + fn new_from_trait(value: u64) -> Result where Self: Sized { + Ok(SHA512(value as u32)) + } +} + +impl From for u32 { + fn from(value: SHA512) -> Self { + value.0 as u32 + } +} + +impl From for i32 { + fn from(value: SHA512) -> Self { + value.0 as i32 + } +} + +impl fmt::Display for SHA512 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + 64 => write!(f, "DIGEST_SIZE"), + 128 => write!(f, "BLOCK_SIZE"), + _ => write!(f, "{}", enum_to_str(self.0 as u64, std::any::TypeId::of::())), + } + } +} + +/// Table 17 Defines for SM3_256 Hash Values +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub struct SM3_256(pub u32); + +impl SM3_256 { + /// Size of digest in octets + pub const DIGEST_SIZE: Self = Self(0x20); // Original value: 32 + + /// Size of hash block in octets + pub const BLOCK_SIZE: Self = Self(0x40); // Original value: 64 + + pub fn try_from(value: u32) -> Result { + match value { + 32 => Ok(Self::DIGEST_SIZE), // Original value: 32 + 64 => Ok(Self::BLOCK_SIZE), // Original value: 64 + _ => Err(TpmError::InvalidEnumValue), + } + } +} + +impl TpmEnum for SM3_256 { + fn get_value(&self) -> u32 { + self.0.into() + } + + fn try_from_trait(value: u64) -> Result where Self: Sized { + SM3_256::try_from(value as u32) + } + + fn new_from_trait(value: u64) -> Result where Self: Sized { + Ok(SM3_256(value as u32)) + } +} + +impl From for u32 { + fn from(value: SM3_256) -> Self { + value.0 as u32 + } +} + +impl From for i32 { + fn from(value: SM3_256) -> Self { + value.0 as i32 + } +} + +impl fmt::Display for SM3_256 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + 32 => write!(f, "DIGEST_SIZE"), + 64 => write!(f, "BLOCK_SIZE"), + _ => write!(f, "{}", enum_to_str(self.0 as u64, std::any::TypeId::of::())), + } + } +} + +/// Table 18 Defines for SHA3_256 Hash Values +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub struct SHA3_256(pub u32); + +impl SHA3_256 { + /// Size of digest in octets + pub const DIGEST_SIZE: Self = Self(0x20); // Original value: 32 + + /// Size of hash block in octets + pub const BLOCK_SIZE: Self = Self(0x88); // Original value: 136 + + pub fn try_from(value: u32) -> Result { + match value { + 32 => Ok(Self::DIGEST_SIZE), // Original value: 32 + 136 => Ok(Self::BLOCK_SIZE), // Original value: 136 + _ => Err(TpmError::InvalidEnumValue), + } + } +} + +impl TpmEnum for SHA3_256 { + fn get_value(&self) -> u32 { + self.0.into() + } + + fn try_from_trait(value: u64) -> Result where Self: Sized { + SHA3_256::try_from(value as u32) + } + + fn new_from_trait(value: u64) -> Result where Self: Sized { + Ok(SHA3_256(value as u32)) + } +} + +impl From for u32 { + fn from(value: SHA3_256) -> Self { + value.0 as u32 + } +} + +impl From for i32 { + fn from(value: SHA3_256) -> Self { + value.0 as i32 + } +} + +impl fmt::Display for SHA3_256 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + 32 => write!(f, "DIGEST_SIZE"), + 136 => write!(f, "BLOCK_SIZE"), + _ => write!(f, "{}", enum_to_str(self.0 as u64, std::any::TypeId::of::())), + } + } +} + +/// Table 19 Defines for SHA3_384 Hash Values +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub struct SHA3_384(pub u32); + +impl SHA3_384 { + /// Size of digest in octets + pub const DIGEST_SIZE: Self = Self(0x30); // Original value: 48 + + /// Size of hash block in octets + pub const BLOCK_SIZE: Self = Self(0x68); // Original value: 104 + + pub fn try_from(value: u32) -> Result { + match value { + 48 => Ok(Self::DIGEST_SIZE), // Original value: 48 + 104 => Ok(Self::BLOCK_SIZE), // Original value: 104 + _ => Err(TpmError::InvalidEnumValue), + } + } +} + +impl TpmEnum for SHA3_384 { + fn get_value(&self) -> u32 { + self.0.into() + } + + fn try_from_trait(value: u64) -> Result where Self: Sized { + SHA3_384::try_from(value as u32) + } + + fn new_from_trait(value: u64) -> Result where Self: Sized { + Ok(SHA3_384(value as u32)) + } +} + +impl From for u32 { + fn from(value: SHA3_384) -> Self { + value.0 as u32 + } +} + +impl From for i32 { + fn from(value: SHA3_384) -> Self { + value.0 as i32 + } +} + +impl fmt::Display for SHA3_384 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + 48 => write!(f, "DIGEST_SIZE"), + 104 => write!(f, "BLOCK_SIZE"), + _ => write!(f, "{}", enum_to_str(self.0 as u64, std::any::TypeId::of::())), + } + } +} + +/// Table 20 Defines for SHA3_512 Hash Values +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub struct SHA3_512(pub u32); + +impl SHA3_512 { + /// Size of digest in octets + pub const DIGEST_SIZE: Self = Self(0x40); // Original value: 64 + + /// Size of hash block in octets + pub const BLOCK_SIZE: Self = Self(0x48); // Original value: 72 + + pub fn try_from(value: u32) -> Result { + match value { + 64 => Ok(Self::DIGEST_SIZE), // Original value: 64 + 72 => Ok(Self::BLOCK_SIZE), // Original value: 72 + _ => Err(TpmError::InvalidEnumValue), + } + } +} + +impl TpmEnum for SHA3_512 { + fn get_value(&self) -> u32 { + self.0.into() + } + + fn try_from_trait(value: u64) -> Result where Self: Sized { + SHA3_512::try_from(value as u32) + } + + fn new_from_trait(value: u64) -> Result where Self: Sized { + Ok(SHA3_512(value as u32)) + } +} + +impl From for u32 { + fn from(value: SHA3_512) -> Self { + value.0 as u32 + } +} + +impl From for i32 { + fn from(value: SHA3_512) -> Self { + value.0 as i32 + } +} + +impl fmt::Display for SHA3_512 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + 64 => write!(f, "DIGEST_SIZE"), + 72 => write!(f, "BLOCK_SIZE"), + _ => write!(f, "{}", enum_to_str(self.0 as u64, std::any::TypeId::of::())), + } + } +} + +/// Table 4 Defines for Logic Values +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub struct Logic(pub u8); + +impl Logic { + pub const TRUE: Self = Self(0x1); // Original value: 1 + pub const FALSE: Self = Self(0x0); // Original value: 0 + pub const YES: Self = Self(0x1); // Original value: 1 + pub const NO: Self = Self(0x0); // Original value: 0 + pub const SET: Self = Self(0x1); // Original value: 1 + pub const CLEAR: Self = Self(0x0); // Original value: 0 + + pub fn try_from(value: u8) -> Result { + match value { + 1 => Ok(Self::SET), // Original value: 1 + 0 => Ok(Self::CLEAR), // Original value: 0 + _ => Err(TpmError::InvalidEnumValue), + } + } +} + +impl TpmEnum for Logic { + fn get_value(&self) -> u8 { + self.0.into() + } + + fn try_from_trait(value: u64) -> Result where Self: Sized { + Logic::try_from(value as u8) + } + + fn new_from_trait(value: u64) -> Result where Self: Sized { + Ok(Logic(value as u8)) + } +} + +impl From for u8 { + fn from(value: Logic) -> Self { + value.0 as u8 + } +} + +impl From for i8 { + fn from(value: Logic) -> Self { + value.0 as i8 + } +} + +impl fmt::Display for Logic { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + 1 => write!(f, "SET"), + 0 => write!(f, "CLEAR"), + _ => write!(f, "{}", enum_to_str(self.0 as u64, std::any::TypeId::of::())), + } + } +} + +/// These values are readable with TPM2_GetCapability() (see 6.13 for the format). +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub struct TPM_SPEC(pub u32); + +impl TPM_SPEC { + /// ASCII 2.0 with null terminator + pub const FAMILY: Self = Self(0x322E3000); + + /// The level number for the specification + pub const LEVEL: Self = Self(0x0); // Original value: 0 + + /// The version number of the spec (001.62 * 100) + pub const VERSION: Self = Self(0xA2); // Original value: 162 + + /// The year of the version + pub const YEAR: Self = Self(0x7E3); // Original value: 2019 + + /// The day of the year (December 26) + pub const DAY_OF_YEAR: Self = Self(0x168); // Original value: 360 + + pub fn try_from(value: u32) -> Result { + match value { + 841887744 => Ok(Self::FAMILY), // Original value: 0x322E3000 + 0 => Ok(Self::LEVEL), // Original value: 0 + 162 => Ok(Self::VERSION), // Original value: 162 + 2019 => Ok(Self::YEAR), // Original value: 2019 + 360 => Ok(Self::DAY_OF_YEAR), // Original value: 360 + _ => Err(TpmError::InvalidEnumValue), + } + } +} + +impl TpmEnum for TPM_SPEC { + fn get_value(&self) -> u32 { + self.0.into() + } + + fn try_from_trait(value: u64) -> Result where Self: Sized { + TPM_SPEC::try_from(value as u32) + } + + fn new_from_trait(value: u64) -> Result where Self: Sized { + Ok(TPM_SPEC(value as u32)) + } +} + +impl From for u32 { + fn from(value: TPM_SPEC) -> Self { + value.0 as u32 + } +} + +impl From for i32 { + fn from(value: TPM_SPEC) -> Self { + value.0 as i32 + } +} + +impl fmt::Display for TPM_SPEC { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + 841887744 => write!(f, "FAMILY"), + 0 => write!(f, "LEVEL"), + 162 => write!(f, "VERSION"), + 2019 => write!(f, "YEAR"), + 360 => write!(f, "DAY_OF_YEAR"), + _ => write!(f, "{}", enum_to_str(self.0 as u64, std::any::TypeId::of::())), + } + } +} + +/// This constant value differentiates TPM-generated structures from non-TPM structures. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub struct TPM_GENERATED(pub u32); + +impl TPM_GENERATED { + /// 0xFF TCG (FF 54 43 4716) + pub const VALUE: Self = Self(0xFF544347); // Original value: 0xff544347 + + pub fn try_from(value: u32) -> Result { + match value { + 4283712327 => Ok(Self::VALUE), // Original value: 0xff544347 + _ => Err(TpmError::InvalidEnumValue), + } + } +} + +impl TpmEnum for TPM_GENERATED { + fn get_value(&self) -> u32 { + self.0.into() + } + + fn try_from_trait(value: u64) -> Result where Self: Sized { + TPM_GENERATED::try_from(value as u32) + } + + fn new_from_trait(value: u64) -> Result where Self: Sized { + Ok(TPM_GENERATED(value as u32)) + } +} + +impl From for u32 { + fn from(value: TPM_GENERATED) -> Self { + value.0 as u32 + } +} + +impl From for i32 { + fn from(value: TPM_GENERATED) -> Self { + value.0 as i32 + } +} + +impl fmt::Display for TPM_GENERATED { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + 4283712327 => write!(f, "VALUE"), + _ => write!(f, "{}", enum_to_str(self.0 as u64, std::any::TypeId::of::())), + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub struct TPM_CC(pub u32); + +impl TPM_CC { + /// Compile variable. May decrease based on implementation. + pub const FIRST: Self = Self(0x11F); // Original value: 0x0000011F + pub const NV_UndefineSpaceSpecial: Self = Self(0x11F); // Original value: 0x0000011F + pub const EvictControl: Self = Self(0x120); // Original value: 0x00000120 + pub const HierarchyControl: Self = Self(0x121); // Original value: 0x00000121 + pub const NV_UndefineSpace: Self = Self(0x122); // Original value: 0x00000122 + pub const ChangeEPS: Self = Self(0x124); // Original value: 0x00000124 + pub const ChangePPS: Self = Self(0x125); // Original value: 0x00000125 + pub const Clear: Self = Self(0x126); // Original value: 0x00000126 + pub const ClearControl: Self = Self(0x127); // Original value: 0x00000127 + pub const ClockSet: Self = Self(0x128); // Original value: 0x00000128 + pub const HierarchyChangeAuth: Self = Self(0x129); // Original value: 0x00000129 + pub const NV_DefineSpace: Self = Self(0x12A); // Original value: 0x0000012A + pub const PCR_Allocate: Self = Self(0x12B); // Original value: 0x0000012B + pub const PCR_SetAuthPolicy: Self = Self(0x12C); // Original value: 0x0000012C + pub const PP_Commands: Self = Self(0x12D); // Original value: 0x0000012D + pub const SetPrimaryPolicy: Self = Self(0x12E); // Original value: 0x0000012E + pub const FieldUpgradeStart: Self = Self(0x12F); // Original value: 0x0000012F + pub const ClockRateAdjust: Self = Self(0x130); // Original value: 0x00000130 + pub const CreatePrimary: Self = Self(0x131); // Original value: 0x00000131 + pub const NV_GlobalWriteLock: Self = Self(0x132); // Original value: 0x00000132 + pub const GetCommandAuditDigest: Self = Self(0x133); // Original value: 0x00000133 + pub const NV_Increment: Self = Self(0x134); // Original value: 0x00000134 + pub const NV_SetBits: Self = Self(0x135); // Original value: 0x00000135 + pub const NV_Extend: Self = Self(0x136); // Original value: 0x00000136 + pub const NV_Write: Self = Self(0x137); // Original value: 0x00000137 + pub const NV_WriteLock: Self = Self(0x138); // Original value: 0x00000138 + pub const DictionaryAttackLockReset: Self = Self(0x139); // Original value: 0x00000139 + pub const DictionaryAttackParameters: Self = Self(0x13A); // Original value: 0x0000013A + pub const NV_ChangeAuth: Self = Self(0x13B); // Original value: 0x0000013B + + /// PCR + pub const PCR_Event: Self = Self(0x13C); // Original value: 0x0000013C + + /// PCR + pub const PCR_Reset: Self = Self(0x13D); // Original value: 0x0000013D + pub const SequenceComplete: Self = Self(0x13E); // Original value: 0x0000013E + pub const SetAlgorithmSet: Self = Self(0x13F); // Original value: 0x0000013F + pub const SetCommandCodeAuditStatus: Self = Self(0x140); // Original value: 0x00000140 + pub const FieldUpgradeData: Self = Self(0x141); // Original value: 0x00000141 + pub const IncrementalSelfTest: Self = Self(0x142); // Original value: 0x00000142 + pub const SelfTest: Self = Self(0x143); // Original value: 0x00000143 + pub const Startup: Self = Self(0x144); // Original value: 0x00000144 + pub const Shutdown: Self = Self(0x145); // Original value: 0x00000145 + pub const StirRandom: Self = Self(0x146); // Original value: 0x00000146 + pub const ActivateCredential: Self = Self(0x147); // Original value: 0x00000147 + pub const Certify: Self = Self(0x148); // Original value: 0x00000148 + + /// Policy + pub const PolicyNV: Self = Self(0x149); // Original value: 0x00000149 + pub const CertifyCreation: Self = Self(0x14A); // Original value: 0x0000014A + pub const Duplicate: Self = Self(0x14B); // Original value: 0x0000014B + pub const GetTime: Self = Self(0x14C); // Original value: 0x0000014C + pub const GetSessionAuditDigest: Self = Self(0x14D); // Original value: 0x0000014D + pub const NV_Read: Self = Self(0x14E); // Original value: 0x0000014E + pub const NV_ReadLock: Self = Self(0x14F); // Original value: 0x0000014F + pub const ObjectChangeAuth: Self = Self(0x150); // Original value: 0x00000150 + + /// Policy + pub const PolicySecret: Self = Self(0x151); // Original value: 0x00000151 + pub const Rewrap: Self = Self(0x152); // Original value: 0x00000152 + pub const Create: Self = Self(0x153); // Original value: 0x00000153 + pub const ECDH_ZGen: Self = Self(0x154); // Original value: 0x00000154 + + /// See NOTE 1 + pub const HMAC: Self = Self(0x155); // Original value: 0x00000155 + + /// See NOTE 1 + pub const MAC: Self = Self(0x155); // Original value: 0x00000155 + pub const Import: Self = Self(0x156); // Original value: 0x00000156 + pub const Load: Self = Self(0x157); // Original value: 0x00000157 + pub const Quote: Self = Self(0x158); // Original value: 0x00000158 + pub const RSA_Decrypt: Self = Self(0x159); // Original value: 0x00000159 + + /// See NOTE 1 + pub const HMAC_Start: Self = Self(0x15B); // Original value: 0x0000015B + + /// See NOTE 1 + pub const MAC_Start: Self = Self(0x15B); // Original value: 0x0000015B + pub const SequenceUpdate: Self = Self(0x15C); // Original value: 0x0000015C + pub const Sign: Self = Self(0x15D); // Original value: 0x0000015D + pub const Unseal: Self = Self(0x15E); // Original value: 0x0000015E + + /// Policy + pub const PolicySigned: Self = Self(0x160); // Original value: 0x00000160 + + /// Context + pub const ContextLoad: Self = Self(0x161); // Original value: 0x00000161 + + /// Context + pub const ContextSave: Self = Self(0x162); // Original value: 0x00000162 + pub const ECDH_KeyGen: Self = Self(0x163); // Original value: 0x00000163 + pub const EncryptDecrypt: Self = Self(0x164); // Original value: 0x00000164 + + /// Context + pub const FlushContext: Self = Self(0x165); // Original value: 0x00000165 + pub const LoadExternal: Self = Self(0x167); // Original value: 0x00000167 + pub const MakeCredential: Self = Self(0x168); // Original value: 0x00000168 + + /// NV + pub const NV_ReadPublic: Self = Self(0x169); // Original value: 0x00000169 + + /// Policy + pub const PolicyAuthorize: Self = Self(0x16A); // Original value: 0x0000016A + + /// Policy + pub const PolicyAuthValue: Self = Self(0x16B); // Original value: 0x0000016B + + /// Policy + pub const PolicyCommandCode: Self = Self(0x16C); // Original value: 0x0000016C + + /// Policy + pub const PolicyCounterTimer: Self = Self(0x16D); // Original value: 0x0000016D + + /// Policy + pub const PolicyCpHash: Self = Self(0x16E); // Original value: 0x0000016E + + /// Policy + pub const PolicyLocality: Self = Self(0x16F); // Original value: 0x0000016F + + /// Policy + pub const PolicyNameHash: Self = Self(0x170); // Original value: 0x00000170 + + /// Policy + pub const PolicyOR: Self = Self(0x171); // Original value: 0x00000171 + + /// Policy + pub const PolicyTicket: Self = Self(0x172); // Original value: 0x00000172 + pub const ReadPublic: Self = Self(0x173); // Original value: 0x00000173 + pub const RSA_Encrypt: Self = Self(0x174); // Original value: 0x00000174 + pub const StartAuthSession: Self = Self(0x176); // Original value: 0x00000176 + pub const VerifySignature: Self = Self(0x177); // Original value: 0x00000177 + pub const ECC_Parameters: Self = Self(0x178); // Original value: 0x00000178 + pub const FirmwareRead: Self = Self(0x179); // Original value: 0x00000179 + pub const GetCapability: Self = Self(0x17A); // Original value: 0x0000017A + pub const GetRandom: Self = Self(0x17B); // Original value: 0x0000017B + pub const GetTestResult: Self = Self(0x17C); // Original value: 0x0000017C + pub const Hash: Self = Self(0x17D); // Original value: 0x0000017D + + /// PCR + pub const PCR_Read: Self = Self(0x17E); // Original value: 0x0000017E + + /// Policy + pub const PolicyPCR: Self = Self(0x17F); // Original value: 0x0000017F + pub const PolicyRestart: Self = Self(0x180); // Original value: 0x00000180 + pub const ReadClock: Self = Self(0x181); // Original value: 0x00000181 + pub const PCR_Extend: Self = Self(0x182); // Original value: 0x00000182 + pub const PCR_SetAuthValue: Self = Self(0x183); // Original value: 0x00000183 + pub const NV_Certify: Self = Self(0x184); // Original value: 0x00000184 + pub const EventSequenceComplete: Self = Self(0x185); // Original value: 0x00000185 + pub const HashSequenceStart: Self = Self(0x186); // Original value: 0x00000186 + + /// Policy + pub const PolicyPhysicalPresence: Self = Self(0x187); // Original value: 0x00000187 + + /// Policy + pub const PolicyDuplicationSelect: Self = Self(0x188); // Original value: 0x00000188 + + /// Policy + pub const PolicyGetDigest: Self = Self(0x189); // Original value: 0x00000189 + pub const TestParms: Self = Self(0x18A); // Original value: 0x0000018A + pub const Commit: Self = Self(0x18B); // Original value: 0x0000018B + + /// Policy + pub const PolicyPassword: Self = Self(0x18C); // Original value: 0x0000018C + pub const ZGen_2Phase: Self = Self(0x18D); // Original value: 0x0000018D + pub const EC_Ephemeral: Self = Self(0x18E); // Original value: 0x0000018E + + /// Policy + pub const PolicyNvWritten: Self = Self(0x18F); // Original value: 0x0000018F + + /// Policy + pub const PolicyTemplate: Self = Self(0x190); // Original value: 0x00000190 + pub const CreateLoaded: Self = Self(0x191); // Original value: 0x00000191 + + /// Policy + pub const PolicyAuthorizeNV: Self = Self(0x192); // Original value: 0x00000192 + pub const EncryptDecrypt2: Self = Self(0x193); // Original value: 0x00000193 + pub const AC_GetCapability: Self = Self(0x194); // Original value: 0x00000194 + pub const AC_Send: Self = Self(0x195); // Original value: 0x00000195 + + /// Policy + pub const Policy_AC_SendSelect: Self = Self(0x196); // Original value: 0x00000196 + pub const CertifyX509: Self = Self(0x197); // Original value: 0x00000197 + pub const ACT_SetTimeout: Self = Self(0x198); // Original value: 0x00000198 + pub const ECC_Encrypt: Self = Self(0x199); // Original value: 0x00000199 + pub const ECC_Decrypt: Self = Self(0x19A); // Original value: 0x0000019A + + /// Compile variable. May increase based on implementation. + pub const LAST: Self = Self(0x19A); // Original value: 0x0000019A + pub const CC_VEND: Self = Self(0x20000000); + + /// Used for testing of command dispatch + pub const Vendor_TCG_Test: Self = Self(0x20000000); // Original value: CC_VEND.into()+0x0000 + + pub fn try_from(value: u32) -> Result { + match value { + 287 => Ok(Self::NV_UndefineSpaceSpecial), // Original value: 0x0000011F + 288 => Ok(Self::EvictControl), // Original value: 0x00000120 + 289 => Ok(Self::HierarchyControl), // Original value: 0x00000121 + 290 => Ok(Self::NV_UndefineSpace), // Original value: 0x00000122 + 292 => Ok(Self::ChangeEPS), // Original value: 0x00000124 + 293 => Ok(Self::ChangePPS), // Original value: 0x00000125 + 294 => Ok(Self::Clear), // Original value: 0x00000126 + 295 => Ok(Self::ClearControl), // Original value: 0x00000127 + 296 => Ok(Self::ClockSet), // Original value: 0x00000128 + 297 => Ok(Self::HierarchyChangeAuth), // Original value: 0x00000129 + 298 => Ok(Self::NV_DefineSpace), // Original value: 0x0000012A + 299 => Ok(Self::PCR_Allocate), // Original value: 0x0000012B + 300 => Ok(Self::PCR_SetAuthPolicy), // Original value: 0x0000012C + 301 => Ok(Self::PP_Commands), // Original value: 0x0000012D + 302 => Ok(Self::SetPrimaryPolicy), // Original value: 0x0000012E + 303 => Ok(Self::FieldUpgradeStart), // Original value: 0x0000012F + 304 => Ok(Self::ClockRateAdjust), // Original value: 0x00000130 + 305 => Ok(Self::CreatePrimary), // Original value: 0x00000131 + 306 => Ok(Self::NV_GlobalWriteLock), // Original value: 0x00000132 + 307 => Ok(Self::GetCommandAuditDigest), // Original value: 0x00000133 + 308 => Ok(Self::NV_Increment), // Original value: 0x00000134 + 309 => Ok(Self::NV_SetBits), // Original value: 0x00000135 + 310 => Ok(Self::NV_Extend), // Original value: 0x00000136 + 311 => Ok(Self::NV_Write), // Original value: 0x00000137 + 312 => Ok(Self::NV_WriteLock), // Original value: 0x00000138 + 313 => Ok(Self::DictionaryAttackLockReset), // Original value: 0x00000139 + 314 => Ok(Self::DictionaryAttackParameters), // Original value: 0x0000013A + 315 => Ok(Self::NV_ChangeAuth), // Original value: 0x0000013B + 316 => Ok(Self::PCR_Event), // Original value: 0x0000013C + 317 => Ok(Self::PCR_Reset), // Original value: 0x0000013D + 318 => Ok(Self::SequenceComplete), // Original value: 0x0000013E + 319 => Ok(Self::SetAlgorithmSet), // Original value: 0x0000013F + 320 => Ok(Self::SetCommandCodeAuditStatus), // Original value: 0x00000140 + 321 => Ok(Self::FieldUpgradeData), // Original value: 0x00000141 + 322 => Ok(Self::IncrementalSelfTest), // Original value: 0x00000142 + 323 => Ok(Self::SelfTest), // Original value: 0x00000143 + 324 => Ok(Self::Startup), // Original value: 0x00000144 + 325 => Ok(Self::Shutdown), // Original value: 0x00000145 + 326 => Ok(Self::StirRandom), // Original value: 0x00000146 + 327 => Ok(Self::ActivateCredential), // Original value: 0x00000147 + 328 => Ok(Self::Certify), // Original value: 0x00000148 + 329 => Ok(Self::PolicyNV), // Original value: 0x00000149 + 330 => Ok(Self::CertifyCreation), // Original value: 0x0000014A + 331 => Ok(Self::Duplicate), // Original value: 0x0000014B + 332 => Ok(Self::GetTime), // Original value: 0x0000014C + 333 => Ok(Self::GetSessionAuditDigest), // Original value: 0x0000014D + 334 => Ok(Self::NV_Read), // Original value: 0x0000014E + 335 => Ok(Self::NV_ReadLock), // Original value: 0x0000014F + 336 => Ok(Self::ObjectChangeAuth), // Original value: 0x00000150 + 337 => Ok(Self::PolicySecret), // Original value: 0x00000151 + 338 => Ok(Self::Rewrap), // Original value: 0x00000152 + 339 => Ok(Self::Create), // Original value: 0x00000153 + 340 => Ok(Self::ECDH_ZGen), // Original value: 0x00000154 + 341 => Ok(Self::MAC), // Original value: 0x00000155 + 342 => Ok(Self::Import), // Original value: 0x00000156 + 343 => Ok(Self::Load), // Original value: 0x00000157 + 344 => Ok(Self::Quote), // Original value: 0x00000158 + 345 => Ok(Self::RSA_Decrypt), // Original value: 0x00000159 + 347 => Ok(Self::MAC_Start), // Original value: 0x0000015B + 348 => Ok(Self::SequenceUpdate), // Original value: 0x0000015C + 349 => Ok(Self::Sign), // Original value: 0x0000015D + 350 => Ok(Self::Unseal), // Original value: 0x0000015E + 352 => Ok(Self::PolicySigned), // Original value: 0x00000160 + 353 => Ok(Self::ContextLoad), // Original value: 0x00000161 + 354 => Ok(Self::ContextSave), // Original value: 0x00000162 + 355 => Ok(Self::ECDH_KeyGen), // Original value: 0x00000163 + 356 => Ok(Self::EncryptDecrypt), // Original value: 0x00000164 + 357 => Ok(Self::FlushContext), // Original value: 0x00000165 + 359 => Ok(Self::LoadExternal), // Original value: 0x00000167 + 360 => Ok(Self::MakeCredential), // Original value: 0x00000168 + 361 => Ok(Self::NV_ReadPublic), // Original value: 0x00000169 + 362 => Ok(Self::PolicyAuthorize), // Original value: 0x0000016A + 363 => Ok(Self::PolicyAuthValue), // Original value: 0x0000016B + 364 => Ok(Self::PolicyCommandCode), // Original value: 0x0000016C + 365 => Ok(Self::PolicyCounterTimer), // Original value: 0x0000016D + 366 => Ok(Self::PolicyCpHash), // Original value: 0x0000016E + 367 => Ok(Self::PolicyLocality), // Original value: 0x0000016F + 368 => Ok(Self::PolicyNameHash), // Original value: 0x00000170 + 369 => Ok(Self::PolicyOR), // Original value: 0x00000171 + 370 => Ok(Self::PolicyTicket), // Original value: 0x00000172 + 371 => Ok(Self::ReadPublic), // Original value: 0x00000173 + 372 => Ok(Self::RSA_Encrypt), // Original value: 0x00000174 + 374 => Ok(Self::StartAuthSession), // Original value: 0x00000176 + 375 => Ok(Self::VerifySignature), // Original value: 0x00000177 + 376 => Ok(Self::ECC_Parameters), // Original value: 0x00000178 + 377 => Ok(Self::FirmwareRead), // Original value: 0x00000179 + 378 => Ok(Self::GetCapability), // Original value: 0x0000017A + 379 => Ok(Self::GetRandom), // Original value: 0x0000017B + 380 => Ok(Self::GetTestResult), // Original value: 0x0000017C + 381 => Ok(Self::Hash), // Original value: 0x0000017D + 382 => Ok(Self::PCR_Read), // Original value: 0x0000017E + 383 => Ok(Self::PolicyPCR), // Original value: 0x0000017F + 384 => Ok(Self::PolicyRestart), // Original value: 0x00000180 + 385 => Ok(Self::ReadClock), // Original value: 0x00000181 + 386 => Ok(Self::PCR_Extend), // Original value: 0x00000182 + 387 => Ok(Self::PCR_SetAuthValue), // Original value: 0x00000183 + 388 => Ok(Self::NV_Certify), // Original value: 0x00000184 + 389 => Ok(Self::EventSequenceComplete), // Original value: 0x00000185 + 390 => Ok(Self::HashSequenceStart), // Original value: 0x00000186 + 391 => Ok(Self::PolicyPhysicalPresence), // Original value: 0x00000187 + 392 => Ok(Self::PolicyDuplicationSelect), // Original value: 0x00000188 + 393 => Ok(Self::PolicyGetDigest), // Original value: 0x00000189 + 394 => Ok(Self::TestParms), // Original value: 0x0000018A + 395 => Ok(Self::Commit), // Original value: 0x0000018B + 396 => Ok(Self::PolicyPassword), // Original value: 0x0000018C + 397 => Ok(Self::ZGen_2Phase), // Original value: 0x0000018D + 398 => Ok(Self::EC_Ephemeral), // Original value: 0x0000018E + 399 => Ok(Self::PolicyNvWritten), // Original value: 0x0000018F + 400 => Ok(Self::PolicyTemplate), // Original value: 0x00000190 + 401 => Ok(Self::CreateLoaded), // Original value: 0x00000191 + 402 => Ok(Self::PolicyAuthorizeNV), // Original value: 0x00000192 + 403 => Ok(Self::EncryptDecrypt2), // Original value: 0x00000193 + 404 => Ok(Self::AC_GetCapability), // Original value: 0x00000194 + 405 => Ok(Self::AC_Send), // Original value: 0x00000195 + 406 => Ok(Self::Policy_AC_SendSelect), // Original value: 0x00000196 + 407 => Ok(Self::CertifyX509), // Original value: 0x00000197 + 408 => Ok(Self::ACT_SetTimeout), // Original value: 0x00000198 + 409 => Ok(Self::ECC_Encrypt), // Original value: 0x00000199 + 410 => Ok(Self::LAST), // Original value: 0x0000019A + 536870912 => Ok(Self::Vendor_TCG_Test), // Original value: CC_VEND.into()+0x0000 + _ => Err(TpmError::InvalidEnumValue), + } + } +} + +impl TpmEnum for TPM_CC { + fn get_value(&self) -> u32 { + self.0.into() + } + + fn try_from_trait(value: u64) -> Result where Self: Sized { + TPM_CC::try_from(value as u32) + } + + fn new_from_trait(value: u64) -> Result where Self: Sized { + Ok(TPM_CC(value as u32)) + } +} + +impl From for u32 { + fn from(value: TPM_CC) -> Self { + value.0 as u32 + } +} + +impl From for i32 { + fn from(value: TPM_CC) -> Self { + value.0 as i32 + } +} + +impl fmt::Display for TPM_CC { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + 287 => write!(f, "NV_UndefineSpaceSpecial"), + 288 => write!(f, "EvictControl"), + 289 => write!(f, "HierarchyControl"), + 290 => write!(f, "NV_UndefineSpace"), + 292 => write!(f, "ChangeEPS"), + 293 => write!(f, "ChangePPS"), + 294 => write!(f, "Clear"), + 295 => write!(f, "ClearControl"), + 296 => write!(f, "ClockSet"), + 297 => write!(f, "HierarchyChangeAuth"), + 298 => write!(f, "NV_DefineSpace"), + 299 => write!(f, "PCR_Allocate"), + 300 => write!(f, "PCR_SetAuthPolicy"), + 301 => write!(f, "PP_Commands"), + 302 => write!(f, "SetPrimaryPolicy"), + 303 => write!(f, "FieldUpgradeStart"), + 304 => write!(f, "ClockRateAdjust"), + 305 => write!(f, "CreatePrimary"), + 306 => write!(f, "NV_GlobalWriteLock"), + 307 => write!(f, "GetCommandAuditDigest"), + 308 => write!(f, "NV_Increment"), + 309 => write!(f, "NV_SetBits"), + 310 => write!(f, "NV_Extend"), + 311 => write!(f, "NV_Write"), + 312 => write!(f, "NV_WriteLock"), + 313 => write!(f, "DictionaryAttackLockReset"), + 314 => write!(f, "DictionaryAttackParameters"), + 315 => write!(f, "NV_ChangeAuth"), + 316 => write!(f, "PCR_Event"), + 317 => write!(f, "PCR_Reset"), + 318 => write!(f, "SequenceComplete"), + 319 => write!(f, "SetAlgorithmSet"), + 320 => write!(f, "SetCommandCodeAuditStatus"), + 321 => write!(f, "FieldUpgradeData"), + 322 => write!(f, "IncrementalSelfTest"), + 323 => write!(f, "SelfTest"), + 324 => write!(f, "Startup"), + 325 => write!(f, "Shutdown"), + 326 => write!(f, "StirRandom"), + 327 => write!(f, "ActivateCredential"), + 328 => write!(f, "Certify"), + 329 => write!(f, "PolicyNV"), + 330 => write!(f, "CertifyCreation"), + 331 => write!(f, "Duplicate"), + 332 => write!(f, "GetTime"), + 333 => write!(f, "GetSessionAuditDigest"), + 334 => write!(f, "NV_Read"), + 335 => write!(f, "NV_ReadLock"), + 336 => write!(f, "ObjectChangeAuth"), + 337 => write!(f, "PolicySecret"), + 338 => write!(f, "Rewrap"), + 339 => write!(f, "Create"), + 340 => write!(f, "ECDH_ZGen"), + 341 => write!(f, "MAC"), + 342 => write!(f, "Import"), + 343 => write!(f, "Load"), + 344 => write!(f, "Quote"), + 345 => write!(f, "RSA_Decrypt"), + 347 => write!(f, "MAC_Start"), + 348 => write!(f, "SequenceUpdate"), + 349 => write!(f, "Sign"), + 350 => write!(f, "Unseal"), + 352 => write!(f, "PolicySigned"), + 353 => write!(f, "ContextLoad"), + 354 => write!(f, "ContextSave"), + 355 => write!(f, "ECDH_KeyGen"), + 356 => write!(f, "EncryptDecrypt"), + 357 => write!(f, "FlushContext"), + 359 => write!(f, "LoadExternal"), + 360 => write!(f, "MakeCredential"), + 361 => write!(f, "NV_ReadPublic"), + 362 => write!(f, "PolicyAuthorize"), + 363 => write!(f, "PolicyAuthValue"), + 364 => write!(f, "PolicyCommandCode"), + 365 => write!(f, "PolicyCounterTimer"), + 366 => write!(f, "PolicyCpHash"), + 367 => write!(f, "PolicyLocality"), + 368 => write!(f, "PolicyNameHash"), + 369 => write!(f, "PolicyOR"), + 370 => write!(f, "PolicyTicket"), + 371 => write!(f, "ReadPublic"), + 372 => write!(f, "RSA_Encrypt"), + 374 => write!(f, "StartAuthSession"), + 375 => write!(f, "VerifySignature"), + 376 => write!(f, "ECC_Parameters"), + 377 => write!(f, "FirmwareRead"), + 378 => write!(f, "GetCapability"), + 379 => write!(f, "GetRandom"), + 380 => write!(f, "GetTestResult"), + 381 => write!(f, "Hash"), + 382 => write!(f, "PCR_Read"), + 383 => write!(f, "PolicyPCR"), + 384 => write!(f, "PolicyRestart"), + 385 => write!(f, "ReadClock"), + 386 => write!(f, "PCR_Extend"), + 387 => write!(f, "PCR_SetAuthValue"), + 388 => write!(f, "NV_Certify"), + 389 => write!(f, "EventSequenceComplete"), + 390 => write!(f, "HashSequenceStart"), + 391 => write!(f, "PolicyPhysicalPresence"), + 392 => write!(f, "PolicyDuplicationSelect"), + 393 => write!(f, "PolicyGetDigest"), + 394 => write!(f, "TestParms"), + 395 => write!(f, "Commit"), + 396 => write!(f, "PolicyPassword"), + 397 => write!(f, "ZGen_2Phase"), + 398 => write!(f, "EC_Ephemeral"), + 399 => write!(f, "PolicyNvWritten"), + 400 => write!(f, "PolicyTemplate"), + 401 => write!(f, "CreateLoaded"), + 402 => write!(f, "PolicyAuthorizeNV"), + 403 => write!(f, "EncryptDecrypt2"), + 404 => write!(f, "AC_GetCapability"), + 405 => write!(f, "AC_Send"), + 406 => write!(f, "Policy_AC_SendSelect"), + 407 => write!(f, "CertifyX509"), + 408 => write!(f, "ACT_SetTimeout"), + 409 => write!(f, "ECC_Encrypt"), + 410 => write!(f, "LAST"), + 536870912 => write!(f, "Vendor_TCG_Test"), + _ => write!(f, "{}", enum_to_str(self.0 as u64, std::any::TypeId::of::())), + } + } +} + +/// Architecturally defined constants +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub struct ImplementationConstants(pub u32); + +impl ImplementationConstants { + pub const Ossl: Self = Self(0x1); // Original value: 1 + pub const Ltc: Self = Self(0x2); // Original value: 2 + pub const Msbn: Self = Self(0x3); // Original value: 3 + pub const Symcrypt: Self = Self(0x4); // Original value: 4 + pub const HASH_COUNT: Self = Self(0x3); // Original value: 3 + pub const MAX_SYM_KEY_BITS: Self = Self(0x100); // Original value: 256 + pub const MAX_SYM_KEY_BYTES: Self = Self(0x20); // Original value: ((MAX_SYM_KEY_BITS.into() + 7) / 8) + pub const MAX_SYM_BLOCK_SIZE: Self = Self(0x10); // Original value: 16 + pub const MAX_CAP_CC: Self = Self(0x19A); // Original value: TPM_CC::LAST.into() + pub const MAX_RSA_KEY_BYTES: Self = Self(0x100); // Original value: 256 + pub const MAX_AES_KEY_BYTES: Self = Self(0x20); // Original value: 32 + pub const MAX_ECC_KEY_BYTES: Self = Self(0x30); // Original value: 48 + pub const LABEL_MAX_BUFFER: Self = Self(0x20); // Original value: 32 + pub const _TPM_CAP_SIZE: Self = Self(0x4); // Original value: 0x4 /* sizeof(UINT32) */ + pub const MAX_CAP_DATA: Self = Self(0x3F8); // Original value: (Implementation::MAX_CAP_BUFFER.into()-_TPM_CAP_SIZE.into()-0x4) /* (MAX_CAP_BUFFER-_TPM_CAP_SIZE-sizeof(UINT32)) */ + pub const MAX_CAP_ALGS: Self = Self(0xA9); // Original value: (MAX_CAP_DATA.into() / 0x6) /* (MAX_CAP_DATA / sizeof(TPMS_ALG_PROPERTY)) */ + pub const MAX_CAP_HANDLES: Self = Self(0xFE); // Original value: (MAX_CAP_DATA.into() / 0x4) /* (MAX_CAP_DATA / sizeof(TPM_HANDLE)) */ + pub const MAX_TPM_PROPERTIES: Self = Self(0x7F); // Original value: (MAX_CAP_DATA.into() / 0x8) /* (MAX_CAP_DATA / sizeof(TPMS_TAGGED_PROPERTY)) */ + pub const MAX_PCR_PROPERTIES: Self = Self(0xCB); // Original value: (MAX_CAP_DATA.into() / 0x5) /* (MAX_CAP_DATA / sizeof(TPMS_TAGGED_PCR_SELECT)) */ + pub const MAX_ECC_CURVES: Self = Self(0x1FC); // Original value: (MAX_CAP_DATA.into() / 0x2) /* (MAX_CAP_DATA / sizeof(TPM_ECC_CURVE)) */ + pub const MAX_TAGGED_POLICIES: Self = Self(0xE); // Original value: (MAX_CAP_DATA.into() / 0x46) /* (MAX_CAP_DATA / sizeof(TPMS_TAGGED_POLICY)) */ + pub const MAX_AC_CAPABILITIES: Self = Self(0x7F); // Original value: (MAX_CAP_DATA.into() / 0x8) /* (MAX_CAP_DATA / sizeof(TPMS_AC_OUTPUT)) */ + pub const MAX_ACT_DATA: Self = Self(0x54); // Original value: MAX_CAP_DATA.into() / 0xC /* MAX_CAP_DATA / sizeof(TPMS_ACT_DATA) */ + + pub fn try_from(value: u32) -> Result { + match value { + 1 => Ok(Self::Ossl), // Original value: 1 + 2 => Ok(Self::Ltc), // Original value: 2 + 3 => Ok(Self::HASH_COUNT), // Original value: 3 + 4 => Ok(Self::_TPM_CAP_SIZE), // Original value: 0x4 /* sizeof(UINT32) */ + 256 => Ok(Self::MAX_RSA_KEY_BYTES), // Original value: 256 + 32 => Ok(Self::LABEL_MAX_BUFFER), // Original value: 32 + 16 => Ok(Self::MAX_SYM_BLOCK_SIZE), // Original value: 16 + 410 => Ok(Self::MAX_CAP_CC), // Original value: TPM_CC::LAST.into() + 48 => Ok(Self::MAX_ECC_KEY_BYTES), // Original value: 48 + 1016 => Ok(Self::MAX_CAP_DATA), // Original value: (Implementation::MAX_CAP_BUFFER.into()-_TPM_CAP_SIZE.into()-0x4) /* (MAX_CAP_BUFFER-_TPM_CAP_SIZE-sizeof(UINT32)) */ + 169 => Ok(Self::MAX_CAP_ALGS), // Original value: (MAX_CAP_DATA.into() / 0x6) /* (MAX_CAP_DATA / sizeof(TPMS_ALG_PROPERTY)) */ + 254 => Ok(Self::MAX_CAP_HANDLES), // Original value: (MAX_CAP_DATA.into() / 0x4) /* (MAX_CAP_DATA / sizeof(TPM_HANDLE)) */ + 127 => Ok(Self::MAX_AC_CAPABILITIES), // Original value: (MAX_CAP_DATA.into() / 0x8) /* (MAX_CAP_DATA / sizeof(TPMS_AC_OUTPUT)) */ + 203 => Ok(Self::MAX_PCR_PROPERTIES), // Original value: (MAX_CAP_DATA.into() / 0x5) /* (MAX_CAP_DATA / sizeof(TPMS_TAGGED_PCR_SELECT)) */ + 508 => Ok(Self::MAX_ECC_CURVES), // Original value: (MAX_CAP_DATA.into() / 0x2) /* (MAX_CAP_DATA / sizeof(TPM_ECC_CURVE)) */ + 14 => Ok(Self::MAX_TAGGED_POLICIES), // Original value: (MAX_CAP_DATA.into() / 0x46) /* (MAX_CAP_DATA / sizeof(TPMS_TAGGED_POLICY)) */ + 84 => Ok(Self::MAX_ACT_DATA), // Original value: MAX_CAP_DATA.into() / 0xC /* MAX_CAP_DATA / sizeof(TPMS_ACT_DATA) */ + _ => Err(TpmError::InvalidEnumValue), + } + } +} + +impl TpmEnum for ImplementationConstants { + fn get_value(&self) -> u32 { + self.0.into() + } + + fn try_from_trait(value: u64) -> Result where Self: Sized { + ImplementationConstants::try_from(value as u32) + } + + fn new_from_trait(value: u64) -> Result where Self: Sized { + Ok(ImplementationConstants(value as u32)) + } +} + +impl From for u32 { + fn from(value: ImplementationConstants) -> Self { + value.0 as u32 + } +} + +impl From for i32 { + fn from(value: ImplementationConstants) -> Self { + value.0 as i32 + } +} + +impl fmt::Display for ImplementationConstants { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + 1 => write!(f, "Ossl"), + 2 => write!(f, "Ltc"), + 3 => write!(f, "HASH_COUNT"), + 4 => write!(f, "_TPM_CAP_SIZE"), + 256 => write!(f, "MAX_RSA_KEY_BYTES"), + 32 => write!(f, "LABEL_MAX_BUFFER"), + 16 => write!(f, "MAX_SYM_BLOCK_SIZE"), + 410 => write!(f, "MAX_CAP_CC"), + 48 => write!(f, "MAX_ECC_KEY_BYTES"), + 1016 => write!(f, "MAX_CAP_DATA"), + 169 => write!(f, "MAX_CAP_ALGS"), + 254 => write!(f, "MAX_CAP_HANDLES"), + 127 => write!(f, "MAX_AC_CAPABILITIES"), + 203 => write!(f, "MAX_PCR_PROPERTIES"), + 508 => write!(f, "MAX_ECC_CURVES"), + 14 => write!(f, "MAX_TAGGED_POLICIES"), + 84 => write!(f, "MAX_ACT_DATA"), + _ => write!(f, "{}", enum_to_str(self.0 as u64, std::any::TypeId::of::())), + } + } +} + +/// In general, response codes defined in TPM 2.0 Part 2 will be unmarshaling errors and +/// will have the F (format) bit SET. Codes that are unique to TPM 2.0 Part 3 will have +/// the F bit CLEAR but the V (version) attribute will be SET to indicate that it is a TPM +/// 2.0 response code. See Response Code Details in TPM 2.0 Part 1. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub struct TPM_RC(pub u32); + +impl TPM_RC { + pub const SUCCESS: Self = Self(0x0); // Original value: 0x000 + + /// Defined for compatibility with TPM 1.2 + pub const BAD_TAG: Self = Self(0x1E); // Original value: 0x01E + + /// Set for all format 0 response codes + pub const RC_VER1: Self = Self(0x100); + + /// TPM not initialized by TPM2_Startup or already initialized + pub const INITIALIZE: Self = Self(0x100); // Original value: RC_VER1.into() + 0x000 + + /// Commands not being accepted because of a TPM failure + /// NOTE This may be returned by TPM2_GetTestResult() as the testResult parameter. + pub const FAILURE: Self = Self(0x101); // Original value: RC_VER1.into() + 0x001 + + /// Improper use of a sequence handle + pub const SEQUENCE: Self = Self(0x103); // Original value: RC_VER1.into() + 0x003 + + /// Not currently used + pub const PRIVATE: Self = Self(0x10B); // Original value: RC_VER1.into() + 0x00B + + /// Not currently used + pub const HMAC: Self = Self(0x119); // Original value: RC_VER1.into() + 0x019 + + /// The command is disabled + pub const DISABLED: Self = Self(0x120); // Original value: RC_VER1.into() + 0x020 + + /// Command failed because audit sequence required exclusivity + pub const EXCLUSIVE: Self = Self(0x121); // Original value: RC_VER1.into() + 0x021 + + /// Authorization handle is not correct for command + pub const AUTH_TYPE: Self = Self(0x124); // Original value: RC_VER1.into() + 0x024 + + /// Command requires an authorization session for handle and it is not present. + pub const AUTH_MISSING: Self = Self(0x125); // Original value: RC_VER1.into() + 0x025 + + /// Policy failure in math operation or an invalid authPolicy value + pub const POLICY: Self = Self(0x126); // Original value: RC_VER1.into() + 0x026 + + /// PCR check fail + pub const PCR: Self = Self(0x127); // Original value: RC_VER1.into() + 0x027 + + /// PCR have changed since checked. + pub const PCR_CHANGED: Self = Self(0x128); // Original value: RC_VER1.into() + 0x028 + + /// For all commands other than TPM2_FieldUpgradeData(), this code indicates that the TPM + /// is in field upgrade mode; for TPM2_FieldUpgradeData(), this code indicates that the + /// TPM is not in field upgrade mode + pub const UPGRADE: Self = Self(0x12D); // Original value: RC_VER1.into() + 0x02D + + /// Context ID counter is at maximum. + pub const TOO_MANY_CONTEXTS: Self = Self(0x12E); // Original value: RC_VER1.into() + 0x02E + + /// AuthValue or authPolicy is not available for selected entity. + pub const AUTH_UNAVAILABLE: Self = Self(0x12F); // Original value: RC_VER1.into() + 0x02F + + /// A _TPM_Init and Startup(CLEAR) is required before the TPM can resume operation. + pub const REBOOT: Self = Self(0x130); // Original value: RC_VER1.into() + 0x030 + + /// The protection algorithms (hash and symmetric) are not reasonably balanced. The digest + /// size of the hash must be larger than the key size of the symmetric algorithm. + pub const UNBALANCED: Self = Self(0x131); // Original value: RC_VER1.into() + 0x031 + + /// Command commandSize value is inconsistent with contents of the command buffer; either + /// the size is not the same as the octets loaded by the hardware interface layer or the + /// value is not large enough to hold a command header + pub const COMMAND_SIZE: Self = Self(0x142); // Original value: RC_VER1.into() + 0x042 + + /// Command code not supported + pub const COMMAND_CODE: Self = Self(0x143); // Original value: RC_VER1.into() + 0x043 + + /// The value of authorizationSize is out of range or the number of octets in the + /// Authorization Area is greater than required + pub const AUTHSIZE: Self = Self(0x144); // Original value: RC_VER1.into() + 0x044 + + /// Use of an authorization session with a context command or another command that cannot + /// have an authorization session. + pub const AUTH_CONTEXT: Self = Self(0x145); // Original value: RC_VER1.into() + 0x045 + + /// NV offset+size is out of range. + pub const NV_RANGE: Self = Self(0x146); // Original value: RC_VER1.into() + 0x046 + + /// Requested allocation size is larger than allowed. + pub const NV_SIZE: Self = Self(0x147); // Original value: RC_VER1.into() + 0x047 + + /// NV access locked. + pub const NV_LOCKED: Self = Self(0x148); // Original value: RC_VER1.into() + 0x048 + + /// NV access authorization fails in command actions (this failure does not affect lockout.action) + pub const NV_AUTHORIZATION: Self = Self(0x149); // Original value: RC_VER1.into() + 0x049 + + /// An NV Index is used before being initialized or the state saved by + /// TPM2_Shutdown(STATE) could not be restored + pub const NV_UNINITIALIZED: Self = Self(0x14A); // Original value: RC_VER1.into() + 0x04A + + /// Insufficient space for NV allocation + pub const NV_SPACE: Self = Self(0x14B); // Original value: RC_VER1.into() + 0x04B + + /// NV Index or persistent object already defined + pub const NV_DEFINED: Self = Self(0x14C); // Original value: RC_VER1.into() + 0x04C + + /// Context in TPM2_ContextLoad() is not valid + pub const BAD_CONTEXT: Self = Self(0x150); // Original value: RC_VER1.into() + 0x050 + + /// CpHash value already set or not correct for use + pub const CPHASH: Self = Self(0x151); // Original value: RC_VER1.into() + 0x051 + + /// Handle for parent is not a valid parent + pub const PARENT: Self = Self(0x152); // Original value: RC_VER1.into() + 0x052 + + /// Some function needs testing. + pub const NEEDS_TEST: Self = Self(0x153); // Original value: RC_VER1.into() + 0x053 + + /// Returned when an internal function cannot process a request due to an unspecified + /// problem. This code is usually related to invalid parameters that are not properly + /// filtered by the input unmarshaling code. + pub const NO_RESULT: Self = Self(0x154); // Original value: RC_VER1.into() + 0x054 + + /// The sensitive area did not unmarshal correctly after decryption this code is used in + /// lieu of the other unmarshaling errors so that an attacker cannot determine where the + /// unmarshaling error occurred + pub const SENSITIVE: Self = Self(0x155); // Original value: RC_VER1.into() + 0x055 + + /// Largest version 1 code that is not a warning + pub const RC_MAX_FM0: Self = Self(0x17F); // Original value: RC_VER1.into() + 0x07F + + /// This bit is SET in all format 1 response codes + /// The codes in this group may have a value added to them to indicate the handle, + /// session, or parameter to which they apply. + pub const RC_FMT1: Self = Self(0x80); // Original value: 0x080 + + /// Asymmetric algorithm not supported or not correct + pub const ASYMMETRIC: Self = Self(0x81); // Original value: RC_FMT1.into() + 0x001 + + /// Inconsistent attributes + pub const ATTRIBUTES: Self = Self(0x82); // Original value: RC_FMT1.into() + 0x002 + + /// Hash algorithm not supported or not appropriate + pub const HASH: Self = Self(0x83); // Original value: RC_FMT1.into() + 0x003 + + /// Value is out of range or is not correct for the context + pub const VALUE: Self = Self(0x84); // Original value: RC_FMT1.into() + 0x004 + + /// Hierarchy is not enabled or is not correct for the use + pub const HIERARCHY: Self = Self(0x85); // Original value: RC_FMT1.into() + 0x005 + + /// Key size is not supported + pub const KEY_SIZE: Self = Self(0x87); // Original value: RC_FMT1.into() + 0x007 + + /// Mask generation function not supported + pub const MGF: Self = Self(0x88); // Original value: RC_FMT1.into() + 0x008 + + /// Mode of operation not supported + pub const MODE: Self = Self(0x89); // Original value: RC_FMT1.into() + 0x009 + + /// The type of the value is not appropriate for the use + pub const TYPE: Self = Self(0x8A); // Original value: RC_FMT1.into() + 0x00A + + /// The handle is not correct for the use + pub const HANDLE: Self = Self(0x8B); // Original value: RC_FMT1.into() + 0x00B + + /// Unsupported key derivation function or function not appropriate for use + pub const KDF: Self = Self(0x8C); // Original value: RC_FMT1.into() + 0x00C + + /// Value was out of allowed range. + pub const RANGE: Self = Self(0x8D); // Original value: RC_FMT1.into() + 0x00D + + /// The authorization HMAC check failed and DA counter incremented + pub const AUTH_FAIL: Self = Self(0x8E); // Original value: RC_FMT1.into() + 0x00E + + /// Invalid nonce size or nonce value mismatch + pub const NONCE: Self = Self(0x8F); // Original value: RC_FMT1.into() + 0x00F + + /// Authorization requires assertion of PP + pub const PP: Self = Self(0x90); // Original value: RC_FMT1.into() + 0x010 + + /// Unsupported or incompatible scheme + pub const SCHEME: Self = Self(0x92); // Original value: RC_FMT1.into() + 0x012 + + /// Structure is the wrong size + pub const SIZE: Self = Self(0x95); // Original value: RC_FMT1.into() + 0x015 + + /// Unsupported symmetric algorithm or key size, or not appropriate for instance + pub const SYMMETRIC: Self = Self(0x96); // Original value: RC_FMT1.into() + 0x016 + + /// Incorrect structure tag + pub const TAG: Self = Self(0x97); // Original value: RC_FMT1.into() + 0x017 + + /// Union selector is incorrect + pub const SELECTOR: Self = Self(0x98); // Original value: RC_FMT1.into() + 0x018 + + /// The TPM was unable to unmarshal a value because there were not enough octets in the + /// input buffer + pub const INSUFFICIENT: Self = Self(0x9A); // Original value: RC_FMT1.into() + 0x01A + + /// The signature is not valid + pub const SIGNATURE: Self = Self(0x9B); // Original value: RC_FMT1.into() + 0x01B + + /// Key fields are not compatible with the selected use + pub const KEY: Self = Self(0x9C); // Original value: RC_FMT1.into() + 0x01C + + /// A policy check failed + pub const POLICY_FAIL: Self = Self(0x9D); // Original value: RC_FMT1.into() + 0x01D + + /// Integrity check failed + pub const INTEGRITY: Self = Self(0x9F); // Original value: RC_FMT1.into() + 0x01F + + /// Invalid ticket + pub const TICKET: Self = Self(0xA0); // Original value: RC_FMT1.into() + 0x020 + + /// Reserved bits not set to zero as required + pub const RESERVED_BITS: Self = Self(0xA1); // Original value: RC_FMT1.into() + 0x021 + + /// Authorization failure without DA implications + pub const BAD_AUTH: Self = Self(0xA2); // Original value: RC_FMT1.into() + 0x022 + + /// The policy has expired + pub const EXPIRED: Self = Self(0xA3); // Original value: RC_FMT1.into() + 0x023 + + /// The commandCode in the policy is not the commandCode of the command or the command + /// code in a policy command references a command that is not implemented + pub const POLICY_CC: Self = Self(0xA4); // Original value: RC_FMT1.into() + 0x024 + + /// Public and sensitive portions of an object are not cryptographically bound + pub const BINDING: Self = Self(0xA5); // Original value: RC_FMT1.into() + 0x025 + + /// Curve not supported + pub const CURVE: Self = Self(0xA6); // Original value: RC_FMT1.into() + 0x026 + + /// Point is not on the required curve. + pub const ECC_POINT: Self = Self(0xA7); // Original value: RC_FMT1.into() + 0x027 + + /// Set for warning response codes + pub const RC_WARN: Self = Self(0x900); + + /// Gap for context ID is too large + pub const CONTEXT_GAP: Self = Self(0x901); // Original value: RC_WARN.into() + 0x001 + + /// Out of memory for object contexts + pub const OBJECT_MEMORY: Self = Self(0x902); // Original value: RC_WARN.into() + 0x002 + + /// Out of memory for session contexts + pub const SESSION_MEMORY: Self = Self(0x903); // Original value: RC_WARN.into() + 0x003 + + /// Out of shared object/session memory or need space for internal operations + pub const MEMORY: Self = Self(0x904); // Original value: RC_WARN.into() + 0x004 + + /// Out of session handles a session must be flushed before a new session may be created + pub const SESSION_HANDLES: Self = Self(0x905); // Original value: RC_WARN.into() + 0x005 + + /// Out of object handles the handle space for objects is depleted and a reboot is required + /// NOTE 1 This cannot occur on the reference implementation. + /// NOTE 2 There is no reason why an implementation would implement a design that would + /// deplete handle space. Platform specifications are encouraged to forbid it. + pub const OBJECT_HANDLES: Self = Self(0x906); // Original value: RC_WARN.into() + 0x006 + + /// Bad locality + pub const LOCALITY: Self = Self(0x907); // Original value: RC_WARN.into() + 0x007 + + /// The TPM has suspended operation on the command; forward progress was made and the + /// command may be retried + /// See TPM 2.0 Part 1, Multi-tasking. + /// NOTE This cannot occur on the reference implementation. + pub const YIELDED: Self = Self(0x908); // Original value: RC_WARN.into() + 0x008 + + /// The command was canceled + pub const CANCELED: Self = Self(0x909); // Original value: RC_WARN.into() + 0x009 + + /// TPM is performing self-tests + pub const TESTING: Self = Self(0x90A); // Original value: RC_WARN.into() + 0x00A + + /// The 1st handle in the handle area references a transient object or session that is not + /// loaded + pub const REFERENCE_H0: Self = Self(0x910); // Original value: RC_WARN.into() + 0x010 + + /// The 2nd handle in the handle area references a transient object or session that is not + /// loaded + pub const REFERENCE_H1: Self = Self(0x911); // Original value: RC_WARN.into() + 0x011 + + /// The 3rd handle in the handle area references a transient object or session that is not + /// loaded + pub const REFERENCE_H2: Self = Self(0x912); // Original value: RC_WARN.into() + 0x012 + + /// The 4th handle in the handle area references a transient object or session that is not + /// loaded + pub const REFERENCE_H3: Self = Self(0x913); // Original value: RC_WARN.into() + 0x013 + + /// The 5th handle in the handle area references a transient object or session that is not + /// loaded + pub const REFERENCE_H4: Self = Self(0x914); // Original value: RC_WARN.into() + 0x014 + + /// The 6th handle in the handle area references a transient object or session that is not + /// loaded + pub const REFERENCE_H5: Self = Self(0x915); // Original value: RC_WARN.into() + 0x015 + + /// The 7th handle in the handle area references a transient object or session that is not + /// loaded + pub const REFERENCE_H6: Self = Self(0x916); // Original value: RC_WARN.into() + 0x016 + + /// The 1st authorization session handle references a session that is not loaded + pub const REFERENCE_S0: Self = Self(0x918); // Original value: RC_WARN.into() + 0x018 + + /// The 2nd authorization session handle references a session that is not loaded + pub const REFERENCE_S1: Self = Self(0x919); // Original value: RC_WARN.into() + 0x019 + + /// The 3rd authorization session handle references a session that is not loaded + pub const REFERENCE_S2: Self = Self(0x91A); // Original value: RC_WARN.into() + 0x01A + + /// The 4th authorization session handle references a session that is not loaded + pub const REFERENCE_S3: Self = Self(0x91B); // Original value: RC_WARN.into() + 0x01B + + /// The 5th session handle references a session that is not loaded + pub const REFERENCE_S4: Self = Self(0x91C); // Original value: RC_WARN.into() + 0x01C + + /// The 6th session handle references a session that is not loaded + pub const REFERENCE_S5: Self = Self(0x91D); // Original value: RC_WARN.into() + 0x01D + + /// The 7th authorization session handle references a session that is not loaded + pub const REFERENCE_S6: Self = Self(0x91E); // Original value: RC_WARN.into() + 0x01E + + /// The TPM is rate-limiting accesses to prevent wearout of NV + pub const NV_RATE: Self = Self(0x920); // Original value: RC_WARN.into() + 0x020 + + /// Authorizations for objects subject to DA protection are not allowed at this time + /// because the TPM is in DA lockout mode + pub const LOCKOUT: Self = Self(0x921); // Original value: RC_WARN.into() + 0x021 + + /// The TPM was not able to start the command + pub const RETRY: Self = Self(0x922); // Original value: RC_WARN.into() + 0x022 + + /// The command may require writing of NV and NV is not current accessible + pub const NV_UNAVAILABLE: Self = Self(0x923); // Original value: RC_WARN.into() + 0x023 + + /// This value is reserved and shall not be returned by the TPM + pub const NOT_USED: Self = Self(0x97F); // Original value: RC_WARN.into() + 0x7F + + /// Add to a handle-related error + pub const H: Self = Self(0x0); // Original value: 0x000 + + /// Add to a parameter-related error + pub const P: Self = Self(0x40); // Original value: 0x040 + + /// Add to a session-related error + pub const S: Self = Self(0x800); + + /// Add to a parameter-, handle-, or session-related error + pub const _1: Self = Self(0x100); + + /// Add to a parameter-, handle-, or session-related error + pub const _2: Self = Self(0x200); + + /// Add to a parameter-, handle-, or session-related error + pub const _3: Self = Self(0x300); + + /// Add to a parameter-, handle-, or session-related error + pub const _4: Self = Self(0x400); + + /// Add to a parameter-, handle-, or session-related error + pub const _5: Self = Self(0x500); + + /// Add to a parameter-, handle-, or session-related error + pub const _6: Self = Self(0x600); + + /// Add to a parameter-, handle-, or session-related error + pub const _7: Self = Self(0x700); + + /// Add to a parameter-related error + pub const _8: Self = Self(0x800); + + /// Add to a parameter-related error + pub const _9: Self = Self(0x900); + + /// Add to a parameter-related error + pub const A: Self = Self(0xA00); + + /// Add to a parameter-related error + pub const B: Self = Self(0xB00); + + /// Add to a parameter-related error + pub const C: Self = Self(0xC00); + + /// Add to a parameter-related error + pub const D: Self = Self(0xD00); + + /// Add to a parameter-related error + pub const E: Self = Self(0xE00); + + /// Add to a parameter-related error + pub const F: Self = Self(0xF00); + + /// Number mask + pub const N_MASK: Self = Self(0xF00); + + /// Response buffer returned by the TPM is too short + pub const TSS_TCP_BAD_HANDSHAKE_RESP: Self = Self(0x40280001); + + /// Too old TCP server version + pub const TSS_TCP_SERVER_TOO_OLD: Self = Self(0x40280002); + + /// Bad ack from the TCP end point + pub const TSS_TCP_BAD_ACK: Self = Self(0x40280003); + + /// Wrong length of the response buffer returned by the TPM + pub const TSS_TCP_BAD_RESP_LEN: Self = Self(0x40280004); + + /// TPM2_Startup returned unexpected response code + pub const TSS_TCP_UNEXPECTED_STARTUP_RESP: Self = Self(0x40280005); + + /// Invalid size tag in the TPM response TCP packet + pub const TSS_TCP_INVALID_SIZE_TAG: Self = Self(0x40280006); + + /// TPM over TCP device is not connected + pub const TSS_TCP_DISCONNECTED: Self = Self(0x40280007); + + /// General TPM command dispatch failure + pub const TSS_DISPATCH_FAILED: Self = Self(0x40280010); + + /// Sending data to TPM failed + pub const TSS_SEND_OP_FAILED: Self = Self(0x40280011); + + /// Response buffer returned by the TPM is too short + pub const TSS_RESP_BUF_TOO_SHORT: Self = Self(0x40280021); + + /// Invalid tag in the response buffer returned by the TPM + pub const TSS_RESP_BUF_INVALID_SESSION_TAG: Self = Self(0x40280022); + + /// Inconsistent TPM response parameters size + pub const TSS_RESP_BUF_INVALID_SIZE: Self = Self(0x40280023); + + /// Windows TBS error TPM_E_COMMAND_BLOCKED + pub const TBS_COMMAND_BLOCKED: Self = Self(0x80280400); + + /// Windows TBS error TPM_E_INVALID_HANDLE + pub const TBS_INVALID_HANDLE: Self = Self(0x80280401); + + /// Windows TBS error TPM_E_DUPLICATE_VHANDLE + pub const TBS_DUPLICATE_V_HANDLE: Self = Self(0x80280402); + + /// Windows TBS error TPM_E_EMBEDDED_COMMAND_BLOCKED + pub const TBS_EMBEDDED_COMMAND_BLOCKED: Self = Self(0x80280403); + + /// Windows TBS error TPM_E_EMBEDDED_COMMAND_UNSUPPORTED + pub const TBS_EMBEDDED_COMMAND_UNSUPPORTED: Self = Self(0x80280404); + + /// Windows TBS returned success but empty response buffer + pub const TBS_UNKNOWN_ERROR: Self = Self(0x80284000); + + /// Windows TBS error TBS_E_INTERNAL_ERROR + pub const TBS_INTERNAL_ERROR: Self = Self(0x80284001); + + /// Windows TBS error TBS_E_BAD_PARAMETER + pub const TBS_BAD_PARAMETER: Self = Self(0x80284002); + + /// Windows TBS error TBS_E_INVALID_OUTPUT_POINTER + pub const TBS_INVALID_OUTPUT_POINTER: Self = Self(0x80284003); + + /// Windows TBS error TBS_E_INVALID_CONTEXT + pub const TBS_INVALID_CONTEXT: Self = Self(0x80284004); + + /// Windows TBS error TBS_E_INSUFFICIENT_BUFFER + pub const TBS_INSUFFICIENT_BUFFER: Self = Self(0x80284005); + + /// Windows TBS error TBS_E_IOERROR + pub const TBS_IO_ERROR: Self = Self(0x80284006); + + /// Windows TBS error TBS_E_INVALID_CONTEXT_PARAM + pub const TBS_INVALID_CONTEXT_PARAM: Self = Self(0x80284007); + + /// Windows TBS error TBS_E_SERVICE_NOT_RUNNING + pub const TBS_SERVICE_NOT_RUNNING: Self = Self(0x80284008); + + /// Windows TBS error TBS_E_TOO_MANY_TBS_CONTEXTS + pub const TBS_TOO_MANY_CONTEXTS: Self = Self(0x80284009); + + /// Windows TBS error TBS_E_TOO_MANY_TBS_RESOURCES + pub const TBS_TOO_MANY_RESOURCES: Self = Self(0x8028400A); + + /// Windows TBS error TBS_E_SERVICE_START_PENDING + pub const TBS_SERVICE_START_PENDING: Self = Self(0x8028400B); + + /// Windows TBS error TBS_E_PPI_NOT_SUPPORTED + pub const TBS_PPI_NOT_SUPPORTED: Self = Self(0x8028400C); + + /// Windows TBS error TBS_E_COMMAND_CANCELED + pub const TBS_COMMAND_CANCELED: Self = Self(0x8028400D); + + /// Windows TBS error TBS_E_BUFFER_TOO_LARGE + pub const TBS_BUFFER_TOO_LARGE: Self = Self(0x8028400E); + + /// Windows TBS error TBS_E_TPM_NOT_FOUND + pub const TBS_TPM_NOT_FOUND: Self = Self(0x8028400F); + + /// Windows TBS error TBS_E_SERVICE_DISABLED + pub const TBS_SERVICE_DISABLED: Self = Self(0x80284010); + + /// Windows TBS error TBS_E_ACCESS_DENIED + pub const TBS_ACCESS_DENIED: Self = Self(0x80284012); + + /// Windows TBS error TBS_E_PPI_FUNCTION_UNSUPPORTED + pub const TBS_PPI_FUNCTION_NOT_SUPPORTED: Self = Self(0x80284014); + + /// Windows TBS error TBS_E_OWNERAUTH_NOT_FOUND + pub const TBS_OWNER_AUTH_NOT_FOUND: Self = Self(0x80284015); + + pub fn try_from(value: u32) -> Result { + match value { + 0 => Ok(Self::H), // Original value: 0x000 + 30 => Ok(Self::BAD_TAG), // Original value: 0x01E + 256 => Ok(Self::_1), // Original value: 0x100 + 257 => Ok(Self::FAILURE), // Original value: RC_VER1.into() + 0x001 + 259 => Ok(Self::SEQUENCE), // Original value: RC_VER1.into() + 0x003 + 267 => Ok(Self::PRIVATE), // Original value: RC_VER1.into() + 0x00B + 281 => Ok(Self::HMAC), // Original value: RC_VER1.into() + 0x019 + 288 => Ok(Self::DISABLED), // Original value: RC_VER1.into() + 0x020 + 289 => Ok(Self::EXCLUSIVE), // Original value: RC_VER1.into() + 0x021 + 292 => Ok(Self::AUTH_TYPE), // Original value: RC_VER1.into() + 0x024 + 293 => Ok(Self::AUTH_MISSING), // Original value: RC_VER1.into() + 0x025 + 294 => Ok(Self::POLICY), // Original value: RC_VER1.into() + 0x026 + 295 => Ok(Self::PCR), // Original value: RC_VER1.into() + 0x027 + 296 => Ok(Self::PCR_CHANGED), // Original value: RC_VER1.into() + 0x028 + 301 => Ok(Self::UPGRADE), // Original value: RC_VER1.into() + 0x02D + 302 => Ok(Self::TOO_MANY_CONTEXTS), // Original value: RC_VER1.into() + 0x02E + 303 => Ok(Self::AUTH_UNAVAILABLE), // Original value: RC_VER1.into() + 0x02F + 304 => Ok(Self::REBOOT), // Original value: RC_VER1.into() + 0x030 + 305 => Ok(Self::UNBALANCED), // Original value: RC_VER1.into() + 0x031 + 322 => Ok(Self::COMMAND_SIZE), // Original value: RC_VER1.into() + 0x042 + 323 => Ok(Self::COMMAND_CODE), // Original value: RC_VER1.into() + 0x043 + 324 => Ok(Self::AUTHSIZE), // Original value: RC_VER1.into() + 0x044 + 325 => Ok(Self::AUTH_CONTEXT), // Original value: RC_VER1.into() + 0x045 + 326 => Ok(Self::NV_RANGE), // Original value: RC_VER1.into() + 0x046 + 327 => Ok(Self::NV_SIZE), // Original value: RC_VER1.into() + 0x047 + 328 => Ok(Self::NV_LOCKED), // Original value: RC_VER1.into() + 0x048 + 329 => Ok(Self::NV_AUTHORIZATION), // Original value: RC_VER1.into() + 0x049 + 330 => Ok(Self::NV_UNINITIALIZED), // Original value: RC_VER1.into() + 0x04A + 331 => Ok(Self::NV_SPACE), // Original value: RC_VER1.into() + 0x04B + 332 => Ok(Self::NV_DEFINED), // Original value: RC_VER1.into() + 0x04C + 336 => Ok(Self::BAD_CONTEXT), // Original value: RC_VER1.into() + 0x050 + 337 => Ok(Self::CPHASH), // Original value: RC_VER1.into() + 0x051 + 338 => Ok(Self::PARENT), // Original value: RC_VER1.into() + 0x052 + 339 => Ok(Self::NEEDS_TEST), // Original value: RC_VER1.into() + 0x053 + 340 => Ok(Self::NO_RESULT), // Original value: RC_VER1.into() + 0x054 + 341 => Ok(Self::SENSITIVE), // Original value: RC_VER1.into() + 0x055 + 383 => Ok(Self::RC_MAX_FM0), // Original value: RC_VER1.into() + 0x07F + 128 => Ok(Self::RC_FMT1), // Original value: 0x080 + 129 => Ok(Self::ASYMMETRIC), // Original value: RC_FMT1.into() + 0x001 + 130 => Ok(Self::ATTRIBUTES), // Original value: RC_FMT1.into() + 0x002 + 131 => Ok(Self::HASH), // Original value: RC_FMT1.into() + 0x003 + 132 => Ok(Self::VALUE), // Original value: RC_FMT1.into() + 0x004 + 133 => Ok(Self::HIERARCHY), // Original value: RC_FMT1.into() + 0x005 + 135 => Ok(Self::KEY_SIZE), // Original value: RC_FMT1.into() + 0x007 + 136 => Ok(Self::MGF), // Original value: RC_FMT1.into() + 0x008 + 137 => Ok(Self::MODE), // Original value: RC_FMT1.into() + 0x009 + 138 => Ok(Self::TYPE), // Original value: RC_FMT1.into() + 0x00A + 139 => Ok(Self::HANDLE), // Original value: RC_FMT1.into() + 0x00B + 140 => Ok(Self::KDF), // Original value: RC_FMT1.into() + 0x00C + 141 => Ok(Self::RANGE), // Original value: RC_FMT1.into() + 0x00D + 142 => Ok(Self::AUTH_FAIL), // Original value: RC_FMT1.into() + 0x00E + 143 => Ok(Self::NONCE), // Original value: RC_FMT1.into() + 0x00F + 144 => Ok(Self::PP), // Original value: RC_FMT1.into() + 0x010 + 146 => Ok(Self::SCHEME), // Original value: RC_FMT1.into() + 0x012 + 149 => Ok(Self::SIZE), // Original value: RC_FMT1.into() + 0x015 + 150 => Ok(Self::SYMMETRIC), // Original value: RC_FMT1.into() + 0x016 + 151 => Ok(Self::TAG), // Original value: RC_FMT1.into() + 0x017 + 152 => Ok(Self::SELECTOR), // Original value: RC_FMT1.into() + 0x018 + 154 => Ok(Self::INSUFFICIENT), // Original value: RC_FMT1.into() + 0x01A + 155 => Ok(Self::SIGNATURE), // Original value: RC_FMT1.into() + 0x01B + 156 => Ok(Self::KEY), // Original value: RC_FMT1.into() + 0x01C + 157 => Ok(Self::POLICY_FAIL), // Original value: RC_FMT1.into() + 0x01D + 159 => Ok(Self::INTEGRITY), // Original value: RC_FMT1.into() + 0x01F + 160 => Ok(Self::TICKET), // Original value: RC_FMT1.into() + 0x020 + 161 => Ok(Self::RESERVED_BITS), // Original value: RC_FMT1.into() + 0x021 + 162 => Ok(Self::BAD_AUTH), // Original value: RC_FMT1.into() + 0x022 + 163 => Ok(Self::EXPIRED), // Original value: RC_FMT1.into() + 0x023 + 164 => Ok(Self::POLICY_CC), // Original value: RC_FMT1.into() + 0x024 + 165 => Ok(Self::BINDING), // Original value: RC_FMT1.into() + 0x025 + 166 => Ok(Self::CURVE), // Original value: RC_FMT1.into() + 0x026 + 167 => Ok(Self::ECC_POINT), // Original value: RC_FMT1.into() + 0x027 + 2304 => Ok(Self::_9), // Original value: 0x900 + 2305 => Ok(Self::CONTEXT_GAP), // Original value: RC_WARN.into() + 0x001 + 2306 => Ok(Self::OBJECT_MEMORY), // Original value: RC_WARN.into() + 0x002 + 2307 => Ok(Self::SESSION_MEMORY), // Original value: RC_WARN.into() + 0x003 + 2308 => Ok(Self::MEMORY), // Original value: RC_WARN.into() + 0x004 + 2309 => Ok(Self::SESSION_HANDLES), // Original value: RC_WARN.into() + 0x005 + 2310 => Ok(Self::OBJECT_HANDLES), // Original value: RC_WARN.into() + 0x006 + 2311 => Ok(Self::LOCALITY), // Original value: RC_WARN.into() + 0x007 + 2312 => Ok(Self::YIELDED), // Original value: RC_WARN.into() + 0x008 + 2313 => Ok(Self::CANCELED), // Original value: RC_WARN.into() + 0x009 + 2314 => Ok(Self::TESTING), // Original value: RC_WARN.into() + 0x00A + 2320 => Ok(Self::REFERENCE_H0), // Original value: RC_WARN.into() + 0x010 + 2321 => Ok(Self::REFERENCE_H1), // Original value: RC_WARN.into() + 0x011 + 2322 => Ok(Self::REFERENCE_H2), // Original value: RC_WARN.into() + 0x012 + 2323 => Ok(Self::REFERENCE_H3), // Original value: RC_WARN.into() + 0x013 + 2324 => Ok(Self::REFERENCE_H4), // Original value: RC_WARN.into() + 0x014 + 2325 => Ok(Self::REFERENCE_H5), // Original value: RC_WARN.into() + 0x015 + 2326 => Ok(Self::REFERENCE_H6), // Original value: RC_WARN.into() + 0x016 + 2328 => Ok(Self::REFERENCE_S0), // Original value: RC_WARN.into() + 0x018 + 2329 => Ok(Self::REFERENCE_S1), // Original value: RC_WARN.into() + 0x019 + 2330 => Ok(Self::REFERENCE_S2), // Original value: RC_WARN.into() + 0x01A + 2331 => Ok(Self::REFERENCE_S3), // Original value: RC_WARN.into() + 0x01B + 2332 => Ok(Self::REFERENCE_S4), // Original value: RC_WARN.into() + 0x01C + 2333 => Ok(Self::REFERENCE_S5), // Original value: RC_WARN.into() + 0x01D + 2334 => Ok(Self::REFERENCE_S6), // Original value: RC_WARN.into() + 0x01E + 2336 => Ok(Self::NV_RATE), // Original value: RC_WARN.into() + 0x020 + 2337 => Ok(Self::LOCKOUT), // Original value: RC_WARN.into() + 0x021 + 2338 => Ok(Self::RETRY), // Original value: RC_WARN.into() + 0x022 + 2339 => Ok(Self::NV_UNAVAILABLE), // Original value: RC_WARN.into() + 0x023 + 2431 => Ok(Self::NOT_USED), // Original value: RC_WARN.into() + 0x7F + 64 => Ok(Self::P), // Original value: 0x040 + 2048 => Ok(Self::_8), // Original value: 0x800 + 512 => Ok(Self::_2), // Original value: 0x200 + 768 => Ok(Self::_3), // Original value: 0x300 + 1024 => Ok(Self::_4), // Original value: 0x400 + 1280 => Ok(Self::_5), // Original value: 0x500 + 1536 => Ok(Self::_6), // Original value: 0x600 + 1792 => Ok(Self::_7), // Original value: 0x700 + 2560 => Ok(Self::A), // Original value: 0xA00 + 2816 => Ok(Self::B), // Original value: 0xB00 + 3072 => Ok(Self::C), // Original value: 0xC00 + 3328 => Ok(Self::D), // Original value: 0xD00 + 3584 => Ok(Self::E), // Original value: 0xE00 + 3840 => Ok(Self::N_MASK), // Original value: 0xF00 + 1076363265 => Ok(Self::TSS_TCP_BAD_HANDSHAKE_RESP), // Original value: 0x40280001 + 1076363266 => Ok(Self::TSS_TCP_SERVER_TOO_OLD), // Original value: 0x40280002 + 1076363267 => Ok(Self::TSS_TCP_BAD_ACK), // Original value: 0x40280003 + 1076363268 => Ok(Self::TSS_TCP_BAD_RESP_LEN), // Original value: 0x40280004 + 1076363269 => Ok(Self::TSS_TCP_UNEXPECTED_STARTUP_RESP), // Original value: 0x40280005 + 1076363270 => Ok(Self::TSS_TCP_INVALID_SIZE_TAG), // Original value: 0x40280006 + 1076363271 => Ok(Self::TSS_TCP_DISCONNECTED), // Original value: 0x40280007 + 1076363280 => Ok(Self::TSS_DISPATCH_FAILED), // Original value: 0x40280010 + 1076363281 => Ok(Self::TSS_SEND_OP_FAILED), // Original value: 0x40280011 + 1076363297 => Ok(Self::TSS_RESP_BUF_TOO_SHORT), // Original value: 0x40280021 + 1076363298 => Ok(Self::TSS_RESP_BUF_INVALID_SESSION_TAG), // Original value: 0x40280022 + 1076363299 => Ok(Self::TSS_RESP_BUF_INVALID_SIZE), // Original value: 0x40280023 + 2150106112 => Ok(Self::TBS_COMMAND_BLOCKED), // Original value: 0x80280400 + 2150106113 => Ok(Self::TBS_INVALID_HANDLE), // Original value: 0x80280401 + 2150106114 => Ok(Self::TBS_DUPLICATE_V_HANDLE), // Original value: 0x80280402 + 2150106115 => Ok(Self::TBS_EMBEDDED_COMMAND_BLOCKED), // Original value: 0x80280403 + 2150106116 => Ok(Self::TBS_EMBEDDED_COMMAND_UNSUPPORTED), // Original value: 0x80280404 + 2150121472 => Ok(Self::TBS_UNKNOWN_ERROR), // Original value: 0x80284000 + 2150121473 => Ok(Self::TBS_INTERNAL_ERROR), // Original value: 0x80284001 + 2150121474 => Ok(Self::TBS_BAD_PARAMETER), // Original value: 0x80284002 + 2150121475 => Ok(Self::TBS_INVALID_OUTPUT_POINTER), // Original value: 0x80284003 + 2150121476 => Ok(Self::TBS_INVALID_CONTEXT), // Original value: 0x80284004 + 2150121477 => Ok(Self::TBS_INSUFFICIENT_BUFFER), // Original value: 0x80284005 + 2150121478 => Ok(Self::TBS_IO_ERROR), // Original value: 0x80284006 + 2150121479 => Ok(Self::TBS_INVALID_CONTEXT_PARAM), // Original value: 0x80284007 + 2150121480 => Ok(Self::TBS_SERVICE_NOT_RUNNING), // Original value: 0x80284008 + 2150121481 => Ok(Self::TBS_TOO_MANY_CONTEXTS), // Original value: 0x80284009 + 2150121482 => Ok(Self::TBS_TOO_MANY_RESOURCES), // Original value: 0x8028400A + 2150121483 => Ok(Self::TBS_SERVICE_START_PENDING), // Original value: 0x8028400B + 2150121484 => Ok(Self::TBS_PPI_NOT_SUPPORTED), // Original value: 0x8028400C + 2150121485 => Ok(Self::TBS_COMMAND_CANCELED), // Original value: 0x8028400D + 2150121486 => Ok(Self::TBS_BUFFER_TOO_LARGE), // Original value: 0x8028400E + 2150121487 => Ok(Self::TBS_TPM_NOT_FOUND), // Original value: 0x8028400F + 2150121488 => Ok(Self::TBS_SERVICE_DISABLED), // Original value: 0x80284010 + 2150121490 => Ok(Self::TBS_ACCESS_DENIED), // Original value: 0x80284012 + 2150121492 => Ok(Self::TBS_PPI_FUNCTION_NOT_SUPPORTED), // Original value: 0x80284014 + 2150121493 => Ok(Self::TBS_OWNER_AUTH_NOT_FOUND), // Original value: 0x80284015 + _ => Err(TpmError::InvalidEnumValue), + } + } +} + +impl TpmEnum for TPM_RC { + fn get_value(&self) -> u32 { + self.0.into() + } + + fn try_from_trait(value: u64) -> Result where Self: Sized { + TPM_RC::try_from(value as u32) + } + + fn new_from_trait(value: u64) -> Result where Self: Sized { + Ok(TPM_RC(value as u32)) + } +} + +impl From for u32 { + fn from(value: TPM_RC) -> Self { + value.0 as u32 + } +} + +impl From for i32 { + fn from(value: TPM_RC) -> Self { + value.0 as i32 + } +} + +impl fmt::Display for TPM_RC { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + 0 => write!(f, "H"), + 30 => write!(f, "BAD_TAG"), + 256 => write!(f, "_1"), + 257 => write!(f, "FAILURE"), + 259 => write!(f, "SEQUENCE"), + 267 => write!(f, "PRIVATE"), + 281 => write!(f, "HMAC"), + 288 => write!(f, "DISABLED"), + 289 => write!(f, "EXCLUSIVE"), + 292 => write!(f, "AUTH_TYPE"), + 293 => write!(f, "AUTH_MISSING"), + 294 => write!(f, "POLICY"), + 295 => write!(f, "PCR"), + 296 => write!(f, "PCR_CHANGED"), + 301 => write!(f, "UPGRADE"), + 302 => write!(f, "TOO_MANY_CONTEXTS"), + 303 => write!(f, "AUTH_UNAVAILABLE"), + 304 => write!(f, "REBOOT"), + 305 => write!(f, "UNBALANCED"), + 322 => write!(f, "COMMAND_SIZE"), + 323 => write!(f, "COMMAND_CODE"), + 324 => write!(f, "AUTHSIZE"), + 325 => write!(f, "AUTH_CONTEXT"), + 326 => write!(f, "NV_RANGE"), + 327 => write!(f, "NV_SIZE"), + 328 => write!(f, "NV_LOCKED"), + 329 => write!(f, "NV_AUTHORIZATION"), + 330 => write!(f, "NV_UNINITIALIZED"), + 331 => write!(f, "NV_SPACE"), + 332 => write!(f, "NV_DEFINED"), + 336 => write!(f, "BAD_CONTEXT"), + 337 => write!(f, "CPHASH"), + 338 => write!(f, "PARENT"), + 339 => write!(f, "NEEDS_TEST"), + 340 => write!(f, "NO_RESULT"), + 341 => write!(f, "SENSITIVE"), + 383 => write!(f, "RC_MAX_FM0"), + 128 => write!(f, "RC_FMT1"), + 129 => write!(f, "ASYMMETRIC"), + 130 => write!(f, "ATTRIBUTES"), + 131 => write!(f, "HASH"), + 132 => write!(f, "VALUE"), + 133 => write!(f, "HIERARCHY"), + 135 => write!(f, "KEY_SIZE"), + 136 => write!(f, "MGF"), + 137 => write!(f, "MODE"), + 138 => write!(f, "TYPE"), + 139 => write!(f, "HANDLE"), + 140 => write!(f, "KDF"), + 141 => write!(f, "RANGE"), + 142 => write!(f, "AUTH_FAIL"), + 143 => write!(f, "NONCE"), + 144 => write!(f, "PP"), + 146 => write!(f, "SCHEME"), + 149 => write!(f, "SIZE"), + 150 => write!(f, "SYMMETRIC"), + 151 => write!(f, "TAG"), + 152 => write!(f, "SELECTOR"), + 154 => write!(f, "INSUFFICIENT"), + 155 => write!(f, "SIGNATURE"), + 156 => write!(f, "KEY"), + 157 => write!(f, "POLICY_FAIL"), + 159 => write!(f, "INTEGRITY"), + 160 => write!(f, "TICKET"), + 161 => write!(f, "RESERVED_BITS"), + 162 => write!(f, "BAD_AUTH"), + 163 => write!(f, "EXPIRED"), + 164 => write!(f, "POLICY_CC"), + 165 => write!(f, "BINDING"), + 166 => write!(f, "CURVE"), + 167 => write!(f, "ECC_POINT"), + 2304 => write!(f, "_9"), + 2305 => write!(f, "CONTEXT_GAP"), + 2306 => write!(f, "OBJECT_MEMORY"), + 2307 => write!(f, "SESSION_MEMORY"), + 2308 => write!(f, "MEMORY"), + 2309 => write!(f, "SESSION_HANDLES"), + 2310 => write!(f, "OBJECT_HANDLES"), + 2311 => write!(f, "LOCALITY"), + 2312 => write!(f, "YIELDED"), + 2313 => write!(f, "CANCELED"), + 2314 => write!(f, "TESTING"), + 2320 => write!(f, "REFERENCE_H0"), + 2321 => write!(f, "REFERENCE_H1"), + 2322 => write!(f, "REFERENCE_H2"), + 2323 => write!(f, "REFERENCE_H3"), + 2324 => write!(f, "REFERENCE_H4"), + 2325 => write!(f, "REFERENCE_H5"), + 2326 => write!(f, "REFERENCE_H6"), + 2328 => write!(f, "REFERENCE_S0"), + 2329 => write!(f, "REFERENCE_S1"), + 2330 => write!(f, "REFERENCE_S2"), + 2331 => write!(f, "REFERENCE_S3"), + 2332 => write!(f, "REFERENCE_S4"), + 2333 => write!(f, "REFERENCE_S5"), + 2334 => write!(f, "REFERENCE_S6"), + 2336 => write!(f, "NV_RATE"), + 2337 => write!(f, "LOCKOUT"), + 2338 => write!(f, "RETRY"), + 2339 => write!(f, "NV_UNAVAILABLE"), + 2431 => write!(f, "NOT_USED"), + 64 => write!(f, "P"), + 2048 => write!(f, "_8"), + 512 => write!(f, "_2"), + 768 => write!(f, "_3"), + 1024 => write!(f, "_4"), + 1280 => write!(f, "_5"), + 1536 => write!(f, "_6"), + 1792 => write!(f, "_7"), + 2560 => write!(f, "A"), + 2816 => write!(f, "B"), + 3072 => write!(f, "C"), + 3328 => write!(f, "D"), + 3584 => write!(f, "E"), + 3840 => write!(f, "N_MASK"), + 1076363265 => write!(f, "TSS_TCP_BAD_HANDSHAKE_RESP"), + 1076363266 => write!(f, "TSS_TCP_SERVER_TOO_OLD"), + 1076363267 => write!(f, "TSS_TCP_BAD_ACK"), + 1076363268 => write!(f, "TSS_TCP_BAD_RESP_LEN"), + 1076363269 => write!(f, "TSS_TCP_UNEXPECTED_STARTUP_RESP"), + 1076363270 => write!(f, "TSS_TCP_INVALID_SIZE_TAG"), + 1076363271 => write!(f, "TSS_TCP_DISCONNECTED"), + 1076363280 => write!(f, "TSS_DISPATCH_FAILED"), + 1076363281 => write!(f, "TSS_SEND_OP_FAILED"), + 1076363297 => write!(f, "TSS_RESP_BUF_TOO_SHORT"), + 1076363298 => write!(f, "TSS_RESP_BUF_INVALID_SESSION_TAG"), + 1076363299 => write!(f, "TSS_RESP_BUF_INVALID_SIZE"), + 2150106112 => write!(f, "TBS_COMMAND_BLOCKED"), + 2150106113 => write!(f, "TBS_INVALID_HANDLE"), + 2150106114 => write!(f, "TBS_DUPLICATE_V_HANDLE"), + 2150106115 => write!(f, "TBS_EMBEDDED_COMMAND_BLOCKED"), + 2150106116 => write!(f, "TBS_EMBEDDED_COMMAND_UNSUPPORTED"), + 2150121472 => write!(f, "TBS_UNKNOWN_ERROR"), + 2150121473 => write!(f, "TBS_INTERNAL_ERROR"), + 2150121474 => write!(f, "TBS_BAD_PARAMETER"), + 2150121475 => write!(f, "TBS_INVALID_OUTPUT_POINTER"), + 2150121476 => write!(f, "TBS_INVALID_CONTEXT"), + 2150121477 => write!(f, "TBS_INSUFFICIENT_BUFFER"), + 2150121478 => write!(f, "TBS_IO_ERROR"), + 2150121479 => write!(f, "TBS_INVALID_CONTEXT_PARAM"), + 2150121480 => write!(f, "TBS_SERVICE_NOT_RUNNING"), + 2150121481 => write!(f, "TBS_TOO_MANY_CONTEXTS"), + 2150121482 => write!(f, "TBS_TOO_MANY_RESOURCES"), + 2150121483 => write!(f, "TBS_SERVICE_START_PENDING"), + 2150121484 => write!(f, "TBS_PPI_NOT_SUPPORTED"), + 2150121485 => write!(f, "TBS_COMMAND_CANCELED"), + 2150121486 => write!(f, "TBS_BUFFER_TOO_LARGE"), + 2150121487 => write!(f, "TBS_TPM_NOT_FOUND"), + 2150121488 => write!(f, "TBS_SERVICE_DISABLED"), + 2150121490 => write!(f, "TBS_ACCESS_DENIED"), + 2150121492 => write!(f, "TBS_PPI_FUNCTION_NOT_SUPPORTED"), + 2150121493 => write!(f, "TBS_OWNER_AUTH_NOT_FOUND"), + _ => write!(f, "{}", enum_to_str(self.0 as u64, std::any::TypeId::of::())), + } + } +} + +/// A TPM_CLOCK_ADJUST value is used to change the rate at which the TPM internal +/// oscillator is divided. A change to the divider will change the rate at which Clock and +/// Time change. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub struct TPM_CLOCK_ADJUST(pub i8); + +impl TPM_CLOCK_ADJUST { + /// Slow the Clock update rate by one coarse adjustment step. + pub const COARSE_SLOWER: Self = Self(-3); + + /// Slow the Clock update rate by one medium adjustment step. + pub const MEDIUM_SLOWER: Self = Self(-2); + + /// Slow the Clock update rate by one fine adjustment step. + pub const FINE_SLOWER: Self = Self(-1); + + /// No change to the Clock update rate. + pub const NO_CHANGE: Self = Self(0); + + /// Speed the Clock update rate by one fine adjustment step. + pub const FINE_FASTER: Self = Self(1); + + /// Speed the Clock update rate by one medium adjustment step. + pub const MEDIUM_FASTER: Self = Self(2); + + /// Speed the Clock update rate by one coarse adjustment step. + pub const COARSE_FASTER: Self = Self(3); + + pub fn try_from(value: i8) -> Result { + match value { + -3 => Ok(Self::COARSE_SLOWER), // Original value: -3 + -2 => Ok(Self::MEDIUM_SLOWER), // Original value: -2 + -1 => Ok(Self::FINE_SLOWER), // Original value: -1 + 0 => Ok(Self::NO_CHANGE), // Original value: 0 + 1 => Ok(Self::FINE_FASTER), // Original value: 1 + 2 => Ok(Self::MEDIUM_FASTER), // Original value: 2 + 3 => Ok(Self::COARSE_FASTER), // Original value: 3 + _ => Err(TpmError::InvalidEnumValue), + } + } +} + +impl TpmEnum for TPM_CLOCK_ADJUST { + fn get_value(&self) -> i8 { + self.0.into() + } + + fn try_from_trait(value: u64) -> Result where Self: Sized { + TPM_CLOCK_ADJUST::try_from(value as i8) + } + + fn new_from_trait(value: u64) -> Result where Self: Sized { + Ok(TPM_CLOCK_ADJUST(value as i8)) + } +} + +impl From for u8 { + fn from(value: TPM_CLOCK_ADJUST) -> Self { + value.0 as u8 + } +} + +impl From for i8 { + fn from(value: TPM_CLOCK_ADJUST) -> Self { + value.0 as i8 + } +} + +impl fmt::Display for TPM_CLOCK_ADJUST { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + -3 => write!(f, "COARSE_SLOWER"), + -2 => write!(f, "MEDIUM_SLOWER"), + -1 => write!(f, "FINE_SLOWER"), + 0 => write!(f, "NO_CHANGE"), + 1 => write!(f, "FINE_FASTER"), + 2 => write!(f, "MEDIUM_FASTER"), + 3 => write!(f, "COARSE_FASTER"), + _ => write!(f, "{}", enum_to_str(self.0 as u64, std::any::TypeId::of::())), + } + } +} + +/// Table 18 Definition of (UINT16) TPM_EO Constants [IN/OUT] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub struct TPM_EO(pub u16); + +impl TPM_EO { + /// A = B + pub const EQ: Self = Self(0x0); // Original value: 0x0000 + + /// A B + pub const NEQ: Self = Self(0x1); // Original value: 0x0001 + + /// A ˃ B signed + pub const SIGNED_GT: Self = Self(0x2); // Original value: 0x0002 + + /// A ˃ B unsigned + pub const UNSIGNED_GT: Self = Self(0x3); // Original value: 0x0003 + + /// A ˂ B signed + pub const SIGNED_LT: Self = Self(0x4); // Original value: 0x0004 + + /// A ˂ B unsigned + pub const UNSIGNED_LT: Self = Self(0x5); // Original value: 0x0005 + + /// A B signed + pub const SIGNED_GE: Self = Self(0x6); // Original value: 0x0006 + + /// A B unsigned + pub const UNSIGNED_GE: Self = Self(0x7); // Original value: 0x0007 + + /// A B signed + pub const SIGNED_LE: Self = Self(0x8); // Original value: 0x0008 + + /// A B unsigned + pub const UNSIGNED_LE: Self = Self(0x9); // Original value: 0x0009 + + /// All bits SET in B are SET in A. ((A∧B)=B) + pub const BITSET: Self = Self(0xA); // Original value: 0x000A + + /// All bits SET in B are CLEAR in A. ((A∧B)=0) + pub const BITCLEAR: Self = Self(0xB); // Original value: 0x000B + + pub fn try_from(value: u16) -> Result { + match value { + 0 => Ok(Self::EQ), // Original value: 0x0000 + 1 => Ok(Self::NEQ), // Original value: 0x0001 + 2 => Ok(Self::SIGNED_GT), // Original value: 0x0002 + 3 => Ok(Self::UNSIGNED_GT), // Original value: 0x0003 + 4 => Ok(Self::SIGNED_LT), // Original value: 0x0004 + 5 => Ok(Self::UNSIGNED_LT), // Original value: 0x0005 + 6 => Ok(Self::SIGNED_GE), // Original value: 0x0006 + 7 => Ok(Self::UNSIGNED_GE), // Original value: 0x0007 + 8 => Ok(Self::SIGNED_LE), // Original value: 0x0008 + 9 => Ok(Self::UNSIGNED_LE), // Original value: 0x0009 + 10 => Ok(Self::BITSET), // Original value: 0x000A + 11 => Ok(Self::BITCLEAR), // Original value: 0x000B + _ => Err(TpmError::InvalidEnumValue), + } + } +} + +impl TpmEnum for TPM_EO { + fn get_value(&self) -> u16 { + self.0.into() + } + + fn try_from_trait(value: u64) -> Result where Self: Sized { + TPM_EO::try_from(value as u16) + } + + fn new_from_trait(value: u64) -> Result where Self: Sized { + Ok(TPM_EO(value as u16)) + } +} + +impl From for u16 { + fn from(value: TPM_EO) -> Self { + value.0 as u16 + } +} + +impl From for i16 { + fn from(value: TPM_EO) -> Self { + value.0 as i16 + } +} + +impl fmt::Display for TPM_EO { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + 0 => write!(f, "EQ"), + 1 => write!(f, "NEQ"), + 2 => write!(f, "SIGNED_GT"), + 3 => write!(f, "UNSIGNED_GT"), + 4 => write!(f, "SIGNED_LT"), + 5 => write!(f, "UNSIGNED_LT"), + 6 => write!(f, "SIGNED_GE"), + 7 => write!(f, "UNSIGNED_GE"), + 8 => write!(f, "SIGNED_LE"), + 9 => write!(f, "UNSIGNED_LE"), + 10 => write!(f, "BITSET"), + 11 => write!(f, "BITCLEAR"), + _ => write!(f, "{}", enum_to_str(self.0 as u64, std::any::TypeId::of::())), + } + } +} + +/// Structure tags are used to disambiguate structures. They are 16-bit values with the +/// most significant bit SET so that they do not overlap TPM_ALG_ID values. A single +/// exception is made for the value associated with TPM_ST_RSP_COMMAND (0x00C4), which has +/// the same value as the TPM_TAG_RSP_COMMAND tag from earlier versions of this +/// specification. This value is used when the TPM is compatible with a previous TPM +/// specification and the TPM cannot determine which family of response code to return +/// because the command tag is not valid. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub struct TPM_ST(pub u16); + +impl TPM_ST { + /// Tag value for a response; used when there is an error in the tag. This is also the + /// value returned from a TPM 1.2 when an error occurs. This value is used in this + /// specification because an error in the command tag may prevent determination of the + /// family. When this tag is used in the response, the response code will be + /// TPM_RC_BAD_TAG (0 1E16), which has the same numeric value as the TPM 1.2 response code + /// for TPM_BADTAG. + /// NOTE In a previously published version of this specification, TPM_RC_BAD_TAG was + /// incorrectly assigned a value of 0x030 instead of 30 (0x01e). Some implementations my + /// return the old value instead of the new value. + pub const RSP_COMMAND: Self = Self(0xC4); // Original value: 0x00C4 + + /// No structure type specified + pub const NULL: Self = Self(0x8000); // Original value: 0X8000 + + /// Tag value for a command/response for a command defined in this specification; + /// indicating that the command/response has no attached sessions and no + /// authorizationSize/parameterSize value is present + /// If the responseCode from the TPM is not TPM_RC_SUCCESS, then the response tag shall + /// have this value. + pub const NO_SESSIONS: Self = Self(0x8001); + + /// Tag value for a command/response for a command defined in this specification; + /// indicating that the command/response has one or more attached sessions and the + /// authorizationSize/parameterSize field is present + pub const SESSIONS: Self = Self(0x8002); + + /// Tag for an attestation structure + pub const ATTEST_NV: Self = Self(0x8014); + + /// Tag for an attestation structure + pub const ATTEST_COMMAND_AUDIT: Self = Self(0x8015); + + /// Tag for an attestation structure + pub const ATTEST_SESSION_AUDIT: Self = Self(0x8016); + + /// Tag for an attestation structure + pub const ATTEST_CERTIFY: Self = Self(0x8017); + + /// Tag for an attestation structure + pub const ATTEST_QUOTE: Self = Self(0x8018); + + /// Tag for an attestation structure + pub const ATTEST_TIME: Self = Self(0x8019); + + /// Tag for an attestation structure + pub const ATTEST_CREATION: Self = Self(0x801A); + + /// Tag for an attestation structure + pub const ATTEST_NV_DIGEST: Self = Self(0x801C); + + /// Tag for a ticket type + pub const CREATION: Self = Self(0x8021); + + /// Tag for a ticket type + pub const VERIFIED: Self = Self(0x8022); + + /// Tag for a ticket type + pub const AUTH_SECRET: Self = Self(0x8023); + + /// Tag for a ticket type + pub const HASHCHECK: Self = Self(0x8024); + + /// Tag for a ticket type + pub const AUTH_SIGNED: Self = Self(0x8025); + + /// Tag for a structure describing a Field Upgrade Policy + pub const FU_MANIFEST: Self = Self(0x8029); + + pub fn try_from(value: u16) -> Result { + match value { + 196 => Ok(Self::RSP_COMMAND), // Original value: 0x00C4 + 32768 => Ok(Self::NULL), // Original value: 0X8000 + 32769 => Ok(Self::NO_SESSIONS), // Original value: 0x8001 + 32770 => Ok(Self::SESSIONS), // Original value: 0x8002 + 32788 => Ok(Self::ATTEST_NV), // Original value: 0x8014 + 32789 => Ok(Self::ATTEST_COMMAND_AUDIT), // Original value: 0x8015 + 32790 => Ok(Self::ATTEST_SESSION_AUDIT), // Original value: 0x8016 + 32791 => Ok(Self::ATTEST_CERTIFY), // Original value: 0x8017 + 32792 => Ok(Self::ATTEST_QUOTE), // Original value: 0x8018 + 32793 => Ok(Self::ATTEST_TIME), // Original value: 0x8019 + 32794 => Ok(Self::ATTEST_CREATION), // Original value: 0x801A + 32796 => Ok(Self::ATTEST_NV_DIGEST), // Original value: 0x801C + 32801 => Ok(Self::CREATION), // Original value: 0x8021 + 32802 => Ok(Self::VERIFIED), // Original value: 0x8022 + 32803 => Ok(Self::AUTH_SECRET), // Original value: 0x8023 + 32804 => Ok(Self::HASHCHECK), // Original value: 0x8024 + 32805 => Ok(Self::AUTH_SIGNED), // Original value: 0x8025 + 32809 => Ok(Self::FU_MANIFEST), // Original value: 0x8029 + _ => Err(TpmError::InvalidEnumValue), + } + } +} + +impl TpmEnum for TPM_ST { + fn get_value(&self) -> u16 { + self.0.into() + } + + fn try_from_trait(value: u64) -> Result where Self: Sized { + TPM_ST::try_from(value as u16) + } + + fn new_from_trait(value: u64) -> Result where Self: Sized { + Ok(TPM_ST(value as u16)) + } +} + +impl From for u16 { + fn from(value: TPM_ST) -> Self { + value.0 as u16 + } +} + +impl From for i16 { + fn from(value: TPM_ST) -> Self { + value.0 as i16 + } +} + +impl fmt::Display for TPM_ST { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + 196 => write!(f, "RSP_COMMAND"), + 32768 => write!(f, "NULL"), + 32769 => write!(f, "NO_SESSIONS"), + 32770 => write!(f, "SESSIONS"), + 32788 => write!(f, "ATTEST_NV"), + 32789 => write!(f, "ATTEST_COMMAND_AUDIT"), + 32790 => write!(f, "ATTEST_SESSION_AUDIT"), + 32791 => write!(f, "ATTEST_CERTIFY"), + 32792 => write!(f, "ATTEST_QUOTE"), + 32793 => write!(f, "ATTEST_TIME"), + 32794 => write!(f, "ATTEST_CREATION"), + 32796 => write!(f, "ATTEST_NV_DIGEST"), + 32801 => write!(f, "CREATION"), + 32802 => write!(f, "VERIFIED"), + 32803 => write!(f, "AUTH_SECRET"), + 32804 => write!(f, "HASHCHECK"), + 32805 => write!(f, "AUTH_SIGNED"), + 32809 => write!(f, "FU_MANIFEST"), + _ => write!(f, "{}", enum_to_str(self.0 as u64, std::any::TypeId::of::())), + } + } +} + +/// These values are used in TPM2_Startup() to indicate the shutdown and startup mode. The +/// defined startup sequences are: +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub struct TPM_SU(pub u16); + +impl TPM_SU { + /// On TPM2_Shutdown(), indicates that the TPM should prepare for loss of power and save + /// state required for an orderly startup (TPM Reset). + /// on TPM2_Startup(), indicates that the TPM should perform TPM Reset or TPM Restart + pub const CLEAR: Self = Self(0x0); // Original value: 0x0000 + + /// On TPM2_Shutdown(), indicates that the TPM should prepare for loss of power and save + /// state required for an orderly startup (TPM Restart or TPM Resume) + /// on TPM2_Startup(), indicates that the TPM should restore the state saved by + /// TPM2_Shutdown(TPM_SU_STATE) + pub const STATE: Self = Self(0x1); // Original value: 0x0001 + + pub fn try_from(value: u16) -> Result { + match value { + 0 => Ok(Self::CLEAR), // Original value: 0x0000 + 1 => Ok(Self::STATE), // Original value: 0x0001 + _ => Err(TpmError::InvalidEnumValue), + } + } +} + +impl TpmEnum for TPM_SU { + fn get_value(&self) -> u16 { + self.0.into() + } + + fn try_from_trait(value: u64) -> Result where Self: Sized { + TPM_SU::try_from(value as u16) + } + + fn new_from_trait(value: u64) -> Result where Self: Sized { + Ok(TPM_SU(value as u16)) + } +} + +impl From for u16 { + fn from(value: TPM_SU) -> Self { + value.0 as u16 + } +} + +impl From for i16 { + fn from(value: TPM_SU) -> Self { + value.0 as i16 + } +} + +impl fmt::Display for TPM_SU { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + 0 => write!(f, "CLEAR"), + 1 => write!(f, "STATE"), + _ => write!(f, "{}", enum_to_str(self.0 as u64, std::any::TypeId::of::())), + } + } +} + +/// This type is used in TPM2_StartAuthSession() to indicate the type of the session to be +/// created. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub struct TPM_SE(pub u8); + +impl TPM_SE { + pub const HMAC: Self = Self(0x0); // Original value: 0x00 + pub const POLICY: Self = Self(0x1); // Original value: 0x01 + + /// The policy session is being used to compute the policyHash and not for command authorization. + /// This setting modifies some policy commands and prevents session from being used to + /// authorize a command. + pub const TRIAL: Self = Self(0x3); // Original value: 0x03 + + pub fn try_from(value: u8) -> Result { + match value { + 0 => Ok(Self::HMAC), // Original value: 0x00 + 1 => Ok(Self::POLICY), // Original value: 0x01 + 3 => Ok(Self::TRIAL), // Original value: 0x03 + _ => Err(TpmError::InvalidEnumValue), + } + } +} + +impl TpmEnum for TPM_SE { + fn get_value(&self) -> u8 { + self.0.into() + } + + fn try_from_trait(value: u64) -> Result where Self: Sized { + TPM_SE::try_from(value as u8) + } + + fn new_from_trait(value: u64) -> Result where Self: Sized { + Ok(TPM_SE(value as u8)) + } +} + +impl From for u8 { + fn from(value: TPM_SE) -> Self { + value.0 as u8 + } +} + +impl From for i8 { + fn from(value: TPM_SE) -> Self { + value.0 as i8 + } +} + +impl fmt::Display for TPM_SE { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + 0 => write!(f, "HMAC"), + 1 => write!(f, "POLICY"), + 3 => write!(f, "TRIAL"), + _ => write!(f, "{}", enum_to_str(self.0 as u64, std::any::TypeId::of::())), + } + } +} + +/// The TPM_CAP values are used in TPM2_GetCapability() to select the type of the value to +/// be returned. The format of the response varies according to the type of the value. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub struct TPM_CAP(pub u32); + +impl TPM_CAP { + pub const FIRST: Self = Self(0x0); // Original value: 0x00000000 + + /// TPML_ALG_PROPERTY + pub const ALGS: Self = Self(0x0); // Original value: 0x00000000 + + /// TPML_HANDLE + pub const HANDLES: Self = Self(0x1); // Original value: 0x00000001 + + /// TPML_CCA + pub const COMMANDS: Self = Self(0x2); // Original value: 0x00000002 + + /// TPML_CC + pub const PP_COMMANDS: Self = Self(0x3); // Original value: 0x00000003 + + /// TPML_CC + pub const AUDIT_COMMANDS: Self = Self(0x4); // Original value: 0x00000004 + + /// TPML_PCR_SELECTION + pub const PCRS: Self = Self(0x5); // Original value: 0x00000005 + + /// TPML_TAGGED_TPM_PROPERTY + pub const TPM_PROPERTIES: Self = Self(0x6); // Original value: 0x00000006 + + /// TPML_TAGGED_PCR_PROPERTY + pub const PCR_PROPERTIES: Self = Self(0x7); // Original value: 0x00000007 + + /// TPML_ECC_CURVE + pub const ECC_CURVES: Self = Self(0x8); // Original value: 0x00000008 + + /// TPML_TAGGED_POLICY + pub const AUTH_POLICIES: Self = Self(0x9); // Original value: 0x00000009 + + /// TPML_ACT_DATA + pub const ACT: Self = Self(0xA); // Original value: 0x0000000A + pub const LAST: Self = Self(0xA); // Original value: 0x0000000A + + /// Manufacturer-specific values + pub const VENDOR_PROPERTY: Self = Self(0x100); // Original value: 0x00000100 + + pub fn try_from(value: u32) -> Result { + match value { + 0 => Ok(Self::ALGS), // Original value: 0x00000000 + 1 => Ok(Self::HANDLES), // Original value: 0x00000001 + 2 => Ok(Self::COMMANDS), // Original value: 0x00000002 + 3 => Ok(Self::PP_COMMANDS), // Original value: 0x00000003 + 4 => Ok(Self::AUDIT_COMMANDS), // Original value: 0x00000004 + 5 => Ok(Self::PCRS), // Original value: 0x00000005 + 6 => Ok(Self::TPM_PROPERTIES), // Original value: 0x00000006 + 7 => Ok(Self::PCR_PROPERTIES), // Original value: 0x00000007 + 8 => Ok(Self::ECC_CURVES), // Original value: 0x00000008 + 9 => Ok(Self::AUTH_POLICIES), // Original value: 0x00000009 + 10 => Ok(Self::LAST), // Original value: 0x0000000A + 256 => Ok(Self::VENDOR_PROPERTY), // Original value: 0x00000100 + _ => Err(TpmError::InvalidEnumValue), + } + } +} + +impl TpmEnum for TPM_CAP { + fn get_value(&self) -> u32 { + self.0.into() + } + + fn try_from_trait(value: u64) -> Result where Self: Sized { + TPM_CAP::try_from(value as u32) + } + + fn new_from_trait(value: u64) -> Result where Self: Sized { + Ok(TPM_CAP(value as u32)) + } +} + +impl From for u32 { + fn from(value: TPM_CAP) -> Self { + value.0 as u32 + } +} + +impl From for i32 { + fn from(value: TPM_CAP) -> Self { + value.0 as i32 + } +} + +impl fmt::Display for TPM_CAP { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + 0 => write!(f, "ALGS"), + 1 => write!(f, "HANDLES"), + 2 => write!(f, "COMMANDS"), + 3 => write!(f, "PP_COMMANDS"), + 4 => write!(f, "AUDIT_COMMANDS"), + 5 => write!(f, "PCRS"), + 6 => write!(f, "TPM_PROPERTIES"), + 7 => write!(f, "PCR_PROPERTIES"), + 8 => write!(f, "ECC_CURVES"), + 9 => write!(f, "AUTH_POLICIES"), + 10 => write!(f, "LAST"), + 256 => write!(f, "VENDOR_PROPERTY"), + _ => write!(f, "{}", enum_to_str(self.0 as u64, std::any::TypeId::of::())), + } + } +} + +/// The TPM_PT constants are used in TPM2_GetCapability(capability = +/// TPM_CAP_TPM_PROPERTIES) to indicate the property being selected or returned. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub struct TPM_PT(pub u32); + +impl TPM_PT { + /// Indicates no property type + pub const NONE: Self = Self(0x0); // Original value: 0x00000000 + + /// The number of properties in each group. + /// NOTE The first group with any properties is group 1 (PT_GROUP * 1). Group 0 is reserved. + pub const PT_GROUP: Self = Self(0x100); // Original value: 0x00000100 + + /// The group of fixed properties returned as TPMS_TAGGED_PROPERTY + /// The values in this group are only changed due to a firmware change in the TPM. + pub const PT_FIXED: Self = Self(0x100); // Original value: PT_GROUP.into() * 1 + + /// A 4-octet character string containing the TPM Family value (TPM_SPEC_FAMILY) + pub const FAMILY_INDICATOR: Self = Self(0x100); // Original value: PT_FIXED.into() + 0 + + /// The level of the specification + /// NOTE 1 For this specification, the level is zero. + /// NOTE 2 The level is on the title page of the specification. + pub const LEVEL: Self = Self(0x101); // Original value: PT_FIXED.into() + 1 + + /// The specification Revision times 100 + /// EXAMPLE Revision 01.01 would have a value of 101. + /// NOTE The Revision value is on the title page of the specification. + pub const REVISION: Self = Self(0x102); // Original value: PT_FIXED.into() + 2 + + /// The specification day of year using TCG calendar + /// EXAMPLE November 15, 2010, has a day of year value of 319 (0000013F16). + /// NOTE The specification date is on the title page of the specification or errata (see 6.1). + pub const DAY_OF_YEAR: Self = Self(0x103); // Original value: PT_FIXED.into() + 3 + + /// The specification year using the CE + /// EXAMPLE The year 2010 has a value of 000007DA16. + /// NOTE The specification date is on the title page of the specification or errata (see 6.1). + pub const YEAR: Self = Self(0x104); // Original value: PT_FIXED.into() + 4 + + /// The vendor ID unique to each TPM manufacturer + pub const MANUFACTURER: Self = Self(0x105); // Original value: PT_FIXED.into() + 5 + + /// The first four characters of the vendor ID string + /// NOTE When the vendor string is fewer than 16 octets, the additional property values do + /// not have to be present. A vendor string of 4 octets can be represented in one 32-bit + /// value and no null terminating character is required. + pub const VENDOR_STRING_1: Self = Self(0x106); // Original value: PT_FIXED.into() + 6 + + /// The second four characters of the vendor ID string + pub const VENDOR_STRING_2: Self = Self(0x107); // Original value: PT_FIXED.into() + 7 + + /// The third four characters of the vendor ID string + pub const VENDOR_STRING_3: Self = Self(0x108); // Original value: PT_FIXED.into() + 8 + + /// The fourth four characters of the vendor ID sting + pub const VENDOR_STRING_4: Self = Self(0x109); // Original value: PT_FIXED.into() + 9 + + /// Vendor-defined value indicating the TPM model + pub const VENDOR_TPM_TYPE: Self = Self(0x10A); // Original value: PT_FIXED.into() + 10 + + /// The most-significant 32 bits of a TPM vendor-specific value indicating the version + /// number of the firmware. See 10.12.2 and 10.12.12. + pub const FIRMWARE_VERSION_1: Self = Self(0x10B); // Original value: PT_FIXED.into() + 11 + + /// The least-significant 32 bits of a TPM vendor-specific value indicating the version + /// number of the firmware. See 10.12.2 and 10.12.12. + pub const FIRMWARE_VERSION_2: Self = Self(0x10C); // Original value: PT_FIXED.into() + 12 + + /// The maximum size of a parameter (typically, a TPM2B_MAX_BUFFER) + pub const INPUT_BUFFER: Self = Self(0x10D); // Original value: PT_FIXED.into() + 13 + + /// The minimum number of transient objects that can be held in TPM RAM + /// NOTE This minimum shall be no less than the minimum value required by the + /// platform-specific specification to which the TPM is built. + pub const HR_TRANSIENT_MIN: Self = Self(0x10E); // Original value: PT_FIXED.into() + 14 + + /// The minimum number of persistent objects that can be held in TPM NV memory + /// NOTE This minimum shall be no less than the minimum value required by the + /// platform-specific specification to which the TPM is built. + pub const HR_PERSISTENT_MIN: Self = Self(0x10F); // Original value: PT_FIXED.into() + 15 + + /// The minimum number of authorization sessions that can be held in TPM RAM + /// NOTE This minimum shall be no less than the minimum value required by the + /// platform-specific specification to which the TPM is built. + pub const HR_LOADED_MIN: Self = Self(0x110); // Original value: PT_FIXED.into() + 16 + + /// The number of authorization sessions that may be active at a time + /// A session is active when it has a context associated with its handle. The context may + /// either be in TPM RAM or be context saved. + /// NOTE This value shall be no less than the minimum value required by the + /// platform-specific specification to which the TPM is built. + pub const ACTIVE_SESSIONS_MAX: Self = Self(0x111); // Original value: PT_FIXED.into() + 17 + + /// The number of PCR implemented + /// NOTE This number is determined by the defined attributes, not the number of PCR that + /// are populated. + pub const PCR_COUNT: Self = Self(0x112); // Original value: PT_FIXED.into() + 18 + + /// The minimum number of octets in a TPMS_PCR_SELECT.sizeOfSelect + /// NOTE This value is not determined by the number of PCR implemented but by the number + /// of PCR required by the platform-specific specification with which the TPM is compliant + /// or by the implementer if not adhering to a platform-specific specification. + pub const PCR_SELECT_MIN: Self = Self(0x113); // Original value: PT_FIXED.into() + 19 + + /// The maximum allowed difference (unsigned) between the contextID values of two saved + /// session contexts + /// This value shall be 2n-1, where n is at least 16. + pub const CONTEXT_GAP_MAX: Self = Self(0x114); // Original value: PT_FIXED.into() + 20 + + /// The maximum number of NV Indexes that are allowed to have the TPM_NT_COUNTER attribute + /// NOTE 1 It is allowed for this value to be larger than the number of NV Indexes that + /// can be defined. This would be indicative of a TPM implementation that did not use + /// different implementation technology for different NV Index types. + /// NOTE 2 The value zero indicates that there is no fixed maximum. The number of counter + /// indexes is determined by the available NV memory pool. + pub const NV_COUNTERS_MAX: Self = Self(0x116); // Original value: PT_FIXED.into() + 22 + + /// The maximum size of an NV Index data area + pub const NV_INDEX_MAX: Self = Self(0x117); // Original value: PT_FIXED.into() + 23 + + /// A TPMA_MEMORY indicating the memory management method for the TPM + pub const MEMORY: Self = Self(0x118); // Original value: PT_FIXED.into() + 24 + + /// Interval, in milliseconds, between updates to the copy of TPMS_CLOCK_INFO.clock in NV + pub const CLOCK_UPDATE: Self = Self(0x119); // Original value: PT_FIXED.into() + 25 + + /// The algorithm used for the integrity HMAC on saved contexts and for hashing the fuData + /// of TPM2_FirmwareRead() + pub const CONTEXT_HASH: Self = Self(0x11A); // Original value: PT_FIXED.into() + 26 + + /// TPM_ALG_ID, the algorithm used for encryption of saved contexts + pub const CONTEXT_SYM: Self = Self(0x11B); // Original value: PT_FIXED.into() + 27 + + /// TPM_KEY_BITS, the size of the key used for encryption of saved contexts + pub const CONTEXT_SYM_SIZE: Self = Self(0x11C); // Original value: PT_FIXED.into() + 28 + + /// The modulus - 1 of the count for NV update of an orderly counter + /// The returned value is MAX_ORDERLY_COUNT. + /// This will have a value of 2N 1 where 1 N 32 + /// NOTE 1 An orderly counter is an NV Index with an TPM_NT of TPM_NV_COUNTER and + /// TPMA_NV_ORDERLY SET. + /// NOTE 2 When the low-order bits of a counter equal this value, an NV write occurs on + /// the next increment. + pub const ORDERLY_COUNT: Self = Self(0x11D); // Original value: PT_FIXED.into() + 29 + + /// The maximum value for commandSize in a command + pub const MAX_COMMAND_SIZE: Self = Self(0x11E); // Original value: PT_FIXED.into() + 30 + + /// The maximum value for responseSize in a response + pub const MAX_RESPONSE_SIZE: Self = Self(0x11F); // Original value: PT_FIXED.into() + 31 + + /// The maximum size of a digest that can be produced by the TPM + pub const MAX_DIGEST: Self = Self(0x120); // Original value: PT_FIXED.into() + 32 + + /// The maximum size of an object context that will be returned by TPM2_ContextSave + pub const MAX_OBJECT_CONTEXT: Self = Self(0x121); // Original value: PT_FIXED.into() + 33 + + /// The maximum size of a session context that will be returned by TPM2_ContextSave + pub const MAX_SESSION_CONTEXT: Self = Self(0x122); // Original value: PT_FIXED.into() + 34 + + /// Platform-specific family (a TPM_PS value)(see Table 25) + /// NOTE The platform-specific values for the TPM_PT_PS parameters are in the relevant + /// platform-specific specification. In the reference implementation, all of these values + /// are 0. + pub const PS_FAMILY_INDICATOR: Self = Self(0x123); // Original value: PT_FIXED.into() + 35 + + /// The level of the platform-specific specification + pub const PS_LEVEL: Self = Self(0x124); // Original value: PT_FIXED.into() + 36 + + /// A platform specific value + pub const PS_REVISION: Self = Self(0x125); // Original value: PT_FIXED.into() + 37 + + /// The platform-specific TPM specification day of year using TCG calendar + /// EXAMPLE November 15, 2010, has a day of year value of 319 (0000013F16). + pub const PS_DAY_OF_YEAR: Self = Self(0x126); // Original value: PT_FIXED.into() + 38 + + /// The platform-specific TPM specification year using the CE + /// EXAMPLE The year 2010 has a value of 000007DA16. + pub const PS_YEAR: Self = Self(0x127); // Original value: PT_FIXED.into() + 39 + + /// The number of split signing operations supported by the TPM + pub const SPLIT_MAX: Self = Self(0x128); // Original value: PT_FIXED.into() + 40 + + /// Total number of commands implemented in the TPM + pub const TOTAL_COMMANDS: Self = Self(0x129); // Original value: PT_FIXED.into() + 41 + + /// Number of commands from the TPM library that are implemented + pub const LIBRARY_COMMANDS: Self = Self(0x12A); // Original value: PT_FIXED.into() + 42 + + /// Number of vendor commands that are implemented + pub const VENDOR_COMMANDS: Self = Self(0x12B); // Original value: PT_FIXED.into() + 43 + + /// The maximum data size in one NV write, NV read, NV extend, or NV certify command + pub const NV_BUFFER_MAX: Self = Self(0x12C); // Original value: PT_FIXED.into() + 44 + + /// A TPMA_MODES value, indicating that the TPM is designed for these modes. + pub const MODES: Self = Self(0x12D); // Original value: PT_FIXED.into() + 45 + + /// The maximum size of a TPMS_CAPABILITY_DATA structure returned in TPM2_GetCapability(). + pub const MAX_CAP_BUFFER: Self = Self(0x12E); // Original value: PT_FIXED.into() + 46 + + /// The group of variable properties returned as TPMS_TAGGED_PROPERTY + /// The properties in this group change because of a Protected Capability other than a + /// firmware update. The values are not necessarily persistent across all power transitions. + pub const PT_VAR: Self = Self(0x200); // Original value: PT_GROUP.into() * 2 + + /// TPMA_PERMANENT + pub const PERMANENT: Self = Self(0x200); // Original value: PT_VAR.into() + 0 + + /// TPMA_STARTUP_CLEAR + pub const STARTUP_CLEAR: Self = Self(0x201); // Original value: PT_VAR.into() + 1 + + /// The number of NV Indexes currently defined + pub const HR_NV_INDEX: Self = Self(0x202); // Original value: PT_VAR.into() + 2 + + /// The number of authorization sessions currently loaded into TPM RAM + pub const HR_LOADED: Self = Self(0x203); // Original value: PT_VAR.into() + 3 + + /// The number of additional authorization sessions, of any type, that could be loaded + /// into TPM RAM + /// This value is an estimate. If this value is at least 1, then at least one + /// authorization session of any type may be loaded. Any command that changes the RAM + /// memory allocation can make this estimate invalid. + /// NOTE A valid implementation may return 1 even if more than one authorization session + /// would fit into RAM. + pub const HR_LOADED_AVAIL: Self = Self(0x204); // Original value: PT_VAR.into() + 4 + + /// The number of active authorization sessions currently being tracked by the TPM + /// This is the sum of the loaded and saved sessions. + pub const HR_ACTIVE: Self = Self(0x205); // Original value: PT_VAR.into() + 5 + + /// The number of additional authorization sessions, of any type, that could be created + /// This value is an estimate. If this value is at least 1, then at least one + /// authorization session of any type may be created. Any command that changes the RAM + /// memory allocation can make this estimate invalid. + /// NOTE A valid implementation may return 1 even if more than one authorization session + /// could be created. + pub const HR_ACTIVE_AVAIL: Self = Self(0x206); // Original value: PT_VAR.into() + 6 + + /// Estimate of the number of additional transient objects that could be loaded into TPM RAM + /// This value is an estimate. If this value is at least 1, then at least one object of + /// any type may be loaded. Any command that changes the memory allocation can make this + /// estimate invalid. + /// NOTE A valid implementation may return 1 even if more than one transient object would + /// fit into RAM. + pub const HR_TRANSIENT_AVAIL: Self = Self(0x207); // Original value: PT_VAR.into() + 7 + + /// The number of persistent objects currently loaded into TPM NV memory + pub const HR_PERSISTENT: Self = Self(0x208); // Original value: PT_VAR.into() + 8 + + /// The number of additional persistent objects that could be loaded into NV memory + /// This value is an estimate. If this value is at least 1, then at least one object of + /// any type may be made persistent. Any command that changes the NV memory allocation can + /// make this estimate invalid. + /// NOTE A valid implementation may return 1 even if more than one persistent object would + /// fit into NV memory. + pub const HR_PERSISTENT_AVAIL: Self = Self(0x209); // Original value: PT_VAR.into() + 9 + + /// The number of defined NV Indexes that have NV the TPM_NT_COUNTER attribute + pub const NV_COUNTERS: Self = Self(0x20A); // Original value: PT_VAR.into() + 10 + + /// The number of additional NV Indexes that can be defined with their TPM_NT of + /// TPM_NV_COUNTER and the TPMA_NV_ORDERLY attribute SET + /// This value is an estimate. If this value is at least 1, then at least one NV Index may + /// be created with a TPM_NT of TPM_NV_COUNTER and the TPMA_NV_ORDERLY attributes. Any + /// command that changes the NV memory allocation can make this estimate invalid. + /// NOTE A valid implementation may return 1 even if more than one NV counter could be defined. + pub const NV_COUNTERS_AVAIL: Self = Self(0x20B); // Original value: PT_VAR.into() + 11 + + /// Code that limits the algorithms that may be used with the TPM + pub const ALGORITHM_SET: Self = Self(0x20C); // Original value: PT_VAR.into() + 12 + + /// The number of loaded ECC curves + pub const LOADED_CURVES: Self = Self(0x20D); // Original value: PT_VAR.into() + 13 + + /// The current value of the lockout counter (failedTries) + pub const LOCKOUT_COUNTER: Self = Self(0x20E); // Original value: PT_VAR.into() + 14 + + /// The number of authorization failures before DA lockout is invoked + pub const MAX_AUTH_FAIL: Self = Self(0x20F); // Original value: PT_VAR.into() + 15 + + /// The number of seconds before the value reported by TPM_PT_LOCKOUT_COUNTER is decremented + pub const LOCKOUT_INTERVAL: Self = Self(0x210); // Original value: PT_VAR.into() + 16 + + /// The number of seconds after a lockoutAuth failure before use of lockoutAuth may be + /// attempted again + pub const LOCKOUT_RECOVERY: Self = Self(0x211); // Original value: PT_VAR.into() + 17 + + /// Number of milliseconds before the TPM will accept another command that will modify NV + /// This value is an approximation and may go up or down over time. + pub const NV_WRITE_RECOVERY: Self = Self(0x212); // Original value: PT_VAR.into() + 18 + + /// The high-order 32 bits of the command audit counter + pub const AUDIT_COUNTER_0: Self = Self(0x213); // Original value: PT_VAR.into() + 19 + + /// The low-order 32 bits of the command audit counter + pub const AUDIT_COUNTER_1: Self = Self(0x214); // Original value: PT_VAR.into() + 20 + + pub fn try_from(value: u32) -> Result { + match value { + 0 => Ok(Self::NONE), // Original value: 0x00000000 + 256 => Ok(Self::FAMILY_INDICATOR), // Original value: PT_FIXED.into() + 0 + 257 => Ok(Self::LEVEL), // Original value: PT_FIXED.into() + 1 + 258 => Ok(Self::REVISION), // Original value: PT_FIXED.into() + 2 + 259 => Ok(Self::DAY_OF_YEAR), // Original value: PT_FIXED.into() + 3 + 260 => Ok(Self::YEAR), // Original value: PT_FIXED.into() + 4 + 261 => Ok(Self::MANUFACTURER), // Original value: PT_FIXED.into() + 5 + 262 => Ok(Self::VENDOR_STRING_1), // Original value: PT_FIXED.into() + 6 + 263 => Ok(Self::VENDOR_STRING_2), // Original value: PT_FIXED.into() + 7 + 264 => Ok(Self::VENDOR_STRING_3), // Original value: PT_FIXED.into() + 8 + 265 => Ok(Self::VENDOR_STRING_4), // Original value: PT_FIXED.into() + 9 + 266 => Ok(Self::VENDOR_TPM_TYPE), // Original value: PT_FIXED.into() + 10 + 267 => Ok(Self::FIRMWARE_VERSION_1), // Original value: PT_FIXED.into() + 11 + 268 => Ok(Self::FIRMWARE_VERSION_2), // Original value: PT_FIXED.into() + 12 + 269 => Ok(Self::INPUT_BUFFER), // Original value: PT_FIXED.into() + 13 + 270 => Ok(Self::HR_TRANSIENT_MIN), // Original value: PT_FIXED.into() + 14 + 271 => Ok(Self::HR_PERSISTENT_MIN), // Original value: PT_FIXED.into() + 15 + 272 => Ok(Self::HR_LOADED_MIN), // Original value: PT_FIXED.into() + 16 + 273 => Ok(Self::ACTIVE_SESSIONS_MAX), // Original value: PT_FIXED.into() + 17 + 274 => Ok(Self::PCR_COUNT), // Original value: PT_FIXED.into() + 18 + 275 => Ok(Self::PCR_SELECT_MIN), // Original value: PT_FIXED.into() + 19 + 276 => Ok(Self::CONTEXT_GAP_MAX), // Original value: PT_FIXED.into() + 20 + 278 => Ok(Self::NV_COUNTERS_MAX), // Original value: PT_FIXED.into() + 22 + 279 => Ok(Self::NV_INDEX_MAX), // Original value: PT_FIXED.into() + 23 + 280 => Ok(Self::MEMORY), // Original value: PT_FIXED.into() + 24 + 281 => Ok(Self::CLOCK_UPDATE), // Original value: PT_FIXED.into() + 25 + 282 => Ok(Self::CONTEXT_HASH), // Original value: PT_FIXED.into() + 26 + 283 => Ok(Self::CONTEXT_SYM), // Original value: PT_FIXED.into() + 27 + 284 => Ok(Self::CONTEXT_SYM_SIZE), // Original value: PT_FIXED.into() + 28 + 285 => Ok(Self::ORDERLY_COUNT), // Original value: PT_FIXED.into() + 29 + 286 => Ok(Self::MAX_COMMAND_SIZE), // Original value: PT_FIXED.into() + 30 + 287 => Ok(Self::MAX_RESPONSE_SIZE), // Original value: PT_FIXED.into() + 31 + 288 => Ok(Self::MAX_DIGEST), // Original value: PT_FIXED.into() + 32 + 289 => Ok(Self::MAX_OBJECT_CONTEXT), // Original value: PT_FIXED.into() + 33 + 290 => Ok(Self::MAX_SESSION_CONTEXT), // Original value: PT_FIXED.into() + 34 + 291 => Ok(Self::PS_FAMILY_INDICATOR), // Original value: PT_FIXED.into() + 35 + 292 => Ok(Self::PS_LEVEL), // Original value: PT_FIXED.into() + 36 + 293 => Ok(Self::PS_REVISION), // Original value: PT_FIXED.into() + 37 + 294 => Ok(Self::PS_DAY_OF_YEAR), // Original value: PT_FIXED.into() + 38 + 295 => Ok(Self::PS_YEAR), // Original value: PT_FIXED.into() + 39 + 296 => Ok(Self::SPLIT_MAX), // Original value: PT_FIXED.into() + 40 + 297 => Ok(Self::TOTAL_COMMANDS), // Original value: PT_FIXED.into() + 41 + 298 => Ok(Self::LIBRARY_COMMANDS), // Original value: PT_FIXED.into() + 42 + 299 => Ok(Self::VENDOR_COMMANDS), // Original value: PT_FIXED.into() + 43 + 300 => Ok(Self::NV_BUFFER_MAX), // Original value: PT_FIXED.into() + 44 + 301 => Ok(Self::MODES), // Original value: PT_FIXED.into() + 45 + 302 => Ok(Self::MAX_CAP_BUFFER), // Original value: PT_FIXED.into() + 46 + 512 => Ok(Self::PERMANENT), // Original value: PT_VAR.into() + 0 + 513 => Ok(Self::STARTUP_CLEAR), // Original value: PT_VAR.into() + 1 + 514 => Ok(Self::HR_NV_INDEX), // Original value: PT_VAR.into() + 2 + 515 => Ok(Self::HR_LOADED), // Original value: PT_VAR.into() + 3 + 516 => Ok(Self::HR_LOADED_AVAIL), // Original value: PT_VAR.into() + 4 + 517 => Ok(Self::HR_ACTIVE), // Original value: PT_VAR.into() + 5 + 518 => Ok(Self::HR_ACTIVE_AVAIL), // Original value: PT_VAR.into() + 6 + 519 => Ok(Self::HR_TRANSIENT_AVAIL), // Original value: PT_VAR.into() + 7 + 520 => Ok(Self::HR_PERSISTENT), // Original value: PT_VAR.into() + 8 + 521 => Ok(Self::HR_PERSISTENT_AVAIL), // Original value: PT_VAR.into() + 9 + 522 => Ok(Self::NV_COUNTERS), // Original value: PT_VAR.into() + 10 + 523 => Ok(Self::NV_COUNTERS_AVAIL), // Original value: PT_VAR.into() + 11 + 524 => Ok(Self::ALGORITHM_SET), // Original value: PT_VAR.into() + 12 + 525 => Ok(Self::LOADED_CURVES), // Original value: PT_VAR.into() + 13 + 526 => Ok(Self::LOCKOUT_COUNTER), // Original value: PT_VAR.into() + 14 + 527 => Ok(Self::MAX_AUTH_FAIL), // Original value: PT_VAR.into() + 15 + 528 => Ok(Self::LOCKOUT_INTERVAL), // Original value: PT_VAR.into() + 16 + 529 => Ok(Self::LOCKOUT_RECOVERY), // Original value: PT_VAR.into() + 17 + 530 => Ok(Self::NV_WRITE_RECOVERY), // Original value: PT_VAR.into() + 18 + 531 => Ok(Self::AUDIT_COUNTER_0), // Original value: PT_VAR.into() + 19 + 532 => Ok(Self::AUDIT_COUNTER_1), // Original value: PT_VAR.into() + 20 + _ => Err(TpmError::InvalidEnumValue), + } + } +} + +impl TpmEnum for TPM_PT { + fn get_value(&self) -> u32 { + self.0.into() + } + + fn try_from_trait(value: u64) -> Result where Self: Sized { + TPM_PT::try_from(value as u32) + } + + fn new_from_trait(value: u64) -> Result where Self: Sized { + Ok(TPM_PT(value as u32)) + } +} + +impl From for u32 { + fn from(value: TPM_PT) -> Self { + value.0 as u32 + } +} + +impl From for i32 { + fn from(value: TPM_PT) -> Self { + value.0 as i32 + } +} + +impl fmt::Display for TPM_PT { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + 0 => write!(f, "NONE"), + 256 => write!(f, "FAMILY_INDICATOR"), + 257 => write!(f, "LEVEL"), + 258 => write!(f, "REVISION"), + 259 => write!(f, "DAY_OF_YEAR"), + 260 => write!(f, "YEAR"), + 261 => write!(f, "MANUFACTURER"), + 262 => write!(f, "VENDOR_STRING_1"), + 263 => write!(f, "VENDOR_STRING_2"), + 264 => write!(f, "VENDOR_STRING_3"), + 265 => write!(f, "VENDOR_STRING_4"), + 266 => write!(f, "VENDOR_TPM_TYPE"), + 267 => write!(f, "FIRMWARE_VERSION_1"), + 268 => write!(f, "FIRMWARE_VERSION_2"), + 269 => write!(f, "INPUT_BUFFER"), + 270 => write!(f, "HR_TRANSIENT_MIN"), + 271 => write!(f, "HR_PERSISTENT_MIN"), + 272 => write!(f, "HR_LOADED_MIN"), + 273 => write!(f, "ACTIVE_SESSIONS_MAX"), + 274 => write!(f, "PCR_COUNT"), + 275 => write!(f, "PCR_SELECT_MIN"), + 276 => write!(f, "CONTEXT_GAP_MAX"), + 278 => write!(f, "NV_COUNTERS_MAX"), + 279 => write!(f, "NV_INDEX_MAX"), + 280 => write!(f, "MEMORY"), + 281 => write!(f, "CLOCK_UPDATE"), + 282 => write!(f, "CONTEXT_HASH"), + 283 => write!(f, "CONTEXT_SYM"), + 284 => write!(f, "CONTEXT_SYM_SIZE"), + 285 => write!(f, "ORDERLY_COUNT"), + 286 => write!(f, "MAX_COMMAND_SIZE"), + 287 => write!(f, "MAX_RESPONSE_SIZE"), + 288 => write!(f, "MAX_DIGEST"), + 289 => write!(f, "MAX_OBJECT_CONTEXT"), + 290 => write!(f, "MAX_SESSION_CONTEXT"), + 291 => write!(f, "PS_FAMILY_INDICATOR"), + 292 => write!(f, "PS_LEVEL"), + 293 => write!(f, "PS_REVISION"), + 294 => write!(f, "PS_DAY_OF_YEAR"), + 295 => write!(f, "PS_YEAR"), + 296 => write!(f, "SPLIT_MAX"), + 297 => write!(f, "TOTAL_COMMANDS"), + 298 => write!(f, "LIBRARY_COMMANDS"), + 299 => write!(f, "VENDOR_COMMANDS"), + 300 => write!(f, "NV_BUFFER_MAX"), + 301 => write!(f, "MODES"), + 302 => write!(f, "MAX_CAP_BUFFER"), + 512 => write!(f, "PERMANENT"), + 513 => write!(f, "STARTUP_CLEAR"), + 514 => write!(f, "HR_NV_INDEX"), + 515 => write!(f, "HR_LOADED"), + 516 => write!(f, "HR_LOADED_AVAIL"), + 517 => write!(f, "HR_ACTIVE"), + 518 => write!(f, "HR_ACTIVE_AVAIL"), + 519 => write!(f, "HR_TRANSIENT_AVAIL"), + 520 => write!(f, "HR_PERSISTENT"), + 521 => write!(f, "HR_PERSISTENT_AVAIL"), + 522 => write!(f, "NV_COUNTERS"), + 523 => write!(f, "NV_COUNTERS_AVAIL"), + 524 => write!(f, "ALGORITHM_SET"), + 525 => write!(f, "LOADED_CURVES"), + 526 => write!(f, "LOCKOUT_COUNTER"), + 527 => write!(f, "MAX_AUTH_FAIL"), + 528 => write!(f, "LOCKOUT_INTERVAL"), + 529 => write!(f, "LOCKOUT_RECOVERY"), + 530 => write!(f, "NV_WRITE_RECOVERY"), + 531 => write!(f, "AUDIT_COUNTER_0"), + 532 => write!(f, "AUDIT_COUNTER_1"), + _ => write!(f, "{}", enum_to_str(self.0 as u64, std::any::TypeId::of::())), + } + } +} + +/// The TPM_PT_PCR constants are used in TPM2_GetCapability() to indicate the property +/// being selected or returned. The PCR properties can be read when capability == +/// TPM_CAP_PCR_PROPERTIES. If there is no property that corresponds to the value of +/// property, the next higher value is returned, if it exists. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub struct TPM_PT_PCR(pub u32); + +impl TPM_PT_PCR { + /// Bottom of the range of TPM_PT_PCR properties + pub const FIRST: Self = Self(0x0); // Original value: 0x00000000 + + /// A SET bit in the TPMS_PCR_SELECT indicates that the PCR is saved and restored by TPM_SU_STATE + pub const SAVE: Self = Self(0x0); // Original value: 0x00000000 + + /// A SET bit in the TPMS_PCR_SELECT indicates that the PCR may be extended from locality 0 + /// This property is only present if a locality other than 0 is implemented. + pub const EXTEND_L0: Self = Self(0x1); // Original value: 0x00000001 + + /// A SET bit in the TPMS_PCR_SELECT indicates that the PCR may be reset by + /// TPM2_PCR_Reset() from locality 0 + pub const RESET_L0: Self = Self(0x2); // Original value: 0x00000002 + + /// A SET bit in the TPMS_PCR_SELECT indicates that the PCR may be extended from locality 1 + /// This property is only present if locality 1 is implemented. + pub const EXTEND_L1: Self = Self(0x3); // Original value: 0x00000003 + + /// A SET bit in the TPMS_PCR_SELECT indicates that the PCR may be reset by + /// TPM2_PCR_Reset() from locality 1 + /// This property is only present if locality 1 is implemented. + pub const RESET_L1: Self = Self(0x4); // Original value: 0x00000004 + + /// A SET bit in the TPMS_PCR_SELECT indicates that the PCR may be extended from locality 2 + /// This property is only present if localities 1 and 2 are implemented. + pub const EXTEND_L2: Self = Self(0x5); // Original value: 0x00000005 + + /// A SET bit in the TPMS_PCR_SELECT indicates that the PCR may be reset by + /// TPM2_PCR_Reset() from locality 2 + /// This property is only present if localities 1 and 2 are implemented. + pub const RESET_L2: Self = Self(0x6); // Original value: 0x00000006 + + /// A SET bit in the TPMS_PCR_SELECT indicates that the PCR may be extended from locality 3 + /// This property is only present if localities 1, 2, and 3 are implemented. + pub const EXTEND_L3: Self = Self(0x7); // Original value: 0x00000007 + + /// A SET bit in the TPMS_PCR_SELECT indicates that the PCR may be reset by + /// TPM2_PCR_Reset() from locality 3 + /// This property is only present if localities 1, 2, and 3 are implemented. + pub const RESET_L3: Self = Self(0x8); // Original value: 0x00000008 + + /// A SET bit in the TPMS_PCR_SELECT indicates that the PCR may be extended from locality 4 + /// This property is only present if localities 1, 2, 3, and 4 are implemented. + pub const EXTEND_L4: Self = Self(0x9); // Original value: 0x00000009 + + /// A SET bit in the TPMS_PCR_SELECT indicates that the PCR may be reset by + /// TPM2_PCR_Reset() from locality 4 + /// This property is only present if localities 1, 2, 3, and 4 are implemented. + pub const RESET_L4: Self = Self(0xA); // Original value: 0x0000000A + + /// A SET bit in the TPMS_PCR_SELECT indicates that modifications to this PCR (reset or + /// Extend) will not increment the pcrUpdateCounter + pub const NO_INCREMENT: Self = Self(0x11); // Original value: 0x00000011 + + /// A SET bit in the TPMS_PCR_SELECT indicates that the PCR is reset by a D-RTM event + /// These PCR are reset to -1 on TPM2_Startup() and reset to 0 on a _TPM_Hash_End event + /// following a _TPM_Hash_Start event. + pub const DRTM_RESET: Self = Self(0x12); // Original value: 0x00000012 + + /// A SET bit in the TPMS_PCR_SELECT indicates that the PCR is controlled by policy + /// This property is only present if the TPM supports policy control of a PCR. + pub const POLICY: Self = Self(0x13); // Original value: 0x00000013 + + /// A SET bit in the TPMS_PCR_SELECT indicates that the PCR is controlled by an + /// authorization value + /// This property is only present if the TPM supports authorization control of a PCR. + pub const AUTH: Self = Self(0x14); // Original value: 0x00000014 + + /// Top of the range of TPM_PT_PCR properties of the implementation + /// If the TPM receives a request for a PCR property with a value larger than this, the + /// TPM will return a zero length list and set the moreData parameter to NO. + /// NOTE This is an implementation-specific value. The value shown reflects the reference + /// code implementation. + pub const LAST: Self = Self(0x14); // Original value: 0x00000014 + + pub fn try_from(value: u32) -> Result { + match value { + 0 => Ok(Self::SAVE), // Original value: 0x00000000 + 1 => Ok(Self::EXTEND_L0), // Original value: 0x00000001 + 2 => Ok(Self::RESET_L0), // Original value: 0x00000002 + 3 => Ok(Self::EXTEND_L1), // Original value: 0x00000003 + 4 => Ok(Self::RESET_L1), // Original value: 0x00000004 + 5 => Ok(Self::EXTEND_L2), // Original value: 0x00000005 + 6 => Ok(Self::RESET_L2), // Original value: 0x00000006 + 7 => Ok(Self::EXTEND_L3), // Original value: 0x00000007 + 8 => Ok(Self::RESET_L3), // Original value: 0x00000008 + 9 => Ok(Self::EXTEND_L4), // Original value: 0x00000009 + 10 => Ok(Self::RESET_L4), // Original value: 0x0000000A + 17 => Ok(Self::NO_INCREMENT), // Original value: 0x00000011 + 18 => Ok(Self::DRTM_RESET), // Original value: 0x00000012 + 19 => Ok(Self::POLICY), // Original value: 0x00000013 + 20 => Ok(Self::LAST), // Original value: 0x00000014 + _ => Err(TpmError::InvalidEnumValue), + } + } +} + +impl TpmEnum for TPM_PT_PCR { + fn get_value(&self) -> u32 { + self.0.into() + } + + fn try_from_trait(value: u64) -> Result where Self: Sized { + TPM_PT_PCR::try_from(value as u32) + } + + fn new_from_trait(value: u64) -> Result where Self: Sized { + Ok(TPM_PT_PCR(value as u32)) + } +} + +impl From for u32 { + fn from(value: TPM_PT_PCR) -> Self { + value.0 as u32 + } +} + +impl From for i32 { + fn from(value: TPM_PT_PCR) -> Self { + value.0 as i32 + } +} + +impl fmt::Display for TPM_PT_PCR { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + 0 => write!(f, "SAVE"), + 1 => write!(f, "EXTEND_L0"), + 2 => write!(f, "RESET_L0"), + 3 => write!(f, "EXTEND_L1"), + 4 => write!(f, "RESET_L1"), + 5 => write!(f, "EXTEND_L2"), + 6 => write!(f, "RESET_L2"), + 7 => write!(f, "EXTEND_L3"), + 8 => write!(f, "RESET_L3"), + 9 => write!(f, "EXTEND_L4"), + 10 => write!(f, "RESET_L4"), + 17 => write!(f, "NO_INCREMENT"), + 18 => write!(f, "DRTM_RESET"), + 19 => write!(f, "POLICY"), + 20 => write!(f, "LAST"), + _ => write!(f, "{}", enum_to_str(self.0 as u64, std::any::TypeId::of::())), + } + } +} + +/// The platform values in Table 25 are used for the TPM_PT_PS_FAMILY_INDICATOR. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub struct TPM_PS(pub u32); + +impl TPM_PS { + /// Not platform specific + pub const MAIN: Self = Self(0x0); // Original value: 0x00000000 + + /// PC Client + pub const PC: Self = Self(0x1); // Original value: 0x00000001 + + /// PDA (includes all mobile devices that are not specifically cell phones) + pub const PDA: Self = Self(0x2); // Original value: 0x00000002 + + /// Cell Phone + pub const CELL_PHONE: Self = Self(0x3); // Original value: 0x00000003 + + /// Server WG + pub const SERVER: Self = Self(0x4); // Original value: 0x00000004 + + /// Peripheral WG + pub const PERIPHERAL: Self = Self(0x5); // Original value: 0x00000005 + + /// TSS WG (deprecated) + pub const TSS: Self = Self(0x6); // Original value: 0x00000006 + + /// Storage WG + pub const STORAGE: Self = Self(0x7); // Original value: 0x00000007 + + /// Authentication WG + pub const AUTHENTICATION: Self = Self(0x8); // Original value: 0x00000008 + + /// Embedded WG + pub const EMBEDDED: Self = Self(0x9); // Original value: 0x00000009 + + /// Hardcopy WG + pub const HARDCOPY: Self = Self(0xA); // Original value: 0x0000000A + + /// Infrastructure WG (deprecated) + pub const INFRASTRUCTURE: Self = Self(0xB); // Original value: 0x0000000B + + /// Virtualization WG + pub const VIRTUALIZATION: Self = Self(0xC); // Original value: 0x0000000C + + /// Trusted Network Connect WG (deprecated) + pub const TNC: Self = Self(0xD); // Original value: 0x0000000D + + /// Multi-tenant WG (deprecated) + pub const MULTI_TENANT: Self = Self(0xE); // Original value: 0x0000000E + + /// Technical Committee (deprecated) + pub const TC: Self = Self(0xF); // Original value: 0x0000000F + + pub fn try_from(value: u32) -> Result { + match value { + 0 => Ok(Self::MAIN), // Original value: 0x00000000 + 1 => Ok(Self::PC), // Original value: 0x00000001 + 2 => Ok(Self::PDA), // Original value: 0x00000002 + 3 => Ok(Self::CELL_PHONE), // Original value: 0x00000003 + 4 => Ok(Self::SERVER), // Original value: 0x00000004 + 5 => Ok(Self::PERIPHERAL), // Original value: 0x00000005 + 6 => Ok(Self::TSS), // Original value: 0x00000006 + 7 => Ok(Self::STORAGE), // Original value: 0x00000007 + 8 => Ok(Self::AUTHENTICATION), // Original value: 0x00000008 + 9 => Ok(Self::EMBEDDED), // Original value: 0x00000009 + 10 => Ok(Self::HARDCOPY), // Original value: 0x0000000A + 11 => Ok(Self::INFRASTRUCTURE), // Original value: 0x0000000B + 12 => Ok(Self::VIRTUALIZATION), // Original value: 0x0000000C + 13 => Ok(Self::TNC), // Original value: 0x0000000D + 14 => Ok(Self::MULTI_TENANT), // Original value: 0x0000000E + 15 => Ok(Self::TC), // Original value: 0x0000000F + _ => Err(TpmError::InvalidEnumValue), + } + } +} + +impl TpmEnum for TPM_PS { + fn get_value(&self) -> u32 { + self.0.into() + } + + fn try_from_trait(value: u64) -> Result where Self: Sized { + TPM_PS::try_from(value as u32) + } + + fn new_from_trait(value: u64) -> Result where Self: Sized { + Ok(TPM_PS(value as u32)) + } +} + +impl From for u32 { + fn from(value: TPM_PS) -> Self { + value.0 as u32 + } +} + +impl From for i32 { + fn from(value: TPM_PS) -> Self { + value.0 as i32 + } +} + +impl fmt::Display for TPM_PS { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + 0 => write!(f, "MAIN"), + 1 => write!(f, "PC"), + 2 => write!(f, "PDA"), + 3 => write!(f, "CELL_PHONE"), + 4 => write!(f, "SERVER"), + 5 => write!(f, "PERIPHERAL"), + 6 => write!(f, "TSS"), + 7 => write!(f, "STORAGE"), + 8 => write!(f, "AUTHENTICATION"), + 9 => write!(f, "EMBEDDED"), + 10 => write!(f, "HARDCOPY"), + 11 => write!(f, "INFRASTRUCTURE"), + 12 => write!(f, "VIRTUALIZATION"), + 13 => write!(f, "TNC"), + 14 => write!(f, "MULTI_TENANT"), + 15 => write!(f, "TC"), + _ => write!(f, "{}", enum_to_str(self.0 as u64, std::any::TypeId::of::())), + } + } +} + +/// The 32-bit handle space is divided into 256 regions of equal size with 224 values in +/// each. Each of these ranges represents a handle type. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub struct TPM_HT(pub u8); + +impl TPM_HT { + /// PCR consecutive numbers, starting at 0, that reference the PCR registers + /// A platform-specific specification will set the minimum number of PCR and an + /// implementation may have more. + pub const PCR: Self = Self(0x0); // Original value: 0x00 + + /// NV Index assigned by the caller + pub const NV_INDEX: Self = Self(0x1); // Original value: 0x01 + + /// HMAC Authorization Session assigned by the TPM when the session is created + pub const HMAC_SESSION: Self = Self(0x2); // Original value: 0x02 + + /// Loaded Authorization Session used only in the context of TPM2_GetCapability + /// This type references both loaded HMAC and loaded policy authorization sessions. + pub const LOADED_SESSION: Self = Self(0x2); // Original value: 0x02 + + /// Policy Authorization Session assigned by the TPM when the session is created + pub const POLICY_SESSION: Self = Self(0x3); // Original value: 0x03 + + /// Saved Authorization Session used only in the context of TPM2_GetCapability + /// This type references saved authorization session contexts for which the TPM is + /// maintaining tracking information. + pub const SAVED_SESSION: Self = Self(0x3); // Original value: 0x03 + + /// Permanent Values assigned by this specification in Table 28 + pub const PERMANENT: Self = Self(0x40); + + /// Transient Objects assigned by the TPM when an object is loaded into transient-object + /// memory or when a persistent object is converted to a transient object + pub const TRANSIENT: Self = Self(0x80); + + /// Persistent Objects assigned by the TPM when a loaded transient object is made persistent + pub const PERSISTENT: Self = Self(0x81); + + /// Attached Component handle for an Attached Component. + pub const AC: Self = Self(0x90); + + pub fn try_from(value: u8) -> Result { + match value { + 0 => Ok(Self::PCR), // Original value: 0x00 + 1 => Ok(Self::NV_INDEX), // Original value: 0x01 + 2 => Ok(Self::LOADED_SESSION), // Original value: 0x02 + 3 => Ok(Self::SAVED_SESSION), // Original value: 0x03 + 64 => Ok(Self::PERMANENT), // Original value: 0x40 + 128 => Ok(Self::TRANSIENT), // Original value: 0x80 + 129 => Ok(Self::PERSISTENT), // Original value: 0x81 + 144 => Ok(Self::AC), // Original value: 0x90 + _ => Err(TpmError::InvalidEnumValue), + } + } +} + +impl TpmEnum for TPM_HT { + fn get_value(&self) -> u8 { + self.0.into() + } + + fn try_from_trait(value: u64) -> Result where Self: Sized { + TPM_HT::try_from(value as u8) + } + + fn new_from_trait(value: u64) -> Result where Self: Sized { + Ok(TPM_HT(value as u8)) + } +} + +impl From for u8 { + fn from(value: TPM_HT) -> Self { + value.0 as u8 + } +} + +impl From for i8 { + fn from(value: TPM_HT) -> Self { + value.0 as i8 + } +} + +impl fmt::Display for TPM_HT { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + 0 => write!(f, "PCR"), + 1 => write!(f, "NV_INDEX"), + 2 => write!(f, "LOADED_SESSION"), + 3 => write!(f, "SAVED_SESSION"), + 64 => write!(f, "PERMANENT"), + 128 => write!(f, "TRANSIENT"), + 129 => write!(f, "PERSISTENT"), + 144 => write!(f, "AC"), + _ => write!(f, "{}", enum_to_str(self.0 as u64, std::any::TypeId::of::())), + } + } +} + +/// Table 28 lists the architecturally defined handles that cannot be changed. The handles +/// include authorization handles, and special handles. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub struct TPM_RH(pub u32); + +impl TPM_RH { + pub const FIRST: Self = Self(0x40000000); + + /// Not used1 + pub const SRK: Self = Self(0x40000000); + + /// Handle references the Storage Primary Seed (SPS), the ownerAuth, and the ownerPolicy + pub const OWNER: Self = Self(0x40000001); + + /// Not used1 + pub const REVOKE: Self = Self(0x40000002); + + /// Not used1 + pub const TRANSPORT: Self = Self(0x40000003); + + /// Not used1 + pub const OPERATOR: Self = Self(0x40000004); + + /// Not used1 + pub const ADMIN: Self = Self(0x40000005); + + /// Not used1 + pub const EK: Self = Self(0x40000006); + + /// A handle associated with the null hierarchy, an EmptyAuth authValue, and an Empty + /// Policy authPolicy. + pub const NULL: Self = Self(0x40000007); + + /// Value reserved to the TPM to indicate a handle location that has not been initialized + /// or assigned + pub const UNASSIGNED: Self = Self(0x40000008); + + /// Authorization value used to indicate a password authorization session + pub const PW: Self = Self(0x40000009); + + /// References the authorization associated with the dictionary attack lockout reset + pub const LOCKOUT: Self = Self(0x4000000A); + + /// References the Endorsement Primary Seed (EPS), endorsementAuth, and endorsementPolicy + pub const ENDORSEMENT: Self = Self(0x4000000B); + + /// References the Platform Primary Seed (PPS), platformAuth, and platformPolicy + pub const PLATFORM: Self = Self(0x4000000C); + + /// For phEnableNV + pub const PLATFORM_NV: Self = Self(0x4000000D); + + /// Start of a range of authorization values that are vendor-specific. A TPM may support + /// any of the values in this range as are needed for vendor-specific purposes. + /// Disabled if ehEnable is CLEAR. + /// NOTE Any includes none. + pub const AUTH_00: Self = Self(0x40000010); + + /// End of the range of vendor-specific authorization values. + pub const AUTH_FF: Self = Self(0x4000010F); + + /// Start of the range of authenticated timers + pub const ACT_0: Self = Self(0x40000110); + + /// End of the range of authenticated timers + pub const ACT_F: Self = Self(0x4000011F); + + /// The top of the reserved handle area + /// This is set to allow TPM2_GetCapability() to know where to stop. It may vary as + /// implementations add to the permanent handle area. + pub const LAST: Self = Self(0x4000011F); + + pub fn try_from(value: u32) -> Result { + match value { + 1073741824 => Ok(Self::SRK), // Original value: 0x40000000 + 1073741825 => Ok(Self::OWNER), // Original value: 0x40000001 + 1073741826 => Ok(Self::REVOKE), // Original value: 0x40000002 + 1073741827 => Ok(Self::TRANSPORT), // Original value: 0x40000003 + 1073741828 => Ok(Self::OPERATOR), // Original value: 0x40000004 + 1073741829 => Ok(Self::ADMIN), // Original value: 0x40000005 + 1073741830 => Ok(Self::EK), // Original value: 0x40000006 + 1073741831 => Ok(Self::NULL), // Original value: 0x40000007 + 1073741832 => Ok(Self::UNASSIGNED), // Original value: 0x40000008 + 1073741833 => Ok(Self::PW), // Original value: 0x40000009 + 1073741834 => Ok(Self::LOCKOUT), // Original value: 0x4000000A + 1073741835 => Ok(Self::ENDORSEMENT), // Original value: 0x4000000B + 1073741836 => Ok(Self::PLATFORM), // Original value: 0x4000000C + 1073741837 => Ok(Self::PLATFORM_NV), // Original value: 0x4000000D + 1073741840 => Ok(Self::AUTH_00), // Original value: 0x40000010 + 1073742095 => Ok(Self::AUTH_FF), // Original value: 0x4000010F + 1073742096 => Ok(Self::ACT_0), // Original value: 0x40000110 + 1073742111 => Ok(Self::LAST), // Original value: 0x4000011F + _ => Err(TpmError::InvalidEnumValue), + } + } +} + +impl TpmEnum for TPM_RH { + fn get_value(&self) -> u32 { + self.0.into() + } + + fn try_from_trait(value: u64) -> Result where Self: Sized { + TPM_RH::try_from(value as u32) + } + + fn new_from_trait(value: u64) -> Result where Self: Sized { + Ok(TPM_RH(value as u32)) + } +} + +impl From for u32 { + fn from(value: TPM_RH) -> Self { + value.0 as u32 + } +} + +impl From for i32 { + fn from(value: TPM_RH) -> Self { + value.0 as i32 + } +} + +impl fmt::Display for TPM_RH { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + 1073741824 => write!(f, "SRK"), + 1073741825 => write!(f, "OWNER"), + 1073741826 => write!(f, "REVOKE"), + 1073741827 => write!(f, "TRANSPORT"), + 1073741828 => write!(f, "OPERATOR"), + 1073741829 => write!(f, "ADMIN"), + 1073741830 => write!(f, "EK"), + 1073741831 => write!(f, "NULL"), + 1073741832 => write!(f, "UNASSIGNED"), + 1073741833 => write!(f, "PW"), + 1073741834 => write!(f, "LOCKOUT"), + 1073741835 => write!(f, "ENDORSEMENT"), + 1073741836 => write!(f, "PLATFORM"), + 1073741837 => write!(f, "PLATFORM_NV"), + 1073741840 => write!(f, "AUTH_00"), + 1073742095 => write!(f, "AUTH_FF"), + 1073742096 => write!(f, "ACT_0"), + 1073742111 => write!(f, "LAST"), + _ => write!(f, "{}", enum_to_str(self.0 as u64, std::any::TypeId::of::())), + } + } +} + +/// This table lists the values of the TPM_NT field of a TPMA_NV. See Table 215 for usage. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub struct TPM_NT(pub u32); + +impl TPM_NT { + /// Ordinary contains data that is opaque to the TPM that can only be modified using TPM2_NV_Write(). + pub const ORDINARY: Self = Self(0x0); + + /// Counter contains an 8-octet value that is to be used as a counter and can only be + /// modified with TPM2_NV_Increment() + pub const COUNTER: Self = Self(0x1); + + /// Bit Field contains an 8-octet value to be used as a bit field and can only be modified + /// with TPM2_NV_SetBits(). + pub const BITS: Self = Self(0x2); + + /// Extend contains a digest-sized value used like a PCR. The Index can only be modified + /// using TPM2_NV_Extend(). The extend will use the nameAlg of the Index. + pub const EXTEND: Self = Self(0x4); + + /// PIN Fail - contains pinCount that increments on a PIN authorization failure and a pinLimit + pub const PIN_FAIL: Self = Self(0x8); + + /// PIN Pass - contains pinCount that increments on a PIN authorization success and a pinLimit + pub const PIN_PASS: Self = Self(0x9); + + pub fn try_from(value: u32) -> Result { + match value { + 0 => Ok(Self::ORDINARY), // Original value: 0x0 + 1 => Ok(Self::COUNTER), // Original value: 0x1 + 2 => Ok(Self::BITS), // Original value: 0x2 + 4 => Ok(Self::EXTEND), // Original value: 0x4 + 8 => Ok(Self::PIN_FAIL), // Original value: 0x8 + 9 => Ok(Self::PIN_PASS), // Original value: 0x9 + _ => Err(TpmError::InvalidEnumValue), + } + } +} + +impl TpmEnum for TPM_NT { + fn get_value(&self) -> u32 { + self.0.into() + } + + fn try_from_trait(value: u64) -> Result where Self: Sized { + TPM_NT::try_from(value as u32) + } + + fn new_from_trait(value: u64) -> Result where Self: Sized { + Ok(TPM_NT(value as u32)) + } +} + +impl From for u32 { + fn from(value: TPM_NT) -> Self { + value.0 as u32 + } +} + +impl From for i32 { + fn from(value: TPM_NT) -> Self { + value.0 as i32 + } +} + +impl fmt::Display for TPM_NT { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + 0 => write!(f, "ORDINARY"), + 1 => write!(f, "COUNTER"), + 2 => write!(f, "BITS"), + 4 => write!(f, "EXTEND"), + 8 => write!(f, "PIN_FAIL"), + 9 => write!(f, "PIN_PASS"), + _ => write!(f, "{}", enum_to_str(self.0 as u64, std::any::TypeId::of::())), + } + } +} + +/// These constants are used in TPM2_AC_GetCapability() to indicate the first tagged value +/// returned from an attached component. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub struct TPM_AT(pub u32); + +impl TPM_AT { + /// In a command, a non-specific request for AC information; in a response, indicates that + /// outputData is not meaningful + pub const ANY: Self = Self(0x0); // Original value: 0x00000000 + + /// Indicates a TCG defined, device-specific error + pub const ERROR: Self = Self(0x1); // Original value: 0x00000001 + + /// Indicates the most significant 32 bits of a pairing value for the AC + pub const PV1: Self = Self(0x2); // Original value: 0x00000002 + + /// Value added to a TPM_AT to indicate a vendor-specific tag value + pub const VEND: Self = Self(0x80000000); + + pub fn try_from(value: u32) -> Result { + match value { + 0 => Ok(Self::ANY), // Original value: 0x00000000 + 1 => Ok(Self::ERROR), // Original value: 0x00000001 + 2 => Ok(Self::PV1), // Original value: 0x00000002 + 2147483648 => Ok(Self::VEND), // Original value: 0x80000000 + _ => Err(TpmError::InvalidEnumValue), + } + } +} + +impl TpmEnum for TPM_AT { + fn get_value(&self) -> u32 { + self.0.into() + } + + fn try_from_trait(value: u64) -> Result where Self: Sized { + TPM_AT::try_from(value as u32) + } + + fn new_from_trait(value: u64) -> Result where Self: Sized { + Ok(TPM_AT(value as u32)) + } +} + +impl From for u32 { + fn from(value: TPM_AT) -> Self { + value.0 as u32 + } +} + +impl From for i32 { + fn from(value: TPM_AT) -> Self { + value.0 as i32 + } +} + +impl fmt::Display for TPM_AT { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + 0 => write!(f, "ANY"), + 1 => write!(f, "ERROR"), + 2 => write!(f, "PV1"), + 2147483648 => write!(f, "VEND"), + _ => write!(f, "{}", enum_to_str(self.0 as u64, std::any::TypeId::of::())), + } + } +} + +/// These constants are the TCG-defined error values returned by an AC. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub struct TPM_AE(pub u32); + +impl TPM_AE { + /// In a command, a non-specific request for AC information; in a response, indicates that + /// outputData is not meaningful + pub const NONE: Self = Self(0x0); // Original value: 0x00000000 + + pub fn try_from(value: u32) -> Result { + match value { + 0 => Ok(Self::NONE), // Original value: 0x00000000 + _ => Err(TpmError::InvalidEnumValue), + } + } +} + +impl TpmEnum for TPM_AE { + fn get_value(&self) -> u32 { + self.0.into() + } + + fn try_from_trait(value: u64) -> Result where Self: Sized { + TPM_AE::try_from(value as u32) + } + + fn new_from_trait(value: u64) -> Result where Self: Sized { + Ok(TPM_AE(value as u32)) + } +} + +impl From for u32 { + fn from(value: TPM_AE) -> Self { + value.0 as u32 + } +} + +impl From for i32 { + fn from(value: TPM_AE) -> Self { + value.0 as i32 + } +} + +impl fmt::Display for TPM_AE { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + 0 => write!(f, "NONE"), + _ => write!(f, "{}", enum_to_str(self.0 as u64, std::any::TypeId::of::())), + } + } +} + +/// These values are readable with TPM2_GetCapability(). They are the TPM_PT_PS_xxx values. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub struct PLATFORM(pub u32); + +impl PLATFORM { + pub const FAMILY: Self = Self(0x322E3000); // Original value: TPM_SPEC::FAMILY.into() + pub const LEVEL: Self = Self(0x0); // Original value: TPM_SPEC::LEVEL.into() + pub const VERSION: Self = Self(0xA2); // Original value: TPM_SPEC::VERSION.into() + pub const YEAR: Self = Self(0x7E3); // Original value: TPM_SPEC::YEAR.into() + pub const DAY_OF_YEAR: Self = Self(0x168); // Original value: TPM_SPEC::DAY_OF_YEAR.into() + + pub fn try_from(value: u32) -> Result { + match value { + 841887744 => Ok(Self::FAMILY), // Original value: TPM_SPEC::FAMILY.into() + 0 => Ok(Self::LEVEL), // Original value: TPM_SPEC::LEVEL.into() + 162 => Ok(Self::VERSION), // Original value: TPM_SPEC::VERSION.into() + 2019 => Ok(Self::YEAR), // Original value: TPM_SPEC::YEAR.into() + 360 => Ok(Self::DAY_OF_YEAR), // Original value: TPM_SPEC::DAY_OF_YEAR.into() + _ => Err(TpmError::InvalidEnumValue), + } + } +} + +impl TpmEnum for PLATFORM { + fn get_value(&self) -> u32 { + self.0.into() + } + + fn try_from_trait(value: u64) -> Result where Self: Sized { + PLATFORM::try_from(value as u32) + } + + fn new_from_trait(value: u64) -> Result where Self: Sized { + Ok(PLATFORM(value as u32)) + } +} + +impl From for u32 { + fn from(value: PLATFORM) -> Self { + value.0 as u32 + } +} + +impl From for i32 { + fn from(value: PLATFORM) -> Self { + value.0 as i32 + } +} + +impl fmt::Display for PLATFORM { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + 841887744 => write!(f, "FAMILY"), + 0 => write!(f, "LEVEL"), + 162 => write!(f, "VERSION"), + 2019 => write!(f, "YEAR"), + 360 => write!(f, "DAY_OF_YEAR"), + _ => write!(f, "{}", enum_to_str(self.0 as u64, std::any::TypeId::of::())), + } + } +} + +/// This table contains a collection of values used in various parts of the reference +/// code. The values shown are illustrative. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub struct Implementation(pub u32); + +impl Implementation { + /// Temporary define + pub const FIELD_UPGRADE_IMPLEMENTED: Self = Self(0x0); // Original value: Logic::NO.into() + + /// Selection of the library that provides the basic hashing functions. + pub const HASH_LIB: Self = Self(0x1); // Original value: ImplementationConstants::Ossl.into() + + /// Selection of the library that provides the low-level symmetric cryptography. Choices + /// are determined by the vendor (See LibSupport.h for implications). + pub const SYM_LIB: Self = Self(0x1); // Original value: ImplementationConstants::Ossl.into() + + /// Selection of the library that provides the big number math including ECC. Choices are + /// determined by the vendor (See LibSupport.h for implications). + pub const MATH_LIB: Self = Self(0x1); // Original value: ImplementationConstants::Ossl.into() + + /// The number of PCR in the TPM + pub const IMPLEMENTATION_PCR: Self = Self(0x18); // Original value: 24 + pub const PCR_SELECT_MAX: Self = Self(0x3); // Original value: ((IMPLEMENTATION_PCR.into()+7)/8) + + /// The number of PCR required by the relevant platform specification + pub const PLATFORM_PCR: Self = Self(0x18); // Original value: 24 + pub const PCR_SELECT_MIN: Self = Self(0x3); // Original value: ((PLATFORM_PCR.into() + 7) / 8) + + /// The D-RTM PCR + /// NOTE This value is not defined when the TPM does not implement D-RTM + pub const DRTM_PCR: Self = Self(0x11); // Original value: 17 + + /// The PCR that will receive the H-CRTM value at TPM2_Startup. This value should not be changed. + pub const HCRTM_PCR: Self = Self(0x0); // Original value: 0 + + /// The number of localities supported by the TPM + /// This is expected to be either 5 for a PC, or 1 for just about everything else. + pub const NUM_LOCALITIES: Self = Self(0x5); // Original value: 5 + + /// The maximum number of handles in the handle area + /// This should be produced by the Part 3 parser but is here for now. + pub const MAX_HANDLE_NUM: Self = Self(0x3); // Original value: 3 + + /// The number of simultaneously active sessions that are supported by the TPM implementation + pub const MAX_ACTIVE_SESSIONS: Self = Self(0x40); // Original value: 64 + + /// The number of sessions that the TPM may have in memory + pub const MAX_LOADED_SESSIONS: Self = Self(0x3); // Original value: 3 + + /// This is the current maximum value + pub const MAX_SESSION_NUM: Self = Self(0x3); // Original value: 3 + + /// The number of simultaneously loaded objects that are supported by the TPM; this number + /// does not include the objects that may be placed in NV memory by TPM2_EvictControl(). + pub const MAX_LOADED_OBJECTS: Self = Self(0x3); // Original value: 3 + + /// The minimum number of evict objects supported by the TPM + pub const MIN_EVICT_OBJECTS: Self = Self(0x2); // Original value: 2 + + /// Number of PCR groups that have individual policies + pub const NUM_POLICY_PCR_GROUP: Self = Self(0x1); // Original value: 1 + + /// Number of PCR groups that have individual authorization values + pub const NUM_AUTHVALUE_PCR_GROUP: Self = Self(0x1); // Original value: 1 + pub const MAX_CONTEXT_SIZE: Self = Self(0x4F0); // Original value: 1264 + pub const MAX_DIGEST_BUFFER: Self = Self(0x400); // Original value: 1024 + + /// Maximum data size allowed in an NV Index + pub const MAX_NV_INDEX_SIZE: Self = Self(0x800); // Original value: 2048 + + /// Maximum data size in one NV read or write command + pub const MAX_NV_BUFFER_SIZE: Self = Self(0x400); // Original value: 1024 + + /// Maximum size of a capability buffer + pub const MAX_CAP_BUFFER: Self = Self(0x400); // Original value: 1024 + + /// Size of NV memory in octets + pub const NV_MEMORY_SIZE: Self = Self(0x4000); // Original value: 16384 + + /// The TPM will not allocate a non-counter index if it would prevent allocation of this + /// number of indices. + pub const MIN_COUNTER_INDICES: Self = Self(0x8); // Original value: 8 + pub const NUM_STATIC_PCR: Self = Self(0x10); // Original value: 16 + + /// Number of algorithms that can be in a list + pub const MAX_ALG_LIST_SIZE: Self = Self(0x40); // Original value: 64 + + /// Size of the Primary Seed in octets + pub const PRIMARY_SEED_SIZE: Self = Self(0x20); // Original value: 32 + + /// Context encryption algorithm + /// Just use the root so that the macros in GpMacros.h will work correctly. + pub const CONTEXT_ENCRYPT_ALGORITHM: Self = Self(0x6); // Original value: TPM_ALG_ID::AES.into() + + /// The update interval expressed as a power of 2 seconds + /// A value of 12 is 4,096 seconds (~68 minutes). + pub const NV_CLOCK_UPDATE_INTERVAL: Self = Self(0xC); // Original value: 12 + + /// Number of PCR groups that allow policy/auth + pub const NUM_POLICY_PCR: Self = Self(0x1); // Original value: 1 + + /// Maximum size of a command + pub const MAX_COMMAND_SIZE: Self = Self(0x1000); // Original value: 4096 + + /// Maximum size of a response + pub const MAX_RESPONSE_SIZE: Self = Self(0x1000); // Original value: 4096 + + /// Number between 1 and 32 inclusive + pub const ORDERLY_BITS: Self = Self(0x8); // Original value: 8 + + /// The maximum number of octets that may be in a sealed blob; 128 is the minimum allowed value + pub const MAX_SYM_DATA: Self = Self(0x80); // Original value: 128 + pub const MAX_RNG_ENTROPY_SIZE: Self = Self(0x40); // Original value: 64 + + /// Number of bytes used for the RAM index space. If this is not large enough, it might + /// not be possible to allocate orderly indices. + pub const RAM_INDEX_SPACE: Self = Self(0x200); // Original value: 512 + + /// 216 + 1 + pub const RSA_DEFAULT_PUBLIC_EXPONENT: Self = Self(0x10001); // Original value: 0x00010001 + + /// Indicates if the TPM_PT_PCR_NO_INCREMENT group is implemented + pub const ENABLE_PCR_NO_INCREMENT: Self = Self(0x1); // Original value: Logic::YES.into() + pub const CRT_FORMAT_RSA: Self = Self(0x1); // Original value: Logic::YES.into() + pub const VENDOR_COMMAND_COUNT: Self = Self(0x0); // Original value: 0 + + /// Maximum size of the vendor-specific buffer + pub const MAX_VENDOR_BUFFER_SIZE: Self = Self(0x400); // Original value: 1024 + + /// L value for a derivation. This is the + /// maximum number of bits allowed from an instantiation of a KDF-DRBG. This is size is OK + /// because RSA keys are never derived keys + pub const MAX_DERIVATION_BITS: Self = Self(0x2000); // Original value: 8192 + pub const RSA_MAX_PRIME: Self = Self(0x80); // Original value: (ImplementationConstants::MAX_RSA_KEY_BYTES.into()/2) + pub const RSA_PRIVATE_SIZE: Self = Self(0x280); // Original value: (RSA_MAX_PRIME.into() * 5) + pub const SIZE_OF_X509_SERIAL_NUMBER: Self = Self(0x14); // Original value: 20 + + /// This is a vendor-specific value so it is in this vendor-speific table. When this is + /// used, RSA_PRIVATE_SIZE will have been defined + pub const PRIVATE_VENDOR_SPECIFIC_BYTES: Self = Self(0x280); // Original value: RSA_PRIVATE_SIZE.into() + + pub fn try_from(value: u32) -> Result { + match value { + 0 => Ok(Self::VENDOR_COMMAND_COUNT), // Original value: 0 + 1 => Ok(Self::CRT_FORMAT_RSA), // Original value: Logic::YES.into() + 24 => Ok(Self::PLATFORM_PCR), // Original value: 24 + 3 => Ok(Self::MAX_LOADED_OBJECTS), // Original value: 3 + 17 => Ok(Self::DRTM_PCR), // Original value: 17 + 5 => Ok(Self::NUM_LOCALITIES), // Original value: 5 + 64 => Ok(Self::MAX_RNG_ENTROPY_SIZE), // Original value: 64 + 2 => Ok(Self::MIN_EVICT_OBJECTS), // Original value: 2 + 1264 => Ok(Self::MAX_CONTEXT_SIZE), // Original value: 1264 + 1024 => Ok(Self::MAX_VENDOR_BUFFER_SIZE), // Original value: 1024 + 2048 => Ok(Self::MAX_NV_INDEX_SIZE), // Original value: 2048 + 16384 => Ok(Self::NV_MEMORY_SIZE), // Original value: 16384 + 8 => Ok(Self::ORDERLY_BITS), // Original value: 8 + 16 => Ok(Self::NUM_STATIC_PCR), // Original value: 16 + 32 => Ok(Self::PRIMARY_SEED_SIZE), // Original value: 32 + 6 => Ok(Self::CONTEXT_ENCRYPT_ALGORITHM), // Original value: TPM_ALG_ID::AES.into() + 12 => Ok(Self::NV_CLOCK_UPDATE_INTERVAL), // Original value: 12 + 4096 => Ok(Self::MAX_RESPONSE_SIZE), // Original value: 4096 + 128 => Ok(Self::RSA_MAX_PRIME), // Original value: (ImplementationConstants::MAX_RSA_KEY_BYTES.into()/2) + 512 => Ok(Self::RAM_INDEX_SPACE), // Original value: 512 + 65537 => Ok(Self::RSA_DEFAULT_PUBLIC_EXPONENT), // Original value: 0x00010001 + 8192 => Ok(Self::MAX_DERIVATION_BITS), // Original value: 8192 + 640 => Ok(Self::PRIVATE_VENDOR_SPECIFIC_BYTES), // Original value: RSA_PRIVATE_SIZE.into() + 20 => Ok(Self::SIZE_OF_X509_SERIAL_NUMBER), // Original value: 20 + _ => Err(TpmError::InvalidEnumValue), + } + } +} + +impl TpmEnum for Implementation { + fn get_value(&self) -> u32 { + self.0.into() + } + + fn try_from_trait(value: u64) -> Result where Self: Sized { + Implementation::try_from(value as u32) + } + + fn new_from_trait(value: u64) -> Result where Self: Sized { + Ok(Implementation(value as u32)) + } +} + +impl From for u32 { + fn from(value: Implementation) -> Self { + value.0 as u32 + } +} + +impl From for i32 { + fn from(value: Implementation) -> Self { + value.0 as i32 + } +} + +impl fmt::Display for Implementation { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + 0 => write!(f, "VENDOR_COMMAND_COUNT"), + 1 => write!(f, "CRT_FORMAT_RSA"), + 24 => write!(f, "PLATFORM_PCR"), + 3 => write!(f, "MAX_LOADED_OBJECTS"), + 17 => write!(f, "DRTM_PCR"), + 5 => write!(f, "NUM_LOCALITIES"), + 64 => write!(f, "MAX_RNG_ENTROPY_SIZE"), + 2 => write!(f, "MIN_EVICT_OBJECTS"), + 1264 => write!(f, "MAX_CONTEXT_SIZE"), + 1024 => write!(f, "MAX_VENDOR_BUFFER_SIZE"), + 2048 => write!(f, "MAX_NV_INDEX_SIZE"), + 16384 => write!(f, "NV_MEMORY_SIZE"), + 8 => write!(f, "ORDERLY_BITS"), + 16 => write!(f, "NUM_STATIC_PCR"), + 32 => write!(f, "PRIMARY_SEED_SIZE"), + 6 => write!(f, "CONTEXT_ENCRYPT_ALGORITHM"), + 12 => write!(f, "NV_CLOCK_UPDATE_INTERVAL"), + 4096 => write!(f, "MAX_RESPONSE_SIZE"), + 128 => write!(f, "RSA_MAX_PRIME"), + 512 => write!(f, "RAM_INDEX_SPACE"), + 65537 => write!(f, "RSA_DEFAULT_PUBLIC_EXPONENT"), + 8192 => write!(f, "MAX_DERIVATION_BITS"), + 640 => write!(f, "PRIVATE_VENDOR_SPECIFIC_BYTES"), + 20 => write!(f, "SIZE_OF_X509_SERIAL_NUMBER"), + _ => write!(f, "{}", enum_to_str(self.0 as u64, std::any::TypeId::of::())), + } + } +} + +/// The definitions in Table 29 are used to define many of the interface data types. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub struct TPM_HC(pub u32); + +impl TPM_HC { + /// To mask off the HR + pub const HR_HANDLE_MASK: Self = Self(0xFFFFFF); // Original value: 0x00FFFFFF + + /// To mask off the variable part + pub const HR_RANGE_MASK: Self = Self(0xFF000000); + pub const HR_SHIFT: Self = Self(0x18); // Original value: 24 + pub const HR_PCR: Self = Self(0x0); // Original value: (TPM_HT::PCR.into() << HR_SHIFT.into()) + pub const HR_HMAC_SESSION: Self = Self(0x2000000); // Original value: (TPM_HT::HMAC_SESSION.into() << HR_SHIFT.into()) + pub const HR_POLICY_SESSION: Self = Self(0x3000000); // Original value: (TPM_HT::POLICY_SESSION.into() << HR_SHIFT.into()) + pub const HR_TRANSIENT: Self = Self(0x80000000); // Original value: (TPM_HT::TRANSIENT.into() << HR_SHIFT.into()) + pub const HR_PERSISTENT: Self = Self(0x81000000); // Original value: (TPM_HT::PERSISTENT.into() << HR_SHIFT.into()) + pub const HR_NV_INDEX: Self = Self(0x1000000); // Original value: (TPM_HT::NV_INDEX.into() << HR_SHIFT.into()) + pub const HR_PERMANENT: Self = Self(0x40000000); // Original value: (TPM_HT::PERMANENT.into() << HR_SHIFT.into()) + + /// First PCR + pub const PCR_FIRST: Self = Self(0x0); // Original value: (HR_PCR.into() + 0) + + /// Last PCR + pub const PCR_LAST: Self = Self(0x17); // Original value: (PCR_FIRST.into() + Implementation::IMPLEMENTATION_PCR.into()-1) + + /// First HMAC session + pub const HMAC_SESSION_FIRST: Self = Self(0x2000000); // Original value: (HR_HMAC_SESSION.into() + 0) + + /// Last HMAC session + pub const HMAC_SESSION_LAST: Self = Self(0x200003F); // Original value: (HMAC_SESSION_FIRST.into()+Implementation::MAX_ACTIVE_SESSIONS.into()-1) + + /// Used in GetCapability + pub const LOADED_SESSION_FIRST: Self = Self(0x2000000); // Original value: HMAC_SESSION_FIRST.into() + + /// Used in GetCapability + pub const LOADED_SESSION_LAST: Self = Self(0x200003F); // Original value: HMAC_SESSION_LAST.into() + + /// First policy session + pub const POLICY_SESSION_FIRST: Self = Self(0x3000000); // Original value: (HR_POLICY_SESSION.into() + 0) + + /// Last policy session + pub const POLICY_SESSION_LAST: Self = Self(0x300003F); // Original value: (POLICY_SESSION_FIRST.into() + Implementation::MAX_ACTIVE_SESSIONS.into()-1) + + /// First transient object + pub const TRANSIENT_FIRST: Self = Self(0x80000000); // Original value: (HR_TRANSIENT.into() + 0) + + /// Used in GetCapability + pub const ACTIVE_SESSION_FIRST: Self = Self(0x3000000); // Original value: POLICY_SESSION_FIRST.into() + + /// Used in GetCapability + pub const ACTIVE_SESSION_LAST: Self = Self(0x300003F); // Original value: POLICY_SESSION_LAST.into() + + /// Last transient object + pub const TRANSIENT_LAST: Self = Self(0x80000002); // Original value: (TRANSIENT_FIRST.into()+Implementation::MAX_LOADED_OBJECTS.into()-1) + + /// First persistent object + pub const PERSISTENT_FIRST: Self = Self(0x81000000); // Original value: (HR_PERSISTENT.into() + 0) + + /// Last persistent object + pub const PERSISTENT_LAST: Self = Self(0x81FFFFFF); // Original value: (PERSISTENT_FIRST.into() + 0x00FFFFFF) + + /// First platform persistent object + pub const PLATFORM_PERSISTENT: Self = Self(0x81800000); // Original value: (PERSISTENT_FIRST.into() + 0x00800000) + + /// First allowed NV Index + pub const NV_INDEX_FIRST: Self = Self(0x1000000); // Original value: (HR_NV_INDEX.into() + 0) + + /// Last allowed NV Index + pub const NV_INDEX_LAST: Self = Self(0x1FFFFFF); // Original value: (NV_INDEX_FIRST.into() + 0x00FFFFFF) + pub const PERMANENT_FIRST: Self = Self(0x40000000); // Original value: TPM_RH::FIRST.into() + pub const PERMANENT_LAST: Self = Self(0x4000011F); // Original value: TPM_RH::LAST.into() + + /// AC aliased NV Index + pub const HR_NV_AC: Self = Self(0x1D00000); // Original value: ((TPM_HT::NV_INDEX.into() << HR_SHIFT.into()) + 0xD00000) + + /// First NV Index aliased to Attached Component + pub const NV_AC_FIRST: Self = Self(0x1D00000); // Original value: (HR_NV_AC.into() + 0) + + /// Last NV Index aliased to Attached Component + pub const NV_AC_LAST: Self = Self(0x1D0FFFF); // Original value: (HR_NV_AC.into() + 0x0000FFFF) + + /// AC Handle + pub const HR_AC: Self = Self(0x90000000); // Original value: (TPM_HT::AC.into() << HR_SHIFT.into()) + + /// First Attached Component + pub const AC_FIRST: Self = Self(0x90000000); // Original value: (HR_AC.into() + 0) + + /// Last Attached Component + pub const AC_LAST: Self = Self(0x9000FFFF); // Original value: (HR_AC.into() + 0x0000FFFF) + + pub fn try_from(value: u32) -> Result { + match value { + 16777215 => Ok(Self::HR_HANDLE_MASK), // Original value: 0x00FFFFFF + 4278190080 => Ok(Self::HR_RANGE_MASK), // Original value: 0xFF000000 + 24 => Ok(Self::HR_SHIFT), // Original value: 24 + 0 => Ok(Self::PCR_FIRST), // Original value: (HR_PCR.into() + 0) + 33554432 => Ok(Self::LOADED_SESSION_FIRST), // Original value: HMAC_SESSION_FIRST.into() + 50331648 => Ok(Self::ACTIVE_SESSION_FIRST), // Original value: POLICY_SESSION_FIRST.into() + 2147483648 => Ok(Self::TRANSIENT_FIRST), // Original value: (HR_TRANSIENT.into() + 0) + 2164260864 => Ok(Self::PERSISTENT_FIRST), // Original value: (HR_PERSISTENT.into() + 0) + 16777216 => Ok(Self::NV_INDEX_FIRST), // Original value: (HR_NV_INDEX.into() + 0) + 1073741824 => Ok(Self::PERMANENT_FIRST), // Original value: TPM_RH::FIRST.into() + 23 => Ok(Self::PCR_LAST), // Original value: (PCR_FIRST.into() + Implementation::IMPLEMENTATION_PCR.into()-1) + 33554495 => Ok(Self::LOADED_SESSION_LAST), // Original value: HMAC_SESSION_LAST.into() + 50331711 => Ok(Self::ACTIVE_SESSION_LAST), // Original value: POLICY_SESSION_LAST.into() + 2147483650 => Ok(Self::TRANSIENT_LAST), // Original value: (TRANSIENT_FIRST.into()+Implementation::MAX_LOADED_OBJECTS.into()-1) + 2181038079 => Ok(Self::PERSISTENT_LAST), // Original value: (PERSISTENT_FIRST.into() + 0x00FFFFFF) + 2172649472 => Ok(Self::PLATFORM_PERSISTENT), // Original value: (PERSISTENT_FIRST.into() + 0x00800000) + 33554431 => Ok(Self::NV_INDEX_LAST), // Original value: (NV_INDEX_FIRST.into() + 0x00FFFFFF) + 1073742111 => Ok(Self::PERMANENT_LAST), // Original value: TPM_RH::LAST.into() + 30408704 => Ok(Self::NV_AC_FIRST), // Original value: (HR_NV_AC.into() + 0) + 30474239 => Ok(Self::NV_AC_LAST), // Original value: (HR_NV_AC.into() + 0x0000FFFF) + 2415919104 => Ok(Self::AC_FIRST), // Original value: (HR_AC.into() + 0) + 2415984639 => Ok(Self::AC_LAST), // Original value: (HR_AC.into() + 0x0000FFFF) + _ => Err(TpmError::InvalidEnumValue), + } + } +} + +impl TpmEnum for TPM_HC { + fn get_value(&self) -> u32 { + self.0.into() + } + + fn try_from_trait(value: u64) -> Result where Self: Sized { + TPM_HC::try_from(value as u32) + } + + fn new_from_trait(value: u64) -> Result where Self: Sized { + Ok(TPM_HC(value as u32)) + } +} + +impl From for u32 { + fn from(value: TPM_HC) -> Self { + value.0 as u32 + } +} + +impl From for i32 { + fn from(value: TPM_HC) -> Self { + value.0 as i32 + } +} + +impl fmt::Display for TPM_HC { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + 16777215 => write!(f, "HR_HANDLE_MASK"), + 4278190080 => write!(f, "HR_RANGE_MASK"), + 24 => write!(f, "HR_SHIFT"), + 0 => write!(f, "PCR_FIRST"), + 33554432 => write!(f, "LOADED_SESSION_FIRST"), + 50331648 => write!(f, "ACTIVE_SESSION_FIRST"), + 2147483648 => write!(f, "TRANSIENT_FIRST"), + 2164260864 => write!(f, "PERSISTENT_FIRST"), + 16777216 => write!(f, "NV_INDEX_FIRST"), + 1073741824 => write!(f, "PERMANENT_FIRST"), + 23 => write!(f, "PCR_LAST"), + 33554495 => write!(f, "LOADED_SESSION_LAST"), + 50331711 => write!(f, "ACTIVE_SESSION_LAST"), + 2147483650 => write!(f, "TRANSIENT_LAST"), + 2181038079 => write!(f, "PERSISTENT_LAST"), + 2172649472 => write!(f, "PLATFORM_PERSISTENT"), + 33554431 => write!(f, "NV_INDEX_LAST"), + 1073742111 => write!(f, "PERMANENT_LAST"), + 30408704 => write!(f, "NV_AC_FIRST"), + 30474239 => write!(f, "NV_AC_LAST"), + 2415919104 => write!(f, "AC_FIRST"), + 2415984639 => write!(f, "AC_LAST"), + _ => write!(f, "{}", enum_to_str(self.0 as u64, std::any::TypeId::of::())), + } + } +} + +/// This structure defines the attributes of an algorithm. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub struct TPMA_ALGORITHM(pub u32); + +impl TPMA_ALGORITHM { + /// SET (1): an asymmetric algorithm with public and private portions + /// CLEAR (0): not an asymmetric algorithm + pub const asymmetric: Self = Self(0x1); + + /// SET (1): a symmetric block cipher + /// CLEAR (0): not a symmetric block cipher + pub const symmetric: Self = Self(0x2); + + /// SET (1): a hash algorithm + /// CLEAR (0): not a hash algorithm + pub const hash: Self = Self(0x4); + + /// SET (1): an algorithm that may be used as an object type + /// CLEAR (0): an algorithm that is not used as an object type + pub const object: Self = Self(0x8); + + /// SET (1): a signing algorithm. The setting of asymmetric, symmetric, and hash will + /// indicate the type of signing algorithm. + /// CLEAR (0): not a signing algorithm + pub const signing: Self = Self(0x100); + + /// SET (1): an encryption/decryption algorithm. The setting of asymmetric, symmetric, and + /// hash will indicate the type of encryption/decryption algorithm. + /// CLEAR (0): not an encryption/decryption algorithm + pub const encrypting: Self = Self(0x200); + + /// SET (1): a method such as a key derivative function (KDF) + /// CLEAR (0): not a method + pub const method: Self = Self(0x400); + + pub fn try_from(value: u32) -> Result { + match value { + 1 => Ok(Self::asymmetric), // Original value: 0x1 + 2 => Ok(Self::symmetric), // Original value: 0x2 + 4 => Ok(Self::hash), // Original value: 0x4 + 8 => Ok(Self::object), // Original value: 0x8 + 256 => Ok(Self::signing), // Original value: 0x100 + 512 => Ok(Self::encrypting), // Original value: 0x200 + 1024 => Ok(Self::method), // Original value: 0x400 + _ => Err(TpmError::InvalidEnumValue), + } + } +} + +impl TpmEnum for TPMA_ALGORITHM { + fn get_value(&self) -> u32 { + self.0.into() + } + + fn try_from_trait(value: u64) -> Result where Self: Sized { + TPMA_ALGORITHM::try_from(value as u32) + } + + fn new_from_trait(value: u64) -> Result where Self: Sized { + Ok(TPMA_ALGORITHM(value as u32)) + } +} + +impl From for u32 { + fn from(value: TPMA_ALGORITHM) -> Self { + value.0 as u32 + } +} + +impl From for i32 { + fn from(value: TPMA_ALGORITHM) -> Self { + value.0 as i32 + } +} + +impl fmt::Display for TPMA_ALGORITHM { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + 1 => write!(f, "asymmetric"), + 2 => write!(f, "symmetric"), + 4 => write!(f, "hash"), + 8 => write!(f, "object"), + 256 => write!(f, "signing"), + 512 => write!(f, "encrypting"), + 1024 => write!(f, "method"), + _ => write!(f, "{}", enum_to_str(self.0 as u64, std::any::TypeId::of::())), + } + } +} + +impl std::ops::BitOr for TPMA_ALGORITHM { + type Output = Self; + + fn bitor(self, rhs: Self) -> Self::Output { + Self(self.0 | rhs.0) + } + +} + +impl From for TPMA_ALGORITHM { + fn from(value: u32) -> Self { + Self(value.into()) + } +} + +/// This attribute structure indicates an objects use, its authorization types, and its +/// relationship to other objects. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub struct TPMA_OBJECT(pub u32); + +impl TPMA_OBJECT { + /// SET (1): The hierarchy of the object, as indicated by its Qualified Name, may not change. + /// CLEAR (0): The hierarchy of the object may change as a result of this object or an + /// ancestor key being duplicated for use in another hierarchy. + /// NOTE fixedTPM does not indicate that key material resides on a single TPM (see + /// sensitiveDataOrigin). + pub const fixedTPM: Self = Self(0x2); + + /// SET (1): Previously saved contexts of this object may not be loaded after Startup(CLEAR). + /// CLEAR (0): Saved contexts of this object may be used after a Shutdown(STATE) and + /// subsequent Startup(). + pub const stClear: Self = Self(0x4); + + /// SET (1): The parent of the object may not change. + /// CLEAR (0): The parent of the object may change as the result of a TPM2_Duplicate() of + /// the object. + pub const fixedParent: Self = Self(0x10); + + /// SET (1): Indicates that, when the object was created with TPM2_Create() or + /// TPM2_CreatePrimary(), the TPM generated all of the sensitive data other than the authValue. + /// CLEAR (0): A portion of the sensitive data, other than the authValue, was provided by + /// the caller. + pub const sensitiveDataOrigin: Self = Self(0x20); + + /// SET (1): Approval of USER role actions with this object may be with an HMAC session or + /// with a password using the authValue of the object or a policy session. + /// CLEAR (0): Approval of USER role actions with this object may only be done with a + /// policy session. + pub const userWithAuth: Self = Self(0x40); + + /// SET (1): Approval of ADMIN role actions with this object may only be done with a + /// policy session. + /// CLEAR (0): Approval of ADMIN role actions with this object may be with an HMAC session + /// or with a password using the authValue of the object or a policy session. + pub const adminWithPolicy: Self = Self(0x80); + + /// SET (1): The object is not subject to dictionary attack protections. + /// CLEAR (0): The object is subject to dictionary attack protections. + pub const noDA: Self = Self(0x400); + + /// SET (1): If the object is duplicated, then symmetricAlg shall not be TPM_ALG_NULL and + /// newParentHandle shall not be TPM_RH_NULL. + /// CLEAR (0): The object may be duplicated without an inner wrapper on the private + /// portion of the object and the new parent may be TPM_RH_NULL. + pub const encryptedDuplication: Self = Self(0x800); + + /// SET (1): Key usage is restricted to manipulate structures of known format; the parent + /// of this key shall have restricted SET. + /// CLEAR (0): Key usage is not restricted to use on special formats. + pub const restricted: Self = Self(0x10000); + + /// SET (1): The private portion of the key may be used to decrypt. + /// CLEAR (0): The private portion of the key may not be used to decrypt. + pub const decrypt: Self = Self(0x20000); + + /// SET (1): For a symmetric cipher object, the private portion of the key may be used to + /// encrypt. For other objects, the private portion of the key may be used to sign. + /// CLEAR (0): The private portion of the key may not be used to sign or encrypt. + pub const sign: Self = Self(0x40000); + + /// Alias to the sign value. + pub const encrypt: Self = Self(0x40000); + + /// SET (1): An asymmetric key that may not be used to sign with TPM2_Sign() + /// CLEAR (0): A key that may be used with TPM2_Sign() if sign is SET + /// NOTE: This attribute only has significance if sign is SET. + pub const x509sign: Self = Self(0x80000); + + pub fn try_from(value: u32) -> Result { + match value { + 2 => Ok(Self::fixedTPM), // Original value: 0x2 + 4 => Ok(Self::stClear), // Original value: 0x4 + 16 => Ok(Self::fixedParent), // Original value: 0x10 + 32 => Ok(Self::sensitiveDataOrigin), // Original value: 0x20 + 64 => Ok(Self::userWithAuth), // Original value: 0x40 + 128 => Ok(Self::adminWithPolicy), // Original value: 0x80 + 1024 => Ok(Self::noDA), // Original value: 0x400 + 2048 => Ok(Self::encryptedDuplication), // Original value: 0x800 + 65536 => Ok(Self::restricted), // Original value: 0x10000 + 131072 => Ok(Self::decrypt), // Original value: 0x20000 + 262144 => Ok(Self::encrypt), // Original value: 0x40000 + 524288 => Ok(Self::x509sign), // Original value: 0x80000 + _ => Err(TpmError::InvalidEnumValue), + } + } +} + +impl TpmEnum for TPMA_OBJECT { + fn get_value(&self) -> u32 { + self.0.into() + } + + fn try_from_trait(value: u64) -> Result where Self: Sized { + TPMA_OBJECT::try_from(value as u32) + } + + fn new_from_trait(value: u64) -> Result where Self: Sized { + Ok(TPMA_OBJECT(value as u32)) + } +} + +impl From for u32 { + fn from(value: TPMA_OBJECT) -> Self { + value.0 as u32 + } +} + +impl From for i32 { + fn from(value: TPMA_OBJECT) -> Self { + value.0 as i32 + } +} + +impl fmt::Display for TPMA_OBJECT { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + 2 => write!(f, "fixedTPM"), + 4 => write!(f, "stClear"), + 16 => write!(f, "fixedParent"), + 32 => write!(f, "sensitiveDataOrigin"), + 64 => write!(f, "userWithAuth"), + 128 => write!(f, "adminWithPolicy"), + 1024 => write!(f, "noDA"), + 2048 => write!(f, "encryptedDuplication"), + 65536 => write!(f, "restricted"), + 131072 => write!(f, "decrypt"), + 262144 => write!(f, "encrypt"), + 524288 => write!(f, "x509sign"), + _ => write!(f, "{}", enum_to_str(self.0 as u64, std::any::TypeId::of::())), + } + } +} + +impl std::ops::BitOr for TPMA_OBJECT { + type Output = Self; + + fn bitor(self, rhs: Self) -> Self::Output { + Self(self.0 | rhs.0) + } + +} + +impl From for TPMA_OBJECT { + fn from(value: u32) -> Self { + Self(value.into()) + } +} + +/// This octet in each session is used to identify the session type, indicate its +/// relationship to any handles in the command, and indicate its use in parameter encryption. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub struct TPMA_SESSION(pub u8); + +impl TPMA_SESSION { + /// SET (1): In a command, this setting indicates that the session is to remain active + /// after successful completion of the command. In a response, it indicates that the + /// session is still active. If SET in the command, this attribute shall be SET in the response. + /// CLEAR (0): In a command, this setting indicates that the TPM should close the session + /// and flush any related context when the command completes successfully. In a response, + /// it indicates that the session is closed and the context is no longer active. + /// This attribute has no meaning for a password authorization and the TPM will allow any + /// setting of the attribute in the command and SET the attribute in the response. + /// This attribute will only be CLEAR in one response for a logical session. If the + /// attribute is CLEAR, the context associated with the session is no longer in use and + /// the space is available. A session created after another session is ended may have the + /// same handle but logically is not the same session. + /// This attribute has no effect if the command does not complete successfully. + pub const continueSession: Self = Self(0x1); + + /// SET (1): In a command, this setting indicates that the command should only be executed + /// if the session is exclusive at the start of the command. In a response, it indicates + /// that the session is exclusive. This setting is only allowed if the audit attribute is + /// SET (TPM_RC_ATTRIBUTES). + /// CLEAR (0): In a command, indicates that the session need not be exclusive at the start + /// of the command. In a response, indicates that the session is not exclusive. + pub const auditExclusive: Self = Self(0x2); + + /// SET (1): In a command, this setting indicates that the audit digest of the session + /// should be initialized and the exclusive status of the session SET. This setting is + /// only allowed if the audit attribute is SET (TPM_RC_ATTRIBUTES). + /// CLEAR (0): In a command, indicates that the audit digest should not be initialized. + /// This bit is always CLEAR in a response. + pub const auditReset: Self = Self(0x4); + + /// SET (1): In a command, this setting indicates that the first parameter in the command + /// is symmetrically encrypted using the parameter encryption scheme described in TPM 2.0 + /// Part 1. The TPM will decrypt the parameter after performing any HMAC computations and + /// before unmarshaling the parameter. In a response, the attribute is copied from the + /// request but has no effect on the response. + /// CLEAR (0): Session not used for encryption. + /// For a password authorization, this attribute will be CLEAR in both the command and response. + /// This attribute may be SET in a session that is not associated with a command handle. + /// Such a session is provided for purposes of encrypting a parameter and not for authorization. + /// This attribute may be SET in combination with any other session attributes. + pub const decrypt: Self = Self(0x20); + + /// SET (1): In a command, this setting indicates that the TPM should use this session to + /// encrypt the first parameter in the response. In a response, it indicates that the + /// attribute was set in the command and that the TPM used the session to encrypt the + /// first parameter in the response using the parameter encryption scheme described in TPM + /// 2.0 Part 1. + /// CLEAR (0): Session not used for encryption. + /// For a password authorization, this attribute will be CLEAR in both the command and response. + /// This attribute may be SET in a session that is not associated with a command handle. + /// Such a session is provided for purposes of encrypting a parameter and not for authorization. + pub const encrypt: Self = Self(0x40); + + /// SET (1): In a command or response, this setting indicates that the session is for + /// audit and that auditExclusive and auditReset have meaning. This session may also be + /// used for authorization, encryption, or decryption. The encrypted and encrypt fields + /// may be SET or CLEAR. + /// CLEAR (0): Session is not used for audit. + /// If SET in the command, then this attribute will be SET in the response. + pub const audit: Self = Self(0x80); + + pub fn try_from(value: u8) -> Result { + match value { + 1 => Ok(Self::continueSession), // Original value: 0x1 + 2 => Ok(Self::auditExclusive), // Original value: 0x2 + 4 => Ok(Self::auditReset), // Original value: 0x4 + 32 => Ok(Self::decrypt), // Original value: 0x20 + 64 => Ok(Self::encrypt), // Original value: 0x40 + 128 => Ok(Self::audit), // Original value: 0x80 + _ => Err(TpmError::InvalidEnumValue), + } + } +} + +impl TpmEnum for TPMA_SESSION { + fn get_value(&self) -> u8 { + self.0.into() + } + + fn try_from_trait(value: u64) -> Result where Self: Sized { + TPMA_SESSION::try_from(value as u8) + } + + fn new_from_trait(value: u64) -> Result where Self: Sized { + Ok(TPMA_SESSION(value as u8)) + } +} + +impl From for u8 { + fn from(value: TPMA_SESSION) -> Self { + value.0 as u8 + } +} + +impl From for i8 { + fn from(value: TPMA_SESSION) -> Self { + value.0 as i8 + } +} + +impl fmt::Display for TPMA_SESSION { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + 1 => write!(f, "continueSession"), + 2 => write!(f, "auditExclusive"), + 4 => write!(f, "auditReset"), + 32 => write!(f, "decrypt"), + 64 => write!(f, "encrypt"), + 128 => write!(f, "audit"), + _ => write!(f, "{}", enum_to_str(self.0 as u64, std::any::TypeId::of::())), + } + } +} + +impl std::ops::BitOr for TPMA_SESSION { + type Output = Self; + + fn bitor(self, rhs: Self) -> Self::Output { + Self(self.0 | rhs.0) + } + +} + +impl From for TPMA_SESSION { + fn from(value: u8) -> Self { + Self(value.into()) + } +} + +/// In a TPMS_CREATION_DATA structure, this structure is used to indicate the locality of +/// the command that created the object. No more than one of the locality attributes shall +/// be set in the creation data. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub struct TPMA_LOCALITY(pub u8); + +impl TPMA_LOCALITY { + pub const LOC_ZERO: Self = Self(0x1); + pub const LOC_ONE: Self = Self(0x2); + pub const LOC_TWO: Self = Self(0x4); + pub const LOC_THREE: Self = Self(0x8); + pub const LOC_FOUR: Self = Self(0x10); + + /// If any of these bits is set, an extended locality is indicated + pub const Extended_BIT_MASK: Self = Self(0xE0); + pub const Extended_BIT_OFFSET: Self = Self(0x5); // Original value: 5 + pub const Extended_BIT_LENGTH: Self = Self(0x3); // Original value: 3 + + pub fn try_from(value: u8) -> Result { + match value { + 1 => Ok(Self::LOC_ZERO), // Original value: 0x1 + 2 => Ok(Self::LOC_ONE), // Original value: 0x2 + 4 => Ok(Self::LOC_TWO), // Original value: 0x4 + 8 => Ok(Self::LOC_THREE), // Original value: 0x8 + 16 => Ok(Self::LOC_FOUR), // Original value: 0x10 + 224 => Ok(Self::Extended_BIT_MASK), // Original value: 0xE0 + 5 => Ok(Self::Extended_BIT_OFFSET), // Original value: 5 + 3 => Ok(Self::Extended_BIT_LENGTH), // Original value: 3 + _ => Err(TpmError::InvalidEnumValue), + } + } +} + +impl TpmEnum for TPMA_LOCALITY { + fn get_value(&self) -> u8 { + self.0.into() + } + + fn try_from_trait(value: u64) -> Result where Self: Sized { + TPMA_LOCALITY::try_from(value as u8) + } + + fn new_from_trait(value: u64) -> Result where Self: Sized { + Ok(TPMA_LOCALITY(value as u8)) + } +} + +impl From for u8 { + fn from(value: TPMA_LOCALITY) -> Self { + value.0 as u8 + } +} + +impl From for i8 { + fn from(value: TPMA_LOCALITY) -> Self { + value.0 as i8 + } +} + +impl fmt::Display for TPMA_LOCALITY { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + 1 => write!(f, "LOC_ZERO"), + 2 => write!(f, "LOC_ONE"), + 4 => write!(f, "LOC_TWO"), + 8 => write!(f, "LOC_THREE"), + 16 => write!(f, "LOC_FOUR"), + 224 => write!(f, "Extended_BIT_MASK"), + 5 => write!(f, "Extended_BIT_OFFSET"), + 3 => write!(f, "Extended_BIT_LENGTH"), + _ => write!(f, "{}", enum_to_str(self.0 as u64, std::any::TypeId::of::())), + } + } +} + +impl std::ops::BitOr for TPMA_LOCALITY { + type Output = Self; + + fn bitor(self, rhs: Self) -> Self::Output { + Self(self.0 | rhs.0) + } + +} + +impl From for TPMA_LOCALITY { + fn from(value: u8) -> Self { + Self(value.into()) + } +} + +/// The attributes in this structure are persistent and are not changed as a result of +/// _TPM_Init or any TPM2_Startup(). Some of the attributes in this structure may change +/// as the result of specific Protected Capabilities. This structure may be read using +/// TPM2_GetCapability(capability = TPM_CAP_TPM_PROPERTIES, property = TPM_PT_PERMANENT). +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub struct TPMA_PERMANENT(pub u32); + +impl TPMA_PERMANENT { + /// SET (1): TPM2_HierarchyChangeAuth() with ownerAuth has been executed since the last TPM2_Clear(). + /// CLEAR (0): ownerAuth has not been changed since TPM2_Clear(). + pub const ownerAuthSet: Self = Self(0x1); + + /// SET (1): TPM2_HierarchyChangeAuth() with endorsementAuth has been executed since the + /// last TPM2_Clear(). + /// CLEAR (0): endorsementAuth has not been changed since TPM2_Clear(). + pub const endorsementAuthSet: Self = Self(0x2); + + /// SET (1): TPM2_HierarchyChangeAuth() with lockoutAuth has been executed since the last + /// TPM2_Clear(). + /// CLEAR (0): lockoutAuth has not been changed since TPM2_Clear(). + pub const lockoutAuthSet: Self = Self(0x4); + + /// SET (1): TPM2_Clear() is disabled. + /// CLEAR (0): TPM2_Clear() is enabled. + /// NOTE See TPM2_ClearControl in TPM 2.0 Part 3 for details on changing this attribute. + pub const disableClear: Self = Self(0x100); + + /// SET (1): The TPM is in lockout, when failedTries is equal to maxTries. + pub const inLockout: Self = Self(0x200); + + /// SET (1): The EPS was created by the TPM. + /// CLEAR (0): The EPS was created outside of the TPM using a manufacturer-specific process. + pub const tpmGeneratedEPS: Self = Self(0x400); + + pub fn try_from(value: u32) -> Result { + match value { + 1 => Ok(Self::ownerAuthSet), // Original value: 0x1 + 2 => Ok(Self::endorsementAuthSet), // Original value: 0x2 + 4 => Ok(Self::lockoutAuthSet), // Original value: 0x4 + 256 => Ok(Self::disableClear), // Original value: 0x100 + 512 => Ok(Self::inLockout), // Original value: 0x200 + 1024 => Ok(Self::tpmGeneratedEPS), // Original value: 0x400 + _ => Err(TpmError::InvalidEnumValue), + } + } +} + +impl TpmEnum for TPMA_PERMANENT { + fn get_value(&self) -> u32 { + self.0.into() + } + + fn try_from_trait(value: u64) -> Result where Self: Sized { + TPMA_PERMANENT::try_from(value as u32) + } + + fn new_from_trait(value: u64) -> Result where Self: Sized { + Ok(TPMA_PERMANENT(value as u32)) + } +} + +impl From for u32 { + fn from(value: TPMA_PERMANENT) -> Self { + value.0 as u32 + } +} + +impl From for i32 { + fn from(value: TPMA_PERMANENT) -> Self { + value.0 as i32 + } +} + +impl fmt::Display for TPMA_PERMANENT { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + 1 => write!(f, "ownerAuthSet"), + 2 => write!(f, "endorsementAuthSet"), + 4 => write!(f, "lockoutAuthSet"), + 256 => write!(f, "disableClear"), + 512 => write!(f, "inLockout"), + 1024 => write!(f, "tpmGeneratedEPS"), + _ => write!(f, "{}", enum_to_str(self.0 as u64, std::any::TypeId::of::())), + } + } +} + +impl std::ops::BitOr for TPMA_PERMANENT { + type Output = Self; + + fn bitor(self, rhs: Self) -> Self::Output { + Self(self.0 | rhs.0) + } + +} + +impl From for TPMA_PERMANENT { + fn from(value: u32) -> Self { + Self(value.into()) + } +} + +/// This structure may be read using TPM2_GetCapability(capability = +/// TPM_CAP_TPM_PROPERTIES, property = TPM_PT_STARTUP_CLEAR). +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub struct TPMA_STARTUP_CLEAR(pub u32); + +impl TPMA_STARTUP_CLEAR { + /// SET (1): The platform hierarchy is enabled and platformAuth or platformPolicy may be + /// used for authorization. + /// CLEAR (0): platformAuth and platformPolicy may not be used for authorizations, and + /// objects in the platform hierarchy, including persistent objects, cannot be used. + /// NOTE See TPM2_HierarchyControl in TPM 2.0 Part 3 for details on changing this attribute. + pub const phEnable: Self = Self(0x1); + + /// SET (1): The Storage hierarchy is enabled and ownerAuth or ownerPolicy may be used for + /// authorization. NV indices defined using owner authorization are accessible. + /// CLEAR (0): ownerAuth and ownerPolicy may not be used for authorizations, and objects + /// in the Storage hierarchy, persistent objects, and NV indices defined using owner + /// authorization cannot be used. + /// NOTE See TPM2_HierarchyControl in TPM 2.0 Part 3 for details on changing this attribute. + pub const shEnable: Self = Self(0x2); + + /// SET (1): The EPS hierarchy is enabled and Endorsement Authorization may be used to + /// authorize commands. + /// CLEAR (0): Endorsement Authorization may not be used for authorizations, and objects + /// in the endorsement hierarchy, including persistent objects, cannot be used. + /// NOTE See TPM2_HierarchyControl in TPM 2.0 Part 3 for details on changing this attribute. + pub const ehEnable: Self = Self(0x4); + + /// SET (1): NV indices that have TPMA_NV_PLATFORMCREATE SET may be read or written. The + /// platform can create define and undefine indices. + /// CLEAR (0): NV indices that have TPMA_NV_PLATFORMCREATE SET may not be read or written + /// (TPM_RC_HANDLE). The platform cannot define (TPM_RC_HIERARCHY) or undefined + /// (TPM_RC_HANDLE) indices. + /// NOTE See TPM2_HierarchyControl in TPM 2.0 Part 3 for details on changing this attribute. + /// NOTE + /// read refers to these commands: TPM2_NV_Read, TPM2_NV_ReadPublic, TPM_NV_Certify, TPM2_PolicyNV + /// write refers to these commands: TPM2_NV_Write, TPM2_NV_Increment, TPM2_NV_Extend, TPM2_NV_SetBits + /// NOTE The TPM must query the index TPMA_NV_PLATFORMCREATE attribute to determine + /// whether phEnableNV is applicable. Since the TPM will return TPM_RC_HANDLE if the index + /// does not exist, it also returns this error code if the index is disabled. Otherwise, + /// the TPM would leak the existence of an index even when disabled. + pub const phEnableNV: Self = Self(0x8); + + /// SET (1): The TPM received a TPM2_Shutdown() and a matching TPM2_Startup(). + /// CLEAR (0): TPM2_Startup(TPM_SU_CLEAR) was not preceded by a TPM2_Shutdown() of any type. + /// NOTE A shutdown is orderly if the TPM receives a TPM2_Shutdown() of any type followed + /// by a TPM2_Startup() of any type. However, the TPM will return an error if + /// TPM2_Startup(TPM_SU_STATE) was not preceded by TPM2_Shutdown(TPM_SU_STATE). + pub const orderly: Self = Self(0x80000000); + + pub fn try_from(value: u32) -> Result { + match value { + 1 => Ok(Self::phEnable), // Original value: 0x1 + 2 => Ok(Self::shEnable), // Original value: 0x2 + 4 => Ok(Self::ehEnable), // Original value: 0x4 + 8 => Ok(Self::phEnableNV), // Original value: 0x8 + 2147483648 => Ok(Self::orderly), // Original value: 0x80000000 + _ => Err(TpmError::InvalidEnumValue), + } + } +} + +impl TpmEnum for TPMA_STARTUP_CLEAR { + fn get_value(&self) -> u32 { + self.0.into() + } + + fn try_from_trait(value: u64) -> Result where Self: Sized { + TPMA_STARTUP_CLEAR::try_from(value as u32) + } + + fn new_from_trait(value: u64) -> Result where Self: Sized { + Ok(TPMA_STARTUP_CLEAR(value as u32)) + } +} + +impl From for u32 { + fn from(value: TPMA_STARTUP_CLEAR) -> Self { + value.0 as u32 + } +} + +impl From for i32 { + fn from(value: TPMA_STARTUP_CLEAR) -> Self { + value.0 as i32 + } +} + +impl fmt::Display for TPMA_STARTUP_CLEAR { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + 1 => write!(f, "phEnable"), + 2 => write!(f, "shEnable"), + 4 => write!(f, "ehEnable"), + 8 => write!(f, "phEnableNV"), + 2147483648 => write!(f, "orderly"), + _ => write!(f, "{}", enum_to_str(self.0 as u64, std::any::TypeId::of::())), + } + } +} + +impl std::ops::BitOr for TPMA_STARTUP_CLEAR { + type Output = Self; + + fn bitor(self, rhs: Self) -> Self::Output { + Self(self.0 | rhs.0) + } + +} + +impl From for TPMA_STARTUP_CLEAR { + fn from(value: u32) -> Self { + Self(value.into()) + } +} + +/// This structure of this attribute is used to report the memory management method used +/// by the TPM for transient objects and authorization sessions. This structure may be +/// read using TPM2_GetCapability(capability = TPM_CAP_TPM_PROPERTIES, property = TPM_PT_MEMORY). +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub struct TPMA_MEMORY(pub u32); + +impl TPMA_MEMORY { + /// SET (1): indicates that the RAM memory used for authorization session contexts is + /// shared with the memory used for transient objects + /// CLEAR (0): indicates that the memory used for authorization sessions is not shared + /// with memory used for transient objects + pub const sharedRAM: Self = Self(0x1); + + /// SET (1): indicates that the NV memory used for persistent objects is shared with the + /// NV memory used for NV Index values + /// CLEAR (0): indicates that the persistent objects and NV Index values are allocated + /// from separate sections of NV + pub const sharedNV: Self = Self(0x2); + + /// SET (1): indicates that the TPM copies persistent objects to a transient-object slot + /// in RAM when the persistent object is referenced in a command. The TRM is required to + /// make sure that an object slot is available. + /// CLEAR (0): indicates that the TPM does not use transient-object slots when persistent + /// objects are referenced + pub const objectCopiedToRam: Self = Self(0x4); + + pub fn try_from(value: u32) -> Result { + match value { + 1 => Ok(Self::sharedRAM), // Original value: 0x1 + 2 => Ok(Self::sharedNV), // Original value: 0x2 + 4 => Ok(Self::objectCopiedToRam), // Original value: 0x4 + _ => Err(TpmError::InvalidEnumValue), + } + } +} + +impl TpmEnum for TPMA_MEMORY { + fn get_value(&self) -> u32 { + self.0.into() + } + + fn try_from_trait(value: u64) -> Result where Self: Sized { + TPMA_MEMORY::try_from(value as u32) + } + + fn new_from_trait(value: u64) -> Result where Self: Sized { + Ok(TPMA_MEMORY(value as u32)) + } +} + +impl From for u32 { + fn from(value: TPMA_MEMORY) -> Self { + value.0 as u32 + } +} + +impl From for i32 { + fn from(value: TPMA_MEMORY) -> Self { + value.0 as i32 + } +} + +impl fmt::Display for TPMA_MEMORY { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + 1 => write!(f, "sharedRAM"), + 2 => write!(f, "sharedNV"), + 4 => write!(f, "objectCopiedToRam"), + _ => write!(f, "{}", enum_to_str(self.0 as u64, std::any::TypeId::of::())), + } + } +} + +impl std::ops::BitOr for TPMA_MEMORY { + type Output = Self; + + fn bitor(self, rhs: Self) -> Self::Output { + Self(self.0 | rhs.0) + } + +} + +impl From for TPMA_MEMORY { + fn from(value: u32) -> Self { + Self(value.into()) + } +} + +/// This structure defines the attributes of a command from a context management +/// perspective. The fields of the structure indicate to the TPM Resource Manager (TRM) +/// the number of resources required by a command and how the command affects the TPMs resources. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub struct TPMA_CC(pub u32); + +impl TPMA_CC { + /// Indicates the command being selected + pub const commandIndex_BIT_MASK: Self = Self(0xFFFF); + pub const commandIndex_BIT_OFFSET: Self = Self(0x0); // Original value: 0 + pub const commandIndex_BIT_LENGTH: Self = Self(0x10); // Original value: 16 + + /// SET (1): indicates that the command may write to NV + /// CLEAR (0): indicates that the command does not write to NV + pub const nv: Self = Self(0x400000); + + /// SET (1): This command could flush any number of loaded contexts. + /// CLEAR (0): no additional changes other than indicated by the flushed attribute + pub const extensive: Self = Self(0x800000); + + /// SET (1): The context associated with any transient handle in the command will be + /// flushed when this command completes. + /// CLEAR (0): No context is flushed as a side effect of this command. + pub const flushed: Self = Self(0x1000000); + + /// Indicates the number of the handles in the handle area for this command + pub const cHandles_BIT_MASK: Self = Self(0xE000000); + pub const cHandles_BIT_OFFSET: Self = Self(0x19); // Original value: 25 + pub const cHandles_BIT_LENGTH: Self = Self(0x3); // Original value: 3 + + /// SET (1): indicates the presence of the handle area in the response + pub const rHandle: Self = Self(0x10000000); + + /// SET (1): indicates that the command is vendor-specific + /// CLEAR (0): indicates that the command is defined in a version of this specification + pub const V: Self = Self(0x20000000); + + /// Allocated for software; shall be zero + pub const Res_BIT_MASK: Self = Self(0xC0000000); + pub const Res_BIT_OFFSET: Self = Self(0x1E); // Original value: 30 + pub const Res_BIT_LENGTH: Self = Self(0x2); // Original value: 2 + + pub fn try_from(value: u32) -> Result { + match value { + 65535 => Ok(Self::commandIndex_BIT_MASK), // Original value: 0xFFFF + 0 => Ok(Self::commandIndex_BIT_OFFSET), // Original value: 0 + 16 => Ok(Self::commandIndex_BIT_LENGTH), // Original value: 16 + 4194304 => Ok(Self::nv), // Original value: 0x400000 + 8388608 => Ok(Self::extensive), // Original value: 0x800000 + 16777216 => Ok(Self::flushed), // Original value: 0x1000000 + 234881024 => Ok(Self::cHandles_BIT_MASK), // Original value: 0xE000000 + 25 => Ok(Self::cHandles_BIT_OFFSET), // Original value: 25 + 3 => Ok(Self::cHandles_BIT_LENGTH), // Original value: 3 + 268435456 => Ok(Self::rHandle), // Original value: 0x10000000 + 536870912 => Ok(Self::V), // Original value: 0x20000000 + 3221225472 => Ok(Self::Res_BIT_MASK), // Original value: 0xC0000000 + 30 => Ok(Self::Res_BIT_OFFSET), // Original value: 30 + 2 => Ok(Self::Res_BIT_LENGTH), // Original value: 2 + _ => Err(TpmError::InvalidEnumValue), + } + } +} + +impl TpmEnum for TPMA_CC { + fn get_value(&self) -> u32 { + self.0.into() + } + + fn try_from_trait(value: u64) -> Result where Self: Sized { + TPMA_CC::try_from(value as u32) + } + + fn new_from_trait(value: u64) -> Result where Self: Sized { + Ok(TPMA_CC(value as u32)) + } +} + +impl From for u32 { + fn from(value: TPMA_CC) -> Self { + value.0 as u32 + } +} + +impl From for i32 { + fn from(value: TPMA_CC) -> Self { + value.0 as i32 + } +} + +impl fmt::Display for TPMA_CC { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + 65535 => write!(f, "commandIndex_BIT_MASK"), + 0 => write!(f, "commandIndex_BIT_OFFSET"), + 16 => write!(f, "commandIndex_BIT_LENGTH"), + 4194304 => write!(f, "nv"), + 8388608 => write!(f, "extensive"), + 16777216 => write!(f, "flushed"), + 234881024 => write!(f, "cHandles_BIT_MASK"), + 25 => write!(f, "cHandles_BIT_OFFSET"), + 3 => write!(f, "cHandles_BIT_LENGTH"), + 268435456 => write!(f, "rHandle"), + 536870912 => write!(f, "V"), + 3221225472 => write!(f, "Res_BIT_MASK"), + 30 => write!(f, "Res_BIT_OFFSET"), + 2 => write!(f, "Res_BIT_LENGTH"), + _ => write!(f, "{}", enum_to_str(self.0 as u64, std::any::TypeId::of::())), + } + } +} + +impl std::ops::BitOr for TPMA_CC { + type Output = Self; + + fn bitor(self, rhs: Self) -> Self::Output { + Self(self.0 | rhs.0) + } + +} + +impl From for TPMA_CC { + fn from(value: u32) -> Self { + Self(value.into()) + } +} + +/// This structure of this attribute is used to report that the TPM is designed for these +/// modes. This structure may be read using TPM2_GetCapability(capability = +/// TPM_CAP_TPM_PROPERTIES, property = TPM_PT_MODES). +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub struct TPMA_MODES(pub u32); + +impl TPMA_MODES { + /// SET (1): indicates that the TPM is designed to comply with all of the FIPS 140-2 + /// requirements at Level 1 or higher. + pub const FIPS_140_2: Self = Self(0x1); + + pub fn try_from(value: u32) -> Result { + match value { + 1 => Ok(Self::FIPS_140_2), // Original value: 0x1 + _ => Err(TpmError::InvalidEnumValue), + } + } +} + +impl TpmEnum for TPMA_MODES { + fn get_value(&self) -> u32 { + self.0.into() + } + + fn try_from_trait(value: u64) -> Result where Self: Sized { + TPMA_MODES::try_from(value as u32) + } + + fn new_from_trait(value: u64) -> Result where Self: Sized { + Ok(TPMA_MODES(value as u32)) + } +} + +impl From for u32 { + fn from(value: TPMA_MODES) -> Self { + value.0 as u32 + } +} + +impl From for i32 { + fn from(value: TPMA_MODES) -> Self { + value.0 as i32 + } +} + +impl fmt::Display for TPMA_MODES { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + 1 => write!(f, "FIPS_140_2"), + _ => write!(f, "{}", enum_to_str(self.0 as u64, std::any::TypeId::of::())), + } + } +} + +impl std::ops::BitOr for TPMA_MODES { + type Output = Self; + + fn bitor(self, rhs: Self) -> Self::Output { + Self(self.0 | rhs.0) + } + +} + +impl From for TPMA_MODES { + fn from(value: u32) -> Self { + Self(value.into()) + } +} + +/// These attributes are as specified in clause 4.2.1.3. of RFC 5280 Internet X.509 Public +/// Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile. For +/// TPM2_CertifyX509, when a caller provides a DER encoded Key Usage in +/// partialCertificate, the TPM will validate that the key to be certified meets the +/// requirements of Key Usage. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub struct TPMA_X509_KEY_USAGE(pub u32); + +impl TPMA_X509_KEY_USAGE { + /// Attributes.Decrypt SET + pub const decipherOnly: Self = Self(0x800000); + + /// Attributes.Decrypt SET + pub const encipherOnly: Self = Self(0x1000000); + + /// Attributes.sign SET + pub const cRLSign: Self = Self(0x2000000); + + /// Attributes.sign SET + pub const keyCertSign: Self = Self(0x4000000); + + /// Attributes.Decrypt SET + pub const keyAgreement: Self = Self(0x8000000); + + /// Attributes.Decrypt SET + pub const dataEncipherment: Self = Self(0x10000000); + + /// Asymmetric key with decrypt and restricted SET key has the attributes of a parent key + pub const keyEncipherment: Self = Self(0x20000000); + + /// FixedTPM SET in Subject Key (objectHandle) + pub const nonrepudiation: Self = Self(0x40000000); + + /// Alias to the nonrepudiation value. + pub const contentCommitment: Self = Self(0x40000000); + + /// Sign SET in Subject Key (objectHandle) + pub const digitalSignature: Self = Self(0x80000000); + + pub fn try_from(value: u32) -> Result { + match value { + 8388608 => Ok(Self::decipherOnly), // Original value: 0x800000 + 16777216 => Ok(Self::encipherOnly), // Original value: 0x1000000 + 33554432 => Ok(Self::cRLSign), // Original value: 0x2000000 + 67108864 => Ok(Self::keyCertSign), // Original value: 0x4000000 + 134217728 => Ok(Self::keyAgreement), // Original value: 0x8000000 + 268435456 => Ok(Self::dataEncipherment), // Original value: 0x10000000 + 536870912 => Ok(Self::keyEncipherment), // Original value: 0x20000000 + 1073741824 => Ok(Self::contentCommitment), // Original value: 0x40000000 + 2147483648 => Ok(Self::digitalSignature), // Original value: 0x80000000 + _ => Err(TpmError::InvalidEnumValue), + } + } +} + +impl TpmEnum for TPMA_X509_KEY_USAGE { + fn get_value(&self) -> u32 { + self.0.into() + } + + fn try_from_trait(value: u64) -> Result where Self: Sized { + TPMA_X509_KEY_USAGE::try_from(value as u32) + } + + fn new_from_trait(value: u64) -> Result where Self: Sized { + Ok(TPMA_X509_KEY_USAGE(value as u32)) + } +} + +impl From for u32 { + fn from(value: TPMA_X509_KEY_USAGE) -> Self { + value.0 as u32 + } +} + +impl From for i32 { + fn from(value: TPMA_X509_KEY_USAGE) -> Self { + value.0 as i32 + } +} + +impl fmt::Display for TPMA_X509_KEY_USAGE { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + 8388608 => write!(f, "decipherOnly"), + 16777216 => write!(f, "encipherOnly"), + 33554432 => write!(f, "cRLSign"), + 67108864 => write!(f, "keyCertSign"), + 134217728 => write!(f, "keyAgreement"), + 268435456 => write!(f, "dataEncipherment"), + 536870912 => write!(f, "keyEncipherment"), + 1073741824 => write!(f, "contentCommitment"), + 2147483648 => write!(f, "digitalSignature"), + _ => write!(f, "{}", enum_to_str(self.0 as u64, std::any::TypeId::of::())), + } + } +} + +impl std::ops::BitOr for TPMA_X509_KEY_USAGE { + type Output = Self; + + fn bitor(self, rhs: Self) -> Self::Output { + Self(self.0 | rhs.0) + } + +} + +impl From for TPMA_X509_KEY_USAGE { + fn from(value: u32) -> Self { + Self(value.into()) + } +} + +/// This attribute is used to report the ACT state. This attribute may be read using +/// TPM2_GetCapability(capability = TPM_CAP_ACT, property = TPM_RH_ACT_x where x is the +/// ACT number (0-F)). The signaled value must be preserved across TPM Resume or if the +/// TPM has not lost power. The signaled value may be preserved over a power cycle of a TPM. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub struct TPMA_ACT(pub u32); + +impl TPMA_ACT { + /// SET (1): The ACT has signaled + /// CLEAR (0): The ACT has not signaled + pub const signaled: Self = Self(0x1); + + /// Preserves the state of signaled, depending on the power cycle + pub const preserveSignaled: Self = Self(0x2); + + pub fn try_from(value: u32) -> Result { + match value { + 1 => Ok(Self::signaled), // Original value: 0x1 + 2 => Ok(Self::preserveSignaled), // Original value: 0x2 + _ => Err(TpmError::InvalidEnumValue), + } + } +} + +impl TpmEnum for TPMA_ACT { + fn get_value(&self) -> u32 { + self.0.into() + } + + fn try_from_trait(value: u64) -> Result where Self: Sized { + TPMA_ACT::try_from(value as u32) + } + + fn new_from_trait(value: u64) -> Result where Self: Sized { + Ok(TPMA_ACT(value as u32)) + } +} + +impl From for u32 { + fn from(value: TPMA_ACT) -> Self { + value.0 as u32 + } +} + +impl From for i32 { + fn from(value: TPMA_ACT) -> Self { + value.0 as i32 + } +} + +impl fmt::Display for TPMA_ACT { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + 1 => write!(f, "signaled"), + 2 => write!(f, "preserveSignaled"), + _ => write!(f, "{}", enum_to_str(self.0 as u64, std::any::TypeId::of::())), + } + } +} + +impl std::ops::BitOr for TPMA_ACT { + type Output = Self; + + fn bitor(self, rhs: Self) -> Self::Output { + Self(self.0 | rhs.0) + } + +} + +impl From for TPMA_ACT { + fn from(value: u32) -> Self { + Self(value.into()) + } +} + +/// A TPM_NV_INDEX is used to reference a defined location in NV memory. The format of the +/// Index is changed from TPM 1.2 in order to include the Index in the reserved handle +/// space. Handles in this range use the digest of the public area of the Index as the +/// Name of the entity in authorization computations +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub struct TPM_NV_INDEX(pub u32); + +impl TPM_NV_INDEX { + /// The Index of the NV location + pub const index_BIT_MASK: Self = Self(0xFFFFFF); + pub const index_BIT_OFFSET: Self = Self(0x0); // Original value: 0 + pub const index_BIT_LENGTH: Self = Self(0x18); // Original value: 24 + + /// Constant value of TPM_HT_NV_INDEX indicating the NV Index range + pub const RhNv_BIT_MASK: Self = Self(0xFF000000); + pub const RhNv_BIT_OFFSET: Self = Self(0x18); // Original value: 24 + pub const RhNv_BIT_LENGTH: Self = Self(0x8); // Original value: 8 + + pub fn try_from(value: u32) -> Result { + match value { + 16777215 => Ok(Self::index_BIT_MASK), // Original value: 0xFFFFFF + 0 => Ok(Self::index_BIT_OFFSET), // Original value: 0 + 24 => Ok(Self::RhNv_BIT_OFFSET), // Original value: 24 + 4278190080 => Ok(Self::RhNv_BIT_MASK), // Original value: 0xFF000000 + 8 => Ok(Self::RhNv_BIT_LENGTH), // Original value: 8 + _ => Err(TpmError::InvalidEnumValue), + } + } +} + +impl TpmEnum for TPM_NV_INDEX { + fn get_value(&self) -> u32 { + self.0.into() + } + + fn try_from_trait(value: u64) -> Result where Self: Sized { + TPM_NV_INDEX::try_from(value as u32) + } + + fn new_from_trait(value: u64) -> Result where Self: Sized { + Ok(TPM_NV_INDEX(value as u32)) + } +} + +impl From for u32 { + fn from(value: TPM_NV_INDEX) -> Self { + value.0 as u32 + } +} + +impl From for i32 { + fn from(value: TPM_NV_INDEX) -> Self { + value.0 as i32 + } +} + +impl fmt::Display for TPM_NV_INDEX { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + 16777215 => write!(f, "index_BIT_MASK"), + 0 => write!(f, "index_BIT_OFFSET"), + 24 => write!(f, "RhNv_BIT_OFFSET"), + 4278190080 => write!(f, "RhNv_BIT_MASK"), + 8 => write!(f, "RhNv_BIT_LENGTH"), + _ => write!(f, "{}", enum_to_str(self.0 as u64, std::any::TypeId::of::())), + } + } +} + +impl std::ops::BitOr for TPM_NV_INDEX { + type Output = Self; + + fn bitor(self, rhs: Self) -> Self::Output { + Self(self.0 | rhs.0) + } + +} + +impl From for TPM_NV_INDEX { + fn from(value: u32) -> Self { + Self(value.into()) + } +} + +/// This structure allows the TPM to keep track of the data and permissions to manipulate +/// an NV Index. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub struct TPMA_NV(pub u32); + +impl TPMA_NV { + /// SET (1): The Index data can be written if Platform Authorization is provided. + /// CLEAR (0): Writing of the Index data cannot be authorized with Platform Authorization. + pub const PPWRITE: Self = Self(0x1); + + /// SET (1): The Index data can be written if Owner Authorization is provided. + /// CLEAR (0): Writing of the Index data cannot be authorized with Owner Authorization. + pub const OWNERWRITE: Self = Self(0x2); + + /// SET (1): Authorizations to change the Index contents that require USER role may be + /// provided with an HMAC session or password. + /// CLEAR (0): Authorizations to change the Index contents that require USER role may not + /// be provided with an HMAC session or password. + pub const AUTHWRITE: Self = Self(0x4); + + /// SET (1): Authorizations to change the Index contents that require USER role may be + /// provided with a policy session. + /// CLEAR (0): Authorizations to change the Index contents that require USER role may not + /// be provided with a policy session. + /// NOTE TPM2_NV_ChangeAuth() always requires that authorization be provided in a policy session. + pub const POLICYWRITE: Self = Self(0x8); + + /// Ordinary contains data that is opaque to the TPM that can only be modified using TPM2_NV_Write(). + pub const ORDINARY: Self = Self(0x0); + + /// Counter contains an 8-octet value that is to be used as a counter and can only be + /// modified with TPM2_NV_Increment() + pub const COUNTER: Self = Self(0x10); + + /// Bit Field contains an 8-octet value to be used as a bit field and can only be modified + /// with TPM2_NV_SetBits(). + pub const BITS: Self = Self(0x20); + + /// Extend contains a digest-sized value used like a PCR. The Index can only be modified + /// using TPM2_NV_Extend(). The extend will use the nameAlg of the Index. + pub const EXTEND: Self = Self(0x40); + + /// PIN Fail - contains pinCount that increments on a PIN authorization failure and a pinLimit + pub const PIN_FAIL: Self = Self(0x80); + + /// PIN Pass - contains pinCount that increments on a PIN authorization success and a pinLimit + pub const PIN_PASS: Self = Self(0x90); + + /// The type of the index. + /// NOTE A TPM is not required to support all TPM_NT values + pub const TpmNt_BIT_MASK: Self = Self(0xF0); + pub const TpmNt_BIT_OFFSET: Self = Self(0x4); // Original value: 4 + pub const TpmNt_BIT_LENGTH: Self = Self(0x4); // Original value: 4 + + /// SET (1): Index may not be deleted unless the authPolicy is satisfied using + /// TPM2_NV_UndefineSpaceSpecial(). + /// CLEAR (0): Index may be deleted with proper platform or owner authorization using + /// TPM2_NV_UndefineSpace(). + /// NOTE An Index with this attribute and a policy that cannot be satisfied (e.g., an + /// Empty Policy) cannot be deleted. + pub const POLICY_DELETE: Self = Self(0x400); + + /// SET (1): Index cannot be written. + /// CLEAR (0): Index can be written. + pub const WRITELOCKED: Self = Self(0x800); + + /// SET (1): A partial write of the Index data is not allowed. The write size shall match + /// the defined space size. + /// CLEAR (0): Partial writes are allowed. This setting is required if the .dataSize of + /// the Index is larger than NV_MAX_BUFFER_SIZE for the implementation. + pub const WRITEALL: Self = Self(0x1000); + + /// SET (1): TPM2_NV_WriteLock() may be used to prevent further writes to this location. + /// CLEAR (0): TPM2_NV_WriteLock() does not block subsequent writes if + /// TPMA_NV_WRITE_STCLEAR is also CLEAR. + pub const WRITEDEFINE: Self = Self(0x2000); + + /// SET (1): TPM2_NV_WriteLock() may be used to prevent further writes to this location + /// until the next TPM Reset or TPM Restart. + /// CLEAR (0): TPM2_NV_WriteLock() does not block subsequent writes if TPMA_NV_WRITEDEFINE + /// is also CLEAR. + pub const WRITE_STCLEAR: Self = Self(0x4000); + + /// SET (1): If TPM2_NV_GlobalWriteLock() is successful, TPMA_NV_WRITELOCKED is set. + /// CLEAR (0): TPM2_NV_GlobalWriteLock() has no effect on the writing of the data at this Index. + pub const GLOBALLOCK: Self = Self(0x8000); + + /// SET (1): The Index data can be read if Platform Authorization is provided. + /// CLEAR (0): Reading of the Index data cannot be authorized with Platform Authorization. + pub const PPREAD: Self = Self(0x10000); + + /// SET (1): The Index data can be read if Owner Authorization is provided. + /// CLEAR (0): Reading of the Index data cannot be authorized with Owner Authorization. + pub const OWNERREAD: Self = Self(0x20000); + + /// SET (1): The Index data may be read if the authValue is provided. + /// CLEAR (0): Reading of the Index data cannot be authorized with the Index authValue. + pub const AUTHREAD: Self = Self(0x40000); + + /// SET (1): The Index data may be read if the authPolicy is satisfied. + /// CLEAR (0): Reading of the Index data cannot be authorized with the Index authPolicy. + pub const POLICYREAD: Self = Self(0x80000); + + /// SET (1): Authorization failures of the Index do not affect the DA logic and + /// authorization of the Index is not blocked when the TPM is in Lockout mode. + /// CLEAR (0): Authorization failures of the Index will increment the authorization + /// failure counter and authorizations of this Index are not allowed when the TPM is in + /// Lockout mode. + pub const NO_DA: Self = Self(0x2000000); + + /// SET (1): NV Index state is only required to be saved when the TPM performs an orderly + /// shutdown (TPM2_Shutdown()). + /// CLEAR (0): NV Index state is required to be persistent after the command to update the + /// Index completes successfully (that is, the NV update is synchronous with the update command). + pub const ORDERLY: Self = Self(0x4000000); + + /// SET (1): TPMA_NV_WRITTEN for the Index is CLEAR by TPM Reset or TPM Restart. + /// CLEAR (0): TPMA_NV_WRITTEN is not changed by TPM Restart. + /// NOTE This attribute may only be SET if TPM_NT is not TPM_NT_COUNTER. + pub const CLEAR_STCLEAR: Self = Self(0x8000000); + + /// SET (1): Reads of the Index are blocked until the next TPM Reset or TPM Restart. + /// CLEAR (0): Reads of the Index are allowed if proper authorization is provided. + pub const READLOCKED: Self = Self(0x10000000); + + /// SET (1): Index has been written. + /// CLEAR (0): Index has not been written. + pub const WRITTEN: Self = Self(0x20000000); + + /// SET (1): This Index may be undefined with Platform Authorization but not with Owner + /// Authorization. + /// CLEAR (0): This Index may be undefined using Owner Authorization but not with Platform + /// Authorization. + /// The TPM will validate that this attribute is SET when the Index is defined using + /// Platform Authorization and will validate that this attribute is CLEAR when the Index + /// is defined using Owner Authorization. + pub const PLATFORMCREATE: Self = Self(0x40000000); + + /// SET (1): TPM2_NV_ReadLock() may be used to SET TPMA_NV_READLOCKED for this Index. + /// CLEAR (0): TPM2_NV_ReadLock() has no effect on this Index. + pub const READ_STCLEAR: Self = Self(0x80000000); + + pub fn try_from(value: u32) -> Result { + match value { + 1 => Ok(Self::PPWRITE), // Original value: 0x1 + 2 => Ok(Self::OWNERWRITE), // Original value: 0x2 + 4 => Ok(Self::TpmNt_BIT_LENGTH), // Original value: 4 + 8 => Ok(Self::POLICYWRITE), // Original value: 0x8 + 0 => Ok(Self::ORDINARY), // Original value: 0x0 + 16 => Ok(Self::COUNTER), // Original value: 0x10 + 32 => Ok(Self::BITS), // Original value: 0x20 + 64 => Ok(Self::EXTEND), // Original value: 0x40 + 128 => Ok(Self::PIN_FAIL), // Original value: 0x80 + 144 => Ok(Self::PIN_PASS), // Original value: 0x90 + 240 => Ok(Self::TpmNt_BIT_MASK), // Original value: 0xF0 + 1024 => Ok(Self::POLICY_DELETE), // Original value: 0x400 + 2048 => Ok(Self::WRITELOCKED), // Original value: 0x800 + 4096 => Ok(Self::WRITEALL), // Original value: 0x1000 + 8192 => Ok(Self::WRITEDEFINE), // Original value: 0x2000 + 16384 => Ok(Self::WRITE_STCLEAR), // Original value: 0x4000 + 32768 => Ok(Self::GLOBALLOCK), // Original value: 0x8000 + 65536 => Ok(Self::PPREAD), // Original value: 0x10000 + 131072 => Ok(Self::OWNERREAD), // Original value: 0x20000 + 262144 => Ok(Self::AUTHREAD), // Original value: 0x40000 + 524288 => Ok(Self::POLICYREAD), // Original value: 0x80000 + 33554432 => Ok(Self::NO_DA), // Original value: 0x2000000 + 67108864 => Ok(Self::ORDERLY), // Original value: 0x4000000 + 134217728 => Ok(Self::CLEAR_STCLEAR), // Original value: 0x8000000 + 268435456 => Ok(Self::READLOCKED), // Original value: 0x10000000 + 536870912 => Ok(Self::WRITTEN), // Original value: 0x20000000 + 1073741824 => Ok(Self::PLATFORMCREATE), // Original value: 0x40000000 + 2147483648 => Ok(Self::READ_STCLEAR), // Original value: 0x80000000 + _ => Err(TpmError::InvalidEnumValue), + } + } +} + +impl TpmEnum for TPMA_NV { + fn get_value(&self) -> u32 { + self.0.into() + } + + fn try_from_trait(value: u64) -> Result where Self: Sized { + TPMA_NV::try_from(value as u32) + } + + fn new_from_trait(value: u64) -> Result where Self: Sized { + Ok(TPMA_NV(value as u32)) + } +} + +impl From for u32 { + fn from(value: TPMA_NV) -> Self { + value.0 as u32 + } +} + +impl From for i32 { + fn from(value: TPMA_NV) -> Self { + value.0 as i32 + } +} + +impl fmt::Display for TPMA_NV { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + 1 => write!(f, "PPWRITE"), + 2 => write!(f, "OWNERWRITE"), + 4 => write!(f, "TpmNt_BIT_LENGTH"), + 8 => write!(f, "POLICYWRITE"), + 0 => write!(f, "ORDINARY"), + 16 => write!(f, "COUNTER"), + 32 => write!(f, "BITS"), + 64 => write!(f, "EXTEND"), + 128 => write!(f, "PIN_FAIL"), + 144 => write!(f, "PIN_PASS"), + 240 => write!(f, "TpmNt_BIT_MASK"), + 1024 => write!(f, "POLICY_DELETE"), + 2048 => write!(f, "WRITELOCKED"), + 4096 => write!(f, "WRITEALL"), + 8192 => write!(f, "WRITEDEFINE"), + 16384 => write!(f, "WRITE_STCLEAR"), + 32768 => write!(f, "GLOBALLOCK"), + 65536 => write!(f, "PPREAD"), + 131072 => write!(f, "OWNERREAD"), + 262144 => write!(f, "AUTHREAD"), + 524288 => write!(f, "POLICYREAD"), + 33554432 => write!(f, "NO_DA"), + 67108864 => write!(f, "ORDERLY"), + 134217728 => write!(f, "CLEAR_STCLEAR"), + 268435456 => write!(f, "READLOCKED"), + 536870912 => write!(f, "WRITTEN"), + 1073741824 => write!(f, "PLATFORMCREATE"), + 2147483648 => write!(f, "READ_STCLEAR"), + _ => write!(f, "{}", enum_to_str(self.0 as u64, std::any::TypeId::of::())), + } + } +} + +impl std::ops::BitOr for TPMA_NV { + type Output = Self; + + fn bitor(self, rhs: Self) -> Self::Output { + Self(self.0 | rhs.0) + } + +} + +impl From for TPMA_NV { + fn from(value: u32) -> Self { + Self(value.into()) + } +} + +/// Table 119 Definition of TPMU_CAPABILITIES Union [OUT] +/// One of: TPML_ALG_PROPERTY, TPML_HANDLE, TPML_CCA, TPML_CC, TPML_PCR_SELECTION, +/// TPML_TAGGED_TPM_PROPERTY, TPML_TAGGED_PCR_PROPERTY, TPML_ECC_CURVE, +/// TPML_TAGGED_POLICY, TPML_ACT_DATA. +#[derive(Clone)] +pub enum TPMU_CAPABILITIES { + algorithms(TPML_ALG_PROPERTY), + handles(TPML_HANDLE), + command(TPML_CCA), + ppCommands(TPML_CC), + auditCommands(TPML_CC), + assignedPCR(TPML_PCR_SELECTION), + tpmProperties(TPML_TAGGED_TPM_PROPERTY), + pcrProperties(TPML_TAGGED_PCR_PROPERTY), + eccCurves(TPML_ECC_CURVE), + authPolicies(TPML_TAGGED_POLICY), + actData(TPML_ACT_DATA), +} + +/// Union selector type +impl TPMU_CAPABILITIES { + pub fn GetUnionSelector(&self) -> TPM_CAP { + match self { + Self::algorithms(_) => TPML_ALG_PROPERTY::GetUnionSelector(), + Self::handles(_) => TPML_HANDLE::GetUnionSelector(), + Self::command(_) => TPML_CCA::GetUnionSelector(), + Self::ppCommands(_) => TPML_CC::GetUnionSelector(), + Self::auditCommands(_) => TPML_CC::GetUnionSelector(), + Self::assignedPCR(_) => TPML_PCR_SELECTION::GetUnionSelector(), + Self::tpmProperties(_) => TPML_TAGGED_TPM_PROPERTY::GetUnionSelector(), + Self::pcrProperties(_) => TPML_TAGGED_PCR_PROPERTY::GetUnionSelector(), + Self::eccCurves(_) => TPML_ECC_CURVE::GetUnionSelector(), + Self::authPolicies(_) => TPML_TAGGED_POLICY::GetUnionSelector(), + Self::actData(_) => TPML_ACT_DATA::GetUnionSelector(), + } + } + + pub fn create(selector: TPM_CAP) -> Result, TpmError> { + match selector { + TPM_CAP::ALGS => Ok(Some(Self::algorithms(TPML_ALG_PROPERTY::default()))), + TPM_CAP::HANDLES => Ok(Some(Self::handles(TPML_HANDLE::default()))), + TPM_CAP::COMMANDS => Ok(Some(Self::command(TPML_CCA::default()))), + TPM_CAP::PP_COMMANDS => Ok(Some(Self::ppCommands(TPML_CC::default()))), + TPM_CAP::AUDIT_COMMANDS => Ok(Some(Self::auditCommands(TPML_CC::default()))), + TPM_CAP::PCRS => Ok(Some(Self::assignedPCR(TPML_PCR_SELECTION::default()))), + TPM_CAP::TPM_PROPERTIES => Ok(Some(Self::tpmProperties(TPML_TAGGED_TPM_PROPERTY::default()))), + TPM_CAP::PCR_PROPERTIES => Ok(Some(Self::pcrProperties(TPML_TAGGED_PCR_PROPERTY::default()))), + TPM_CAP::ECC_CURVES => Ok(Some(Self::eccCurves(TPML_ECC_CURVE::default()))), + TPM_CAP::AUTH_POLICIES => Ok(Some(Self::authPolicies(TPML_TAGGED_POLICY::default()))), + TPM_CAP::ACT => Ok(Some(Self::actData(TPML_ACT_DATA::default()))), + _ => Err(TpmError::InvalidUnion), + } + } +} + +impl fmt::Debug for TPMU_CAPABILITIES { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::algorithms(inner) => write!(f, "TPMU_CAPABILITIES::algorithms({:?})", inner), + Self::handles(inner) => write!(f, "TPMU_CAPABILITIES::handles({:?})", inner), + Self::command(inner) => write!(f, "TPMU_CAPABILITIES::command({:?})", inner), + Self::ppCommands(inner) => write!(f, "TPMU_CAPABILITIES::ppCommands({:?})", inner), + Self::auditCommands(inner) => write!(f, "TPMU_CAPABILITIES::auditCommands({:?})", inner), + Self::assignedPCR(inner) => write!(f, "TPMU_CAPABILITIES::assignedPCR({:?})", inner), + Self::tpmProperties(inner) => write!(f, "TPMU_CAPABILITIES::tpmProperties({:?})", inner), + Self::pcrProperties(inner) => write!(f, "TPMU_CAPABILITIES::pcrProperties({:?})", inner), + Self::eccCurves(inner) => write!(f, "TPMU_CAPABILITIES::eccCurves({:?})", inner), + Self::authPolicies(inner) => write!(f, "TPMU_CAPABILITIES::authPolicies({:?})", inner), + Self::actData(inner) => write!(f, "TPMU_CAPABILITIES::actData({:?})", inner), + } + } +} +impl TpmStructure for TPMU_CAPABILITIES { + fn serialize(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::algorithms(inner) => inner.serialize(buffer), + Self::handles(inner) => inner.serialize(buffer), + Self::command(inner) => inner.serialize(buffer), + Self::ppCommands(inner) => inner.serialize(buffer), + Self::auditCommands(inner) => inner.serialize(buffer), + Self::assignedPCR(inner) => inner.serialize(buffer), + Self::tpmProperties(inner) => inner.serialize(buffer), + Self::pcrProperties(inner) => inner.serialize(buffer), + Self::eccCurves(inner) => inner.serialize(buffer), + Self::authPolicies(inner) => inner.serialize(buffer), + Self::actData(inner) => inner.serialize(buffer), + } + } + + fn deserialize(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::algorithms(inner) => inner.deserialize(buffer), + Self::handles(inner) => inner.deserialize(buffer), + Self::command(inner) => inner.deserialize(buffer), + Self::ppCommands(inner) => inner.deserialize(buffer), + Self::auditCommands(inner) => inner.deserialize(buffer), + Self::assignedPCR(inner) => inner.deserialize(buffer), + Self::tpmProperties(inner) => inner.deserialize(buffer), + Self::pcrProperties(inner) => inner.deserialize(buffer), + Self::eccCurves(inner) => inner.deserialize(buffer), + Self::authPolicies(inner) => inner.deserialize(buffer), + Self::actData(inner) => inner.deserialize(buffer), + } + } + + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::algorithms(inner) => inner.fromTpm(buffer), + Self::handles(inner) => inner.fromTpm(buffer), + Self::command(inner) => inner.fromTpm(buffer), + Self::ppCommands(inner) => inner.fromTpm(buffer), + Self::auditCommands(inner) => inner.fromTpm(buffer), + Self::assignedPCR(inner) => inner.fromTpm(buffer), + Self::tpmProperties(inner) => inner.fromTpm(buffer), + Self::pcrProperties(inner) => inner.fromTpm(buffer), + Self::eccCurves(inner) => inner.fromTpm(buffer), + Self::authPolicies(inner) => inner.fromTpm(buffer), + Self::actData(inner) => inner.fromTpm(buffer), + } + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + match self { + Self::algorithms(inner) => inner.fromBytes(buffer), + Self::handles(inner) => inner.fromBytes(buffer), + Self::command(inner) => inner.fromBytes(buffer), + Self::ppCommands(inner) => inner.fromBytes(buffer), + Self::auditCommands(inner) => inner.fromBytes(buffer), + Self::assignedPCR(inner) => inner.fromBytes(buffer), + Self::tpmProperties(inner) => inner.fromBytes(buffer), + Self::pcrProperties(inner) => inner.fromBytes(buffer), + Self::eccCurves(inner) => inner.fromBytes(buffer), + Self::authPolicies(inner) => inner.fromBytes(buffer), + Self::actData(inner) => inner.fromBytes(buffer), + } + } + +} + +impl TpmMarshaller for TPMU_CAPABILITIES { + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::algorithms(inner) => inner.toTpm(buffer), + Self::handles(inner) => inner.toTpm(buffer), + Self::command(inner) => inner.toTpm(buffer), + Self::ppCommands(inner) => inner.toTpm(buffer), + Self::auditCommands(inner) => inner.toTpm(buffer), + Self::assignedPCR(inner) => inner.toTpm(buffer), + Self::tpmProperties(inner) => inner.toTpm(buffer), + Self::pcrProperties(inner) => inner.toTpm(buffer), + Self::eccCurves(inner) => inner.toTpm(buffer), + Self::authPolicies(inner) => inner.toTpm(buffer), + Self::actData(inner) => inner.toTpm(buffer), + } + } + + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::algorithms(inner) => inner.initFromTpm(buffer), + Self::handles(inner) => inner.initFromTpm(buffer), + Self::command(inner) => inner.initFromTpm(buffer), + Self::ppCommands(inner) => inner.initFromTpm(buffer), + Self::auditCommands(inner) => inner.initFromTpm(buffer), + Self::assignedPCR(inner) => inner.initFromTpm(buffer), + Self::tpmProperties(inner) => inner.initFromTpm(buffer), + Self::pcrProperties(inner) => inner.initFromTpm(buffer), + Self::eccCurves(inner) => inner.initFromTpm(buffer), + Self::authPolicies(inner) => inner.initFromTpm(buffer), + Self::actData(inner) => inner.initFromTpm(buffer), + } + } + +} + +/// Table 132 Definition of TPMU_ATTEST Union [OUT] +/// One of: TPMS_CERTIFY_INFO, TPMS_CREATION_INFO, TPMS_QUOTE_INFO, +/// TPMS_COMMAND_AUDIT_INFO, TPMS_SESSION_AUDIT_INFO, TPMS_TIME_ATTEST_INFO, +/// TPMS_NV_CERTIFY_INFO, TPMS_NV_DIGEST_CERTIFY_INFO. +#[derive(Clone)] +pub enum TPMU_ATTEST { + certify(TPMS_CERTIFY_INFO), + creation(TPMS_CREATION_INFO), + quote(TPMS_QUOTE_INFO), + commandAudit(TPMS_COMMAND_AUDIT_INFO), + sessionAudit(TPMS_SESSION_AUDIT_INFO), + time(TPMS_TIME_ATTEST_INFO), + nv(TPMS_NV_CERTIFY_INFO), + nvDigest(TPMS_NV_DIGEST_CERTIFY_INFO), +} + +/// Union selector type +impl TPMU_ATTEST { + pub fn GetUnionSelector(&self) -> TPM_ST { + match self { + Self::certify(_) => TPMS_CERTIFY_INFO::GetUnionSelector(), + Self::creation(_) => TPMS_CREATION_INFO::GetUnionSelector(), + Self::quote(_) => TPMS_QUOTE_INFO::GetUnionSelector(), + Self::commandAudit(_) => TPMS_COMMAND_AUDIT_INFO::GetUnionSelector(), + Self::sessionAudit(_) => TPMS_SESSION_AUDIT_INFO::GetUnionSelector(), + Self::time(_) => TPMS_TIME_ATTEST_INFO::GetUnionSelector(), + Self::nv(_) => TPMS_NV_CERTIFY_INFO::GetUnionSelector(), + Self::nvDigest(_) => TPMS_NV_DIGEST_CERTIFY_INFO::GetUnionSelector(), + } + } + + pub fn create(selector: TPM_ST) -> Result, TpmError> { + match selector { + TPM_ST::ATTEST_CERTIFY => Ok(Some(Self::certify(TPMS_CERTIFY_INFO::default()))), + TPM_ST::ATTEST_CREATION => Ok(Some(Self::creation(TPMS_CREATION_INFO::default()))), + TPM_ST::ATTEST_QUOTE => Ok(Some(Self::quote(TPMS_QUOTE_INFO::default()))), + TPM_ST::ATTEST_COMMAND_AUDIT => Ok(Some(Self::commandAudit(TPMS_COMMAND_AUDIT_INFO::default()))), + TPM_ST::ATTEST_SESSION_AUDIT => Ok(Some(Self::sessionAudit(TPMS_SESSION_AUDIT_INFO::default()))), + TPM_ST::ATTEST_TIME => Ok(Some(Self::time(TPMS_TIME_ATTEST_INFO::default()))), + TPM_ST::ATTEST_NV => Ok(Some(Self::nv(TPMS_NV_CERTIFY_INFO::default()))), + TPM_ST::ATTEST_NV_DIGEST => Ok(Some(Self::nvDigest(TPMS_NV_DIGEST_CERTIFY_INFO::default()))), + _ => Err(TpmError::InvalidUnion), + } + } +} + +impl fmt::Debug for TPMU_ATTEST { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::certify(inner) => write!(f, "TPMU_ATTEST::certify({:?})", inner), + Self::creation(inner) => write!(f, "TPMU_ATTEST::creation({:?})", inner), + Self::quote(inner) => write!(f, "TPMU_ATTEST::quote({:?})", inner), + Self::commandAudit(inner) => write!(f, "TPMU_ATTEST::commandAudit({:?})", inner), + Self::sessionAudit(inner) => write!(f, "TPMU_ATTEST::sessionAudit({:?})", inner), + Self::time(inner) => write!(f, "TPMU_ATTEST::time({:?})", inner), + Self::nv(inner) => write!(f, "TPMU_ATTEST::nv({:?})", inner), + Self::nvDigest(inner) => write!(f, "TPMU_ATTEST::nvDigest({:?})", inner), + } + } +} +impl TpmStructure for TPMU_ATTEST { + fn serialize(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::certify(inner) => inner.serialize(buffer), + Self::creation(inner) => inner.serialize(buffer), + Self::quote(inner) => inner.serialize(buffer), + Self::commandAudit(inner) => inner.serialize(buffer), + Self::sessionAudit(inner) => inner.serialize(buffer), + Self::time(inner) => inner.serialize(buffer), + Self::nv(inner) => inner.serialize(buffer), + Self::nvDigest(inner) => inner.serialize(buffer), + } + } + + fn deserialize(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::certify(inner) => inner.deserialize(buffer), + Self::creation(inner) => inner.deserialize(buffer), + Self::quote(inner) => inner.deserialize(buffer), + Self::commandAudit(inner) => inner.deserialize(buffer), + Self::sessionAudit(inner) => inner.deserialize(buffer), + Self::time(inner) => inner.deserialize(buffer), + Self::nv(inner) => inner.deserialize(buffer), + Self::nvDigest(inner) => inner.deserialize(buffer), + } + } + + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::certify(inner) => inner.fromTpm(buffer), + Self::creation(inner) => inner.fromTpm(buffer), + Self::quote(inner) => inner.fromTpm(buffer), + Self::commandAudit(inner) => inner.fromTpm(buffer), + Self::sessionAudit(inner) => inner.fromTpm(buffer), + Self::time(inner) => inner.fromTpm(buffer), + Self::nv(inner) => inner.fromTpm(buffer), + Self::nvDigest(inner) => inner.fromTpm(buffer), + } + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + match self { + Self::certify(inner) => inner.fromBytes(buffer), + Self::creation(inner) => inner.fromBytes(buffer), + Self::quote(inner) => inner.fromBytes(buffer), + Self::commandAudit(inner) => inner.fromBytes(buffer), + Self::sessionAudit(inner) => inner.fromBytes(buffer), + Self::time(inner) => inner.fromBytes(buffer), + Self::nv(inner) => inner.fromBytes(buffer), + Self::nvDigest(inner) => inner.fromBytes(buffer), + } + } + +} + +impl TpmMarshaller for TPMU_ATTEST { + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::certify(inner) => inner.toTpm(buffer), + Self::creation(inner) => inner.toTpm(buffer), + Self::quote(inner) => inner.toTpm(buffer), + Self::commandAudit(inner) => inner.toTpm(buffer), + Self::sessionAudit(inner) => inner.toTpm(buffer), + Self::time(inner) => inner.toTpm(buffer), + Self::nv(inner) => inner.toTpm(buffer), + Self::nvDigest(inner) => inner.toTpm(buffer), + } + } + + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::certify(inner) => inner.initFromTpm(buffer), + Self::creation(inner) => inner.initFromTpm(buffer), + Self::quote(inner) => inner.initFromTpm(buffer), + Self::commandAudit(inner) => inner.initFromTpm(buffer), + Self::sessionAudit(inner) => inner.initFromTpm(buffer), + Self::time(inner) => inner.initFromTpm(buffer), + Self::nv(inner) => inner.initFromTpm(buffer), + Self::nvDigest(inner) => inner.initFromTpm(buffer), + } + } + +} + +/// This union allows additional parameters to be added for a symmetric cipher. Currently, +/// no additional parameters are required for any of the symmetric algorithms. +/// One of: TPMS_TDES_SYM_DETAILS, TPMS_AES_SYM_DETAILS, TPMS_SM4_SYM_DETAILS, +/// TPMS_CAMELLIA_SYM_DETAILS, TPMS_ANY_SYM_DETAILS, TPMS_XOR_SYM_DETAILS, TPMS_NULL_SYM_DETAILS. +#[derive(Clone)] +pub enum TPMU_SYM_DETAILS { + tdes(TPMS_TDES_SYM_DETAILS), + aes(TPMS_AES_SYM_DETAILS), + sm4(TPMS_SM4_SYM_DETAILS), + camellia(TPMS_CAMELLIA_SYM_DETAILS), + sym(TPMS_ANY_SYM_DETAILS), + xor(TPMS_XOR_SYM_DETAILS), + null(TPMS_NULL_SYM_DETAILS), +} + +/// Union selector type +impl TPMU_SYM_DETAILS { + pub fn GetUnionSelector(&self) -> TPM_ALG_ID { + match self { + Self::tdes(_) => TPMS_TDES_SYM_DETAILS::GetUnionSelector(), + Self::aes(_) => TPMS_AES_SYM_DETAILS::GetUnionSelector(), + Self::sm4(_) => TPMS_SM4_SYM_DETAILS::GetUnionSelector(), + Self::camellia(_) => TPMS_CAMELLIA_SYM_DETAILS::GetUnionSelector(), + Self::sym(_) => TPMS_ANY_SYM_DETAILS::GetUnionSelector(), + Self::xor(_) => TPMS_XOR_SYM_DETAILS::GetUnionSelector(), + Self::null(_) => TPMS_NULL_SYM_DETAILS::GetUnionSelector(), + } + } + + pub fn create(selector: TPM_ALG_ID) -> Result, TpmError> { + match selector { + TPM_ALG_ID::TDES => Ok(Some(Self::tdes(TPMS_TDES_SYM_DETAILS::default()))), + TPM_ALG_ID::AES => Ok(Some(Self::aes(TPMS_AES_SYM_DETAILS::default()))), + TPM_ALG_ID::SM4 => Ok(Some(Self::sm4(TPMS_SM4_SYM_DETAILS::default()))), + TPM_ALG_ID::CAMELLIA => Ok(Some(Self::camellia(TPMS_CAMELLIA_SYM_DETAILS::default()))), + TPM_ALG_ID::ANY => Ok(Some(Self::sym(TPMS_ANY_SYM_DETAILS::default()))), + TPM_ALG_ID::XOR => Ok(Some(Self::xor(TPMS_XOR_SYM_DETAILS::default()))), + TPM_ALG_ID::NULL => Ok(Some(Self::null(TPMS_NULL_SYM_DETAILS::default()))), + _ => Err(TpmError::InvalidUnion), + } + } +} + +impl fmt::Debug for TPMU_SYM_DETAILS { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::tdes(inner) => write!(f, "TPMU_SYM_DETAILS::tdes({:?})", inner), + Self::aes(inner) => write!(f, "TPMU_SYM_DETAILS::aes({:?})", inner), + Self::sm4(inner) => write!(f, "TPMU_SYM_DETAILS::sm4({:?})", inner), + Self::camellia(inner) => write!(f, "TPMU_SYM_DETAILS::camellia({:?})", inner), + Self::sym(inner) => write!(f, "TPMU_SYM_DETAILS::sym({:?})", inner), + Self::xor(inner) => write!(f, "TPMU_SYM_DETAILS::xor({:?})", inner), + Self::null(inner) => write!(f, "TPMU_SYM_DETAILS::null({:?})", inner), + } + } +} +impl TpmStructure for TPMU_SYM_DETAILS { + fn serialize(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::tdes(inner) => inner.serialize(buffer), + Self::aes(inner) => inner.serialize(buffer), + Self::sm4(inner) => inner.serialize(buffer), + Self::camellia(inner) => inner.serialize(buffer), + Self::sym(inner) => inner.serialize(buffer), + Self::xor(inner) => inner.serialize(buffer), + Self::null(inner) => inner.serialize(buffer), + } + } + + fn deserialize(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::tdes(inner) => inner.deserialize(buffer), + Self::aes(inner) => inner.deserialize(buffer), + Self::sm4(inner) => inner.deserialize(buffer), + Self::camellia(inner) => inner.deserialize(buffer), + Self::sym(inner) => inner.deserialize(buffer), + Self::xor(inner) => inner.deserialize(buffer), + Self::null(inner) => inner.deserialize(buffer), + } + } + + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::tdes(inner) => inner.fromTpm(buffer), + Self::aes(inner) => inner.fromTpm(buffer), + Self::sm4(inner) => inner.fromTpm(buffer), + Self::camellia(inner) => inner.fromTpm(buffer), + Self::sym(inner) => inner.fromTpm(buffer), + Self::xor(inner) => inner.fromTpm(buffer), + Self::null(inner) => inner.fromTpm(buffer), + } + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + match self { + Self::tdes(inner) => inner.fromBytes(buffer), + Self::aes(inner) => inner.fromBytes(buffer), + Self::sm4(inner) => inner.fromBytes(buffer), + Self::camellia(inner) => inner.fromBytes(buffer), + Self::sym(inner) => inner.fromBytes(buffer), + Self::xor(inner) => inner.fromBytes(buffer), + Self::null(inner) => inner.fromBytes(buffer), + } + } + +} + +impl TpmMarshaller for TPMU_SYM_DETAILS { + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::tdes(inner) => inner.toTpm(buffer), + Self::aes(inner) => inner.toTpm(buffer), + Self::sm4(inner) => inner.toTpm(buffer), + Self::camellia(inner) => inner.toTpm(buffer), + Self::sym(inner) => inner.toTpm(buffer), + Self::xor(inner) => inner.toTpm(buffer), + Self::null(inner) => inner.toTpm(buffer), + } + } + + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::tdes(inner) => inner.initFromTpm(buffer), + Self::aes(inner) => inner.initFromTpm(buffer), + Self::sm4(inner) => inner.initFromTpm(buffer), + Self::camellia(inner) => inner.initFromTpm(buffer), + Self::sym(inner) => inner.initFromTpm(buffer), + Self::xor(inner) => inner.initFromTpm(buffer), + Self::null(inner) => inner.initFromTpm(buffer), + } + } + +} + +/// This structure allows a TPM2B_SENSITIVE_CREATE structure to carry either a +/// TPM2B_SENSITVE_DATA or a TPM2B_DERIVE structure. The contents of the union are +/// determined by context. When an object is being derived, the derivation values are present. +/// One of: u8, TPMS_DERIVE. +#[derive(Clone)] +pub enum TPMU_SENSITIVE_CREATE { + create, + derive(TPMS_DERIVE), +} + +/// Union selector type +impl TPMU_SENSITIVE_CREATE { + pub fn GetUnionSelector(&self) -> TPM_ALG_ID { + match self { + Self::create => TPM_ALG_ID::ANY, + Self::derive(_) => TPMS_DERIVE::GetUnionSelector(), + } + } + + pub fn create(selector: TPM_ALG_ID) -> Result, TpmError> { + match selector { + TPM_ALG_ID::ANY => Ok(None), + TPM_ALG_ID::ANY2 => Ok(Some(Self::derive(TPMS_DERIVE::default()))), + _ => Err(TpmError::InvalidUnion), + } + } +} + +impl fmt::Debug for TPMU_SENSITIVE_CREATE { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::create => write!(f, "TPMU_SENSITIVE_CREATE::create"), + Self::derive(inner) => write!(f, "TPMU_SENSITIVE_CREATE::derive({:?})", inner), + } + } +} +impl TpmStructure for TPMU_SENSITIVE_CREATE { + fn serialize(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::create => Ok(()), + Self::derive(inner) => inner.serialize(buffer), + } + } + + fn deserialize(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::create => Ok(()), + Self::derive(inner) => inner.deserialize(buffer), + } + } + + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::create => Ok(()), + Self::derive(inner) => inner.fromTpm(buffer), + } + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + match self { + Self::create => Ok(()), + Self::derive(inner) => inner.fromBytes(buffer), + } + } + +} + +impl TpmMarshaller for TPMU_SENSITIVE_CREATE { + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::create => Ok(()), + Self::derive(inner) => inner.toTpm(buffer), + } + } + + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::create => Ok(()), + Self::derive(inner) => inner.initFromTpm(buffer), + } + } + +} + +/// Table 157 Definition of TPMU_SCHEME_KEYEDHASH Union [IN/OUT] +/// One of: TPMS_SCHEME_HMAC, TPMS_SCHEME_XOR, TPMS_NULL_SCHEME_KEYEDHASH. +#[derive(Clone)] +pub enum TPMU_SCHEME_KEYEDHASH { + hmac(TPMS_SCHEME_HMAC), + xor(TPMS_SCHEME_XOR), + null(TPMS_NULL_SCHEME_KEYEDHASH), +} + +/// Union selector type +impl TPMU_SCHEME_KEYEDHASH { + pub fn GetUnionSelector(&self) -> TPM_ALG_ID { + match self { + Self::hmac(_) => TPMS_SCHEME_HMAC::GetUnionSelector(), + Self::xor(_) => TPMS_SCHEME_XOR::GetUnionSelector(), + Self::null(_) => TPMS_NULL_SCHEME_KEYEDHASH::GetUnionSelector(), + } + } + + pub fn create(selector: TPM_ALG_ID) -> Result, TpmError> { + match selector { + TPM_ALG_ID::HMAC => Ok(Some(Self::hmac(TPMS_SCHEME_HMAC::default()))), + TPM_ALG_ID::XOR => Ok(Some(Self::xor(TPMS_SCHEME_XOR::default()))), + TPM_ALG_ID::NULL => Ok(Some(Self::null(TPMS_NULL_SCHEME_KEYEDHASH::default()))), + _ => Err(TpmError::InvalidUnion), + } + } +} + +impl fmt::Debug for TPMU_SCHEME_KEYEDHASH { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::hmac(inner) => write!(f, "TPMU_SCHEME_KEYEDHASH::hmac({:?})", inner), + Self::xor(inner) => write!(f, "TPMU_SCHEME_KEYEDHASH::xor({:?})", inner), + Self::null(inner) => write!(f, "TPMU_SCHEME_KEYEDHASH::null({:?})", inner), + } + } +} +impl TpmStructure for TPMU_SCHEME_KEYEDHASH { + fn serialize(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::hmac(inner) => inner.serialize(buffer), + Self::xor(inner) => inner.serialize(buffer), + Self::null(inner) => inner.serialize(buffer), + } + } + + fn deserialize(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::hmac(inner) => inner.deserialize(buffer), + Self::xor(inner) => inner.deserialize(buffer), + Self::null(inner) => inner.deserialize(buffer), + } + } + + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::hmac(inner) => inner.fromTpm(buffer), + Self::xor(inner) => inner.fromTpm(buffer), + Self::null(inner) => inner.fromTpm(buffer), + } + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + match self { + Self::hmac(inner) => inner.fromBytes(buffer), + Self::xor(inner) => inner.fromBytes(buffer), + Self::null(inner) => inner.fromBytes(buffer), + } + } + +} + +impl TpmMarshaller for TPMU_SCHEME_KEYEDHASH { + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::hmac(inner) => inner.toTpm(buffer), + Self::xor(inner) => inner.toTpm(buffer), + Self::null(inner) => inner.toTpm(buffer), + } + } + + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::hmac(inner) => inner.initFromTpm(buffer), + Self::xor(inner) => inner.initFromTpm(buffer), + Self::null(inner) => inner.initFromTpm(buffer), + } + } + +} + +/// This is the union of all of the signature schemes. +/// One of: TPMS_SIG_SCHEME_RSASSA, TPMS_SIG_SCHEME_RSAPSS, TPMS_SIG_SCHEME_ECDSA, +/// TPMS_SIG_SCHEME_ECDAA, TPMS_SIG_SCHEME_SM2, TPMS_SIG_SCHEME_ECSCHNORR, +/// TPMS_SCHEME_HMAC, TPMS_SCHEME_HASH, TPMS_NULL_SIG_SCHEME. +#[derive(Clone)] +pub enum TPMU_SIG_SCHEME { + rsassa(TPMS_SIG_SCHEME_RSASSA), + rsapss(TPMS_SIG_SCHEME_RSAPSS), + ecdsa(TPMS_SIG_SCHEME_ECDSA), + ecdaa(TPMS_SIG_SCHEME_ECDAA), + sm2(TPMS_SIG_SCHEME_SM2), + ecschnorr(TPMS_SIG_SCHEME_ECSCHNORR), + hmac(TPMS_SCHEME_HMAC), + any(TPMS_SCHEME_HASH), + null(TPMS_NULL_SIG_SCHEME), +} + +/// Union selector type +impl TPMU_SIG_SCHEME { + pub fn GetUnionSelector(&self) -> TPM_ALG_ID { + match self { + Self::rsassa(_) => TPMS_SIG_SCHEME_RSASSA::GetUnionSelector(), + Self::rsapss(_) => TPMS_SIG_SCHEME_RSAPSS::GetUnionSelector(), + Self::ecdsa(_) => TPMS_SIG_SCHEME_ECDSA::GetUnionSelector(), + Self::ecdaa(_) => TPMS_SIG_SCHEME_ECDAA::GetUnionSelector(), + Self::sm2(_) => TPMS_SIG_SCHEME_SM2::GetUnionSelector(), + Self::ecschnorr(_) => TPMS_SIG_SCHEME_ECSCHNORR::GetUnionSelector(), + Self::hmac(_) => TPMS_SCHEME_HMAC::GetUnionSelector(), + Self::any(_) => TPMS_SCHEME_HASH::GetUnionSelector(), + Self::null(_) => TPMS_NULL_SIG_SCHEME::GetUnionSelector(), + } + } + + pub fn create(selector: TPM_ALG_ID) -> Result, TpmError> { + match selector { + TPM_ALG_ID::RSASSA => Ok(Some(Self::rsassa(TPMS_SIG_SCHEME_RSASSA::default()))), + TPM_ALG_ID::RSAPSS => Ok(Some(Self::rsapss(TPMS_SIG_SCHEME_RSAPSS::default()))), + TPM_ALG_ID::ECDSA => Ok(Some(Self::ecdsa(TPMS_SIG_SCHEME_ECDSA::default()))), + TPM_ALG_ID::ECDAA => Ok(Some(Self::ecdaa(TPMS_SIG_SCHEME_ECDAA::default()))), + TPM_ALG_ID::SM2 => Ok(Some(Self::sm2(TPMS_SIG_SCHEME_SM2::default()))), + TPM_ALG_ID::ECSCHNORR => Ok(Some(Self::ecschnorr(TPMS_SIG_SCHEME_ECSCHNORR::default()))), + TPM_ALG_ID::HMAC => Ok(Some(Self::hmac(TPMS_SCHEME_HMAC::default()))), + TPM_ALG_ID::ANY => Ok(Some(Self::any(TPMS_SCHEME_HASH::default()))), + TPM_ALG_ID::NULL => Ok(Some(Self::null(TPMS_NULL_SIG_SCHEME::default()))), + _ => Err(TpmError::InvalidUnion), + } + } +} + +impl fmt::Debug for TPMU_SIG_SCHEME { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::rsassa(inner) => write!(f, "TPMU_SIG_SCHEME::rsassa({:?})", inner), + Self::rsapss(inner) => write!(f, "TPMU_SIG_SCHEME::rsapss({:?})", inner), + Self::ecdsa(inner) => write!(f, "TPMU_SIG_SCHEME::ecdsa({:?})", inner), + Self::ecdaa(inner) => write!(f, "TPMU_SIG_SCHEME::ecdaa({:?})", inner), + Self::sm2(inner) => write!(f, "TPMU_SIG_SCHEME::sm2({:?})", inner), + Self::ecschnorr(inner) => write!(f, "TPMU_SIG_SCHEME::ecschnorr({:?})", inner), + Self::hmac(inner) => write!(f, "TPMU_SIG_SCHEME::hmac({:?})", inner), + Self::any(inner) => write!(f, "TPMU_SIG_SCHEME::any({:?})", inner), + Self::null(inner) => write!(f, "TPMU_SIG_SCHEME::null({:?})", inner), + } + } +} +impl TpmStructure for TPMU_SIG_SCHEME { + fn serialize(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::rsassa(inner) => inner.serialize(buffer), + Self::rsapss(inner) => inner.serialize(buffer), + Self::ecdsa(inner) => inner.serialize(buffer), + Self::ecdaa(inner) => inner.serialize(buffer), + Self::sm2(inner) => inner.serialize(buffer), + Self::ecschnorr(inner) => inner.serialize(buffer), + Self::hmac(inner) => inner.serialize(buffer), + Self::any(inner) => inner.serialize(buffer), + Self::null(inner) => inner.serialize(buffer), + } + } + + fn deserialize(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::rsassa(inner) => inner.deserialize(buffer), + Self::rsapss(inner) => inner.deserialize(buffer), + Self::ecdsa(inner) => inner.deserialize(buffer), + Self::ecdaa(inner) => inner.deserialize(buffer), + Self::sm2(inner) => inner.deserialize(buffer), + Self::ecschnorr(inner) => inner.deserialize(buffer), + Self::hmac(inner) => inner.deserialize(buffer), + Self::any(inner) => inner.deserialize(buffer), + Self::null(inner) => inner.deserialize(buffer), + } + } + + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::rsassa(inner) => inner.fromTpm(buffer), + Self::rsapss(inner) => inner.fromTpm(buffer), + Self::ecdsa(inner) => inner.fromTpm(buffer), + Self::ecdaa(inner) => inner.fromTpm(buffer), + Self::sm2(inner) => inner.fromTpm(buffer), + Self::ecschnorr(inner) => inner.fromTpm(buffer), + Self::hmac(inner) => inner.fromTpm(buffer), + Self::any(inner) => inner.fromTpm(buffer), + Self::null(inner) => inner.fromTpm(buffer), + } + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + match self { + Self::rsassa(inner) => inner.fromBytes(buffer), + Self::rsapss(inner) => inner.fromBytes(buffer), + Self::ecdsa(inner) => inner.fromBytes(buffer), + Self::ecdaa(inner) => inner.fromBytes(buffer), + Self::sm2(inner) => inner.fromBytes(buffer), + Self::ecschnorr(inner) => inner.fromBytes(buffer), + Self::hmac(inner) => inner.fromBytes(buffer), + Self::any(inner) => inner.fromBytes(buffer), + Self::null(inner) => inner.fromBytes(buffer), + } + } + +} + +impl TpmMarshaller for TPMU_SIG_SCHEME { + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::rsassa(inner) => inner.toTpm(buffer), + Self::rsapss(inner) => inner.toTpm(buffer), + Self::ecdsa(inner) => inner.toTpm(buffer), + Self::ecdaa(inner) => inner.toTpm(buffer), + Self::sm2(inner) => inner.toTpm(buffer), + Self::ecschnorr(inner) => inner.toTpm(buffer), + Self::hmac(inner) => inner.toTpm(buffer), + Self::any(inner) => inner.toTpm(buffer), + Self::null(inner) => inner.toTpm(buffer), + } + } + + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::rsassa(inner) => inner.initFromTpm(buffer), + Self::rsapss(inner) => inner.initFromTpm(buffer), + Self::ecdsa(inner) => inner.initFromTpm(buffer), + Self::ecdaa(inner) => inner.initFromTpm(buffer), + Self::sm2(inner) => inner.initFromTpm(buffer), + Self::ecschnorr(inner) => inner.initFromTpm(buffer), + Self::hmac(inner) => inner.initFromTpm(buffer), + Self::any(inner) => inner.initFromTpm(buffer), + Self::null(inner) => inner.initFromTpm(buffer), + } + } + +} + +/// Table 166 Definition of TPMU_KDF_SCHEME Union [IN/OUT] +/// One of: TPMS_KDF_SCHEME_MGF1, TPMS_KDF_SCHEME_KDF1_SP800_56A, TPMS_KDF_SCHEME_KDF2, +/// TPMS_KDF_SCHEME_KDF1_SP800_108, TPMS_SCHEME_HASH, TPMS_NULL_KDF_SCHEME. +#[derive(Clone)] +pub enum TPMU_KDF_SCHEME { + mgf1(TPMS_KDF_SCHEME_MGF1), + kdf1_sp800_56a(TPMS_KDF_SCHEME_KDF1_SP800_56A), + kdf2(TPMS_KDF_SCHEME_KDF2), + kdf1_sp800_108(TPMS_KDF_SCHEME_KDF1_SP800_108), + anyKdf(TPMS_SCHEME_HASH), + null(TPMS_NULL_KDF_SCHEME), +} + +/// Union selector type +impl TPMU_KDF_SCHEME { + pub fn GetUnionSelector(&self) -> TPM_ALG_ID { + match self { + Self::mgf1(_) => TPMS_KDF_SCHEME_MGF1::GetUnionSelector(), + Self::kdf1_sp800_56a(_) => TPMS_KDF_SCHEME_KDF1_SP800_56A::GetUnionSelector(), + Self::kdf2(_) => TPMS_KDF_SCHEME_KDF2::GetUnionSelector(), + Self::kdf1_sp800_108(_) => TPMS_KDF_SCHEME_KDF1_SP800_108::GetUnionSelector(), + Self::anyKdf(_) => TPMS_SCHEME_HASH::GetUnionSelector(), + Self::null(_) => TPMS_NULL_KDF_SCHEME::GetUnionSelector(), + } + } + + pub fn create(selector: TPM_ALG_ID) -> Result, TpmError> { + match selector { + TPM_ALG_ID::MGF1 => Ok(Some(Self::mgf1(TPMS_KDF_SCHEME_MGF1::default()))), + TPM_ALG_ID::KDF1_SP800_56A => Ok(Some(Self::kdf1_sp800_56a(TPMS_KDF_SCHEME_KDF1_SP800_56A::default()))), + TPM_ALG_ID::KDF2 => Ok(Some(Self::kdf2(TPMS_KDF_SCHEME_KDF2::default()))), + TPM_ALG_ID::KDF1_SP800_108 => Ok(Some(Self::kdf1_sp800_108(TPMS_KDF_SCHEME_KDF1_SP800_108::default()))), + TPM_ALG_ID::ANY => Ok(Some(Self::anyKdf(TPMS_SCHEME_HASH::default()))), + TPM_ALG_ID::NULL => Ok(Some(Self::null(TPMS_NULL_KDF_SCHEME::default()))), + _ => Err(TpmError::InvalidUnion), + } + } +} + +impl fmt::Debug for TPMU_KDF_SCHEME { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::mgf1(inner) => write!(f, "TPMU_KDF_SCHEME::mgf1({:?})", inner), + Self::kdf1_sp800_56a(inner) => write!(f, "TPMU_KDF_SCHEME::kdf1_sp800_56a({:?})", inner), + Self::kdf2(inner) => write!(f, "TPMU_KDF_SCHEME::kdf2({:?})", inner), + Self::kdf1_sp800_108(inner) => write!(f, "TPMU_KDF_SCHEME::kdf1_sp800_108({:?})", inner), + Self::anyKdf(inner) => write!(f, "TPMU_KDF_SCHEME::anyKdf({:?})", inner), + Self::null(inner) => write!(f, "TPMU_KDF_SCHEME::null({:?})", inner), + } + } +} +impl TpmStructure for TPMU_KDF_SCHEME { + fn serialize(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::mgf1(inner) => inner.serialize(buffer), + Self::kdf1_sp800_56a(inner) => inner.serialize(buffer), + Self::kdf2(inner) => inner.serialize(buffer), + Self::kdf1_sp800_108(inner) => inner.serialize(buffer), + Self::anyKdf(inner) => inner.serialize(buffer), + Self::null(inner) => inner.serialize(buffer), + } + } + + fn deserialize(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::mgf1(inner) => inner.deserialize(buffer), + Self::kdf1_sp800_56a(inner) => inner.deserialize(buffer), + Self::kdf2(inner) => inner.deserialize(buffer), + Self::kdf1_sp800_108(inner) => inner.deserialize(buffer), + Self::anyKdf(inner) => inner.deserialize(buffer), + Self::null(inner) => inner.deserialize(buffer), + } + } + + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::mgf1(inner) => inner.fromTpm(buffer), + Self::kdf1_sp800_56a(inner) => inner.fromTpm(buffer), + Self::kdf2(inner) => inner.fromTpm(buffer), + Self::kdf1_sp800_108(inner) => inner.fromTpm(buffer), + Self::anyKdf(inner) => inner.fromTpm(buffer), + Self::null(inner) => inner.fromTpm(buffer), + } + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + match self { + Self::mgf1(inner) => inner.fromBytes(buffer), + Self::kdf1_sp800_56a(inner) => inner.fromBytes(buffer), + Self::kdf2(inner) => inner.fromBytes(buffer), + Self::kdf1_sp800_108(inner) => inner.fromBytes(buffer), + Self::anyKdf(inner) => inner.fromBytes(buffer), + Self::null(inner) => inner.fromBytes(buffer), + } + } + +} + +impl TpmMarshaller for TPMU_KDF_SCHEME { + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::mgf1(inner) => inner.toTpm(buffer), + Self::kdf1_sp800_56a(inner) => inner.toTpm(buffer), + Self::kdf2(inner) => inner.toTpm(buffer), + Self::kdf1_sp800_108(inner) => inner.toTpm(buffer), + Self::anyKdf(inner) => inner.toTpm(buffer), + Self::null(inner) => inner.toTpm(buffer), + } + } + + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::mgf1(inner) => inner.initFromTpm(buffer), + Self::kdf1_sp800_56a(inner) => inner.initFromTpm(buffer), + Self::kdf2(inner) => inner.initFromTpm(buffer), + Self::kdf1_sp800_108(inner) => inner.initFromTpm(buffer), + Self::anyKdf(inner) => inner.initFromTpm(buffer), + Self::null(inner) => inner.initFromTpm(buffer), + } + } + +} + +/// This union of all asymmetric schemes is used in each of the asymmetric scheme +/// structures. The actual scheme structure is defined by the interface type used for the +/// selector (TPMI_ALG_ASYM_SCHEME). +/// One of: TPMS_KEY_SCHEME_ECDH, TPMS_KEY_SCHEME_ECMQV, TPMS_SIG_SCHEME_RSASSA, +/// TPMS_SIG_SCHEME_RSAPSS, TPMS_SIG_SCHEME_ECDSA, TPMS_SIG_SCHEME_ECDAA, +/// TPMS_SIG_SCHEME_SM2, TPMS_SIG_SCHEME_ECSCHNORR, TPMS_ENC_SCHEME_RSAES, +/// TPMS_ENC_SCHEME_OAEP, TPMS_SCHEME_HASH, TPMS_NULL_ASYM_SCHEME. +#[derive(Clone)] +pub enum TPMU_ASYM_SCHEME { + ecdh(TPMS_KEY_SCHEME_ECDH), + ecmqv(TPMS_KEY_SCHEME_ECMQV), + rsassa(TPMS_SIG_SCHEME_RSASSA), + rsapss(TPMS_SIG_SCHEME_RSAPSS), + ecdsa(TPMS_SIG_SCHEME_ECDSA), + ecdaa(TPMS_SIG_SCHEME_ECDAA), + sm2(TPMS_SIG_SCHEME_SM2), + ecschnorr(TPMS_SIG_SCHEME_ECSCHNORR), + rsaes(TPMS_ENC_SCHEME_RSAES), + oaep(TPMS_ENC_SCHEME_OAEP), + anySig(TPMS_SCHEME_HASH), + null(TPMS_NULL_ASYM_SCHEME), +} + +/// Union selector type +impl TPMU_ASYM_SCHEME { + pub fn GetUnionSelector(&self) -> TPM_ALG_ID { + match self { + Self::ecdh(_) => TPMS_KEY_SCHEME_ECDH::GetUnionSelector(), + Self::ecmqv(_) => TPMS_KEY_SCHEME_ECMQV::GetUnionSelector(), + Self::rsassa(_) => TPMS_SIG_SCHEME_RSASSA::GetUnionSelector(), + Self::rsapss(_) => TPMS_SIG_SCHEME_RSAPSS::GetUnionSelector(), + Self::ecdsa(_) => TPMS_SIG_SCHEME_ECDSA::GetUnionSelector(), + Self::ecdaa(_) => TPMS_SIG_SCHEME_ECDAA::GetUnionSelector(), + Self::sm2(_) => TPMS_SIG_SCHEME_SM2::GetUnionSelector(), + Self::ecschnorr(_) => TPMS_SIG_SCHEME_ECSCHNORR::GetUnionSelector(), + Self::rsaes(_) => TPMS_ENC_SCHEME_RSAES::GetUnionSelector(), + Self::oaep(_) => TPMS_ENC_SCHEME_OAEP::GetUnionSelector(), + Self::anySig(_) => TPMS_SCHEME_HASH::GetUnionSelector(), + Self::null(_) => TPMS_NULL_ASYM_SCHEME::GetUnionSelector(), + } + } + + pub fn create(selector: TPM_ALG_ID) -> Result, TpmError> { + match selector { + TPM_ALG_ID::ECDH => Ok(Some(Self::ecdh(TPMS_KEY_SCHEME_ECDH::default()))), + TPM_ALG_ID::ECMQV => Ok(Some(Self::ecmqv(TPMS_KEY_SCHEME_ECMQV::default()))), + TPM_ALG_ID::RSASSA => Ok(Some(Self::rsassa(TPMS_SIG_SCHEME_RSASSA::default()))), + TPM_ALG_ID::RSAPSS => Ok(Some(Self::rsapss(TPMS_SIG_SCHEME_RSAPSS::default()))), + TPM_ALG_ID::ECDSA => Ok(Some(Self::ecdsa(TPMS_SIG_SCHEME_ECDSA::default()))), + TPM_ALG_ID::ECDAA => Ok(Some(Self::ecdaa(TPMS_SIG_SCHEME_ECDAA::default()))), + TPM_ALG_ID::SM2 => Ok(Some(Self::sm2(TPMS_SIG_SCHEME_SM2::default()))), + TPM_ALG_ID::ECSCHNORR => Ok(Some(Self::ecschnorr(TPMS_SIG_SCHEME_ECSCHNORR::default()))), + TPM_ALG_ID::RSAES => Ok(Some(Self::rsaes(TPMS_ENC_SCHEME_RSAES::default()))), + TPM_ALG_ID::OAEP => Ok(Some(Self::oaep(TPMS_ENC_SCHEME_OAEP::default()))), + TPM_ALG_ID::ANY => Ok(Some(Self::anySig(TPMS_SCHEME_HASH::default()))), + TPM_ALG_ID::NULL => Ok(Some(Self::null(TPMS_NULL_ASYM_SCHEME::default()))), + _ => Err(TpmError::InvalidUnion), + } + } +} + +impl fmt::Debug for TPMU_ASYM_SCHEME { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::ecdh(inner) => write!(f, "TPMU_ASYM_SCHEME::ecdh({:?})", inner), + Self::ecmqv(inner) => write!(f, "TPMU_ASYM_SCHEME::ecmqv({:?})", inner), + Self::rsassa(inner) => write!(f, "TPMU_ASYM_SCHEME::rsassa({:?})", inner), + Self::rsapss(inner) => write!(f, "TPMU_ASYM_SCHEME::rsapss({:?})", inner), + Self::ecdsa(inner) => write!(f, "TPMU_ASYM_SCHEME::ecdsa({:?})", inner), + Self::ecdaa(inner) => write!(f, "TPMU_ASYM_SCHEME::ecdaa({:?})", inner), + Self::sm2(inner) => write!(f, "TPMU_ASYM_SCHEME::sm2({:?})", inner), + Self::ecschnorr(inner) => write!(f, "TPMU_ASYM_SCHEME::ecschnorr({:?})", inner), + Self::rsaes(inner) => write!(f, "TPMU_ASYM_SCHEME::rsaes({:?})", inner), + Self::oaep(inner) => write!(f, "TPMU_ASYM_SCHEME::oaep({:?})", inner), + Self::anySig(inner) => write!(f, "TPMU_ASYM_SCHEME::anySig({:?})", inner), + Self::null(inner) => write!(f, "TPMU_ASYM_SCHEME::null({:?})", inner), + } + } +} +impl TpmStructure for TPMU_ASYM_SCHEME { + fn serialize(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::ecdh(inner) => inner.serialize(buffer), + Self::ecmqv(inner) => inner.serialize(buffer), + Self::rsassa(inner) => inner.serialize(buffer), + Self::rsapss(inner) => inner.serialize(buffer), + Self::ecdsa(inner) => inner.serialize(buffer), + Self::ecdaa(inner) => inner.serialize(buffer), + Self::sm2(inner) => inner.serialize(buffer), + Self::ecschnorr(inner) => inner.serialize(buffer), + Self::rsaes(inner) => inner.serialize(buffer), + Self::oaep(inner) => inner.serialize(buffer), + Self::anySig(inner) => inner.serialize(buffer), + Self::null(inner) => inner.serialize(buffer), + } + } + + fn deserialize(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::ecdh(inner) => inner.deserialize(buffer), + Self::ecmqv(inner) => inner.deserialize(buffer), + Self::rsassa(inner) => inner.deserialize(buffer), + Self::rsapss(inner) => inner.deserialize(buffer), + Self::ecdsa(inner) => inner.deserialize(buffer), + Self::ecdaa(inner) => inner.deserialize(buffer), + Self::sm2(inner) => inner.deserialize(buffer), + Self::ecschnorr(inner) => inner.deserialize(buffer), + Self::rsaes(inner) => inner.deserialize(buffer), + Self::oaep(inner) => inner.deserialize(buffer), + Self::anySig(inner) => inner.deserialize(buffer), + Self::null(inner) => inner.deserialize(buffer), + } + } + + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::ecdh(inner) => inner.fromTpm(buffer), + Self::ecmqv(inner) => inner.fromTpm(buffer), + Self::rsassa(inner) => inner.fromTpm(buffer), + Self::rsapss(inner) => inner.fromTpm(buffer), + Self::ecdsa(inner) => inner.fromTpm(buffer), + Self::ecdaa(inner) => inner.fromTpm(buffer), + Self::sm2(inner) => inner.fromTpm(buffer), + Self::ecschnorr(inner) => inner.fromTpm(buffer), + Self::rsaes(inner) => inner.fromTpm(buffer), + Self::oaep(inner) => inner.fromTpm(buffer), + Self::anySig(inner) => inner.fromTpm(buffer), + Self::null(inner) => inner.fromTpm(buffer), + } + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + match self { + Self::ecdh(inner) => inner.fromBytes(buffer), + Self::ecmqv(inner) => inner.fromBytes(buffer), + Self::rsassa(inner) => inner.fromBytes(buffer), + Self::rsapss(inner) => inner.fromBytes(buffer), + Self::ecdsa(inner) => inner.fromBytes(buffer), + Self::ecdaa(inner) => inner.fromBytes(buffer), + Self::sm2(inner) => inner.fromBytes(buffer), + Self::ecschnorr(inner) => inner.fromBytes(buffer), + Self::rsaes(inner) => inner.fromBytes(buffer), + Self::oaep(inner) => inner.fromBytes(buffer), + Self::anySig(inner) => inner.fromBytes(buffer), + Self::null(inner) => inner.fromBytes(buffer), + } + } + +} + +impl TpmMarshaller for TPMU_ASYM_SCHEME { + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::ecdh(inner) => inner.toTpm(buffer), + Self::ecmqv(inner) => inner.toTpm(buffer), + Self::rsassa(inner) => inner.toTpm(buffer), + Self::rsapss(inner) => inner.toTpm(buffer), + Self::ecdsa(inner) => inner.toTpm(buffer), + Self::ecdaa(inner) => inner.toTpm(buffer), + Self::sm2(inner) => inner.toTpm(buffer), + Self::ecschnorr(inner) => inner.toTpm(buffer), + Self::rsaes(inner) => inner.toTpm(buffer), + Self::oaep(inner) => inner.toTpm(buffer), + Self::anySig(inner) => inner.toTpm(buffer), + Self::null(inner) => inner.toTpm(buffer), + } + } + + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::ecdh(inner) => inner.initFromTpm(buffer), + Self::ecmqv(inner) => inner.initFromTpm(buffer), + Self::rsassa(inner) => inner.initFromTpm(buffer), + Self::rsapss(inner) => inner.initFromTpm(buffer), + Self::ecdsa(inner) => inner.initFromTpm(buffer), + Self::ecdaa(inner) => inner.initFromTpm(buffer), + Self::sm2(inner) => inner.initFromTpm(buffer), + Self::ecschnorr(inner) => inner.initFromTpm(buffer), + Self::rsaes(inner) => inner.initFromTpm(buffer), + Self::oaep(inner) => inner.initFromTpm(buffer), + Self::anySig(inner) => inner.initFromTpm(buffer), + Self::null(inner) => inner.initFromTpm(buffer), + } + } + +} + +/// A TPMU_SIGNATURE_COMPOSITE is a union of the various signatures that are supported by +/// a particular TPM implementation. The union allows substitution of any signature +/// algorithm wherever a signature is required in a structure. +/// One of: TPMS_SIGNATURE_RSASSA, TPMS_SIGNATURE_RSAPSS, TPMS_SIGNATURE_ECDSA, +/// TPMS_SIGNATURE_ECDAA, TPMS_SIGNATURE_SM2, TPMS_SIGNATURE_ECSCHNORR, TPMT_HA, +/// TPMS_SCHEME_HASH, TPMS_NULL_SIGNATURE. +#[derive(Clone)] +pub enum TPMU_SIGNATURE { + rsassa(TPMS_SIGNATURE_RSASSA), + rsapss(TPMS_SIGNATURE_RSAPSS), + ecdsa(TPMS_SIGNATURE_ECDSA), + ecdaa(TPMS_SIGNATURE_ECDAA), + sm2(TPMS_SIGNATURE_SM2), + ecschnorr(TPMS_SIGNATURE_ECSCHNORR), + hmac(TPMT_HA), + any(TPMS_SCHEME_HASH), + null(TPMS_NULL_SIGNATURE), +} + +/// Union selector type +impl TPMU_SIGNATURE { + pub fn GetUnionSelector(&self) -> TPM_ALG_ID { + match self { + Self::rsassa(_) => TPMS_SIGNATURE_RSASSA::GetUnionSelector(), + Self::rsapss(_) => TPMS_SIGNATURE_RSAPSS::GetUnionSelector(), + Self::ecdsa(_) => TPMS_SIGNATURE_ECDSA::GetUnionSelector(), + Self::ecdaa(_) => TPMS_SIGNATURE_ECDAA::GetUnionSelector(), + Self::sm2(_) => TPMS_SIGNATURE_SM2::GetUnionSelector(), + Self::ecschnorr(_) => TPMS_SIGNATURE_ECSCHNORR::GetUnionSelector(), + Self::hmac(_) => TPMT_HA::GetUnionSelector(), + Self::any(_) => TPMS_SCHEME_HASH::GetUnionSelector(), + Self::null(_) => TPMS_NULL_SIGNATURE::GetUnionSelector(), + } + } + + pub fn create(selector: TPM_ALG_ID) -> Result, TpmError> { + match selector { + TPM_ALG_ID::RSASSA => Ok(Some(Self::rsassa(TPMS_SIGNATURE_RSASSA::default()))), + TPM_ALG_ID::RSAPSS => Ok(Some(Self::rsapss(TPMS_SIGNATURE_RSAPSS::default()))), + TPM_ALG_ID::ECDSA => Ok(Some(Self::ecdsa(TPMS_SIGNATURE_ECDSA::default()))), + TPM_ALG_ID::ECDAA => Ok(Some(Self::ecdaa(TPMS_SIGNATURE_ECDAA::default()))), + TPM_ALG_ID::SM2 => Ok(Some(Self::sm2(TPMS_SIGNATURE_SM2::default()))), + TPM_ALG_ID::ECSCHNORR => Ok(Some(Self::ecschnorr(TPMS_SIGNATURE_ECSCHNORR::default()))), + TPM_ALG_ID::HMAC => Ok(Some(Self::hmac(TPMT_HA::default()))), + TPM_ALG_ID::ANY => Ok(Some(Self::any(TPMS_SCHEME_HASH::default()))), + TPM_ALG_ID::NULL => Ok(Some(Self::null(TPMS_NULL_SIGNATURE::default()))), + _ => Err(TpmError::InvalidUnion), + } + } +} + +impl fmt::Debug for TPMU_SIGNATURE { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::rsassa(inner) => write!(f, "TPMU_SIGNATURE::rsassa({:?})", inner), + Self::rsapss(inner) => write!(f, "TPMU_SIGNATURE::rsapss({:?})", inner), + Self::ecdsa(inner) => write!(f, "TPMU_SIGNATURE::ecdsa({:?})", inner), + Self::ecdaa(inner) => write!(f, "TPMU_SIGNATURE::ecdaa({:?})", inner), + Self::sm2(inner) => write!(f, "TPMU_SIGNATURE::sm2({:?})", inner), + Self::ecschnorr(inner) => write!(f, "TPMU_SIGNATURE::ecschnorr({:?})", inner), + Self::hmac(inner) => write!(f, "TPMU_SIGNATURE::hmac({:?})", inner), + Self::any(inner) => write!(f, "TPMU_SIGNATURE::any({:?})", inner), + Self::null(inner) => write!(f, "TPMU_SIGNATURE::null({:?})", inner), + } + } +} +impl TpmStructure for TPMU_SIGNATURE { + fn serialize(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::rsassa(inner) => inner.serialize(buffer), + Self::rsapss(inner) => inner.serialize(buffer), + Self::ecdsa(inner) => inner.serialize(buffer), + Self::ecdaa(inner) => inner.serialize(buffer), + Self::sm2(inner) => inner.serialize(buffer), + Self::ecschnorr(inner) => inner.serialize(buffer), + Self::hmac(inner) => inner.serialize(buffer), + Self::any(inner) => inner.serialize(buffer), + Self::null(inner) => inner.serialize(buffer), + } + } + + fn deserialize(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::rsassa(inner) => inner.deserialize(buffer), + Self::rsapss(inner) => inner.deserialize(buffer), + Self::ecdsa(inner) => inner.deserialize(buffer), + Self::ecdaa(inner) => inner.deserialize(buffer), + Self::sm2(inner) => inner.deserialize(buffer), + Self::ecschnorr(inner) => inner.deserialize(buffer), + Self::hmac(inner) => inner.deserialize(buffer), + Self::any(inner) => inner.deserialize(buffer), + Self::null(inner) => inner.deserialize(buffer), + } + } + + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::rsassa(inner) => inner.fromTpm(buffer), + Self::rsapss(inner) => inner.fromTpm(buffer), + Self::ecdsa(inner) => inner.fromTpm(buffer), + Self::ecdaa(inner) => inner.fromTpm(buffer), + Self::sm2(inner) => inner.fromTpm(buffer), + Self::ecschnorr(inner) => inner.fromTpm(buffer), + Self::hmac(inner) => inner.fromTpm(buffer), + Self::any(inner) => inner.fromTpm(buffer), + Self::null(inner) => inner.fromTpm(buffer), + } + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + match self { + Self::rsassa(inner) => inner.fromBytes(buffer), + Self::rsapss(inner) => inner.fromBytes(buffer), + Self::ecdsa(inner) => inner.fromBytes(buffer), + Self::ecdaa(inner) => inner.fromBytes(buffer), + Self::sm2(inner) => inner.fromBytes(buffer), + Self::ecschnorr(inner) => inner.fromBytes(buffer), + Self::hmac(inner) => inner.fromBytes(buffer), + Self::any(inner) => inner.fromBytes(buffer), + Self::null(inner) => inner.fromBytes(buffer), + } + } + +} + +impl TpmMarshaller for TPMU_SIGNATURE { + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::rsassa(inner) => inner.toTpm(buffer), + Self::rsapss(inner) => inner.toTpm(buffer), + Self::ecdsa(inner) => inner.toTpm(buffer), + Self::ecdaa(inner) => inner.toTpm(buffer), + Self::sm2(inner) => inner.toTpm(buffer), + Self::ecschnorr(inner) => inner.toTpm(buffer), + Self::hmac(inner) => inner.toTpm(buffer), + Self::any(inner) => inner.toTpm(buffer), + Self::null(inner) => inner.toTpm(buffer), + } + } + + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::rsassa(inner) => inner.initFromTpm(buffer), + Self::rsapss(inner) => inner.initFromTpm(buffer), + Self::ecdsa(inner) => inner.initFromTpm(buffer), + Self::ecdaa(inner) => inner.initFromTpm(buffer), + Self::sm2(inner) => inner.initFromTpm(buffer), + Self::ecschnorr(inner) => inner.initFromTpm(buffer), + Self::hmac(inner) => inner.initFromTpm(buffer), + Self::any(inner) => inner.initFromTpm(buffer), + Self::null(inner) => inner.initFromTpm(buffer), + } + } + +} + +/// This is the union of all values allowed in in the unique field of a TPMT_PUBLIC. +/// One of: TPM2B_DIGEST_KEYEDHASH, TPM2B_DIGEST_SYMCIPHER, TPM2B_PUBLIC_KEY_RSA, +/// TPMS_ECC_POINT, TPMS_DERIVE. +#[derive(Clone)] +pub enum TPMU_PUBLIC_ID { + keyedHash(TPM2B_DIGEST_KEYEDHASH), + sym(TPM2B_DIGEST_SYMCIPHER), + rsa(TPM2B_PUBLIC_KEY_RSA), + ecc(TPMS_ECC_POINT), + derive(TPMS_DERIVE), +} + +/// Union selector type +impl TPMU_PUBLIC_ID { + pub fn GetUnionSelector(&self) -> TPM_ALG_ID { + match self { + Self::keyedHash(_) => TPM2B_DIGEST_KEYEDHASH::GetUnionSelector(), + Self::sym(_) => TPM2B_DIGEST_SYMCIPHER::GetUnionSelector(), + Self::rsa(_) => TPM2B_PUBLIC_KEY_RSA::GetUnionSelector(), + Self::ecc(_) => TPMS_ECC_POINT::GetUnionSelector(), + Self::derive(_) => TPMS_DERIVE::GetUnionSelector(), + } + } + + pub fn create(selector: TPM_ALG_ID) -> Result, TpmError> { + match selector { + TPM_ALG_ID::KEYEDHASH => Ok(Some(Self::keyedHash(TPM2B_DIGEST_KEYEDHASH::default()))), + TPM_ALG_ID::SYMCIPHER => Ok(Some(Self::sym(TPM2B_DIGEST_SYMCIPHER::default()))), + TPM_ALG_ID::RSA => Ok(Some(Self::rsa(TPM2B_PUBLIC_KEY_RSA::default()))), + TPM_ALG_ID::ECC => Ok(Some(Self::ecc(TPMS_ECC_POINT::default()))), + TPM_ALG_ID::ANY => Ok(Some(Self::derive(TPMS_DERIVE::default()))), + _ => Err(TpmError::InvalidUnion), + } + } +} + +impl fmt::Debug for TPMU_PUBLIC_ID { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::keyedHash(inner) => write!(f, "TPMU_PUBLIC_ID::keyedHash({:?})", inner), + Self::sym(inner) => write!(f, "TPMU_PUBLIC_ID::sym({:?})", inner), + Self::rsa(inner) => write!(f, "TPMU_PUBLIC_ID::rsa({:?})", inner), + Self::ecc(inner) => write!(f, "TPMU_PUBLIC_ID::ecc({:?})", inner), + Self::derive(inner) => write!(f, "TPMU_PUBLIC_ID::derive({:?})", inner), + } + } +} +impl TpmStructure for TPMU_PUBLIC_ID { + fn serialize(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::keyedHash(inner) => inner.serialize(buffer), + Self::sym(inner) => inner.serialize(buffer), + Self::rsa(inner) => inner.serialize(buffer), + Self::ecc(inner) => inner.serialize(buffer), + Self::derive(inner) => inner.serialize(buffer), + } + } + + fn deserialize(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::keyedHash(inner) => inner.deserialize(buffer), + Self::sym(inner) => inner.deserialize(buffer), + Self::rsa(inner) => inner.deserialize(buffer), + Self::ecc(inner) => inner.deserialize(buffer), + Self::derive(inner) => inner.deserialize(buffer), + } + } + + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::keyedHash(inner) => inner.fromTpm(buffer), + Self::sym(inner) => inner.fromTpm(buffer), + Self::rsa(inner) => inner.fromTpm(buffer), + Self::ecc(inner) => inner.fromTpm(buffer), + Self::derive(inner) => inner.fromTpm(buffer), + } + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + match self { + Self::keyedHash(inner) => inner.fromBytes(buffer), + Self::sym(inner) => inner.fromBytes(buffer), + Self::rsa(inner) => inner.fromBytes(buffer), + Self::ecc(inner) => inner.fromBytes(buffer), + Self::derive(inner) => inner.fromBytes(buffer), + } + } + +} + +impl TpmMarshaller for TPMU_PUBLIC_ID { + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::keyedHash(inner) => inner.toTpm(buffer), + Self::sym(inner) => inner.toTpm(buffer), + Self::rsa(inner) => inner.toTpm(buffer), + Self::ecc(inner) => inner.toTpm(buffer), + Self::derive(inner) => inner.toTpm(buffer), + } + } + + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::keyedHash(inner) => inner.initFromTpm(buffer), + Self::sym(inner) => inner.initFromTpm(buffer), + Self::rsa(inner) => inner.initFromTpm(buffer), + Self::ecc(inner) => inner.initFromTpm(buffer), + Self::derive(inner) => inner.initFromTpm(buffer), + } + } + +} + +/// Table 199 defines the possible parameter definition structures that may be contained +/// in the public portion of a key. If the Object can be a parent, the first field must be +/// a TPMT_SYM_DEF_OBJECT. See 11.1.7. +/// One of: TPMS_KEYEDHASH_PARMS, TPMS_SYMCIPHER_PARMS, TPMS_RSA_PARMS, TPMS_ECC_PARMS, +/// TPMS_ASYM_PARMS. +#[derive(Clone)] +pub enum TPMU_PUBLIC_PARMS { + keyedHashDetail(TPMS_KEYEDHASH_PARMS), + symDetail(TPMS_SYMCIPHER_PARMS), + rsaDetail(TPMS_RSA_PARMS), + eccDetail(TPMS_ECC_PARMS), + asymDetail(TPMS_ASYM_PARMS), +} + +/// Union selector type +impl TPMU_PUBLIC_PARMS { + pub fn GetUnionSelector(&self) -> TPM_ALG_ID { + match self { + Self::keyedHashDetail(_) => TPMS_KEYEDHASH_PARMS::GetUnionSelector(), + Self::symDetail(_) => TPMS_SYMCIPHER_PARMS::GetUnionSelector(), + Self::rsaDetail(_) => TPMS_RSA_PARMS::GetUnionSelector(), + Self::eccDetail(_) => TPMS_ECC_PARMS::GetUnionSelector(), + Self::asymDetail(_) => TPMS_ASYM_PARMS::GetUnionSelector(), + } + } + + pub fn create(selector: TPM_ALG_ID) -> Result, TpmError> { + match selector { + TPM_ALG_ID::KEYEDHASH => Ok(Some(Self::keyedHashDetail(TPMS_KEYEDHASH_PARMS::default()))), + TPM_ALG_ID::SYMCIPHER => Ok(Some(Self::symDetail(TPMS_SYMCIPHER_PARMS::default()))), + TPM_ALG_ID::RSA => Ok(Some(Self::rsaDetail(TPMS_RSA_PARMS::default()))), + TPM_ALG_ID::ECC => Ok(Some(Self::eccDetail(TPMS_ECC_PARMS::default()))), + TPM_ALG_ID::ANY => Ok(Some(Self::asymDetail(TPMS_ASYM_PARMS::default()))), + _ => Err(TpmError::InvalidUnion), + } + } +} + +impl fmt::Debug for TPMU_PUBLIC_PARMS { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::keyedHashDetail(inner) => write!(f, "TPMU_PUBLIC_PARMS::keyedHashDetail({:?})", inner), + Self::symDetail(inner) => write!(f, "TPMU_PUBLIC_PARMS::symDetail({:?})", inner), + Self::rsaDetail(inner) => write!(f, "TPMU_PUBLIC_PARMS::rsaDetail({:?})", inner), + Self::eccDetail(inner) => write!(f, "TPMU_PUBLIC_PARMS::eccDetail({:?})", inner), + Self::asymDetail(inner) => write!(f, "TPMU_PUBLIC_PARMS::asymDetail({:?})", inner), + } + } +} +impl TpmStructure for TPMU_PUBLIC_PARMS { + fn serialize(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::keyedHashDetail(inner) => inner.serialize(buffer), + Self::symDetail(inner) => inner.serialize(buffer), + Self::rsaDetail(inner) => inner.serialize(buffer), + Self::eccDetail(inner) => inner.serialize(buffer), + Self::asymDetail(inner) => inner.serialize(buffer), + } + } + + fn deserialize(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::keyedHashDetail(inner) => inner.deserialize(buffer), + Self::symDetail(inner) => inner.deserialize(buffer), + Self::rsaDetail(inner) => inner.deserialize(buffer), + Self::eccDetail(inner) => inner.deserialize(buffer), + Self::asymDetail(inner) => inner.deserialize(buffer), + } + } + + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::keyedHashDetail(inner) => inner.fromTpm(buffer), + Self::symDetail(inner) => inner.fromTpm(buffer), + Self::rsaDetail(inner) => inner.fromTpm(buffer), + Self::eccDetail(inner) => inner.fromTpm(buffer), + Self::asymDetail(inner) => inner.fromTpm(buffer), + } + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + match self { + Self::keyedHashDetail(inner) => inner.fromBytes(buffer), + Self::symDetail(inner) => inner.fromBytes(buffer), + Self::rsaDetail(inner) => inner.fromBytes(buffer), + Self::eccDetail(inner) => inner.fromBytes(buffer), + Self::asymDetail(inner) => inner.fromBytes(buffer), + } + } + +} + +impl TpmMarshaller for TPMU_PUBLIC_PARMS { + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::keyedHashDetail(inner) => inner.toTpm(buffer), + Self::symDetail(inner) => inner.toTpm(buffer), + Self::rsaDetail(inner) => inner.toTpm(buffer), + Self::eccDetail(inner) => inner.toTpm(buffer), + Self::asymDetail(inner) => inner.toTpm(buffer), + } + } + + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::keyedHashDetail(inner) => inner.initFromTpm(buffer), + Self::symDetail(inner) => inner.initFromTpm(buffer), + Self::rsaDetail(inner) => inner.initFromTpm(buffer), + Self::eccDetail(inner) => inner.initFromTpm(buffer), + Self::asymDetail(inner) => inner.initFromTpm(buffer), + } + } + +} + +/// Table 205 Definition of TPMU_SENSITIVE_COMPOSITE Union [IN/OUT] +/// One of: TPM2B_PRIVATE_KEY_RSA, TPM2B_ECC_PARAMETER, TPM2B_SENSITIVE_DATA, +/// TPM2B_SYM_KEY, TPM2B_PRIVATE_VENDOR_SPECIFIC. +#[derive(Clone)] +pub enum TPMU_SENSITIVE_COMPOSITE { + rsa(TPM2B_PRIVATE_KEY_RSA), + ecc(TPM2B_ECC_PARAMETER), + bits(TPM2B_SENSITIVE_DATA), + sym(TPM2B_SYM_KEY), + any(TPM2B_PRIVATE_VENDOR_SPECIFIC), +} + +/// Union selector type +impl TPMU_SENSITIVE_COMPOSITE { + pub fn GetUnionSelector(&self) -> TPM_ALG_ID { + match self { + Self::rsa(_) => TPM2B_PRIVATE_KEY_RSA::GetUnionSelector(), + Self::ecc(_) => TPM2B_ECC_PARAMETER::GetUnionSelector(), + Self::bits(_) => TPM2B_SENSITIVE_DATA::GetUnionSelector(), + Self::sym(_) => TPM2B_SYM_KEY::GetUnionSelector(), + Self::any(_) => TPM2B_PRIVATE_VENDOR_SPECIFIC::GetUnionSelector(), + } + } + + pub fn create(selector: TPM_ALG_ID) -> Result, TpmError> { + match selector { + TPM_ALG_ID::RSA => Ok(Some(Self::rsa(TPM2B_PRIVATE_KEY_RSA::default()))), + TPM_ALG_ID::ECC => Ok(Some(Self::ecc(TPM2B_ECC_PARAMETER::default()))), + TPM_ALG_ID::KEYEDHASH => Ok(Some(Self::bits(TPM2B_SENSITIVE_DATA::default()))), + TPM_ALG_ID::SYMCIPHER => Ok(Some(Self::sym(TPM2B_SYM_KEY::default()))), + TPM_ALG_ID::ANY => Ok(Some(Self::any(TPM2B_PRIVATE_VENDOR_SPECIFIC::default()))), + _ => Err(TpmError::InvalidUnion), + } + } +} + +impl fmt::Debug for TPMU_SENSITIVE_COMPOSITE { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::rsa(inner) => write!(f, "TPMU_SENSITIVE_COMPOSITE::rsa({:?})", inner), + Self::ecc(inner) => write!(f, "TPMU_SENSITIVE_COMPOSITE::ecc({:?})", inner), + Self::bits(inner) => write!(f, "TPMU_SENSITIVE_COMPOSITE::bits({:?})", inner), + Self::sym(inner) => write!(f, "TPMU_SENSITIVE_COMPOSITE::sym({:?})", inner), + Self::any(inner) => write!(f, "TPMU_SENSITIVE_COMPOSITE::any({:?})", inner), + } + } +} +impl TpmStructure for TPMU_SENSITIVE_COMPOSITE { + fn serialize(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::rsa(inner) => inner.serialize(buffer), + Self::ecc(inner) => inner.serialize(buffer), + Self::bits(inner) => inner.serialize(buffer), + Self::sym(inner) => inner.serialize(buffer), + Self::any(inner) => inner.serialize(buffer), + } + } + + fn deserialize(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::rsa(inner) => inner.deserialize(buffer), + Self::ecc(inner) => inner.deserialize(buffer), + Self::bits(inner) => inner.deserialize(buffer), + Self::sym(inner) => inner.deserialize(buffer), + Self::any(inner) => inner.deserialize(buffer), + } + } + + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::rsa(inner) => inner.fromTpm(buffer), + Self::ecc(inner) => inner.fromTpm(buffer), + Self::bits(inner) => inner.fromTpm(buffer), + Self::sym(inner) => inner.fromTpm(buffer), + Self::any(inner) => inner.fromTpm(buffer), + } + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + match self { + Self::rsa(inner) => inner.fromBytes(buffer), + Self::ecc(inner) => inner.fromBytes(buffer), + Self::bits(inner) => inner.fromBytes(buffer), + Self::sym(inner) => inner.fromBytes(buffer), + Self::any(inner) => inner.fromBytes(buffer), + } + } + +} + +impl TpmMarshaller for TPMU_SENSITIVE_COMPOSITE { + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::rsa(inner) => inner.toTpm(buffer), + Self::ecc(inner) => inner.toTpm(buffer), + Self::bits(inner) => inner.toTpm(buffer), + Self::sym(inner) => inner.toTpm(buffer), + Self::any(inner) => inner.toTpm(buffer), + } + } + + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + match self { + Self::rsa(inner) => inner.initFromTpm(buffer), + Self::ecc(inner) => inner.initFromTpm(buffer), + Self::bits(inner) => inner.initFromTpm(buffer), + Self::sym(inner) => inner.initFromTpm(buffer), + Self::any(inner) => inner.initFromTpm(buffer), + } + } + +} + +/// Handle of a loaded TPM key or other object [TSS] +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM_HANDLE { + /// Handle value + #[derivative(Default(value="TPM_RH::NULL.into()"))] + pub handle: u32, + + /// The authorization value associated with this handle + pub auth_value: Vec, + + /// The name associated with this handle + pub name: Vec, +} + +impl TPM_HANDLE { + /// Creates a new instance with the specified values + pub fn new( + handle: u32, + ) -> Self { + Self { + handle: handle.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM_HANDLE { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeInt(self.handle as u32); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.handle = buf.readInt() as u32; + Ok(()) + } + +} + +impl TpmMarshaller for TPM_HANDLE { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// Base class for empty union elements. +/// An empty union element does not contain any data to marshal. +/// This data structure can be used in place of any other union +/// initialized with its own empty element. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_NULL_UNION { +} + +impl TPMS_NULL_UNION { + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::NULL + } +} + +impl TpmStructure for TPMS_NULL_UNION { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_NULL_UNION { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This structure is used as a placeholder. In some cases, a union will have a selector +/// value with no data to unmarshal when that type is selected. Rather than leave the +/// entry empty, TPMS_EMPTY may be selected. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_EMPTY { +} + +impl TPMS_EMPTY { + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::RSAES + } +} + +impl TpmStructure for TPMS_EMPTY { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_EMPTY { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This structure is a return value for a TPM2_GetCapability() that reads the installed algorithms. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_ALGORITHM_DESCRIPTION { + /// An algorithm + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub alg: TPM_ALG_ID, + + /// The attributes of the algorithm + pub attributes: TPMA_ALGORITHM, +} + +impl TPMS_ALGORITHM_DESCRIPTION { + /// Creates a new instance with the specified values + pub fn new( + alg: TPM_ALG_ID, + attributes: TPMA_ALGORITHM, + ) -> Self { + Self { + alg: alg.clone(), + attributes: attributes.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPMS_ALGORITHM_DESCRIPTION { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeShort(self.alg.into()); + buf.writeInt(self.attributes.into()); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.alg = TPM_ALG_ID(buf.readShort() as u16); + self.attributes = TPMA_ALGORITHM(buf.readInt() as u32); + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_ALGORITHM_DESCRIPTION { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// Table 80 shows the basic hash-agile structure used in this specification. To handle +/// hash agility, this structure uses the hashAlg parameter to indicate the algorithm used +/// to compute the digest and, by implication, the size of the digest. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMT_HA { + /// Selector of the hash contained in the digest that implies the size of the digest + /// NOTE The leading + on the type indicates that this structure should pass an indication + /// to the unmarshaling function for TPMI_ALG_HASH so that TPM_ALG_NULL will be allowed if + /// a use of a TPMT_HA allows TPM_ALG_NULL. + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub hashAlg: TPM_ALG_ID, + + /// Hash value + pub digest: Vec, +} + +impl TPMT_HA { + /// Creates a new instance with the specified values + pub fn new( + hashAlg: TPM_ALG_ID, + digest: &Vec, + ) -> Self { + Self { + hashAlg: hashAlg.clone(), + digest: digest.clone(), + ..Default::default() + } + } + + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::HMAC + } +} + +impl TpmStructure for TPMT_HA { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeShort(self.hashAlg.into()); + buf.writeByteBuf(&self.digest); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.hashAlg = TPM_ALG_ID(buf.readShort() as u16); + self.digest = buf.readByteBuf(Crypto::digestSize(self.hashAlg)); + Ok(()) + } + +} + +impl TpmMarshaller for TPMT_HA { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This structure is used for a sized buffer that cannot be larger than the largest +/// digest produced by any hash algorithm implemented on the TPM. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2B_DIGEST { + /// The buffer area that can be no larger than a digest + pub buffer: Vec, +} + +impl TPM2B_DIGEST { + /// Creates a new instance with the specified values + pub fn new( + buffer: &Vec, + ) -> Self { + Self { + buffer: buffer.clone(), + ..Default::default() + } + } + + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::KEYEDHASH + } +} + +impl TpmStructure for TPM2B_DIGEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.buffer, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.buffer = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2B_DIGEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This structure is used for a data buffer that is required to be no larger than the +/// size of the Name of an object. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2B_DATA { + pub buffer: Vec, +} + +impl TPM2B_DATA { + /// Creates a new instance with the specified values + pub fn new( + buffer: &Vec, + ) -> Self { + Self { + buffer: buffer.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2B_DATA { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.buffer, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.buffer = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2B_DATA { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// Table 83 Definition of Types for TPM2B_NONCE +pub type TPM2B_NONCE = TPM2B_DIGEST; + +/// This structure is used for an authorization value and limits an authValue to being no +/// larger than the largest digest produced by a TPM. In order to ensure consistency +/// within an object, the authValue may be no larger than the size of the digest produced +/// by the objects nameAlg. This ensures that any TPM that can load the object will be +/// able to handle the authValue of the object. +pub type TPM2B_AUTH = TPM2B_DIGEST; + +/// This type is a sized buffer that can hold an operand for a comparison with an NV Index +/// location. The maximum size of the operand is implementation dependent but a TPM is +/// required to support an operand size that is at least as big as the digest produced by +/// any of the hash algorithms implemented on the TPM. +pub type TPM2B_OPERAND = TPM2B_DIGEST; + +/// This type is a sized buffer that can hold event data. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2B_EVENT { + /// The operand + pub buffer: Vec, +} + +impl TPM2B_EVENT { + /// Creates a new instance with the specified values + pub fn new( + buffer: &Vec, + ) -> Self { + Self { + buffer: buffer.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2B_EVENT { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.buffer, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.buffer = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2B_EVENT { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This type is a sized buffer that can hold a maximally sized buffer for commands that +/// use a large data buffer such as TPM2_Hash(), TPM2_SequenceUpdate(), or TPM2_FieldUpgradeData(). +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2B_MAX_BUFFER { + /// The operand + pub buffer: Vec, +} + +impl TPM2B_MAX_BUFFER { + /// Creates a new instance with the specified values + pub fn new( + buffer: &Vec, + ) -> Self { + Self { + buffer: buffer.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2B_MAX_BUFFER { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.buffer, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.buffer = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2B_MAX_BUFFER { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This type is a sized buffer that can hold a maximally sized buffer for NV data +/// commands such as TPM2_NV_Read(), TPM2_NV_Write(), and TPM2_NV_Certify(). +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2B_MAX_NV_BUFFER { + /// The operand + /// NOTE MAX_NV_BUFFER_SIZE is TPM-dependent + pub buffer: Vec, +} + +impl TPM2B_MAX_NV_BUFFER { + /// Creates a new instance with the specified values + pub fn new( + buffer: &Vec, + ) -> Self { + Self { + buffer: buffer.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2B_MAX_NV_BUFFER { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.buffer, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.buffer = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2B_MAX_NV_BUFFER { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This TPM-dependent structure is used to provide the timeout value for an +/// authorization. The size shall be 8 or less. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2B_TIMEOUT { + /// The timeout value + pub buffer: Vec, +} + +impl TPM2B_TIMEOUT { + /// Creates a new instance with the specified values + pub fn new( + buffer: &Vec, + ) -> Self { + Self { + buffer: buffer.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2B_TIMEOUT { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.buffer, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.buffer = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2B_TIMEOUT { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This structure is used for passing an initial value for a symmetric block cipher to or +/// from the TPM. The size is set to be the largest block size of any implemented +/// symmetric cipher implemented on the TPM. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2B_IV { + /// The IV value + pub buffer: Vec, +} + +impl TPM2B_IV { + /// Creates a new instance with the specified values + pub fn new( + buffer: &Vec, + ) -> Self { + Self { + buffer: buffer.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2B_IV { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.buffer, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.buffer = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2B_IV { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This buffer holds a Name for any entity type. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2B_NAME { + /// The Name structure + pub name: Vec, +} + +impl TPM2B_NAME { + /// Creates a new instance with the specified values + pub fn new( + name: &Vec, + ) -> Self { + Self { + name: name.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2B_NAME { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.name, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.name = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2B_NAME { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This structure provides a standard method of specifying a list of PCR. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_PCR_SELECT { + /// The bit map of selected PCR + pub pcrSelect: Vec, +} + +impl TPMS_PCR_SELECT { + /// Creates a new instance with the specified values + pub fn new( + pcrSelect: &Vec, + ) -> Self { + Self { + pcrSelect: pcrSelect.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPMS_PCR_SELECT { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.pcrSelect, 1); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.pcrSelect = buf.readSizedByteBuf(1); + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_PCR_SELECT { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// Table 94 Definition of TPMS_PCR_SELECTION Structure +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_PCR_SELECTION { + /// The hash algorithm associated with the selection + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub hash: TPM_ALG_ID, + + /// The bit map of selected PCR + pub pcrSelect: Vec, +} + +impl TPMS_PCR_SELECTION { + /// Creates a new instance with the specified values + pub fn new( + hash: TPM_ALG_ID, + pcrSelect: &Vec, + ) -> Self { + Self { + hash: hash.clone(), + pcrSelect: pcrSelect.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPMS_PCR_SELECTION { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeShort(self.hash.into()); + buf.writeSizedByteBuf(&self.pcrSelect, 1); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.hash = TPM_ALG_ID(buf.readShort() as u16); + self.pcrSelect = buf.readSizedByteBuf(1); + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_PCR_SELECTION { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This ticket is produced by TPM2_Create() or TPM2_CreatePrimary(). It is used to bind +/// the creation data to the object to which it applies. The ticket is computed by +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMT_TK_CREATION { + /// The hierarchy containing name + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub hierarchy: TPM_HANDLE, + + /// This shall be the HMAC produced using a proof value of hierarchy. + pub digest: Vec, +} + +impl TPMT_TK_CREATION { + /// Creates a new instance with the specified values + pub fn new( + hierarchy: &TPM_HANDLE, + digest: &Vec, + ) -> Self { + Self { + hierarchy: hierarchy.clone(), + digest: digest.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPMT_TK_CREATION { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeShort(TPM_ST::CREATION.into()); + self.hierarchy.toTpm(buf)?; + buf.writeSizedByteBuf(&self.digest, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readShort(); + self.hierarchy.initFromTpm(buf)?; + self.digest = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPMT_TK_CREATION { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This ticket is produced by TPM2_VerifySignature(). This formulation is used for +/// multiple ticket uses. The ticket provides evidence that the TPM has validated that a +/// digest was signed by a key with the Name of keyName. The ticket is computed by +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMT_TK_VERIFIED { + /// The hierarchy containing keyName + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub hierarchy: TPM_HANDLE, + + /// This shall be the HMAC produced using a proof value of hierarchy. + pub digest: Vec, +} + +impl TPMT_TK_VERIFIED { + /// Creates a new instance with the specified values + pub fn new( + hierarchy: &TPM_HANDLE, + digest: &Vec, + ) -> Self { + Self { + hierarchy: hierarchy.clone(), + digest: digest.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPMT_TK_VERIFIED { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeShort(TPM_ST::VERIFIED.into()); + self.hierarchy.toTpm(buf)?; + buf.writeSizedByteBuf(&self.digest, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readShort(); + self.hierarchy.initFromTpm(buf)?; + self.digest = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPMT_TK_VERIFIED { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This ticket is produced by TPM2_PolicySigned() and TPM2_PolicySecret() when the +/// authorization has an expiration time. If nonceTPM was provided in the policy command, +/// the ticket is computed by +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMT_TK_AUTH { + /// Ticket structure tag + pub tag: TPM_ST, + + /// The hierarchy of the object used to produce the ticket + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub hierarchy: TPM_HANDLE, + + /// This shall be the HMAC produced using a proof value of hierarchy. + pub digest: Vec, +} + +impl TPMT_TK_AUTH { + /// Creates a new instance with the specified values + pub fn new( + tag: TPM_ST, + hierarchy: &TPM_HANDLE, + digest: &Vec, + ) -> Self { + Self { + tag: tag.clone(), + hierarchy: hierarchy.clone(), + digest: digest.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPMT_TK_AUTH { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeShort(self.tag.into()); + self.hierarchy.toTpm(buf)?; + buf.writeSizedByteBuf(&self.digest, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.tag = TPM_ST(buf.readShort() as u16); + self.hierarchy.initFromTpm(buf)?; + self.digest = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPMT_TK_AUTH { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This ticket is produced by TPM2_SequenceComplete() or TPM2_Hash() when the message +/// that was digested did not start with TPM_GENERATED_VALUE. The ticket is computed by +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMT_TK_HASHCHECK { + /// The hierarchy + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub hierarchy: TPM_HANDLE, + + /// This shall be the HMAC produced using a proof value of hierarchy. + pub digest: Vec, +} + +impl TPMT_TK_HASHCHECK { + /// Creates a new instance with the specified values + pub fn new( + hierarchy: &TPM_HANDLE, + digest: &Vec, + ) -> Self { + Self { + hierarchy: hierarchy.clone(), + digest: digest.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPMT_TK_HASHCHECK { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeShort(TPM_ST::HASHCHECK.into()); + self.hierarchy.toTpm(buf)?; + buf.writeSizedByteBuf(&self.digest, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readShort(); + self.hierarchy.initFromTpm(buf)?; + self.digest = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPMT_TK_HASHCHECK { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This structure is used to report the properties of an algorithm identifier. It is +/// returned in response to a TPM2_GetCapability() with capability = TPM_CAP_ALG. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_ALG_PROPERTY { + /// An algorithm identifier + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub alg: TPM_ALG_ID, + + /// The attributes of the algorithm + pub algProperties: TPMA_ALGORITHM, +} + +impl TPMS_ALG_PROPERTY { + /// Creates a new instance with the specified values + pub fn new( + alg: TPM_ALG_ID, + algProperties: TPMA_ALGORITHM, + ) -> Self { + Self { + alg: alg.clone(), + algProperties: algProperties.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPMS_ALG_PROPERTY { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeShort(self.alg.into()); + buf.writeInt(self.algProperties.into()); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.alg = TPM_ALG_ID(buf.readShort() as u16); + self.algProperties = TPMA_ALGORITHM(buf.readInt() as u32); + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_ALG_PROPERTY { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This structure is used to report the properties that are UINT32 values. It is returned +/// in response to a TPM2_GetCapability(). +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_TAGGED_PROPERTY { + /// A property identifier + pub property: TPM_PT, + + /// The value of the property + pub value: u32, +} + +impl TPMS_TAGGED_PROPERTY { + /// Creates a new instance with the specified values + pub fn new( + property: TPM_PT, + value: u32, + ) -> Self { + Self { + property: property.clone(), + value: value.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPMS_TAGGED_PROPERTY { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeInt(self.property.into()); + buf.writeInt(self.value as u32); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.property = TPM_PT(buf.readInt() as u32); + self.value = buf.readInt() as u32; + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_TAGGED_PROPERTY { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This structure is used in TPM2_GetCapability() to return the attributes of the PCR. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_TAGGED_PCR_SELECT { + /// The property identifier + pub tag: TPM_PT_PCR, + + /// The bit map of PCR with the identified property + pub pcrSelect: Vec, +} + +impl TPMS_TAGGED_PCR_SELECT { + /// Creates a new instance with the specified values + pub fn new( + tag: TPM_PT_PCR, + pcrSelect: &Vec, + ) -> Self { + Self { + tag: tag.clone(), + pcrSelect: pcrSelect.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPMS_TAGGED_PCR_SELECT { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeInt(self.tag.into()); + buf.writeSizedByteBuf(&self.pcrSelect, 1); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.tag = TPM_PT_PCR(buf.readInt() as u32); + self.pcrSelect = buf.readSizedByteBuf(1); + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_TAGGED_PCR_SELECT { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This structure is used in TPM2_GetCapability() to return the policy associated with a +/// permanent handle. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_TAGGED_POLICY { + /// A permanent handle + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub handle: TPM_HANDLE, + + /// The policy algorithm and hash + pub policyHash: TPMT_HA, +} + +impl TPMS_TAGGED_POLICY { + /// Creates a new instance with the specified values + pub fn new( + handle: &TPM_HANDLE, + policyHash: &TPMT_HA, + ) -> Self { + Self { + handle: handle.clone(), + policyHash: policyHash.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPMS_TAGGED_POLICY { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + self.handle.toTpm(buf)?; + self.policyHash.toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.handle.initFromTpm(buf)?; + self.policyHash.initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_TAGGED_POLICY { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This structure is used in TPM2_GetCapability() to return the ACT data. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_ACT_DATA { + /// A permanent handle + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub handle: TPM_HANDLE, + + /// The current timeout of the ACT + pub timeout: u32, + + /// The state of the ACT + pub attributes: TPMA_ACT, +} + +impl TPMS_ACT_DATA { + /// Creates a new instance with the specified values + pub fn new( + handle: &TPM_HANDLE, + timeout: u32, + attributes: TPMA_ACT, + ) -> Self { + Self { + handle: handle.clone(), + timeout: timeout.clone(), + attributes: attributes.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPMS_ACT_DATA { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + self.handle.toTpm(buf)?; + buf.writeInt(self.timeout as u32); + buf.writeInt(self.attributes.into()); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.handle.initFromTpm(buf)?; + self.timeout = buf.readInt() as u32; + self.attributes = TPMA_ACT(buf.readInt() as u32); + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_ACT_DATA { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// A list of command codes may be input to the TPM or returned by the TPM depending on +/// the command. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPML_CC { + /// A list of command codes + /// The maximum only applies to a command code list in a command. The response size is + /// limited only by the size of the parameter buffer. + pub commandCodes: Vec, +} + +impl TPML_CC { + /// Creates a new instance with the specified values + pub fn new( + commandCodes: &Vec, + ) -> Self { + Self { + commandCodes: commandCodes.clone(), + ..Default::default() + } + } + + fn GetUnionSelector() -> TPM_CAP { + TPM_CAP::PP_COMMANDS + } +} + +impl TpmStructure for TPML_CC { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeValArr(self.commandCodes.as_ref(), 4); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readValArr(self.commandCodes.as_mut(), 4)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPML_CC { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This list is only used in TPM2_GetCapability(capability = TPM_CAP_COMMANDS). +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPML_CCA { + /// A list of command codes attributes + pub commandAttributes: Vec, +} + +impl TPML_CCA { + /// Creates a new instance with the specified values + pub fn new( + commandAttributes: &Vec, + ) -> Self { + Self { + commandAttributes: commandAttributes.clone(), + ..Default::default() + } + } + + fn GetUnionSelector() -> TPM_CAP { + TPM_CAP::COMMANDS + } +} + +impl TpmStructure for TPML_CCA { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeValArr(self.commandAttributes.as_ref(), 4); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readValArr(self.commandAttributes.as_mut(), 4)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPML_CCA { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This list is returned by TPM2_IncrementalSelfTest(). +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPML_ALG { + /// A list of algorithm IDs + /// The maximum only applies to an algorithm list in a command. The response size is + /// limited only by the size of the parameter buffer. + pub algorithms: Vec, +} + +impl TPML_ALG { + /// Creates a new instance with the specified values + pub fn new( + algorithms: &Vec, + ) -> Self { + Self { + algorithms: algorithms.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPML_ALG { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeValArr(self.algorithms.as_ref(), 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readValArr(self.algorithms.as_mut(), 2)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPML_ALG { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This structure is used when the TPM returns a list of loaded handles when the +/// capability in TPM2_GetCapability() is TPM_CAP_HANDLE. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPML_HANDLE { + /// An array of handles + pub handle: Vec, +} + +impl TPML_HANDLE { + /// Creates a new instance with the specified values + pub fn new( + handle: &Vec, + ) -> Self { + Self { + handle: handle.clone(), + ..Default::default() + } + } + + fn GetUnionSelector() -> TPM_CAP { + TPM_CAP::HANDLES + } +} + +impl TpmStructure for TPML_HANDLE { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeObjArr(self.handle.as_ref())?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readObjArr(self.handle.as_mut())?; + Ok(()) + } + +} + +impl TpmMarshaller for TPML_HANDLE { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This list is used to convey a list of digest values. This type is used in +/// TPM2_PolicyOR() and in TPM2_PCR_Read(). +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPML_DIGEST { + /// A list of digests + /// For TPM2_PolicyOR(), all digests will have been computed using the digest of the + /// policy session. For TPM2_PCR_Read(), each digest will be the size of the digest for + /// the bank containing the PCR. + pub digests: Vec, +} + +impl TPML_DIGEST { + /// Creates a new instance with the specified values + pub fn new( + digests: &Vec, + ) -> Self { + Self { + digests: digests.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPML_DIGEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeObjArr(self.digests.as_ref())?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readObjArr(self.digests.as_mut())?; + Ok(()) + } + +} + +impl TpmMarshaller for TPML_DIGEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This list is used to convey a list of digest values. This type is returned by +/// TPM2_PCR_Event() and TPM2_EventSequenceComplete() and is an input for TPM2_PCR_Extend(). +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPML_DIGEST_VALUES { + /// A list of tagged digests + pub digests: Vec, +} + +impl TPML_DIGEST_VALUES { + /// Creates a new instance with the specified values + pub fn new( + digests: &Vec, + ) -> Self { + Self { + digests: digests.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPML_DIGEST_VALUES { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeObjArr(self.digests.as_ref())?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readObjArr(self.digests.as_mut())?; + Ok(()) + } + +} + +impl TpmMarshaller for TPML_DIGEST_VALUES { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This list is used to indicate the PCR that are included in a selection when more than +/// one PCR value may be selected. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPML_PCR_SELECTION { + /// List of selections + pub pcrSelections: Vec, +} + +impl TPML_PCR_SELECTION { + /// Creates a new instance with the specified values + pub fn new( + pcrSelections: &Vec, + ) -> Self { + Self { + pcrSelections: pcrSelections.clone(), + ..Default::default() + } + } + + fn GetUnionSelector() -> TPM_CAP { + TPM_CAP::PCRS + } +} + +impl TpmStructure for TPML_PCR_SELECTION { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeObjArr(self.pcrSelections.as_ref())?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readObjArr(self.pcrSelections.as_mut())?; + Ok(()) + } + +} + +impl TpmMarshaller for TPML_PCR_SELECTION { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This list is used to report on a list of algorithm attributes. It is returned in a +/// TPM2_GetCapability(). +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPML_ALG_PROPERTY { + /// List of properties + pub algProperties: Vec, +} + +impl TPML_ALG_PROPERTY { + /// Creates a new instance with the specified values + pub fn new( + algProperties: &Vec, + ) -> Self { + Self { + algProperties: algProperties.clone(), + ..Default::default() + } + } + + fn GetUnionSelector() -> TPM_CAP { + TPM_CAP::ALGS + } +} + +impl TpmStructure for TPML_ALG_PROPERTY { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeObjArr(self.algProperties.as_ref())?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readObjArr(self.algProperties.as_mut())?; + Ok(()) + } + +} + +impl TpmMarshaller for TPML_ALG_PROPERTY { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This list is used to report on a list of properties that are TPMS_TAGGED_PROPERTY +/// values. It is returned by a TPM2_GetCapability(). +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPML_TAGGED_TPM_PROPERTY { + /// An array of tagged properties + pub tpmProperty: Vec, +} + +impl TPML_TAGGED_TPM_PROPERTY { + /// Creates a new instance with the specified values + pub fn new( + tpmProperty: &Vec, + ) -> Self { + Self { + tpmProperty: tpmProperty.clone(), + ..Default::default() + } + } + + fn GetUnionSelector() -> TPM_CAP { + TPM_CAP::TPM_PROPERTIES + } +} + +impl TpmStructure for TPML_TAGGED_TPM_PROPERTY { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeObjArr(self.tpmProperty.as_ref())?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readObjArr(self.tpmProperty.as_mut())?; + Ok(()) + } + +} + +impl TpmMarshaller for TPML_TAGGED_TPM_PROPERTY { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This list is used to report on a list of properties that are TPMS_PCR_SELECT values. +/// It is returned by a TPM2_GetCapability(). +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPML_TAGGED_PCR_PROPERTY { + /// A tagged PCR selection + pub pcrProperty: Vec, +} + +impl TPML_TAGGED_PCR_PROPERTY { + /// Creates a new instance with the specified values + pub fn new( + pcrProperty: &Vec, + ) -> Self { + Self { + pcrProperty: pcrProperty.clone(), + ..Default::default() + } + } + + fn GetUnionSelector() -> TPM_CAP { + TPM_CAP::PCR_PROPERTIES + } +} + +impl TpmStructure for TPML_TAGGED_PCR_PROPERTY { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeObjArr(self.pcrProperty.as_ref())?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readObjArr(self.pcrProperty.as_mut())?; + Ok(()) + } + +} + +impl TpmMarshaller for TPML_TAGGED_PCR_PROPERTY { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This list is used to report the ECC curve ID values supported by the TPM. It is +/// returned by a TPM2_GetCapability(). +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPML_ECC_CURVE { + /// Array of ECC curve identifiers + pub eccCurves: Vec, +} + +impl TPML_ECC_CURVE { + /// Creates a new instance with the specified values + pub fn new( + eccCurves: &Vec, + ) -> Self { + Self { + eccCurves: eccCurves.clone(), + ..Default::default() + } + } + + fn GetUnionSelector() -> TPM_CAP { + TPM_CAP::ECC_CURVES + } +} + +impl TpmStructure for TPML_ECC_CURVE { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeValArr(self.eccCurves.as_ref(), 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readValArr(self.eccCurves.as_mut(), 2)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPML_ECC_CURVE { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This list is used to report the authorization policy values for permanent handles. +/// This is list may be generated by TPM2_GetCapabiltiy(). A permanent handle that cannot +/// have a policy is not included in the list. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPML_TAGGED_POLICY { + /// Array of tagged policies + pub policies: Vec, +} + +impl TPML_TAGGED_POLICY { + /// Creates a new instance with the specified values + pub fn new( + policies: &Vec, + ) -> Self { + Self { + policies: policies.clone(), + ..Default::default() + } + } + + fn GetUnionSelector() -> TPM_CAP { + TPM_CAP::AUTH_POLICIES + } +} + +impl TpmStructure for TPML_TAGGED_POLICY { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeObjArr(self.policies.as_ref())?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readObjArr(self.policies.as_mut())?; + Ok(()) + } + +} + +impl TpmMarshaller for TPML_TAGGED_POLICY { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This list is used to report the timeout and state for the ACT. This list may be +/// generated by TPM2_GetCapabilty(). Only implemented ACT are present in the list +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPML_ACT_DATA { + /// Array of ACT data + pub actData: Vec, +} + +impl TPML_ACT_DATA { + /// Creates a new instance with the specified values + pub fn new( + actData: &Vec, + ) -> Self { + Self { + actData: actData.clone(), + ..Default::default() + } + } + + fn GetUnionSelector() -> TPM_CAP { + TPM_CAP::ACT + } +} + +impl TpmStructure for TPML_ACT_DATA { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeObjArr(self.actData.as_ref())?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readObjArr(self.actData.as_mut())?; + Ok(()) + } + +} + +impl TpmMarshaller for TPML_ACT_DATA { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This data area is returned in response to a TPM2_GetCapability(). +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_CAPABILITY_DATA { + /// The capability + + /// The capability data + /// One of: TPML_ALG_PROPERTY, TPML_HANDLE, TPML_CCA, TPML_CC, TPML_PCR_SELECTION, + /// TPML_TAGGED_TPM_PROPERTY, TPML_TAGGED_PCR_PROPERTY, TPML_ECC_CURVE, + /// TPML_TAGGED_POLICY, TPML_ACT_DATA. + pub data: Option, +} + +impl TPMS_CAPABILITY_DATA { + /// Creates a new instance with the specified values + pub fn new( + data: &Option, + ) -> Self { + Self { + data: data.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPMS_CAPABILITY_DATA { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + if (self.data.is_none()) { return Ok(()) }; + buf.writeInt(self.data.as_ref().unwrap().GetUnionSelector().into()); + self.data.as_ref().unwrap().toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + let r#capability: TPM_CAP = TPM_CAP(buf.readInt() as u32); + self.data = TPMU_CAPABILITIES::create(r#capability)?; + self.data.as_mut().unwrap().initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_CAPABILITY_DATA { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This structure is used in each of the attestation commands. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_CLOCK_INFO { + /// Time value in milliseconds that advances while the TPM is powered + /// NOTE The interpretation of the time-origin (clock=0) is out of the scope of this + /// specification, although Coordinated Universal Time (UTC) is expected to be a common + /// convention. This structure element is used to report on the TPM's Clock value. + /// This value is reset to zero when the Storage Primary Seed is changed (TPM2_Clear()). + /// This value may be advanced by TPM2_ClockSet(). + pub clock: u64, + + /// Number of occurrences of TPM Reset since the last TPM2_Clear() + pub resetCount: u32, + + /// Number of times that TPM2_Shutdown() or _TPM_Hash_Start have occurred since the last + /// TPM Reset or TPM2_Clear(). + pub restartCount: u32, + + /// No value of Clock greater than the current value of Clock has been previously reported + /// by the TPM. Set to YES on TPM2_Clear(). + pub safe: u8, +} + +impl TPMS_CLOCK_INFO { + /// Creates a new instance with the specified values + pub fn new( + clock: u64, + resetCount: u32, + restartCount: u32, + safe: u8, + ) -> Self { + Self { + clock: clock.clone(), + resetCount: resetCount.clone(), + restartCount: restartCount.clone(), + safe: safe.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPMS_CLOCK_INFO { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeInt64(self.clock as u64); + buf.writeInt(self.resetCount as u32); + buf.writeInt(self.restartCount as u32); + buf.writeByte(self.safe as u8); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.clock = buf.readInt64() as u64; + self.resetCount = buf.readInt() as u32; + self.restartCount = buf.readInt() as u32; + self.safe = buf.readByte() as u8; + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_CLOCK_INFO { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This structure is used in, e.g., the TPM2_GetTime() attestation and TPM2_ReadClock(). +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_TIME_INFO { + /// Time in milliseconds since the TIme circuit was last reset + /// This structure element is used to report on the TPM's Time value. + pub time: u64, + + /// A structure containing the clock information + pub clockInfo: TPMS_CLOCK_INFO, +} + +impl TPMS_TIME_INFO { + /// Creates a new instance with the specified values + pub fn new( + time: u64, + clockInfo: &TPMS_CLOCK_INFO, + ) -> Self { + Self { + time: time.clone(), + clockInfo: clockInfo.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPMS_TIME_INFO { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeInt64(self.time as u64); + self.clockInfo.toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.time = buf.readInt64() as u64; + self.clockInfo.initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_TIME_INFO { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This structure is used when the TPM performs TPM2_GetTime. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_TIME_ATTEST_INFO { + /// The Time, Clock, resetCount, restartCount, and Safe indicator + pub time: TPMS_TIME_INFO, + + /// A TPM vendor-specific value indicating the version number of the firmware + pub firmwareVersion: u64, +} + +impl TPMS_TIME_ATTEST_INFO { + /// Creates a new instance with the specified values + pub fn new( + time: &TPMS_TIME_INFO, + firmwareVersion: u64, + ) -> Self { + Self { + time: time.clone(), + firmwareVersion: firmwareVersion.clone(), + ..Default::default() + } + } + + fn GetUnionSelector() -> TPM_ST { + TPM_ST::ATTEST_TIME + } +} + +impl TpmStructure for TPMS_TIME_ATTEST_INFO { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + self.time.toTpm(buf)?; + buf.writeInt64(self.firmwareVersion as u64); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.time.initFromTpm(buf)?; + self.firmwareVersion = buf.readInt64() as u64; + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_TIME_ATTEST_INFO { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This is the attested data for TPM2_Certify(). +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_CERTIFY_INFO { + /// Name of the certified object + pub name: Vec, + + /// Qualified Name of the certified object + pub qualifiedName: Vec, +} + +impl TPMS_CERTIFY_INFO { + /// Creates a new instance with the specified values + pub fn new( + name: &Vec, + qualifiedName: &Vec, + ) -> Self { + Self { + name: name.clone(), + qualifiedName: qualifiedName.clone(), + ..Default::default() + } + } + + fn GetUnionSelector() -> TPM_ST { + TPM_ST::ATTEST_CERTIFY + } +} + +impl TpmStructure for TPMS_CERTIFY_INFO { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.name, 2); + buf.writeSizedByteBuf(&self.qualifiedName, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.name = buf.readSizedByteBuf(2); + self.qualifiedName = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_CERTIFY_INFO { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This is the attested data for TPM2_Quote(). +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_QUOTE_INFO { + /// Information on algID, PCR selected and digest + pub pcrSelect: Vec, + + /// Digest of the selected PCR using the hash of the signing key + pub pcrDigest: Vec, +} + +impl TPMS_QUOTE_INFO { + /// Creates a new instance with the specified values + pub fn new( + pcrSelect: &Vec, + pcrDigest: &Vec, + ) -> Self { + Self { + pcrSelect: pcrSelect.clone(), + pcrDigest: pcrDigest.clone(), + ..Default::default() + } + } + + fn GetUnionSelector() -> TPM_ST { + TPM_ST::ATTEST_QUOTE + } +} + +impl TpmStructure for TPMS_QUOTE_INFO { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeObjArr(self.pcrSelect.as_ref())?; + buf.writeSizedByteBuf(&self.pcrDigest, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readObjArr(self.pcrSelect.as_mut())?; + self.pcrDigest = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_QUOTE_INFO { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This is the attested data for TPM2_GetCommandAuditDigest(). +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_COMMAND_AUDIT_INFO { + /// The monotonic audit counter + pub auditCounter: u64, + + /// Hash algorithm used for the command audit + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub digestAlg: TPM_ALG_ID, + + /// The current value of the audit digest + pub auditDigest: Vec, + + /// Digest of the command codes being audited using digestAlg + pub commandDigest: Vec, +} + +impl TPMS_COMMAND_AUDIT_INFO { + /// Creates a new instance with the specified values + pub fn new( + auditCounter: u64, + digestAlg: TPM_ALG_ID, + auditDigest: &Vec, + commandDigest: &Vec, + ) -> Self { + Self { + auditCounter: auditCounter.clone(), + digestAlg: digestAlg.clone(), + auditDigest: auditDigest.clone(), + commandDigest: commandDigest.clone(), + ..Default::default() + } + } + + fn GetUnionSelector() -> TPM_ST { + TPM_ST::ATTEST_COMMAND_AUDIT + } +} + +impl TpmStructure for TPMS_COMMAND_AUDIT_INFO { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeInt64(self.auditCounter as u64); + buf.writeShort(self.digestAlg.into()); + buf.writeSizedByteBuf(&self.auditDigest, 2); + buf.writeSizedByteBuf(&self.commandDigest, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.auditCounter = buf.readInt64() as u64; + self.digestAlg = TPM_ALG_ID(buf.readShort() as u16); + self.auditDigest = buf.readSizedByteBuf(2); + self.commandDigest = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_COMMAND_AUDIT_INFO { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This is the attested data for TPM2_GetSessionAuditDigest(). +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_SESSION_AUDIT_INFO { + /// Current exclusive status of the session + /// TRUE if all of the commands recorded in the sessionDigest were executed without any + /// intervening TPM command that did not use this audit session + pub exclusiveSession: u8, + + /// The current value of the session audit digest + pub sessionDigest: Vec, +} + +impl TPMS_SESSION_AUDIT_INFO { + /// Creates a new instance with the specified values + pub fn new( + exclusiveSession: u8, + sessionDigest: &Vec, + ) -> Self { + Self { + exclusiveSession: exclusiveSession.clone(), + sessionDigest: sessionDigest.clone(), + ..Default::default() + } + } + + fn GetUnionSelector() -> TPM_ST { + TPM_ST::ATTEST_SESSION_AUDIT + } +} + +impl TpmStructure for TPMS_SESSION_AUDIT_INFO { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeByte(self.exclusiveSession as u8); + buf.writeSizedByteBuf(&self.sessionDigest, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.exclusiveSession = buf.readByte() as u8; + self.sessionDigest = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_SESSION_AUDIT_INFO { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This is the attested data for TPM2_CertifyCreation(). +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_CREATION_INFO { + /// Name of the object + pub objectName: Vec, + + /// CreationHash + pub creationHash: Vec, +} + +impl TPMS_CREATION_INFO { + /// Creates a new instance with the specified values + pub fn new( + objectName: &Vec, + creationHash: &Vec, + ) -> Self { + Self { + objectName: objectName.clone(), + creationHash: creationHash.clone(), + ..Default::default() + } + } + + fn GetUnionSelector() -> TPM_ST { + TPM_ST::ATTEST_CREATION + } +} + +impl TpmStructure for TPMS_CREATION_INFO { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.objectName, 2); + buf.writeSizedByteBuf(&self.creationHash, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.objectName = buf.readSizedByteBuf(2); + self.creationHash = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_CREATION_INFO { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This structure contains the Name and contents of the selected NV Index that is +/// certified by TPM2_NV_Certify(). +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_NV_CERTIFY_INFO { + /// Name of the NV Index + pub indexName: Vec, + + /// The offset parameter of TPM2_NV_Certify() + pub offset: u16, + + /// Contents of the NV Index + pub nvContents: Vec, +} + +impl TPMS_NV_CERTIFY_INFO { + /// Creates a new instance with the specified values + pub fn new( + indexName: &Vec, + offset: u16, + nvContents: &Vec, + ) -> Self { + Self { + indexName: indexName.clone(), + offset: offset.clone(), + nvContents: nvContents.clone(), + ..Default::default() + } + } + + fn GetUnionSelector() -> TPM_ST { + TPM_ST::ATTEST_NV + } +} + +impl TpmStructure for TPMS_NV_CERTIFY_INFO { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.indexName, 2); + buf.writeShort(self.offset as u16); + buf.writeSizedByteBuf(&self.nvContents, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.indexName = buf.readSizedByteBuf(2); + self.offset = buf.readShort() as u16; + self.nvContents = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_NV_CERTIFY_INFO { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This structure contains the Name and hash of the contents of the selected NV Index +/// that is certified by TPM2_NV_Certify(). The data is hashed using hash of the signing scheme. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_NV_DIGEST_CERTIFY_INFO { + /// Name of the NV Index + pub indexName: Vec, + + /// Hash of the contents of the index + pub nvDigest: Vec, +} + +impl TPMS_NV_DIGEST_CERTIFY_INFO { + /// Creates a new instance with the specified values + pub fn new( + indexName: &Vec, + nvDigest: &Vec, + ) -> Self { + Self { + indexName: indexName.clone(), + nvDigest: nvDigest.clone(), + ..Default::default() + } + } + + fn GetUnionSelector() -> TPM_ST { + TPM_ST::ATTEST_NV_DIGEST + } +} + +impl TpmStructure for TPMS_NV_DIGEST_CERTIFY_INFO { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.indexName, 2); + buf.writeSizedByteBuf(&self.nvDigest, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.indexName = buf.readSizedByteBuf(2); + self.nvDigest = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_NV_DIGEST_CERTIFY_INFO { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This structure is used on each TPM-generated signed structure. The signature is over +/// this structure. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_ATTEST { + /// The indication that this structure was created by a TPM (always TPM_GENERATED_VALUE) + pub magic: TPM_GENERATED, + + /// Type of the attestation structure + + /// Qualified Name of the signing key + pub qualifiedSigner: Vec, + + /// External information supplied by caller + /// NOTE A TPM2B_DATA structure provides room for a digest and a method indicator to + /// indicate the components of the digest. The definition of this method indicator is + /// outside the scope of this specification. + pub extraData: Vec, + + /// Clock, resetCount, restartCount, and Safe + pub clockInfo: TPMS_CLOCK_INFO, + + /// TPM-vendor-specific value identifying the version number of the firmware + pub firmwareVersion: u64, + + /// The type-specific attestation information + /// One of: TPMS_CERTIFY_INFO, TPMS_CREATION_INFO, TPMS_QUOTE_INFO, + /// TPMS_COMMAND_AUDIT_INFO, TPMS_SESSION_AUDIT_INFO, TPMS_TIME_ATTEST_INFO, + /// TPMS_NV_CERTIFY_INFO, TPMS_NV_DIGEST_CERTIFY_INFO. + pub attested: Option, +} + +impl TPMS_ATTEST { + /// Creates a new instance with the specified values + pub fn new( + magic: TPM_GENERATED, + qualifiedSigner: &Vec, + extraData: &Vec, + clockInfo: &TPMS_CLOCK_INFO, + firmwareVersion: u64, + attested: &Option, + ) -> Self { + Self { + magic: magic.clone(), + qualifiedSigner: qualifiedSigner.clone(), + extraData: extraData.clone(), + clockInfo: clockInfo.clone(), + firmwareVersion: firmwareVersion.clone(), + attested: attested.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPMS_ATTEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeInt(self.magic.into()); + buf.writeShort(self.attested.as_ref().unwrap().GetUnionSelector().into()); + buf.writeSizedByteBuf(&self.qualifiedSigner, 2); + buf.writeSizedByteBuf(&self.extraData, 2); + self.clockInfo.toTpm(buf)?; + buf.writeInt64(self.firmwareVersion as u64); + self.attested.as_ref().unwrap().toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.magic = TPM_GENERATED(buf.readInt() as u32); + let r#type: TPM_ST = TPM_ST(buf.readShort() as u16); + self.qualifiedSigner = buf.readSizedByteBuf(2); + self.extraData = buf.readSizedByteBuf(2); + self.clockInfo.initFromTpm(buf)?; + self.firmwareVersion = buf.readInt64() as u64; + self.attested = TPMU_ATTEST::create(r#type)?; + self.attested.as_mut().unwrap().initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_ATTEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This sized buffer to contain the signed structure. The attestationData is the signed +/// portion of the structure. The size parameter is not signed. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2B_ATTEST { + /// The signed structure + pub attestationData: TPMS_ATTEST, +} + +impl TPM2B_ATTEST { + /// Creates a new instance with the specified values + pub fn new( + attestationData: &TPMS_ATTEST, + ) -> Self { + Self { + attestationData: attestationData.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2B_ATTEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedObj(&self.attestationData)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readSizedObj(&mut self.attestationData)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2B_ATTEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This is the format used for each of the authorizations in the session area of a command. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_AUTH_COMMAND { + /// The session handle + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub sessionHandle: TPM_HANDLE, + + /// The session nonce, may be the Empty Buffer + pub nonce: Vec, + + /// The session attributes + pub sessionAttributes: TPMA_SESSION, + + /// Either an HMAC, a password, or an EmptyAuth + pub hmac: Vec, +} + +impl TPMS_AUTH_COMMAND { + /// Creates a new instance with the specified values + pub fn new( + sessionHandle: &TPM_HANDLE, + nonce: &Vec, + sessionAttributes: TPMA_SESSION, + hmac: &Vec, + ) -> Self { + Self { + sessionHandle: sessionHandle.clone(), + nonce: nonce.clone(), + sessionAttributes: sessionAttributes.clone(), + hmac: hmac.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPMS_AUTH_COMMAND { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + self.sessionHandle.toTpm(buf)?; + buf.writeSizedByteBuf(&self.nonce, 2); + buf.writeByte(self.sessionAttributes.into()); + buf.writeSizedByteBuf(&self.hmac, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.sessionHandle.initFromTpm(buf)?; + self.nonce = buf.readSizedByteBuf(2); + self.sessionAttributes = TPMA_SESSION(buf.readByte() as u8); + self.hmac = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_AUTH_COMMAND { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This is the format for each of the authorizations in the session area of the response. +/// If the TPM returns TPM_RC_SUCCESS, then the session area of the response contains the +/// same number of authorizations as the command and the authorizations are in the same order. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_AUTH_RESPONSE { + /// The session nonce, may be the Empty Buffer + pub nonce: Vec, + + /// The session attributes + pub sessionAttributes: TPMA_SESSION, + + /// Either an HMAC or an EmptyAuth + pub hmac: Vec, +} + +impl TPMS_AUTH_RESPONSE { + /// Creates a new instance with the specified values + pub fn new( + nonce: &Vec, + sessionAttributes: TPMA_SESSION, + hmac: &Vec, + ) -> Self { + Self { + nonce: nonce.clone(), + sessionAttributes: sessionAttributes.clone(), + hmac: hmac.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPMS_AUTH_RESPONSE { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.nonce, 2); + buf.writeByte(self.sessionAttributes.into()); + buf.writeSizedByteBuf(&self.hmac, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.nonce = buf.readSizedByteBuf(2); + self.sessionAttributes = TPMA_SESSION(buf.readByte() as u8); + self.hmac = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_AUTH_RESPONSE { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// Custom data structure representing an empty element (i.e. the one with +/// no data to marshal) for selector algorithm TPM_ALG_TDES for the union TPMU_SYM_DETAILS +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_TDES_SYM_DETAILS { +} + +impl TPMS_TDES_SYM_DETAILS { + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::TDES + } +} + +impl TpmStructure for TPMS_TDES_SYM_DETAILS { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_TDES_SYM_DETAILS { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// Custom data structure representing an empty element (i.e. the one with +/// no data to marshal) for selector algorithm TPM_ALG_AES for the union TPMU_SYM_DETAILS +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_AES_SYM_DETAILS { +} + +impl TPMS_AES_SYM_DETAILS { + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::AES + } +} + +impl TpmStructure for TPMS_AES_SYM_DETAILS { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_AES_SYM_DETAILS { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// Custom data structure representing an empty element (i.e. the one with +/// no data to marshal) for selector algorithm TPM_ALG_SM4 for the union TPMU_SYM_DETAILS +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_SM4_SYM_DETAILS { +} + +impl TPMS_SM4_SYM_DETAILS { + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::SM4 + } +} + +impl TpmStructure for TPMS_SM4_SYM_DETAILS { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_SM4_SYM_DETAILS { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// Custom data structure representing an empty element (i.e. the one with +/// no data to marshal) for selector algorithm TPM_ALG_CAMELLIA for the union TPMU_SYM_DETAILS +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_CAMELLIA_SYM_DETAILS { +} + +impl TPMS_CAMELLIA_SYM_DETAILS { + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::CAMELLIA + } +} + +impl TpmStructure for TPMS_CAMELLIA_SYM_DETAILS { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_CAMELLIA_SYM_DETAILS { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// Custom data structure representing an empty element (i.e. the one with +/// no data to marshal) for selector algorithm TPM_ALG_ANY for the union TPMU_SYM_DETAILS +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_ANY_SYM_DETAILS { +} + +impl TPMS_ANY_SYM_DETAILS { + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::ANY + } +} + +impl TpmStructure for TPMS_ANY_SYM_DETAILS { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_ANY_SYM_DETAILS { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// Custom data structure representing an empty element (i.e. the one with +/// no data to marshal) for selector algorithm TPM_ALG_XOR for the union TPMU_SYM_DETAILS +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_XOR_SYM_DETAILS { +} + +impl TPMS_XOR_SYM_DETAILS { + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::XOR + } +} + +impl TpmStructure for TPMS_XOR_SYM_DETAILS { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_XOR_SYM_DETAILS { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// Custom data structure representing an empty element (i.e. the one with +/// no data to marshal) for selector algorithm TPM_ALG_NULL for the union TPMU_SYM_DETAILS +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_NULL_SYM_DETAILS { +} + +impl TPMS_NULL_SYM_DETAILS { + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::NULL + } +} + +impl TpmStructure for TPMS_NULL_SYM_DETAILS { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_NULL_SYM_DETAILS { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// The TPMT_SYM_DEF structure is used to select an algorithm to be used for parameter +/// encryption in those cases when different symmetric algorithms may be selected. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMT_SYM_DEF { + /// Indicates a symmetric algorithm + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub algorithm: TPM_ALG_ID, + + /// A supported key size + pub keyBits: u16, + + /// The mode for the key + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub mode: TPM_ALG_ID, +} + +impl TPMT_SYM_DEF { + /// Creates a new instance with the specified values + pub fn new( + algorithm: TPM_ALG_ID, + keyBits: u16, + mode: TPM_ALG_ID, + ) -> Self { + Self { + algorithm: algorithm.clone(), + keyBits: keyBits.clone(), + mode: mode.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPMT_SYM_DEF { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeShort(self.algorithm.into()); + if (self.algorithm == TPM_ALG_ID::NULL) { return Ok(()) }; + buf.writeShort(self.keyBits as u16); + buf.writeShort(self.mode.into()); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.algorithm = TPM_ALG_ID(buf.readShort() as u16); + if (self.algorithm == TPM_ALG_ID::NULL) { return Ok(()) }; + self.keyBits = buf.readShort() as u16; + self.mode = TPM_ALG_ID(buf.readShort() as u16); + Ok(()) + } + +} + +impl TpmMarshaller for TPMT_SYM_DEF { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This structure is used when different symmetric block cipher (not XOR) algorithms may +/// be selected. If the Object can be an ordinary parent (not a derivation parent), this +/// must be the first field in the Object's parameter (see 12.2.3.7) field. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMT_SYM_DEF_OBJECT { + /// Selects a symmetric block cipher + /// When used in the parameter area of a parent object, this shall be a supported block + /// cipher and not TPM_ALG_NULL + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub algorithm: TPM_ALG_ID, + + /// The key size + pub keyBits: u16, + + /// Default mode + /// When used in the parameter area of a parent object, this shall be TPM_ALG_CFB. + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub mode: TPM_ALG_ID, +} + +impl TPMT_SYM_DEF_OBJECT { + /// Creates a new instance with the specified values + pub fn new( + algorithm: TPM_ALG_ID, + keyBits: u16, + mode: TPM_ALG_ID, + ) -> Self { + Self { + algorithm: algorithm.clone(), + keyBits: keyBits.clone(), + mode: mode.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPMT_SYM_DEF_OBJECT { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeShort(self.algorithm.into()); + if (self.algorithm == TPM_ALG_ID::NULL) { return Ok(()) }; + buf.writeShort(self.keyBits as u16); + buf.writeShort(self.mode.into()); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.algorithm = TPM_ALG_ID(buf.readShort() as u16); + if (self.algorithm == TPM_ALG_ID::NULL) { return Ok(()) }; + self.keyBits = buf.readShort() as u16; + self.mode = TPM_ALG_ID(buf.readShort() as u16); + Ok(()) + } + +} + +impl TpmMarshaller for TPMT_SYM_DEF_OBJECT { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This structure is used to hold a symmetric key in the sensitive area of an asymmetric object. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2B_SYM_KEY { + /// The key + pub buffer: Vec, +} + +impl TPM2B_SYM_KEY { + /// Creates a new instance with the specified values + pub fn new( + buffer: &Vec, + ) -> Self { + Self { + buffer: buffer.clone(), + ..Default::default() + } + } + + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::SYMCIPHER + } +} + +impl TpmStructure for TPM2B_SYM_KEY { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.buffer, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.buffer = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2B_SYM_KEY { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This structure contains the parameters for a symmetric block cipher object. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_SYMCIPHER_PARMS { + /// A symmetric block cipher + pub sym: TPMT_SYM_DEF_OBJECT, +} + +impl TPMS_SYMCIPHER_PARMS { + /// Creates a new instance with the specified values + pub fn new( + sym: &TPMT_SYM_DEF_OBJECT, + ) -> Self { + Self { + sym: sym.clone(), + ..Default::default() + } + } + + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::SYMCIPHER + } +} + +impl TpmStructure for TPMS_SYMCIPHER_PARMS { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + self.sym.toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.sym.initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_SYMCIPHER_PARMS { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This buffer holds a label or context value. For interoperability and backwards +/// compatibility, LABEL_MAX_BUFFER is the minimum of the largest digest on the device and +/// the largest ECC parameter (MAX_ECC_KEY_BYTES) but no more than 32 bytes. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2B_LABEL { + /// Symmetric data for a created object or the label and context for a derived object + pub buffer: Vec, +} + +impl TPM2B_LABEL { + /// Creates a new instance with the specified values + pub fn new( + buffer: &Vec, + ) -> Self { + Self { + buffer: buffer.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2B_LABEL { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.buffer, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.buffer = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2B_LABEL { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This structure contains the label and context fields for a derived object. These +/// values are used in the derivation KDF. The values in the unique field of inPublic area +/// template take precedence over the values in the inSensitive parameter. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_DERIVE { + pub label: Vec, + pub context: Vec, +} + +impl TPMS_DERIVE { + /// Creates a new instance with the specified values + pub fn new( + label: &Vec, + context: &Vec, + ) -> Self { + Self { + label: label.clone(), + context: context.clone(), + ..Default::default() + } + } + + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::ANY2 + } +} + +impl TpmStructure for TPMS_DERIVE { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.label, 2); + buf.writeSizedByteBuf(&self.context, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.label = buf.readSizedByteBuf(2); + self.context = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_DERIVE { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// Table 147 Definition of TPM2B_DERIVE Structure +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2B_DERIVE { + /// Symmetric data for a created object or the label and context for a derived object + pub buffer: TPMS_DERIVE, +} + +impl TPM2B_DERIVE { + /// Creates a new instance with the specified values + pub fn new( + buffer: &TPMS_DERIVE, + ) -> Self { + Self { + buffer: buffer.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2B_DERIVE { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedObj(&self.buffer)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readSizedObj(&mut self.buffer)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2B_DERIVE { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This buffer wraps the TPMU_SENSITIVE_CREATE structure. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2B_SENSITIVE_DATA { + /// Symmetric data for a created object or the label and context for a derived object + pub buffer: Vec, +} + +impl TPM2B_SENSITIVE_DATA { + /// Creates a new instance with the specified values + pub fn new( + buffer: &Vec, + ) -> Self { + Self { + buffer: buffer.clone(), + ..Default::default() + } + } + + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::KEYEDHASH + } +} + +impl TpmStructure for TPM2B_SENSITIVE_DATA { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.buffer, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.buffer = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2B_SENSITIVE_DATA { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This structure defines the values to be placed in the sensitive area of a created +/// object. This structure is only used within a TPM2B_SENSITIVE_CREATE structure. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_SENSITIVE_CREATE { + /// The USER auth secret value + pub userAuth: Vec, + + /// Data to be sealed, a key, or derivation values + pub data: Vec, +} + +impl TPMS_SENSITIVE_CREATE { + /// Creates a new instance with the specified values + pub fn new( + userAuth: &Vec, + data: &Vec, + ) -> Self { + Self { + userAuth: userAuth.clone(), + data: data.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPMS_SENSITIVE_CREATE { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.userAuth, 2); + buf.writeSizedByteBuf(&self.data, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.userAuth = buf.readSizedByteBuf(2); + self.data = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_SENSITIVE_CREATE { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This structure contains the sensitive creation data in a sized buffer. This structure +/// is defined so that both the userAuth and data values of the TPMS_SENSITIVE_CREATE may +/// be passed as a single parameter for parameter encryption purposes. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2B_SENSITIVE_CREATE { + /// Data to be sealed or a symmetric key value. + pub sensitive: TPMS_SENSITIVE_CREATE, +} + +impl TPM2B_SENSITIVE_CREATE { + /// Creates a new instance with the specified values + pub fn new( + sensitive: &TPMS_SENSITIVE_CREATE, + ) -> Self { + Self { + sensitive: sensitive.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2B_SENSITIVE_CREATE { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedObj(&self.sensitive)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readSizedObj(&mut self.sensitive)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2B_SENSITIVE_CREATE { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This structure is the scheme data for schemes that only require a hash to complete +/// their definition. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_SCHEME_HASH { + /// The hash algorithm used to digest the message + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub hashAlg: TPM_ALG_ID, +} + +impl TPMS_SCHEME_HASH { + /// Creates a new instance with the specified values + pub fn new( + hashAlg: TPM_ALG_ID, + ) -> Self { + Self { + hashAlg: hashAlg.clone(), + ..Default::default() + } + } + + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::HMAC + } +} + +impl TpmStructure for TPMS_SCHEME_HASH { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeShort(self.hashAlg.into()); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.hashAlg = TPM_ALG_ID(buf.readShort() as u16); + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_SCHEME_HASH { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This definition is for split signing schemes that require a commit count. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_SCHEME_ECDAA { + /// The hash algorithm used to digest the message + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub hashAlg: TPM_ALG_ID, + + /// The counter value that is used between TPM2_Commit() and the sign operation + pub count: u16, +} + +impl TPMS_SCHEME_ECDAA { + /// Creates a new instance with the specified values + pub fn new( + hashAlg: TPM_ALG_ID, + count: u16, + ) -> Self { + Self { + hashAlg: hashAlg.clone(), + count: count.clone(), + ..Default::default() + } + } + + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::ECDAA + } +} + +impl TpmStructure for TPMS_SCHEME_ECDAA { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeShort(self.hashAlg.into()); + buf.writeShort(self.count as u16); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.hashAlg = TPM_ALG_ID(buf.readShort() as u16); + self.count = buf.readShort() as u16; + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_SCHEME_ECDAA { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// Table 155 Definition of Types for HMAC_SIG_SCHEME +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_SCHEME_HMAC { + /// The hash algorithm used to digest the message + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub hashAlg: TPM_ALG_ID, +} + +impl TPMS_SCHEME_HMAC { + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::HMAC + } +} + +impl TpmStructure for TPMS_SCHEME_HMAC { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeShort(self.hashAlg.into()); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.hashAlg = TPM_ALG_ID(buf.readShort() as u16); + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_SCHEME_HMAC { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This structure is for the XOR encryption scheme. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_SCHEME_XOR { + /// The hash algorithm used to digest the message + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub hashAlg: TPM_ALG_ID, + + /// The key derivation function + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub kdf: TPM_ALG_ID, +} + +impl TPMS_SCHEME_XOR { + /// Creates a new instance with the specified values + pub fn new( + hashAlg: TPM_ALG_ID, + kdf: TPM_ALG_ID, + ) -> Self { + Self { + hashAlg: hashAlg.clone(), + kdf: kdf.clone(), + ..Default::default() + } + } + + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::XOR + } +} + +impl TpmStructure for TPMS_SCHEME_XOR { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeShort(self.hashAlg.into()); + buf.writeShort(self.kdf.into()); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.hashAlg = TPM_ALG_ID(buf.readShort() as u16); + self.kdf = TPM_ALG_ID(buf.readShort() as u16); + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_SCHEME_XOR { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// Custom data structure representing an empty element (i.e. the one with +/// no data to marshal) for selector algorithm TPM_ALG_NULL for the union TPMU_SCHEME_KEYEDHASH +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_NULL_SCHEME_KEYEDHASH { +} + +impl TPMS_NULL_SCHEME_KEYEDHASH { + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::NULL + } +} + +impl TpmStructure for TPMS_NULL_SCHEME_KEYEDHASH { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_NULL_SCHEME_KEYEDHASH { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This structure is used for a hash signing object. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMT_KEYEDHASH_SCHEME { + /// Selects the scheme + + /// The scheme parameters + /// One of: TPMS_SCHEME_HMAC, TPMS_SCHEME_XOR, TPMS_NULL_SCHEME_KEYEDHASH. + pub details: Option, +} + +impl TPMT_KEYEDHASH_SCHEME { + /// Creates a new instance with the specified values + pub fn new( + details: &Option, + ) -> Self { + Self { + details: details.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPMT_KEYEDHASH_SCHEME { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + if (self.details.is_none()) { return Ok(()) }; + buf.writeShort(self.details.as_ref().unwrap().GetUnionSelector().into()); + self.details.as_ref().unwrap().toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + let r#scheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); + self.details = TPMU_SCHEME_KEYEDHASH::create(r#scheme)?; + self.details.as_mut().unwrap().initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPMT_KEYEDHASH_SCHEME { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// These are the RSA schemes that only need a hash algorithm as a scheme parameter. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_SIG_SCHEME_RSASSA { + /// The hash algorithm used to digest the message + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub hashAlg: TPM_ALG_ID, +} + +impl TPMS_SIG_SCHEME_RSASSA { + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::RSASSA + } +} + +impl TpmStructure for TPMS_SIG_SCHEME_RSASSA { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeShort(self.hashAlg.into()); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.hashAlg = TPM_ALG_ID(buf.readShort() as u16); + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_SIG_SCHEME_RSASSA { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// These are the RSA schemes that only need a hash algorithm as a scheme parameter. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_SIG_SCHEME_RSAPSS { + /// The hash algorithm used to digest the message + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub hashAlg: TPM_ALG_ID, +} + +impl TPMS_SIG_SCHEME_RSAPSS { + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::RSAPSS + } +} + +impl TpmStructure for TPMS_SIG_SCHEME_RSAPSS { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeShort(self.hashAlg.into()); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.hashAlg = TPM_ALG_ID(buf.readShort() as u16); + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_SIG_SCHEME_RSAPSS { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// Most of the ECC signature schemes only require a hash algorithm to complete the +/// definition and can be typed as TPMS_SCHEME_HASH. Anonymous algorithms also require a +/// count value so they are typed to be TPMS_SCHEME_ECDAA. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_SIG_SCHEME_ECDSA { + /// The hash algorithm used to digest the message + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub hashAlg: TPM_ALG_ID, +} + +impl TPMS_SIG_SCHEME_ECDSA { + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::ECDSA + } +} + +impl TpmStructure for TPMS_SIG_SCHEME_ECDSA { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeShort(self.hashAlg.into()); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.hashAlg = TPM_ALG_ID(buf.readShort() as u16); + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_SIG_SCHEME_ECDSA { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// Most of the ECC signature schemes only require a hash algorithm to complete the +/// definition and can be typed as TPMS_SCHEME_HASH. Anonymous algorithms also require a +/// count value so they are typed to be TPMS_SCHEME_ECDAA. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_SIG_SCHEME_SM2 { + /// The hash algorithm used to digest the message + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub hashAlg: TPM_ALG_ID, +} + +impl TPMS_SIG_SCHEME_SM2 { + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::SM2 + } +} + +impl TpmStructure for TPMS_SIG_SCHEME_SM2 { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeShort(self.hashAlg.into()); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.hashAlg = TPM_ALG_ID(buf.readShort() as u16); + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_SIG_SCHEME_SM2 { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// Most of the ECC signature schemes only require a hash algorithm to complete the +/// definition and can be typed as TPMS_SCHEME_HASH. Anonymous algorithms also require a +/// count value so they are typed to be TPMS_SCHEME_ECDAA. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_SIG_SCHEME_ECSCHNORR { + /// The hash algorithm used to digest the message + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub hashAlg: TPM_ALG_ID, +} + +impl TPMS_SIG_SCHEME_ECSCHNORR { + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::ECSCHNORR + } +} + +impl TpmStructure for TPMS_SIG_SCHEME_ECSCHNORR { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeShort(self.hashAlg.into()); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.hashAlg = TPM_ALG_ID(buf.readShort() as u16); + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_SIG_SCHEME_ECSCHNORR { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// Most of the ECC signature schemes only require a hash algorithm to complete the +/// definition and can be typed as TPMS_SCHEME_HASH. Anonymous algorithms also require a +/// count value so they are typed to be TPMS_SCHEME_ECDAA. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_SIG_SCHEME_ECDAA { + /// The hash algorithm used to digest the message + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub hashAlg: TPM_ALG_ID, + + /// The counter value that is used between TPM2_Commit() and the sign operation + pub count: u16, +} + +impl TPMS_SIG_SCHEME_ECDAA { + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::ECDAA + } +} + +impl TpmStructure for TPMS_SIG_SCHEME_ECDAA { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeShort(self.hashAlg.into()); + buf.writeShort(self.count as u16); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.hashAlg = TPM_ALG_ID(buf.readShort() as u16); + self.count = buf.readShort() as u16; + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_SIG_SCHEME_ECDAA { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// Custom data structure representing an empty element (i.e. the one with +/// no data to marshal) for selector algorithm TPM_ALG_NULL for the union TPMU_SIG_SCHEME +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_NULL_SIG_SCHEME { +} + +impl TPMS_NULL_SIG_SCHEME { + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::NULL + } +} + +impl TpmStructure for TPMS_NULL_SIG_SCHEME { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_NULL_SIG_SCHEME { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// Table 162 Definition of TPMT_SIG_SCHEME Structure +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMT_SIG_SCHEME { + /// Scheme selector + + /// Scheme parameters + /// One of: TPMS_SIG_SCHEME_RSASSA, TPMS_SIG_SCHEME_RSAPSS, TPMS_SIG_SCHEME_ECDSA, + /// TPMS_SIG_SCHEME_ECDAA, TPMS_SIG_SCHEME_SM2, TPMS_SIG_SCHEME_ECSCHNORR, + /// TPMS_SCHEME_HMAC, TPMS_SCHEME_HASH, TPMS_NULL_SIG_SCHEME. + pub details: Option, +} + +impl TPMT_SIG_SCHEME { + /// Creates a new instance with the specified values + pub fn new( + details: &Option, + ) -> Self { + Self { + details: details.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPMT_SIG_SCHEME { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + if (self.details.is_none()) { return Ok(()) }; + buf.writeShort(self.details.as_ref().unwrap().GetUnionSelector().into()); + self.details.as_ref().unwrap().toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + let r#scheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); + self.details = TPMU_SIG_SCHEME::create(r#scheme)?; + self.details.as_mut().unwrap().initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPMT_SIG_SCHEME { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// These are the RSA encryption schemes that only need a hash algorithm as a controlling parameter. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_ENC_SCHEME_OAEP { + /// The hash algorithm used to digest the message + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub hashAlg: TPM_ALG_ID, +} + +impl TPMS_ENC_SCHEME_OAEP { + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::OAEP + } +} + +impl TpmStructure for TPMS_ENC_SCHEME_OAEP { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeShort(self.hashAlg.into()); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.hashAlg = TPM_ALG_ID(buf.readShort() as u16); + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_ENC_SCHEME_OAEP { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// These are the RSA encryption schemes that only need a hash algorithm as a controlling parameter. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_ENC_SCHEME_RSAES { +} + +impl TPMS_ENC_SCHEME_RSAES { + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::RSAES + } +} + +impl TpmStructure for TPMS_ENC_SCHEME_RSAES { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_ENC_SCHEME_RSAES { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// These are the ECC schemes that only need a hash algorithm as a controlling parameter. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_KEY_SCHEME_ECDH { + /// The hash algorithm used to digest the message + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub hashAlg: TPM_ALG_ID, +} + +impl TPMS_KEY_SCHEME_ECDH { + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::ECDH + } +} + +impl TpmStructure for TPMS_KEY_SCHEME_ECDH { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeShort(self.hashAlg.into()); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.hashAlg = TPM_ALG_ID(buf.readShort() as u16); + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_KEY_SCHEME_ECDH { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// These are the ECC schemes that only need a hash algorithm as a controlling parameter. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_KEY_SCHEME_ECMQV { + /// The hash algorithm used to digest the message + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub hashAlg: TPM_ALG_ID, +} + +impl TPMS_KEY_SCHEME_ECMQV { + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::ECMQV + } +} + +impl TpmStructure for TPMS_KEY_SCHEME_ECMQV { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeShort(self.hashAlg.into()); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.hashAlg = TPM_ALG_ID(buf.readShort() as u16); + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_KEY_SCHEME_ECMQV { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// These structures are used to define the key derivation for symmetric secret sharing +/// using asymmetric methods. A secret sharing scheme is required in any asymmetric key +/// with the decrypt attribute SET. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_KDF_SCHEME_MGF1 { + /// The hash algorithm used to digest the message + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub hashAlg: TPM_ALG_ID, +} + +impl TPMS_KDF_SCHEME_MGF1 { + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::MGF1 + } +} + +impl TpmStructure for TPMS_KDF_SCHEME_MGF1 { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeShort(self.hashAlg.into()); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.hashAlg = TPM_ALG_ID(buf.readShort() as u16); + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_KDF_SCHEME_MGF1 { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// These structures are used to define the key derivation for symmetric secret sharing +/// using asymmetric methods. A secret sharing scheme is required in any asymmetric key +/// with the decrypt attribute SET. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_KDF_SCHEME_KDF1_SP800_56A { + /// The hash algorithm used to digest the message + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub hashAlg: TPM_ALG_ID, +} + +impl TPMS_KDF_SCHEME_KDF1_SP800_56A { + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::KDF1_SP800_56A + } +} + +impl TpmStructure for TPMS_KDF_SCHEME_KDF1_SP800_56A { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeShort(self.hashAlg.into()); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.hashAlg = TPM_ALG_ID(buf.readShort() as u16); + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_KDF_SCHEME_KDF1_SP800_56A { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// These structures are used to define the key derivation for symmetric secret sharing +/// using asymmetric methods. A secret sharing scheme is required in any asymmetric key +/// with the decrypt attribute SET. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_KDF_SCHEME_KDF2 { + /// The hash algorithm used to digest the message + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub hashAlg: TPM_ALG_ID, +} + +impl TPMS_KDF_SCHEME_KDF2 { + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::KDF2 + } +} + +impl TpmStructure for TPMS_KDF_SCHEME_KDF2 { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeShort(self.hashAlg.into()); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.hashAlg = TPM_ALG_ID(buf.readShort() as u16); + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_KDF_SCHEME_KDF2 { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// These structures are used to define the key derivation for symmetric secret sharing +/// using asymmetric methods. A secret sharing scheme is required in any asymmetric key +/// with the decrypt attribute SET. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_KDF_SCHEME_KDF1_SP800_108 { + /// The hash algorithm used to digest the message + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub hashAlg: TPM_ALG_ID, +} + +impl TPMS_KDF_SCHEME_KDF1_SP800_108 { + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::KDF1_SP800_108 + } +} + +impl TpmStructure for TPMS_KDF_SCHEME_KDF1_SP800_108 { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeShort(self.hashAlg.into()); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.hashAlg = TPM_ALG_ID(buf.readShort() as u16); + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_KDF_SCHEME_KDF1_SP800_108 { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// Custom data structure representing an empty element (i.e. the one with +/// no data to marshal) for selector algorithm TPM_ALG_NULL for the union TPMU_KDF_SCHEME +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_NULL_KDF_SCHEME { +} + +impl TPMS_NULL_KDF_SCHEME { + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::NULL + } +} + +impl TpmStructure for TPMS_NULL_KDF_SCHEME { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_NULL_KDF_SCHEME { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// Table 167 Definition of TPMT_KDF_SCHEME Structure +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMT_KDF_SCHEME { + /// Scheme selector + + /// Scheme parameters + /// One of: TPMS_KDF_SCHEME_MGF1, TPMS_KDF_SCHEME_KDF1_SP800_56A, TPMS_KDF_SCHEME_KDF2, + /// TPMS_KDF_SCHEME_KDF1_SP800_108, TPMS_SCHEME_HASH, TPMS_NULL_KDF_SCHEME. + pub details: Option, +} + +impl TPMT_KDF_SCHEME { + /// Creates a new instance with the specified values + pub fn new( + details: &Option, + ) -> Self { + Self { + details: details.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPMT_KDF_SCHEME { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + if (self.details.is_none()) { return Ok(()) }; + buf.writeShort(self.details.as_ref().unwrap().GetUnionSelector().into()); + self.details.as_ref().unwrap().toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + let r#scheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); + self.details = TPMU_KDF_SCHEME::create(r#scheme)?; + self.details.as_mut().unwrap().initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPMT_KDF_SCHEME { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// Custom data structure representing an empty element (i.e. the one with +/// no data to marshal) for selector algorithm TPM_ALG_NULL for the union TPMU_ASYM_SCHEME +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_NULL_ASYM_SCHEME { +} + +impl TPMS_NULL_ASYM_SCHEME { + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::NULL + } +} + +impl TpmStructure for TPMS_NULL_ASYM_SCHEME { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_NULL_ASYM_SCHEME { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This structure is defined to allow overlay of all of the schemes for any asymmetric +/// object. This structure is not sent on the interface. It is defined so that common +/// functions may operate on any similar scheme structure. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMT_ASYM_SCHEME { + /// Scheme selector + + /// Scheme parameters + /// One of: TPMS_KEY_SCHEME_ECDH, TPMS_KEY_SCHEME_ECMQV, TPMS_SIG_SCHEME_RSASSA, + /// TPMS_SIG_SCHEME_RSAPSS, TPMS_SIG_SCHEME_ECDSA, TPMS_SIG_SCHEME_ECDAA, + /// TPMS_SIG_SCHEME_SM2, TPMS_SIG_SCHEME_ECSCHNORR, TPMS_ENC_SCHEME_RSAES, + /// TPMS_ENC_SCHEME_OAEP, TPMS_SCHEME_HASH, TPMS_NULL_ASYM_SCHEME. + pub details: Option, +} + +impl TPMT_ASYM_SCHEME { + /// Creates a new instance with the specified values + pub fn new( + details: &Option, + ) -> Self { + Self { + details: details.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPMT_ASYM_SCHEME { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + if (self.details.is_none()) { return Ok(()) }; + buf.writeShort(self.details.as_ref().unwrap().GetUnionSelector().into()); + self.details.as_ref().unwrap().toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + let r#scheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); + self.details = TPMU_ASYM_SCHEME::create(r#scheme)?; + self.details.as_mut().unwrap().initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPMT_ASYM_SCHEME { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// Table 172 Definition of {RSA} TPMT_RSA_SCHEME Structure +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMT_RSA_SCHEME { + /// Scheme selector + + /// Scheme parameters + /// One of: TPMS_KEY_SCHEME_ECDH, TPMS_KEY_SCHEME_ECMQV, TPMS_SIG_SCHEME_RSASSA, + /// TPMS_SIG_SCHEME_RSAPSS, TPMS_SIG_SCHEME_ECDSA, TPMS_SIG_SCHEME_ECDAA, + /// TPMS_SIG_SCHEME_SM2, TPMS_SIG_SCHEME_ECSCHNORR, TPMS_ENC_SCHEME_RSAES, + /// TPMS_ENC_SCHEME_OAEP, TPMS_SCHEME_HASH, TPMS_NULL_ASYM_SCHEME. + pub details: Option, +} + +impl TPMT_RSA_SCHEME { + /// Creates a new instance with the specified values + pub fn new( + details: &Option, + ) -> Self { + Self { + details: details.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPMT_RSA_SCHEME { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + if (self.details.is_none()) { return Ok(()) }; + buf.writeShort(self.details.as_ref().unwrap().GetUnionSelector().into()); + self.details.as_ref().unwrap().toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + let r#scheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); + self.details = TPMU_ASYM_SCHEME::create(r#scheme)?; + self.details.as_mut().unwrap().initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPMT_RSA_SCHEME { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// Table 174 Definition of {RSA} TPMT_RSA_DECRYPT Structure +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMT_RSA_DECRYPT { + /// Scheme selector + + /// Scheme parameters + /// One of: TPMS_KEY_SCHEME_ECDH, TPMS_KEY_SCHEME_ECMQV, TPMS_SIG_SCHEME_RSASSA, + /// TPMS_SIG_SCHEME_RSAPSS, TPMS_SIG_SCHEME_ECDSA, TPMS_SIG_SCHEME_ECDAA, + /// TPMS_SIG_SCHEME_SM2, TPMS_SIG_SCHEME_ECSCHNORR, TPMS_ENC_SCHEME_RSAES, + /// TPMS_ENC_SCHEME_OAEP, TPMS_SCHEME_HASH, TPMS_NULL_ASYM_SCHEME. + pub details: Option, +} + +impl TPMT_RSA_DECRYPT { + /// Creates a new instance with the specified values + pub fn new( + details: &Option, + ) -> Self { + Self { + details: details.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPMT_RSA_DECRYPT { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + if (self.details.is_none()) { return Ok(()) }; + buf.writeShort(self.details.as_ref().unwrap().GetUnionSelector().into()); + self.details.as_ref().unwrap().toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + let r#scheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); + self.details = TPMU_ASYM_SCHEME::create(r#scheme)?; + self.details.as_mut().unwrap().initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPMT_RSA_DECRYPT { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This sized buffer holds the largest RSA public key supported by the TPM. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2B_PUBLIC_KEY_RSA { + /// Value + pub buffer: Vec, +} + +impl TPM2B_PUBLIC_KEY_RSA { + /// Creates a new instance with the specified values + pub fn new( + buffer: &Vec, + ) -> Self { + Self { + buffer: buffer.clone(), + ..Default::default() + } + } + + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::RSA + } +} + +impl TpmStructure for TPM2B_PUBLIC_KEY_RSA { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.buffer, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.buffer = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2B_PUBLIC_KEY_RSA { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This sized buffer holds the largest RSA prime number supported by the TPM. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2B_PRIVATE_KEY_RSA { + pub buffer: Vec, +} + +impl TPM2B_PRIVATE_KEY_RSA { + /// Creates a new instance with the specified values + pub fn new( + buffer: &Vec, + ) -> Self { + Self { + buffer: buffer.clone(), + ..Default::default() + } + } + + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::RSA + } +} + +impl TpmStructure for TPM2B_PRIVATE_KEY_RSA { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.buffer, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.buffer = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2B_PRIVATE_KEY_RSA { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This sized buffer holds the largest ECC parameter (coordinate) supported by the TPM. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2B_ECC_PARAMETER { + /// The parameter data + pub buffer: Vec, +} + +impl TPM2B_ECC_PARAMETER { + /// Creates a new instance with the specified values + pub fn new( + buffer: &Vec, + ) -> Self { + Self { + buffer: buffer.clone(), + ..Default::default() + } + } + + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::ECC + } +} + +impl TpmStructure for TPM2B_ECC_PARAMETER { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.buffer, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.buffer = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2B_ECC_PARAMETER { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This structure holds two ECC coordinates that, together, make up an ECC point. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_ECC_POINT { + /// X coordinate + pub x: Vec, + + /// Y coordinate + pub y: Vec, +} + +impl TPMS_ECC_POINT { + /// Creates a new instance with the specified values + pub fn new( + x: &Vec, + y: &Vec, + ) -> Self { + Self { + x: x.clone(), + y: y.clone(), + ..Default::default() + } + } + + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::ECC + } +} + +impl TpmStructure for TPMS_ECC_POINT { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.x, 2); + buf.writeSizedByteBuf(&self.y, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.x = buf.readSizedByteBuf(2); + self.y = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_ECC_POINT { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This structure is defined to allow a point to be a single sized parameter so that it +/// may be encrypted. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2B_ECC_POINT { + /// Coordinates + pub point: TPMS_ECC_POINT, +} + +impl TPM2B_ECC_POINT { + /// Creates a new instance with the specified values + pub fn new( + point: &TPMS_ECC_POINT, + ) -> Self { + Self { + point: point.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2B_ECC_POINT { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedObj(&self.point)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readSizedObj(&mut self.point)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2B_ECC_POINT { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// Table 183 Definition of (TPMT_SIG_SCHEME) {ECC} TPMT_ECC_SCHEME Structure +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMT_ECC_SCHEME { + /// Scheme selector + + /// Scheme parameters + /// One of: TPMS_KEY_SCHEME_ECDH, TPMS_KEY_SCHEME_ECMQV, TPMS_SIG_SCHEME_RSASSA, + /// TPMS_SIG_SCHEME_RSAPSS, TPMS_SIG_SCHEME_ECDSA, TPMS_SIG_SCHEME_ECDAA, + /// TPMS_SIG_SCHEME_SM2, TPMS_SIG_SCHEME_ECSCHNORR, TPMS_ENC_SCHEME_RSAES, + /// TPMS_ENC_SCHEME_OAEP, TPMS_SCHEME_HASH, TPMS_NULL_ASYM_SCHEME. + pub details: Option, +} + +impl TPMT_ECC_SCHEME { + /// Creates a new instance with the specified values + pub fn new( + details: &Option, + ) -> Self { + Self { + details: details.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPMT_ECC_SCHEME { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + if (self.details.is_none()) { return Ok(()) }; + buf.writeShort(self.details.as_ref().unwrap().GetUnionSelector().into()); + self.details.as_ref().unwrap().toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + let r#scheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); + self.details = TPMU_ASYM_SCHEME::create(r#scheme)?; + self.details.as_mut().unwrap().initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPMT_ECC_SCHEME { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This structure is used to report on the curve parameters of an ECC curve. It is +/// returned by TPM2_ECC_Parameters(). +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_ALGORITHM_DETAIL_ECC { + /// Identifier for the curve + pub curveID: TPM_ECC_CURVE, + + /// Size in bits of the key + pub keySize: u16, + + /// Scheme selector + + /// If not TPM_ALG_NULL, the required KDF and hash algorithm used in secret sharing operations + /// One of: TPMS_KDF_SCHEME_MGF1, TPMS_KDF_SCHEME_KDF1_SP800_56A, TPMS_KDF_SCHEME_KDF2, + /// TPMS_KDF_SCHEME_KDF1_SP800_108, TPMS_SCHEME_HASH, TPMS_NULL_KDF_SCHEME. + pub kdf: Option, + + /// Scheme selector + + /// If not TPM_ALG_NULL, this is the mandatory signature scheme that is required to be + /// used with this curve. + /// One of: TPMS_KEY_SCHEME_ECDH, TPMS_KEY_SCHEME_ECMQV, TPMS_SIG_SCHEME_RSASSA, + /// TPMS_SIG_SCHEME_RSAPSS, TPMS_SIG_SCHEME_ECDSA, TPMS_SIG_SCHEME_ECDAA, + /// TPMS_SIG_SCHEME_SM2, TPMS_SIG_SCHEME_ECSCHNORR, TPMS_ENC_SCHEME_RSAES, + /// TPMS_ENC_SCHEME_OAEP, TPMS_SCHEME_HASH, TPMS_NULL_ASYM_SCHEME. + pub sign: Option, + + /// Fp (the modulus) + pub p: Vec, + + /// Coefficient of the linear term in the curve equation + pub a: Vec, + + /// Constant term for curve equation + pub b: Vec, + + /// X coordinate of base point G + pub gX: Vec, + + /// Y coordinate of base point G + pub gY: Vec, + + /// Order of G + pub n: Vec, + + /// Cofactor (a size of zero indicates a cofactor of 1) + pub h: Vec, +} + +impl TPMS_ALGORITHM_DETAIL_ECC { + /// Creates a new instance with the specified values + pub fn new( + curveID: TPM_ECC_CURVE, + keySize: u16, + kdf: &Option, + sign: &Option, + p: &Vec, + a: &Vec, + b: &Vec, + gX: &Vec, + gY: &Vec, + n: &Vec, + h: &Vec, + ) -> Self { + Self { + curveID: curveID.clone(), + keySize: keySize.clone(), + kdf: kdf.clone(), + sign: sign.clone(), + p: p.clone(), + a: a.clone(), + b: b.clone(), + gX: gX.clone(), + gY: gY.clone(), + n: n.clone(), + h: h.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPMS_ALGORITHM_DETAIL_ECC { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeShort(self.curveID.into()); + buf.writeShort(self.keySize as u16); + buf.writeShort(self.kdf.as_ref().unwrap().GetUnionSelector().into()); + self.kdf.as_ref().unwrap().toTpm(buf)?; + buf.writeShort(self.sign.as_ref().unwrap().GetUnionSelector().into()); + self.sign.as_ref().unwrap().toTpm(buf)?; + buf.writeSizedByteBuf(&self.p, 2); + buf.writeSizedByteBuf(&self.a, 2); + buf.writeSizedByteBuf(&self.b, 2); + buf.writeSizedByteBuf(&self.gX, 2); + buf.writeSizedByteBuf(&self.gY, 2); + buf.writeSizedByteBuf(&self.n, 2); + buf.writeSizedByteBuf(&self.h, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.curveID = TPM_ECC_CURVE(buf.readShort() as u16); + self.keySize = buf.readShort() as u16; + let r#kdfScheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); + self.kdf = TPMU_KDF_SCHEME::create(r#kdfScheme)?; + self.kdf.as_mut().unwrap().initFromTpm(buf)?; + let r#signScheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); + self.sign = TPMU_ASYM_SCHEME::create(r#signScheme)?; + self.sign.as_mut().unwrap().initFromTpm(buf)?; + self.p = buf.readSizedByteBuf(2); + self.a = buf.readSizedByteBuf(2); + self.b = buf.readSizedByteBuf(2); + self.gX = buf.readSizedByteBuf(2); + self.gY = buf.readSizedByteBuf(2); + self.n = buf.readSizedByteBuf(2); + self.h = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_ALGORITHM_DETAIL_ECC { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// Table 185 Definition of {RSA} TPMS_SIGNATURE_RSA Structure +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_SIGNATURE_RSA { + /// The hash algorithm used to digest the message + /// TPM_ALG_NULL is not allowed. + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub hash: TPM_ALG_ID, + + /// The signature is the size of a public key. + pub sig: Vec, +} + +impl TPMS_SIGNATURE_RSA { + /// Creates a new instance with the specified values + pub fn new( + hash: TPM_ALG_ID, + sig: &Vec, + ) -> Self { + Self { + hash: hash.clone(), + sig: sig.clone(), + ..Default::default() + } + } + + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::RSASSA + } +} + +impl TpmStructure for TPMS_SIGNATURE_RSA { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeShort(self.hash.into()); + buf.writeSizedByteBuf(&self.sig, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.hash = TPM_ALG_ID(buf.readShort() as u16); + self.sig = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_SIGNATURE_RSA { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// Table 185 Definition of {RSA} TPMS_SIGNATURE_RSA Structure +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_SIGNATURE_RSASSA { + /// The hash algorithm used to digest the message + /// TPM_ALG_NULL is not allowed. + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub hash: TPM_ALG_ID, + + /// The signature is the size of a public key. + pub sig: Vec, +} + +impl TPMS_SIGNATURE_RSASSA { + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::RSASSA + } +} + +impl TpmStructure for TPMS_SIGNATURE_RSASSA { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeShort(self.hash.into()); + buf.writeSizedByteBuf(&self.sig, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.hash = TPM_ALG_ID(buf.readShort() as u16); + self.sig = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_SIGNATURE_RSASSA { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// Table 185 Definition of {RSA} TPMS_SIGNATURE_RSA Structure +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_SIGNATURE_RSAPSS { + /// The hash algorithm used to digest the message + /// TPM_ALG_NULL is not allowed. + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub hash: TPM_ALG_ID, + + /// The signature is the size of a public key. + pub sig: Vec, +} + +impl TPMS_SIGNATURE_RSAPSS { + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::RSAPSS + } +} + +impl TpmStructure for TPMS_SIGNATURE_RSAPSS { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeShort(self.hash.into()); + buf.writeSizedByteBuf(&self.sig, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.hash = TPM_ALG_ID(buf.readShort() as u16); + self.sig = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_SIGNATURE_RSAPSS { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// Table 187 Definition of {ECC} TPMS_SIGNATURE_ECC Structure +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_SIGNATURE_ECC { + /// The hash algorithm used in the signature process + /// TPM_ALG_NULL is not allowed. + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub hash: TPM_ALG_ID, + pub signatureR: Vec, + pub signatureS: Vec, +} + +impl TPMS_SIGNATURE_ECC { + /// Creates a new instance with the specified values + pub fn new( + hash: TPM_ALG_ID, + signatureR: &Vec, + signatureS: &Vec, + ) -> Self { + Self { + hash: hash.clone(), + signatureR: signatureR.clone(), + signatureS: signatureS.clone(), + ..Default::default() + } + } + + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::ECDSA + } +} + +impl TpmStructure for TPMS_SIGNATURE_ECC { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeShort(self.hash.into()); + buf.writeSizedByteBuf(&self.signatureR, 2); + buf.writeSizedByteBuf(&self.signatureS, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.hash = TPM_ALG_ID(buf.readShort() as u16); + self.signatureR = buf.readSizedByteBuf(2); + self.signatureS = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_SIGNATURE_ECC { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// Table 187 Definition of {ECC} TPMS_SIGNATURE_ECC Structure +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_SIGNATURE_ECDSA { + /// The hash algorithm used in the signature process + /// TPM_ALG_NULL is not allowed. + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub hash: TPM_ALG_ID, + pub signatureR: Vec, + pub signatureS: Vec, +} + +impl TPMS_SIGNATURE_ECDSA { + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::ECDSA + } +} + +impl TpmStructure for TPMS_SIGNATURE_ECDSA { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeShort(self.hash.into()); + buf.writeSizedByteBuf(&self.signatureR, 2); + buf.writeSizedByteBuf(&self.signatureS, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.hash = TPM_ALG_ID(buf.readShort() as u16); + self.signatureR = buf.readSizedByteBuf(2); + self.signatureS = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_SIGNATURE_ECDSA { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// Table 187 Definition of {ECC} TPMS_SIGNATURE_ECC Structure +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_SIGNATURE_ECDAA { + /// The hash algorithm used in the signature process + /// TPM_ALG_NULL is not allowed. + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub hash: TPM_ALG_ID, + pub signatureR: Vec, + pub signatureS: Vec, +} + +impl TPMS_SIGNATURE_ECDAA { + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::ECDAA + } +} + +impl TpmStructure for TPMS_SIGNATURE_ECDAA { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeShort(self.hash.into()); + buf.writeSizedByteBuf(&self.signatureR, 2); + buf.writeSizedByteBuf(&self.signatureS, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.hash = TPM_ALG_ID(buf.readShort() as u16); + self.signatureR = buf.readSizedByteBuf(2); + self.signatureS = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_SIGNATURE_ECDAA { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// Table 187 Definition of {ECC} TPMS_SIGNATURE_ECC Structure +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_SIGNATURE_SM2 { + /// The hash algorithm used in the signature process + /// TPM_ALG_NULL is not allowed. + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub hash: TPM_ALG_ID, + pub signatureR: Vec, + pub signatureS: Vec, +} + +impl TPMS_SIGNATURE_SM2 { + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::SM2 + } +} + +impl TpmStructure for TPMS_SIGNATURE_SM2 { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeShort(self.hash.into()); + buf.writeSizedByteBuf(&self.signatureR, 2); + buf.writeSizedByteBuf(&self.signatureS, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.hash = TPM_ALG_ID(buf.readShort() as u16); + self.signatureR = buf.readSizedByteBuf(2); + self.signatureS = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_SIGNATURE_SM2 { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// Table 187 Definition of {ECC} TPMS_SIGNATURE_ECC Structure +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_SIGNATURE_ECSCHNORR { + /// The hash algorithm used in the signature process + /// TPM_ALG_NULL is not allowed. + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub hash: TPM_ALG_ID, + pub signatureR: Vec, + pub signatureS: Vec, +} + +impl TPMS_SIGNATURE_ECSCHNORR { + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::ECSCHNORR + } +} + +impl TpmStructure for TPMS_SIGNATURE_ECSCHNORR { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeShort(self.hash.into()); + buf.writeSizedByteBuf(&self.signatureR, 2); + buf.writeSizedByteBuf(&self.signatureS, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.hash = TPM_ALG_ID(buf.readShort() as u16); + self.signatureR = buf.readSizedByteBuf(2); + self.signatureS = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_SIGNATURE_ECSCHNORR { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// Custom data structure representing an empty element (i.e. the one with +/// no data to marshal) for selector algorithm TPM_ALG_NULL for the union TPMU_SIGNATURE +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_NULL_SIGNATURE { +} + +impl TPMS_NULL_SIGNATURE { + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::NULL + } +} + +impl TpmStructure for TPMS_NULL_SIGNATURE { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_NULL_SIGNATURE { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// Table 190 shows the basic algorithm-agile structure when a symmetric or asymmetric +/// signature is indicated. The sigAlg parameter indicates the algorithm used for the +/// signature. This structure is output from commands such as the attestation commands and +/// TPM2_Sign, and is an input to commands such as TPM2_VerifySignature(), +/// TPM2_PolicySigned(), and TPM2_FieldUpgradeStart(). +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMT_SIGNATURE { + /// Selector of the algorithm used to construct the signature + + /// This shall be the actual signature information. + /// One of: TPMS_SIGNATURE_RSASSA, TPMS_SIGNATURE_RSAPSS, TPMS_SIGNATURE_ECDSA, + /// TPMS_SIGNATURE_ECDAA, TPMS_SIGNATURE_SM2, TPMS_SIGNATURE_ECSCHNORR, TPMT_HA, + /// TPMS_SCHEME_HASH, TPMS_NULL_SIGNATURE. + pub signature: Option, +} + +impl TPMT_SIGNATURE { + /// Creates a new instance with the specified values + pub fn new( + signature: &Option, + ) -> Self { + Self { + signature: signature.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPMT_SIGNATURE { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + if (self.signature.is_none()) { return Ok(()) }; + buf.writeShort(self.signature.as_ref().unwrap().GetUnionSelector().into()); + self.signature.as_ref().unwrap().toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + let r#sigAlg: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); + self.signature = TPMU_SIGNATURE::create(r#sigAlg)?; + self.signature.as_mut().unwrap().initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPMT_SIGNATURE { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// Table 192 Definition of TPM2B_ENCRYPTED_SECRET Structure +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2B_ENCRYPTED_SECRET { + /// Secret + pub secret: Vec, +} + +impl TPM2B_ENCRYPTED_SECRET { + /// Creates a new instance with the specified values + pub fn new( + secret: &Vec, + ) -> Self { + Self { + secret: secret.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2B_ENCRYPTED_SECRET { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.secret, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.secret = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2B_ENCRYPTED_SECRET { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This structure describes the parameters that would appear in the public area of a +/// KEYEDHASH object. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_KEYEDHASH_PARMS { + /// Selects the scheme + + /// Indicates the signing method used for a keyedHash signing object. This field also + /// determines the size of the data field for a data object created with TPM2_Create() or + /// TPM2_CreatePrimary(). + /// One of: TPMS_SCHEME_HMAC, TPMS_SCHEME_XOR, TPMS_NULL_SCHEME_KEYEDHASH. + pub scheme: Option, +} + +impl TPMS_KEYEDHASH_PARMS { + /// Creates a new instance with the specified values + pub fn new( + scheme: &Option, + ) -> Self { + Self { + scheme: scheme.clone(), + ..Default::default() + } + } + + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::KEYEDHASH + } +} + +impl TpmStructure for TPMS_KEYEDHASH_PARMS { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + if (self.scheme.is_none()) { return Ok(()) }; + buf.writeShort(self.scheme.as_ref().unwrap().GetUnionSelector().into()); + self.scheme.as_ref().unwrap().toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + let r#schemeScheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); + self.scheme = TPMU_SCHEME_KEYEDHASH::create(r#schemeScheme)?; + self.scheme.as_mut().unwrap().initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_KEYEDHASH_PARMS { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This structure contains the common public area parameters for an asymmetric key. The +/// first two parameters of the parameter definition structures of an asymmetric key shall +/// have the same two first components. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_ASYM_PARMS { + /// The companion symmetric algorithm for a restricted decryption key and shall be set to + /// a supported symmetric algorithm + /// This field is optional for keys that are not decryption keys and shall be set to + /// TPM_ALG_NULL if not used. + pub symmetric: TPMT_SYM_DEF_OBJECT, + + /// Scheme selector + + /// For a key with the sign attribute SET, a valid signing scheme for the key type + /// for a key with the decrypt attribute SET, a valid key exchange protocol + /// for a key with sign and decrypt attributes, shall be TPM_ALG_NULL + /// One of: TPMS_KEY_SCHEME_ECDH, TPMS_KEY_SCHEME_ECMQV, TPMS_SIG_SCHEME_RSASSA, + /// TPMS_SIG_SCHEME_RSAPSS, TPMS_SIG_SCHEME_ECDSA, TPMS_SIG_SCHEME_ECDAA, + /// TPMS_SIG_SCHEME_SM2, TPMS_SIG_SCHEME_ECSCHNORR, TPMS_ENC_SCHEME_RSAES, + /// TPMS_ENC_SCHEME_OAEP, TPMS_SCHEME_HASH, TPMS_NULL_ASYM_SCHEME. + pub scheme: Option, +} + +impl TPMS_ASYM_PARMS { + /// Creates a new instance with the specified values + pub fn new( + symmetric: &TPMT_SYM_DEF_OBJECT, + scheme: &Option, + ) -> Self { + Self { + symmetric: symmetric.clone(), + scheme: scheme.clone(), + ..Default::default() + } + } + + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::ANY + } +} + +impl TpmStructure for TPMS_ASYM_PARMS { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + self.symmetric.toTpm(buf)?; + buf.writeShort(self.scheme.as_ref().unwrap().GetUnionSelector().into()); + self.scheme.as_ref().unwrap().toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.symmetric.initFromTpm(buf)?; + let r#schemeScheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); + self.scheme = TPMU_ASYM_SCHEME::create(r#schemeScheme)?; + self.scheme.as_mut().unwrap().initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_ASYM_PARMS { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// A TPM compatible with this specification and supporting RSA shall support two primes +/// and an exponent of zero. An exponent of zero indicates that the exponent is the +/// default of 216 + 1. Support for other values is optional. Use of other exponents in +/// duplicated keys is not recommended because the resulting keys would not be +/// interoperable with other TPMs. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_RSA_PARMS { + /// For a restricted decryption key, shall be set to a supported symmetric algorithm, key + /// size, and mode. + /// if the key is not a restricted decryption key, this field shall be set to TPM_ALG_NULL. + pub symmetric: TPMT_SYM_DEF_OBJECT, + + /// Scheme selector + + /// Scheme.scheme shall be: + /// for an unrestricted signing key, either TPM_ALG_RSAPSS TPM_ALG_RSASSA or TPM_ALG_NULL + /// for a restricted signing key, either TPM_ALG_RSAPSS or TPM_ALG_RSASSA + /// for an unrestricted decryption key, TPM_ALG_RSAES, TPM_ALG_OAEP, or TPM_ALG_NULL + /// unless the object also has the sign attribute + /// for a restricted decryption key, TPM_ALG_NULL + /// NOTE When both sign and decrypt are SET, restricted shall be CLEAR and scheme shall be + /// TPM_ALG_NULL. + /// One of: TPMS_KEY_SCHEME_ECDH, TPMS_KEY_SCHEME_ECMQV, TPMS_SIG_SCHEME_RSASSA, + /// TPMS_SIG_SCHEME_RSAPSS, TPMS_SIG_SCHEME_ECDSA, TPMS_SIG_SCHEME_ECDAA, + /// TPMS_SIG_SCHEME_SM2, TPMS_SIG_SCHEME_ECSCHNORR, TPMS_ENC_SCHEME_RSAES, + /// TPMS_ENC_SCHEME_OAEP, TPMS_SCHEME_HASH, TPMS_NULL_ASYM_SCHEME. + pub scheme: Option, + + /// Number of bits in the public modulus + pub keyBits: u16, + + /// The public exponent + /// A prime number greater than 2. + pub exponent: u32, +} + +impl TPMS_RSA_PARMS { + /// Creates a new instance with the specified values + pub fn new( + symmetric: &TPMT_SYM_DEF_OBJECT, + scheme: &Option, + keyBits: u16, + exponent: u32, + ) -> Self { + Self { + symmetric: symmetric.clone(), + scheme: scheme.clone(), + keyBits: keyBits.clone(), + exponent: exponent.clone(), + ..Default::default() + } + } + + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::RSA + } +} + +impl TpmStructure for TPMS_RSA_PARMS { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + self.symmetric.toTpm(buf)?; + buf.writeShort(self.scheme.as_ref().unwrap().GetUnionSelector().into()); + self.scheme.as_ref().unwrap().toTpm(buf)?; + buf.writeShort(self.keyBits as u16); + buf.writeInt(self.exponent as u32); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.symmetric.initFromTpm(buf)?; + let r#schemeScheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); + self.scheme = TPMU_ASYM_SCHEME::create(r#schemeScheme)?; + self.scheme.as_mut().unwrap().initFromTpm(buf)?; + self.keyBits = buf.readShort() as u16; + self.exponent = buf.readInt() as u32; + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_RSA_PARMS { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This structure contains the parameters for prime modulus ECC. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_ECC_PARMS { + /// For a restricted decryption key, shall be set to a supported symmetric algorithm, key + /// size. and mode. + /// if the key is not a restricted decryption key, this field shall be set to TPM_ALG_NULL. + pub symmetric: TPMT_SYM_DEF_OBJECT, + + /// Scheme selector + + /// If the sign attribute of the key is SET, then this shall be a valid signing scheme. + /// NOTE If the sign parameter in curveID indicates a mandatory scheme, then this field + /// shall have the same value. + /// If the decrypt attribute of the key is SET, then this shall be a valid key exchange + /// scheme or TPM_ALG_NULL. + /// If the key is a Storage Key, then this field shall be TPM_ALG_NULL. + /// One of: TPMS_KEY_SCHEME_ECDH, TPMS_KEY_SCHEME_ECMQV, TPMS_SIG_SCHEME_RSASSA, + /// TPMS_SIG_SCHEME_RSAPSS, TPMS_SIG_SCHEME_ECDSA, TPMS_SIG_SCHEME_ECDAA, + /// TPMS_SIG_SCHEME_SM2, TPMS_SIG_SCHEME_ECSCHNORR, TPMS_ENC_SCHEME_RSAES, + /// TPMS_ENC_SCHEME_OAEP, TPMS_SCHEME_HASH, TPMS_NULL_ASYM_SCHEME. + pub scheme: Option, + + /// ECC curve ID + pub curveID: TPM_ECC_CURVE, + + /// Scheme selector + + /// An optional key derivation scheme for generating a symmetric key from a Z value + /// If the kdf parameter associated with curveID is not TPM_ALG_NULL then this is required + /// to be NULL. + /// NOTE There are currently no commands where this parameter has effect and, in the + /// reference code, this field needs to be set to TPM_ALG_NULL. + /// One of: TPMS_KDF_SCHEME_MGF1, TPMS_KDF_SCHEME_KDF1_SP800_56A, TPMS_KDF_SCHEME_KDF2, + /// TPMS_KDF_SCHEME_KDF1_SP800_108, TPMS_SCHEME_HASH, TPMS_NULL_KDF_SCHEME. + pub kdf: Option, +} + +impl TPMS_ECC_PARMS { + /// Creates a new instance with the specified values + pub fn new( + symmetric: &TPMT_SYM_DEF_OBJECT, + scheme: &Option, + curveID: TPM_ECC_CURVE, + kdf: &Option, + ) -> Self { + Self { + symmetric: symmetric.clone(), + scheme: scheme.clone(), + curveID: curveID.clone(), + kdf: kdf.clone(), + ..Default::default() + } + } + + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::ECC + } +} + +impl TpmStructure for TPMS_ECC_PARMS { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + self.symmetric.toTpm(buf)?; + buf.writeShort(self.scheme.as_ref().unwrap().GetUnionSelector().into()); + self.scheme.as_ref().unwrap().toTpm(buf)?; + buf.writeShort(self.curveID.into()); + buf.writeShort(self.kdf.as_ref().unwrap().GetUnionSelector().into()); + self.kdf.as_ref().unwrap().toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.symmetric.initFromTpm(buf)?; + let r#schemeScheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); + self.scheme = TPMU_ASYM_SCHEME::create(r#schemeScheme)?; + self.scheme.as_mut().unwrap().initFromTpm(buf)?; + self.curveID = TPM_ECC_CURVE(buf.readShort() as u16); + let r#kdfScheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); + self.kdf = TPMU_KDF_SCHEME::create(r#kdfScheme)?; + self.kdf.as_mut().unwrap().initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_ECC_PARMS { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This structure is used in TPM2_TestParms() to validate that a set of algorithm +/// parameters is supported by the TPM. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMT_PUBLIC_PARMS { + /// The algorithm to be tested + + /// The algorithm details + /// One of: TPMS_KEYEDHASH_PARMS, TPMS_SYMCIPHER_PARMS, TPMS_RSA_PARMS, TPMS_ECC_PARMS, + /// TPMS_ASYM_PARMS. + pub parameters: Option, +} + +impl TPMT_PUBLIC_PARMS { + /// Creates a new instance with the specified values + pub fn new( + parameters: &Option, + ) -> Self { + Self { + parameters: parameters.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPMT_PUBLIC_PARMS { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + if (self.parameters.is_none()) { return Ok(()) }; + buf.writeShort(self.parameters.as_ref().unwrap().GetUnionSelector().into()); + self.parameters.as_ref().unwrap().toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + let r#type: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); + self.parameters = TPMU_PUBLIC_PARMS::create(r#type)?; + self.parameters.as_mut().unwrap().initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPMT_PUBLIC_PARMS { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// Table 201 defines the public area structure. The Name of the object is nameAlg +/// concatenated with the digest of this structure using nameAlg. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMT_PUBLIC { + /// Algorithm associated with this object + + /// Algorithm used for computing the Name of the object + /// NOTE The "+" indicates that the instance of a TPMT_PUBLIC may have a "+" to indicate + /// that the nameAlg may be TPM_ALG_NULL. + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub nameAlg: TPM_ALG_ID, + + /// Attributes that, along with type, determine the manipulations of this object + pub objectAttributes: TPMA_OBJECT, + + /// Optional policy for using this key + /// The policy is computed using the nameAlg of the object. + /// NOTE Shall be the Empty Policy if no authorization policy is present. + pub authPolicy: Vec, + + /// The algorithm or structure details + /// One of: TPMS_KEYEDHASH_PARMS, TPMS_SYMCIPHER_PARMS, TPMS_RSA_PARMS, TPMS_ECC_PARMS, + /// TPMS_ASYM_PARMS. + pub parameters: Option, + + /// The unique identifier of the structure + /// For an asymmetric key, this would be the public key. + /// One of: TPM2B_DIGEST_KEYEDHASH, TPM2B_DIGEST_SYMCIPHER, TPM2B_PUBLIC_KEY_RSA, + /// TPMS_ECC_POINT, TPMS_DERIVE. + pub unique: Option, +} + +impl TPMT_PUBLIC { + /// Creates a new instance with the specified values + pub fn new( + nameAlg: TPM_ALG_ID, + objectAttributes: TPMA_OBJECT, + authPolicy: &Vec, + parameters: &Option, + unique: &Option, + ) -> Self { + Self { + nameAlg: nameAlg.clone(), + objectAttributes: objectAttributes.clone(), + authPolicy: authPolicy.clone(), + parameters: parameters.clone(), + unique: unique.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPMT_PUBLIC { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + if (self.parameters.is_none()) { return Ok(()) }; + buf.writeShort(self.parameters.as_ref().unwrap().GetUnionSelector().into()); + buf.writeShort(self.nameAlg.into()); + buf.writeInt(self.objectAttributes.into()); + buf.writeSizedByteBuf(&self.authPolicy, 2); + self.parameters.as_ref().unwrap().toTpm(buf)?; + self.unique.as_ref().unwrap().toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + let r#type: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); + self.nameAlg = TPM_ALG_ID(buf.readShort() as u16); + self.objectAttributes = TPMA_OBJECT(buf.readInt() as u32); + self.authPolicy = buf.readSizedByteBuf(2); + self.parameters = TPMU_PUBLIC_PARMS::create(r#type)?; + self.parameters.as_mut().unwrap().initFromTpm(buf)?; + self.unique = TPMU_PUBLIC_ID::create(r#type)?; + self.unique.as_mut().unwrap().initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPMT_PUBLIC { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This sized buffer is used to embed a TPMT_PUBLIC in a load command and in any response +/// that returns a public area. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2B_PUBLIC { + /// The public area + /// NOTE The + indicates that the caller may specify that use of TPM_ALG_NULL is allowed + /// for nameAlg. + pub publicArea: TPMT_PUBLIC, +} + +impl TPM2B_PUBLIC { + /// Creates a new instance with the specified values + pub fn new( + publicArea: &TPMT_PUBLIC, + ) -> Self { + Self { + publicArea: publicArea.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2B_PUBLIC { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedObj(&self.publicArea)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readSizedObj(&mut self.publicArea)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2B_PUBLIC { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This sized buffer is used to embed a TPMT_TEMPLATE for TPM2_CreateLoaded(). +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2B_TEMPLATE { + /// The public area + pub buffer: Vec, +} + +impl TPM2B_TEMPLATE { + /// Creates a new instance with the specified values + pub fn new( + buffer: &Vec, + ) -> Self { + Self { + buffer: buffer.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2B_TEMPLATE { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.buffer, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.buffer = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2B_TEMPLATE { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This structure is defined for coding purposes. For IO to the TPM, the sensitive +/// portion of the key will be in a canonical form. For an RSA key, this will be one of +/// the prime factors of the public modulus. After loading, it is typical that other +/// values will be computed so that computations using the private key will not need to +/// start with just one prime factor. This structure can be used to store the results of +/// such vendor-specific calculations. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2B_PRIVATE_VENDOR_SPECIFIC { + pub buffer: Vec, +} + +impl TPM2B_PRIVATE_VENDOR_SPECIFIC { + /// Creates a new instance with the specified values + pub fn new( + buffer: &Vec, + ) -> Self { + Self { + buffer: buffer.clone(), + ..Default::default() + } + } + + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::ANY + } +} + +impl TpmStructure for TPM2B_PRIVATE_VENDOR_SPECIFIC { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.buffer, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.buffer = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2B_PRIVATE_VENDOR_SPECIFIC { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// AuthValue shall not be larger than the size of the digest produced by the nameAlg of +/// the object. seedValue shall be the size of the digest produced by the nameAlg of the object. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMT_SENSITIVE { + /// Identifier for the sensitive area + /// This shall be the same as the type parameter of the associated public area. + + /// User authorization data + /// The authValue may be a zero-length string. + pub authValue: Vec, + + /// For a parent object, the optional protection seed; for other objects, the obfuscation value + pub seedValue: Vec, + + /// The type-specific private data + /// One of: TPM2B_PRIVATE_KEY_RSA, TPM2B_ECC_PARAMETER, TPM2B_SENSITIVE_DATA, + /// TPM2B_SYM_KEY, TPM2B_PRIVATE_VENDOR_SPECIFIC. + pub sensitive: Option, +} + +impl TPMT_SENSITIVE { + /// Creates a new instance with the specified values + pub fn new( + authValue: &Vec, + seedValue: &Vec, + sensitive: &Option, + ) -> Self { + Self { + authValue: authValue.clone(), + seedValue: seedValue.clone(), + sensitive: sensitive.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPMT_SENSITIVE { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + if (self.sensitive.is_none()) { return Ok(()) }; + buf.writeShort(self.sensitive.as_ref().unwrap().GetUnionSelector().into()); + buf.writeSizedByteBuf(&self.authValue, 2); + buf.writeSizedByteBuf(&self.seedValue, 2); + self.sensitive.as_ref().unwrap().toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + let r#sensitiveType: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); + self.authValue = buf.readSizedByteBuf(2); + self.seedValue = buf.readSizedByteBuf(2); + self.sensitive = TPMU_SENSITIVE_COMPOSITE::create(r#sensitiveType)?; + self.sensitive.as_mut().unwrap().initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPMT_SENSITIVE { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// The TPM2B_SENSITIVE structure is used as a parameter in TPM2_LoadExternal(). It is an +/// unencrypted sensitive area but it may be encrypted using parameter encryption. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2B_SENSITIVE { + /// An unencrypted sensitive area + pub sensitiveArea: TPMT_SENSITIVE, +} + +impl TPM2B_SENSITIVE { + /// Creates a new instance with the specified values + pub fn new( + sensitiveArea: &TPMT_SENSITIVE, + ) -> Self { + Self { + sensitiveArea: sensitiveArea.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2B_SENSITIVE { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedObj(&self.sensitiveArea)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readSizedObj(&mut self.sensitiveArea)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2B_SENSITIVE { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This structure is defined to size the contents of a TPM2B_PRIVATE. This structure is +/// not directly marshaled or unmarshaled. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct _PRIVATE { + pub integrityOuter: Vec, + + /// Could also be a TPM2B_IV + pub integrityInner: Vec, + + /// The sensitive area + pub sensitive: TPMT_SENSITIVE, +} + +impl _PRIVATE { + /// Creates a new instance with the specified values + pub fn new( + integrityOuter: &Vec, + integrityInner: &Vec, + sensitive: &TPMT_SENSITIVE, + ) -> Self { + Self { + integrityOuter: integrityOuter.clone(), + integrityInner: integrityInner.clone(), + sensitive: sensitive.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for _PRIVATE { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::<_PRIVATE>()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.integrityOuter, 2); + buf.writeSizedByteBuf(&self.integrityInner, 2); + buf.writeSizedObj(&self.sensitive)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.integrityOuter = buf.readSizedByteBuf(2); + self.integrityInner = buf.readSizedByteBuf(2); + buf.readSizedObj(&mut self.sensitive)?; + Ok(()) + } + +} + +impl TpmMarshaller for _PRIVATE { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// The TPM2B_PRIVATE structure is used as a parameter in multiple commands that create, +/// load, and modify the sensitive area of an object. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2B_PRIVATE { + /// An encrypted private area + pub buffer: Vec, +} + +impl TPM2B_PRIVATE { + /// Creates a new instance with the specified values + pub fn new( + buffer: &Vec, + ) -> Self { + Self { + buffer: buffer.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2B_PRIVATE { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.buffer, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.buffer = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2B_PRIVATE { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This structure is used for sizing the TPM2B_ID_OBJECT. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_ID_OBJECT { + /// HMAC using the nameAlg of the storage key on the target TPM + pub integrityHMAC: Vec, + + /// Credential protector information returned if name matches the referenced object + /// All of the encIdentity is encrypted, including the size field. + /// NOTE The TPM is not required to check that the size is not larger than the digest of + /// the nameAlg. However, if the size is larger, the ID object may not be usable on a TPM + /// that has no digest larger than produced by nameAlg. + pub encIdentity: Vec, +} + +impl TPMS_ID_OBJECT { + /// Creates a new instance with the specified values + pub fn new( + integrityHMAC: &Vec, + encIdentity: &Vec, + ) -> Self { + Self { + integrityHMAC: integrityHMAC.clone(), + encIdentity: encIdentity.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPMS_ID_OBJECT { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.integrityHMAC, 2); + buf.writeByteBuf(&self.encIdentity); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.integrityHMAC = buf.readSizedByteBuf(2); + self.encIdentity = buf.readByteBuf(buf.getCurStuctRemainingSize()); + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_ID_OBJECT { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This structure is an output from TPM2_MakeCredential() and is an input to +/// TPM2_ActivateCredential(). +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2B_ID_OBJECT { + /// An encrypted credential area + pub credential: TPMS_ID_OBJECT, +} + +impl TPM2B_ID_OBJECT { + /// Creates a new instance with the specified values + pub fn new( + credential: &TPMS_ID_OBJECT, + ) -> Self { + Self { + credential: credential.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2B_ID_OBJECT { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedObj(&self.credential)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readSizedObj(&mut self.credential)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2B_ID_OBJECT { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This is the data that can be written to and read from a TPM_NT_PIN_PASS or +/// TPM_NT_PIN_FAIL non-volatile index. pinCount is the most significant octets. pinLimit +/// is the least significant octets. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_NV_PIN_COUNTER_PARAMETERS { + /// This counter shows the current number of successful authValue authorization attempts + /// to access a TPM_NT_PIN_PASS index or the current number of unsuccessful authValue + /// authorization attempts to access a TPM_NT_PIN_FAIL index. + pub pinCount: u32, + + /// This threshold is the value of pinCount at which the authValue authorization of the + /// host TPM_NT_PIN_PASS or TPM_NT_PIN_FAIL index is locked out. + pub pinLimit: u32, +} + +impl TPMS_NV_PIN_COUNTER_PARAMETERS { + /// Creates a new instance with the specified values + pub fn new( + pinCount: u32, + pinLimit: u32, + ) -> Self { + Self { + pinCount: pinCount.clone(), + pinLimit: pinLimit.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPMS_NV_PIN_COUNTER_PARAMETERS { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeInt(self.pinCount as u32); + buf.writeInt(self.pinLimit as u32); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.pinCount = buf.readInt() as u32; + self.pinLimit = buf.readInt() as u32; + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_NV_PIN_COUNTER_PARAMETERS { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This structure describes an NV Index. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_NV_PUBLIC { + /// The handle of the data area + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub nvIndex: TPM_HANDLE, + + /// Hash algorithm used to compute the name of the Index and used for the authPolicy. For + /// an extend index, the hash algorithm used for the extend. + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub nameAlg: TPM_ALG_ID, + + /// The Index attributes + pub attributes: TPMA_NV, + + /// Optional access policy for the Index + /// The policy is computed using the nameAlg + /// NOTE Shall be the Empty Policy if no authorization policy is present. + pub authPolicy: Vec, + + /// The size of the data area + /// The maximum size is implementation-dependent. The minimum maximum size is platform-specific. + pub dataSize: u16, +} + +impl TPMS_NV_PUBLIC { + /// Creates a new instance with the specified values + pub fn new( + nvIndex: &TPM_HANDLE, + nameAlg: TPM_ALG_ID, + attributes: TPMA_NV, + authPolicy: &Vec, + dataSize: u16, + ) -> Self { + Self { + nvIndex: nvIndex.clone(), + nameAlg: nameAlg.clone(), + attributes: attributes.clone(), + authPolicy: authPolicy.clone(), + dataSize: dataSize.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPMS_NV_PUBLIC { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + self.nvIndex.toTpm(buf)?; + buf.writeShort(self.nameAlg.into()); + buf.writeInt(self.attributes.into()); + buf.writeSizedByteBuf(&self.authPolicy, 2); + buf.writeShort(self.dataSize as u16); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.nvIndex.initFromTpm(buf)?; + self.nameAlg = TPM_ALG_ID(buf.readShort() as u16); + self.attributes = TPMA_NV(buf.readInt() as u32); + self.authPolicy = buf.readSizedByteBuf(2); + self.dataSize = buf.readShort() as u16; + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_NV_PUBLIC { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This structure is used when a TPMS_NV_PUBLIC is sent on the TPM interface. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2B_NV_PUBLIC { + /// The public area + pub nvPublic: TPMS_NV_PUBLIC, +} + +impl TPM2B_NV_PUBLIC { + /// Creates a new instance with the specified values + pub fn new( + nvPublic: &TPMS_NV_PUBLIC, + ) -> Self { + Self { + nvPublic: nvPublic.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2B_NV_PUBLIC { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedObj(&self.nvPublic)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readSizedObj(&mut self.nvPublic)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2B_NV_PUBLIC { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This structure holds the object or session context data. When saved, the full +/// structure is encrypted. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2B_CONTEXT_SENSITIVE { + /// The sensitive data + pub buffer: Vec, +} + +impl TPM2B_CONTEXT_SENSITIVE { + /// Creates a new instance with the specified values + pub fn new( + buffer: &Vec, + ) -> Self { + Self { + buffer: buffer.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2B_CONTEXT_SENSITIVE { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.buffer, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.buffer = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2B_CONTEXT_SENSITIVE { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This structure holds the integrity value and the encrypted data for a context. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_CONTEXT_DATA { + /// The integrity value + pub integrity: Vec, + + /// The sensitive area + pub encrypted: Vec, +} + +impl TPMS_CONTEXT_DATA { + /// Creates a new instance with the specified values + pub fn new( + integrity: &Vec, + encrypted: &Vec, + ) -> Self { + Self { + integrity: integrity.clone(), + encrypted: encrypted.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPMS_CONTEXT_DATA { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.integrity, 2); + buf.writeByteBuf(&self.encrypted); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.integrity = buf.readSizedByteBuf(2); + self.encrypted = buf.readByteBuf(buf.getCurStuctRemainingSize()); + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_CONTEXT_DATA { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This structure is used in a TPMS_CONTEXT. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2B_CONTEXT_DATA { + pub buffer: TPMS_CONTEXT_DATA, +} + +impl TPM2B_CONTEXT_DATA { + /// Creates a new instance with the specified values + pub fn new( + buffer: &TPMS_CONTEXT_DATA, + ) -> Self { + Self { + buffer: buffer.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2B_CONTEXT_DATA { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedObj(&self.buffer)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readSizedObj(&mut self.buffer)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2B_CONTEXT_DATA { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This structure is used in TPM2_ContextLoad() and TPM2_ContextSave(). If the values of +/// the TPMS_CONTEXT structure in TPM2_ContextLoad() are not the same as the values when +/// the context was saved (TPM2_ContextSave()), then the TPM shall not load the context. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_CONTEXT { + /// The sequence number of the context + /// NOTE Transient object contexts and session contexts used different counters. + pub sequence: u64, + + /// A handle indicating if the context is a session, object, or sequence object (see Table + /// 222 Context Handle Values + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub savedHandle: TPM_HANDLE, + + /// The hierarchy of the context + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub hierarchy: TPM_HANDLE, + + /// The context data and integrity HMAC + pub contextBlob: TPMS_CONTEXT_DATA, +} + +impl TPMS_CONTEXT { + /// Creates a new instance with the specified values + pub fn new( + sequence: u64, + savedHandle: &TPM_HANDLE, + hierarchy: &TPM_HANDLE, + contextBlob: &TPMS_CONTEXT_DATA, + ) -> Self { + Self { + sequence: sequence.clone(), + savedHandle: savedHandle.clone(), + hierarchy: hierarchy.clone(), + contextBlob: contextBlob.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPMS_CONTEXT { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeInt64(self.sequence as u64); + self.savedHandle.toTpm(buf)?; + self.hierarchy.toTpm(buf)?; + buf.writeSizedObj(&self.contextBlob)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.sequence = buf.readInt64() as u64; + self.savedHandle.initFromTpm(buf)?; + self.hierarchy.initFromTpm(buf)?; + buf.readSizedObj(&mut self.contextBlob)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_CONTEXT { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This structure provides information relating to the creation environment for the +/// object. The creation data includes the parent Name, parent Qualified Name, and the +/// digest of selected PCR. These values represent the environment in which the object was +/// created. Creation data allows a relying party to determine if an object was created +/// when some appropriate protections were present. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_CREATION_DATA { + /// List indicating the PCR included in pcrDigest + pub pcrSelect: Vec, + + /// Digest of the selected PCR using nameAlg of the object for which this structure is + /// being created + /// pcrDigest.size shall be zero if the pcrSelect list is empty. + pub pcrDigest: Vec, + + /// The locality at which the object was created + pub locality: TPMA_LOCALITY, + + /// NameAlg of the parent + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub parentNameAlg: TPM_ALG_ID, + + /// Name of the parent at time of creation + /// The size will match digest size associated with parentNameAlg unless it is + /// TPM_ALG_NULL, in which case the size will be 4 and parentName will be the hierarchy handle. + pub parentName: Vec, + + /// Qualified Name of the parent at the time of creation + /// Size is the same as parentName. + pub parentQualifiedName: Vec, + + /// Association with additional information added by the key creator + /// This will be the contents of the outsideInfo parameter in TPM2_Create() or TPM2_CreatePrimary(). + pub outsideInfo: Vec, +} + +impl TPMS_CREATION_DATA { + /// Creates a new instance with the specified values + pub fn new( + pcrSelect: &Vec, + pcrDigest: &Vec, + locality: TPMA_LOCALITY, + parentNameAlg: TPM_ALG_ID, + parentName: &Vec, + parentQualifiedName: &Vec, + outsideInfo: &Vec, + ) -> Self { + Self { + pcrSelect: pcrSelect.clone(), + pcrDigest: pcrDigest.clone(), + locality: locality.clone(), + parentNameAlg: parentNameAlg.clone(), + parentName: parentName.clone(), + parentQualifiedName: parentQualifiedName.clone(), + outsideInfo: outsideInfo.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPMS_CREATION_DATA { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeObjArr(self.pcrSelect.as_ref())?; + buf.writeSizedByteBuf(&self.pcrDigest, 2); + buf.writeByte(self.locality.into()); + buf.writeShort(self.parentNameAlg.into()); + buf.writeSizedByteBuf(&self.parentName, 2); + buf.writeSizedByteBuf(&self.parentQualifiedName, 2); + buf.writeSizedByteBuf(&self.outsideInfo, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readObjArr(self.pcrSelect.as_mut())?; + self.pcrDigest = buf.readSizedByteBuf(2); + self.locality = TPMA_LOCALITY(buf.readByte() as u8); + self.parentNameAlg = TPM_ALG_ID(buf.readShort() as u16); + self.parentName = buf.readSizedByteBuf(2); + self.parentQualifiedName = buf.readSizedByteBuf(2); + self.outsideInfo = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_CREATION_DATA { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This structure is created by TPM2_Create() and TPM2_CreatePrimary(). It is never +/// entered into the TPM and never has a size of zero. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2B_CREATION_DATA { + pub creationData: TPMS_CREATION_DATA, +} + +impl TPM2B_CREATION_DATA { + /// Creates a new instance with the specified values + pub fn new( + creationData: &TPMS_CREATION_DATA, + ) -> Self { + Self { + creationData: creationData.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2B_CREATION_DATA { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedObj(&self.creationData)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readSizedObj(&mut self.creationData)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2B_CREATION_DATA { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// TPMS_AC_OUTPUT is used to return information about an AC. The tag structure parameter +/// indicates the type of the data value. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPMS_AC_OUTPUT { + /// Tag indicating the contents of data + pub tag: TPM_AT, + + /// The data returned from the AC + pub data: u32, +} + +impl TPMS_AC_OUTPUT { + /// Creates a new instance with the specified values + pub fn new( + tag: TPM_AT, + data: u32, + ) -> Self { + Self { + tag: tag.clone(), + data: data.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPMS_AC_OUTPUT { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeInt(self.tag.into()); + buf.writeInt(self.data as u32); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.tag = TPM_AT(buf.readInt() as u32); + self.data = buf.readInt() as u32; + Ok(()) + } + +} + +impl TpmMarshaller for TPMS_AC_OUTPUT { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// This list is only used in TPM2_AC_GetCapability(). +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPML_AC_CAPABILITIES { + /// A list of AC values + pub acCapabilities: Vec, +} + +impl TPML_AC_CAPABILITIES { + /// Creates a new instance with the specified values + pub fn new( + acCapabilities: &Vec, + ) -> Self { + Self { + acCapabilities: acCapabilities.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPML_AC_CAPABILITIES { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeObjArr(self.acCapabilities.as_ref())?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readObjArr(self.acCapabilities.as_mut())?; + Ok(()) + } + +} + +impl TpmMarshaller for TPML_AC_CAPABILITIES { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// TPM2_Startup() is always preceded by _TPM_Init, which is the physical indication that +/// TPM initialization is necessary because of a system-wide reset. TPM2_Startup() is only +/// valid after _TPM_Init. Additional TPM2_Startup() commands are not allowed after it has +/// completed successfully. If a TPM requires TPM2_Startup() and another command is +/// received, or if the TPM receives TPM2_Startup() when it is not required, the TPM shall +/// return TPM_RC_INITIALIZE. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_Startup_REQUEST { + /// TPM_SU_CLEAR or TPM_SU_STATE + pub startupType: TPM_SU, +} + +impl TPM2_Startup_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + startupType: TPM_SU, + ) -> Self { + Self { + startupType: startupType.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_Startup_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeShort(self.startupType.into()); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.startupType = TPM_SU(buf.readShort() as u16); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_Startup_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_Startup_REQUEST { + fn num_handles(&self) -> u16 { 0 } + +} + +impl ReqStructure for TPM2_Startup_REQUEST { + fn num_auth_handles(&self) -> u16 { 0 } + + fn get_handles(&self) -> Vec { vec![] } +} + +/// This command is used to prepare the TPM for a power cycle. The shutdownType parameter +/// indicates how the subsequent TPM2_Startup() will be processed. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_Shutdown_REQUEST { + /// TPM_SU_CLEAR or TPM_SU_STATE + pub shutdownType: TPM_SU, +} + +impl TPM2_Shutdown_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + shutdownType: TPM_SU, + ) -> Self { + Self { + shutdownType: shutdownType.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_Shutdown_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeShort(self.shutdownType.into()); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.shutdownType = TPM_SU(buf.readShort() as u16); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_Shutdown_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_Shutdown_REQUEST { + fn num_handles(&self) -> u16 { 0 } + +} + +impl ReqStructure for TPM2_Shutdown_REQUEST { + fn num_auth_handles(&self) -> u16 { 0 } + + fn get_handles(&self) -> Vec { vec![] } +} + +/// This command causes the TPM to perform a test of its capabilities. If the fullTest is +/// YES, the TPM will test all functions. If fullTest = NO, the TPM will only test those +/// functions that have not previously been tested. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_SelfTest_REQUEST { + /// YES if full test to be performed + /// NO if only test of untested functions required + pub fullTest: u8, +} + +impl TPM2_SelfTest_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + fullTest: u8, + ) -> Self { + Self { + fullTest: fullTest.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_SelfTest_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeByte(self.fullTest as u8); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.fullTest = buf.readByte() as u8; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_SelfTest_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_SelfTest_REQUEST { + fn num_handles(&self) -> u16 { 0 } + +} + +impl ReqStructure for TPM2_SelfTest_REQUEST { + fn num_auth_handles(&self) -> u16 { 0 } + + fn get_handles(&self) -> Vec { vec![] } +} + +/// This command causes the TPM to perform a test of the selected algorithms. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_IncrementalSelfTest_REQUEST { + /// List of algorithms that should be tested + pub toTest: Vec, +} + +impl TPM2_IncrementalSelfTest_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + toTest: &Vec, + ) -> Self { + Self { + toTest: toTest.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_IncrementalSelfTest_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeValArr(self.toTest.as_ref(), 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readValArr(self.toTest.as_mut(), 2)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_IncrementalSelfTest_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_IncrementalSelfTest_REQUEST { + fn num_handles(&self) -> u16 { 0 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 4, val_len: 2 } } +} + +impl ReqStructure for TPM2_IncrementalSelfTest_REQUEST { + fn num_auth_handles(&self) -> u16 { 0 } + + fn get_handles(&self) -> Vec { vec![] } +} + +/// This command causes the TPM to perform a test of the selected algorithms. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct IncrementalSelfTestResponse { + /// List of algorithms that need testing + pub toDoList: Vec, +} + +impl IncrementalSelfTestResponse { +} + +impl TpmStructure for IncrementalSelfTestResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeValArr(self.toDoList.as_ref(), 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readValArr(self.toDoList.as_mut(), 2)?; + Ok(()) + } + +} + +impl TpmMarshaller for IncrementalSelfTestResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for IncrementalSelfTestResponse { + fn num_handles(&self) -> u16 { 0 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 4, val_len: 2 } } +} + +impl RespStructure for IncrementalSelfTestResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// This command returns manufacturer-specific information regarding the results of a +/// self-test and an indication of the test status. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_GetTestResult_REQUEST { +} + +impl TPM2_GetTestResult_REQUEST { +} + +impl TpmStructure for TPM2_GetTestResult_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_GetTestResult_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_GetTestResult_REQUEST { + fn num_handles(&self) -> u16 { 0 } + +} + +impl ReqStructure for TPM2_GetTestResult_REQUEST { + fn num_auth_handles(&self) -> u16 { 0 } + + fn get_handles(&self) -> Vec { vec![] } +} + +/// This command returns manufacturer-specific information regarding the results of a +/// self-test and an indication of the test status. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct GetTestResultResponse { + /// Test result data + /// contains manufacturer-specific information + pub outData: Vec, + pub testResult: TPM_RC, +} + +impl GetTestResultResponse { +} + +impl TpmStructure for GetTestResultResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.outData, 2); + buf.writeInt(self.testResult.into()); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.outData = buf.readSizedByteBuf(2); + self.testResult = TPM_RC(buf.readInt() as u32); + Ok(()) + } + +} + +impl TpmMarshaller for GetTestResultResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for GetTestResultResponse { + fn num_handles(&self) -> u16 { 0 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl RespStructure for GetTestResultResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// This command is used to start an authorization session using alternative methods of +/// establishing the session key (sessionKey). The session key is then used to derive +/// values used for authorization and for encrypting parameters. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_StartAuthSession_REQUEST { + /// Handle of a loaded decrypt key used to encrypt salt + /// may be TPM_RH_NULL + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub tpmKey: TPM_HANDLE, + + /// Entity providing the authValue + /// may be TPM_RH_NULL + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub bind: TPM_HANDLE, + + /// Initial nonceCaller, sets nonceTPM size for the session + /// shall be at least 16 octets + pub nonceCaller: Vec, + + /// Value encrypted according to the type of tpmKey + /// If tpmKey is TPM_RH_NULL, this shall be the Empty Buffer. + pub encryptedSalt: Vec, + + /// Indicates the type of the session; simple HMAC or policy (including a trial policy) + pub sessionType: TPM_SE, + + /// The algorithm and key size for parameter encryption + /// may select TPM_ALG_NULL + pub symmetric: TPMT_SYM_DEF, + + /// Hash algorithm to use for the session + /// Shall be a hash algorithm supported by the TPM and not TPM_ALG_NULL + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub authHash: TPM_ALG_ID, +} + +impl TPM2_StartAuthSession_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + tpmKey: &TPM_HANDLE, + bind: &TPM_HANDLE, + nonceCaller: &Vec, + encryptedSalt: &Vec, + sessionType: TPM_SE, + symmetric: &TPMT_SYM_DEF, + authHash: TPM_ALG_ID, + ) -> Self { + Self { + tpmKey: tpmKey.clone(), + bind: bind.clone(), + nonceCaller: nonceCaller.clone(), + encryptedSalt: encryptedSalt.clone(), + sessionType: sessionType.clone(), + symmetric: symmetric.clone(), + authHash: authHash.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_StartAuthSession_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.nonceCaller, 2); + buf.writeSizedByteBuf(&self.encryptedSalt, 2); + buf.writeByte(self.sessionType.into()); + self.symmetric.toTpm(buf)?; + buf.writeShort(self.authHash.into()); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.nonceCaller = buf.readSizedByteBuf(2); + self.encryptedSalt = buf.readSizedByteBuf(2); + self.sessionType = TPM_SE(buf.readByte() as u8); + self.symmetric.initFromTpm(buf)?; + self.authHash = TPM_ALG_ID(buf.readShort() as u16); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_StartAuthSession_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_StartAuthSession_REQUEST { + fn num_handles(&self) -> u16 { 2 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_StartAuthSession_REQUEST { + fn num_auth_handles(&self) -> u16 { 0 } + + fn get_handles(&self) -> Vec { vec![self.tpmKey.clone(), self.bind.clone()] } +} + +/// This command is used to start an authorization session using alternative methods of +/// establishing the session key (sessionKey). The session key is then used to derive +/// values used for authorization and for encrypting parameters. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct StartAuthSessionResponse { + /// Handle for the newly created session + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub handle: TPM_HANDLE, + + /// The initial nonce from the TPM, used in the computation of the sessionKey + pub nonceTPM: Vec, +} + +impl StartAuthSessionResponse { +} + +impl TpmStructure for StartAuthSessionResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.nonceTPM, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.nonceTPM = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for StartAuthSessionResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for StartAuthSessionResponse { + fn num_handles(&self) -> u16 { 1 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl RespStructure for StartAuthSessionResponse { + fn get_handle(&self) -> TPM_HANDLE { self.handle.clone() } + + fn set_handle(&mut self, handle: &TPM_HANDLE) { self.handle = handle.clone(); } +} + +/// This command allows a policy authorization session to be returned to its initial +/// state. This command is used after the TPM returns TPM_RC_PCR_CHANGED. That response +/// code indicates that a policy will fail because the PCR have changed after +/// TPM2_PolicyPCR() was executed. Restarting the session allows the authorizations to be +/// replayed because the session restarts with the same nonceTPM. If the PCR are valid for +/// the policy, the policy may then succeed. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_PolicyRestart_REQUEST { + /// The handle for the policy session + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub sessionHandle: TPM_HANDLE, +} + +impl TPM2_PolicyRestart_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + sessionHandle: &TPM_HANDLE, + ) -> Self { + Self { + sessionHandle: sessionHandle.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_PolicyRestart_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_PolicyRestart_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_PolicyRestart_REQUEST { + fn num_handles(&self) -> u16 { 1 } + +} + +impl ReqStructure for TPM2_PolicyRestart_REQUEST { + fn num_auth_handles(&self) -> u16 { 0 } + + fn get_handles(&self) -> Vec { vec![self.sessionHandle.clone()] } +} + +/// This command is used to create an object that can be loaded into a TPM using +/// TPM2_Load(). If the command completes successfully, the TPM will create the new object +/// and return the objects creation data (creationData), its public area (outPublic), and +/// its encrypted sensitive area (outPrivate). Preservation of the returned data is the +/// responsibility of the caller. The object will need to be loaded (TPM2_Load()) before +/// it may be used. The only difference between the inPublic TPMT_PUBLIC template and the +/// outPublic TPMT_PUBLIC object is in the unique field. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_Create_REQUEST { + /// Handle of parent for new object + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub parentHandle: TPM_HANDLE, + + /// The sensitive data + pub inSensitive: TPMS_SENSITIVE_CREATE, + + /// The public template + pub inPublic: TPMT_PUBLIC, + + /// Data that will be included in the creation data for this object to provide permanent, + /// verifiable linkage between this object and some object owner data + pub outsideInfo: Vec, + + /// PCR that will be used in creation data + pub creationPCR: Vec, +} + +impl TPM2_Create_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + parentHandle: &TPM_HANDLE, + inSensitive: &TPMS_SENSITIVE_CREATE, + inPublic: &TPMT_PUBLIC, + outsideInfo: &Vec, + creationPCR: &Vec, + ) -> Self { + Self { + parentHandle: parentHandle.clone(), + inSensitive: inSensitive.clone(), + inPublic: inPublic.clone(), + outsideInfo: outsideInfo.clone(), + creationPCR: creationPCR.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_Create_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedObj(&self.inSensitive)?; + buf.writeSizedObj(&self.inPublic)?; + buf.writeSizedByteBuf(&self.outsideInfo, 2); + buf.writeObjArr(self.creationPCR.as_ref())?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readSizedObj(&mut self.inSensitive)?; + buf.readSizedObj(&mut self.inPublic)?; + self.outsideInfo = buf.readSizedByteBuf(2); + buf.readObjArr(self.creationPCR.as_mut())?; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_Create_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_Create_REQUEST { + fn num_handles(&self) -> u16 { 1 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_Create_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.parentHandle.clone()] } +} + +/// This command is used to create an object that can be loaded into a TPM using +/// TPM2_Load(). If the command completes successfully, the TPM will create the new object +/// and return the objects creation data (creationData), its public area (outPublic), and +/// its encrypted sensitive area (outPrivate). Preservation of the returned data is the +/// responsibility of the caller. The object will need to be loaded (TPM2_Load()) before +/// it may be used. The only difference between the inPublic TPMT_PUBLIC template and the +/// outPublic TPMT_PUBLIC object is in the unique field. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct CreateResponse { + /// The private portion of the object + pub outPrivate: TPM2B_PRIVATE, + + /// The public portion of the created object + pub outPublic: TPMT_PUBLIC, + + /// Contains a TPMS_CREATION_DATA + pub creationData: TPMS_CREATION_DATA, + + /// Digest of creationData using nameAlg of outPublic + pub creationHash: Vec, + + /// Ticket used by TPM2_CertifyCreation() to validate that the creation data was produced + /// by the TPM + pub creationTicket: TPMT_TK_CREATION, +} + +impl CreateResponse { +} + +impl TpmStructure for CreateResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + self.outPrivate.toTpm(buf)?; + buf.writeSizedObj(&self.outPublic)?; + buf.writeSizedObj(&self.creationData)?; + buf.writeSizedByteBuf(&self.creationHash, 2); + self.creationTicket.toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.outPrivate.initFromTpm(buf)?; + buf.readSizedObj(&mut self.outPublic)?; + buf.readSizedObj(&mut self.creationData)?; + self.creationHash = buf.readSizedByteBuf(2); + self.creationTicket.initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for CreateResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for CreateResponse { + fn num_handles(&self) -> u16 { 0 } + +} + +impl RespStructure for CreateResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// This command is used to load objects into the TPM. This command is used when both a +/// TPM2B_PUBLIC and TPM2B_PRIVATE are to be loaded. If only a TPM2B_PUBLIC is to be +/// loaded, the TPM2_LoadExternal command is used. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_Load_REQUEST { + /// TPM handle of parent key; shall not be a reserved handle + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub parentHandle: TPM_HANDLE, + + /// The private portion of the object + pub inPrivate: TPM2B_PRIVATE, + + /// The public portion of the object + pub inPublic: TPMT_PUBLIC, +} + +impl TPM2_Load_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + parentHandle: &TPM_HANDLE, + inPrivate: &TPM2B_PRIVATE, + inPublic: &TPMT_PUBLIC, + ) -> Self { + Self { + parentHandle: parentHandle.clone(), + inPrivate: inPrivate.clone(), + inPublic: inPublic.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_Load_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + self.inPrivate.toTpm(buf)?; + buf.writeSizedObj(&self.inPublic)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.inPrivate.initFromTpm(buf)?; + buf.readSizedObj(&mut self.inPublic)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_Load_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_Load_REQUEST { + fn num_handles(&self) -> u16 { 1 } + +} + +impl ReqStructure for TPM2_Load_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.parentHandle.clone()] } +} + +/// This command is used to load objects into the TPM. This command is used when both a +/// TPM2B_PUBLIC and TPM2B_PRIVATE are to be loaded. If only a TPM2B_PUBLIC is to be +/// loaded, the TPM2_LoadExternal command is used. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct LoadResponse { + /// Handle of type TPM_HT_TRANSIENT for the loaded object + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub handle: TPM_HANDLE, + + /// Name of the loaded object + pub name: Vec, +} + +impl LoadResponse { +} + +impl TpmStructure for LoadResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.name, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.name = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for LoadResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for LoadResponse { + fn num_handles(&self) -> u16 { 1 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl RespStructure for LoadResponse { + fn get_handle(&self) -> TPM_HANDLE { self.handle.clone() } + + fn set_handle(&mut self, handle: &TPM_HANDLE) { self.handle = handle.clone(); } + + fn get_resp_name(&self) -> Vec { self.name.clone() } +} + +/// This command is used to load an object that is not a Protected Object into the TPM. +/// The command allows loading of a public area or both a public and sensitive area. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_LoadExternal_REQUEST { + /// The sensitive portion of the object (optional) + pub inPrivate: TPMT_SENSITIVE, + + /// The public portion of the object + pub inPublic: TPMT_PUBLIC, + + /// Hierarchy with which the object area is associated + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub hierarchy: TPM_HANDLE, +} + +impl TPM2_LoadExternal_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + inPrivate: &TPMT_SENSITIVE, + inPublic: &TPMT_PUBLIC, + hierarchy: &TPM_HANDLE, + ) -> Self { + Self { + inPrivate: inPrivate.clone(), + inPublic: inPublic.clone(), + hierarchy: hierarchy.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_LoadExternal_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedObj(&self.inPrivate)?; + buf.writeSizedObj(&self.inPublic)?; + self.hierarchy.toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readSizedObj(&mut self.inPrivate)?; + buf.readSizedObj(&mut self.inPublic)?; + self.hierarchy.initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_LoadExternal_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_LoadExternal_REQUEST { + fn num_handles(&self) -> u16 { 0 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_LoadExternal_REQUEST { + fn num_auth_handles(&self) -> u16 { 0 } + + fn get_handles(&self) -> Vec { vec![] } +} + +/// This command is used to load an object that is not a Protected Object into the TPM. +/// The command allows loading of a public area or both a public and sensitive area. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct LoadExternalResponse { + /// Handle of type TPM_HT_TRANSIENT for the loaded object + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub handle: TPM_HANDLE, + + /// Name of the loaded object + pub name: Vec, +} + +impl LoadExternalResponse { +} + +impl TpmStructure for LoadExternalResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.name, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.name = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for LoadExternalResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for LoadExternalResponse { + fn num_handles(&self) -> u16 { 1 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl RespStructure for LoadExternalResponse { + fn get_handle(&self) -> TPM_HANDLE { self.handle.clone() } + + fn set_handle(&mut self, handle: &TPM_HANDLE) { self.handle = handle.clone(); } + + fn get_resp_name(&self) -> Vec { self.name.clone() } +} + +/// This command allows access to the public area of a loaded object. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_ReadPublic_REQUEST { + /// TPM handle of an object + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub objectHandle: TPM_HANDLE, +} + +impl TPM2_ReadPublic_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + objectHandle: &TPM_HANDLE, + ) -> Self { + Self { + objectHandle: objectHandle.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_ReadPublic_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_ReadPublic_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_ReadPublic_REQUEST { + fn num_handles(&self) -> u16 { 1 } + +} + +impl ReqStructure for TPM2_ReadPublic_REQUEST { + fn num_auth_handles(&self) -> u16 { 0 } + + fn get_handles(&self) -> Vec { vec![self.objectHandle.clone()] } +} + +/// This command allows access to the public area of a loaded object. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct ReadPublicResponse { + /// Structure containing the public area of an object + pub outPublic: TPMT_PUBLIC, + + /// Name of the object + pub name: Vec, + + /// The Qualified Name of the object + pub qualifiedName: Vec, +} + +impl ReadPublicResponse { +} + +impl TpmStructure for ReadPublicResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedObj(&self.outPublic)?; + buf.writeSizedByteBuf(&self.name, 2); + buf.writeSizedByteBuf(&self.qualifiedName, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readSizedObj(&mut self.outPublic)?; + self.name = buf.readSizedByteBuf(2); + self.qualifiedName = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for ReadPublicResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for ReadPublicResponse { + fn num_handles(&self) -> u16 { 0 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl RespStructure for ReadPublicResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } + + fn get_resp_name(&self) -> Vec { self.name.clone() } +} + +/// This command enables the association of a credential with an object in a way that +/// ensures that the TPM has validated the parameters of the credentialed object. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_ActivateCredential_REQUEST { + /// Handle of the object associated with certificate in credentialBlob + /// Auth Index: 1 + /// Auth Role: ADMIN + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub activateHandle: TPM_HANDLE, + + /// Loaded key used to decrypt the TPMS_SENSITIVE in credentialBlob + /// Auth Index: 2 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub keyHandle: TPM_HANDLE, + + /// The credential + pub credentialBlob: TPMS_ID_OBJECT, + + /// KeyHandle algorithm-dependent encrypted seed that protects credentialBlob + pub secret: Vec, +} + +impl TPM2_ActivateCredential_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + activateHandle: &TPM_HANDLE, + keyHandle: &TPM_HANDLE, + credentialBlob: &TPMS_ID_OBJECT, + secret: &Vec, + ) -> Self { + Self { + activateHandle: activateHandle.clone(), + keyHandle: keyHandle.clone(), + credentialBlob: credentialBlob.clone(), + secret: secret.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_ActivateCredential_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedObj(&self.credentialBlob)?; + buf.writeSizedByteBuf(&self.secret, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readSizedObj(&mut self.credentialBlob)?; + self.secret = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_ActivateCredential_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_ActivateCredential_REQUEST { + fn num_handles(&self) -> u16 { 2 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_ActivateCredential_REQUEST { + fn num_auth_handles(&self) -> u16 { 2 } + + fn get_handles(&self) -> Vec { vec![self.activateHandle.clone(), self.keyHandle.clone()] } +} + +/// This command enables the association of a credential with an object in a way that +/// ensures that the TPM has validated the parameters of the credentialed object. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct ActivateCredentialResponse { + /// The decrypted certificate information + /// the data should be no larger than the size of the digest of the nameAlg associated + /// with keyHandle + pub certInfo: Vec, +} + +impl ActivateCredentialResponse { +} + +impl TpmStructure for ActivateCredentialResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.certInfo, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.certInfo = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for ActivateCredentialResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for ActivateCredentialResponse { + fn num_handles(&self) -> u16 { 0 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl RespStructure for ActivateCredentialResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// This command allows the TPM to perform the actions required of a Certificate Authority +/// (CA) in creating a TPM2B_ID_OBJECT containing an activation credential. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_MakeCredential_REQUEST { + /// Loaded public area, used to encrypt the sensitive area containing the credential key + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub handle: TPM_HANDLE, + + /// The credential information + pub credential: Vec, + + /// Name of the object to which the credential applies + pub objectName: Vec, +} + +impl TPM2_MakeCredential_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + handle: &TPM_HANDLE, + credential: &Vec, + objectName: &Vec, + ) -> Self { + Self { + handle: handle.clone(), + credential: credential.clone(), + objectName: objectName.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_MakeCredential_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.credential, 2); + buf.writeSizedByteBuf(&self.objectName, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.credential = buf.readSizedByteBuf(2); + self.objectName = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_MakeCredential_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_MakeCredential_REQUEST { + fn num_handles(&self) -> u16 { 1 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_MakeCredential_REQUEST { + fn num_auth_handles(&self) -> u16 { 0 } + + fn get_handles(&self) -> Vec { vec![self.handle.clone()] } +} + +/// This command allows the TPM to perform the actions required of a Certificate Authority +/// (CA) in creating a TPM2B_ID_OBJECT containing an activation credential. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct MakeCredentialResponse { + /// The credential + pub credentialBlob: TPMS_ID_OBJECT, + + /// Handle algorithm-dependent data that wraps the key that encrypts credentialBlob + pub secret: Vec, +} + +impl MakeCredentialResponse { +} + +impl TpmStructure for MakeCredentialResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedObj(&self.credentialBlob)?; + buf.writeSizedByteBuf(&self.secret, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readSizedObj(&mut self.credentialBlob)?; + self.secret = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for MakeCredentialResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for MakeCredentialResponse { + fn num_handles(&self) -> u16 { 0 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl RespStructure for MakeCredentialResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// This command returns the data in a loaded Sealed Data Object. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_Unseal_REQUEST { + /// Handle of a loaded data object + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub itemHandle: TPM_HANDLE, +} + +impl TPM2_Unseal_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + itemHandle: &TPM_HANDLE, + ) -> Self { + Self { + itemHandle: itemHandle.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_Unseal_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_Unseal_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_Unseal_REQUEST { + fn num_handles(&self) -> u16 { 1 } + +} + +impl ReqStructure for TPM2_Unseal_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.itemHandle.clone()] } +} + +/// This command returns the data in a loaded Sealed Data Object. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct UnsealResponse { + /// Unsealed data + /// Size of outData is limited to be no more than 128 octets. + pub outData: Vec, +} + +impl UnsealResponse { +} + +impl TpmStructure for UnsealResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.outData, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.outData = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for UnsealResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for UnsealResponse { + fn num_handles(&self) -> u16 { 0 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl RespStructure for UnsealResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// This command is used to change the authorization secret for a TPM-resident object. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_ObjectChangeAuth_REQUEST { + /// Handle of the object + /// Auth Index: 1 + /// Auth Role: ADMIN + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub objectHandle: TPM_HANDLE, + + /// Handle of the parent + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub parentHandle: TPM_HANDLE, + + /// New authorization value + pub newAuth: Vec, +} + +impl TPM2_ObjectChangeAuth_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + objectHandle: &TPM_HANDLE, + parentHandle: &TPM_HANDLE, + newAuth: &Vec, + ) -> Self { + Self { + objectHandle: objectHandle.clone(), + parentHandle: parentHandle.clone(), + newAuth: newAuth.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_ObjectChangeAuth_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.newAuth, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.newAuth = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_ObjectChangeAuth_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_ObjectChangeAuth_REQUEST { + fn num_handles(&self) -> u16 { 2 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_ObjectChangeAuth_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.objectHandle.clone(), self.parentHandle.clone()] } +} + +/// This command is used to change the authorization secret for a TPM-resident object. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct ObjectChangeAuthResponse { + /// Private area containing the new authorization value + pub outPrivate: TPM2B_PRIVATE, +} + +impl ObjectChangeAuthResponse { +} + +impl TpmStructure for ObjectChangeAuthResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + self.outPrivate.toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.outPrivate.initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for ObjectChangeAuthResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for ObjectChangeAuthResponse { + fn num_handles(&self) -> u16 { 0 } + +} + +impl RespStructure for ObjectChangeAuthResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// This command creates an object and loads it in the TPM. This command allows creation +/// of any type of object (Primary, Ordinary, or Derived) depending on the type of +/// parentHandle. If parentHandle references a Primary Seed, then a Primary Object is +/// created; if parentHandle references a Storage Parent, then an Ordinary Object is +/// created; and if parentHandle references a Derivation Parent, then a Derived Object is generated. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_CreateLoaded_REQUEST { + /// Handle of a transient storage key, a persistent storage key, TPM_RH_ENDORSEMENT, + /// TPM_RH_OWNER, TPM_RH_PLATFORM+{PP}, or TPM_RH_NULL + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub parentHandle: TPM_HANDLE, + + /// The sensitive data, see TPM 2.0 Part 1 Sensitive Values + pub inSensitive: TPMS_SENSITIVE_CREATE, + + /// The public template + pub inPublic: Vec, +} + +impl TPM2_CreateLoaded_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + parentHandle: &TPM_HANDLE, + inSensitive: &TPMS_SENSITIVE_CREATE, + inPublic: &Vec, + ) -> Self { + Self { + parentHandle: parentHandle.clone(), + inSensitive: inSensitive.clone(), + inPublic: inPublic.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_CreateLoaded_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedObj(&self.inSensitive)?; + buf.writeSizedByteBuf(&self.inPublic, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readSizedObj(&mut self.inSensitive)?; + self.inPublic = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_CreateLoaded_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_CreateLoaded_REQUEST { + fn num_handles(&self) -> u16 { 1 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_CreateLoaded_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.parentHandle.clone()] } +} + +/// This command creates an object and loads it in the TPM. This command allows creation +/// of any type of object (Primary, Ordinary, or Derived) depending on the type of +/// parentHandle. If parentHandle references a Primary Seed, then a Primary Object is +/// created; if parentHandle references a Storage Parent, then an Ordinary Object is +/// created; and if parentHandle references a Derivation Parent, then a Derived Object is generated. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct CreateLoadedResponse { + /// Handle of type TPM_HT_TRANSIENT for created object + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub handle: TPM_HANDLE, + + /// The sensitive area of the object (optional) + pub outPrivate: TPM2B_PRIVATE, + + /// The public portion of the created object + pub outPublic: TPMT_PUBLIC, + + /// The name of the created object + pub name: Vec, +} + +impl CreateLoadedResponse { +} + +impl TpmStructure for CreateLoadedResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + self.outPrivate.toTpm(buf)?; + buf.writeSizedObj(&self.outPublic)?; + buf.writeSizedByteBuf(&self.name, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.outPrivate.initFromTpm(buf)?; + buf.readSizedObj(&mut self.outPublic)?; + self.name = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for CreateLoadedResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for CreateLoadedResponse { + fn num_handles(&self) -> u16 { 1 } + +} + +impl RespStructure for CreateLoadedResponse { + fn get_handle(&self) -> TPM_HANDLE { self.handle.clone() } + + fn set_handle(&mut self, handle: &TPM_HANDLE) { self.handle = handle.clone(); } + + fn get_resp_name(&self) -> Vec { self.name.clone() } +} + +/// This command duplicates a loaded object so that it may be used in a different +/// hierarchy. The new parent key for the duplicate may be on the same or different TPM or +/// TPM_RH_NULL. Only the public area of newParentHandle is required to be loaded. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_Duplicate_REQUEST { + /// Loaded object to duplicate + /// Auth Index: 1 + /// Auth Role: DUP + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub objectHandle: TPM_HANDLE, + + /// Shall reference the public area of an asymmetric key + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub newParentHandle: TPM_HANDLE, + + /// Optional symmetric encryption key + /// The size for this key is set to zero when the TPM is to generate the key. This + /// parameter may be encrypted. + pub encryptionKeyIn: Vec, + + /// Definition for the symmetric algorithm to be used for the inner wrapper + /// may be TPM_ALG_NULL if no inner wrapper is applied + pub symmetricAlg: TPMT_SYM_DEF_OBJECT, +} + +impl TPM2_Duplicate_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + objectHandle: &TPM_HANDLE, + newParentHandle: &TPM_HANDLE, + encryptionKeyIn: &Vec, + symmetricAlg: &TPMT_SYM_DEF_OBJECT, + ) -> Self { + Self { + objectHandle: objectHandle.clone(), + newParentHandle: newParentHandle.clone(), + encryptionKeyIn: encryptionKeyIn.clone(), + symmetricAlg: symmetricAlg.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_Duplicate_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.encryptionKeyIn, 2); + self.symmetricAlg.toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.encryptionKeyIn = buf.readSizedByteBuf(2); + self.symmetricAlg.initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_Duplicate_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_Duplicate_REQUEST { + fn num_handles(&self) -> u16 { 2 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_Duplicate_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.objectHandle.clone(), self.newParentHandle.clone()] } +} + +/// This command duplicates a loaded object so that it may be used in a different +/// hierarchy. The new parent key for the duplicate may be on the same or different TPM or +/// TPM_RH_NULL. Only the public area of newParentHandle is required to be loaded. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct DuplicateResponse { + /// If the caller provided an encryption key or if symmetricAlg was TPM_ALG_NULL, then + /// this will be the Empty Buffer; otherwise, it shall contain the TPM-generated, + /// symmetric encryption key for the inner wrapper. + pub encryptionKeyOut: Vec, + + /// Private area that may be encrypted by encryptionKeyIn; and may be doubly encrypted + pub duplicate: TPM2B_PRIVATE, + + /// Seed protected by the asymmetric algorithms of new parent (NP) + pub outSymSeed: Vec, +} + +impl DuplicateResponse { +} + +impl TpmStructure for DuplicateResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.encryptionKeyOut, 2); + self.duplicate.toTpm(buf)?; + buf.writeSizedByteBuf(&self.outSymSeed, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.encryptionKeyOut = buf.readSizedByteBuf(2); + self.duplicate.initFromTpm(buf)?; + self.outSymSeed = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for DuplicateResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for DuplicateResponse { + fn num_handles(&self) -> u16 { 0 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl RespStructure for DuplicateResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// This command allows the TPM to serve in the role as a Duplication Authority. If proper +/// authorization for use of the oldParent is provided, then an HMAC key and a symmetric +/// key are recovered from inSymSeed and used to integrity check and decrypt inDuplicate. +/// A new protection seed value is generated according to the methods appropriate for +/// newParent and the blob is re-encrypted and a new integrity value is computed. The +/// re-encrypted blob is returned in outDuplicate and the symmetric key returned in outSymKey. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_Rewrap_REQUEST { + /// Parent of object + /// Auth Index: 1 + /// Auth Role: User + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub oldParent: TPM_HANDLE, + + /// New parent of the object + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub newParent: TPM_HANDLE, + + /// An object encrypted using symmetric key derived from inSymSeed + pub inDuplicate: TPM2B_PRIVATE, + + /// The Name of the object being rewrapped + pub name: Vec, + + /// The seed for the symmetric key and HMAC key + /// needs oldParent private key to recover the seed and generate the symmetric key + pub inSymSeed: Vec, +} + +impl TPM2_Rewrap_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + oldParent: &TPM_HANDLE, + newParent: &TPM_HANDLE, + inDuplicate: &TPM2B_PRIVATE, + name: &Vec, + inSymSeed: &Vec, + ) -> Self { + Self { + oldParent: oldParent.clone(), + newParent: newParent.clone(), + inDuplicate: inDuplicate.clone(), + name: name.clone(), + inSymSeed: inSymSeed.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_Rewrap_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + self.inDuplicate.toTpm(buf)?; + buf.writeSizedByteBuf(&self.name, 2); + buf.writeSizedByteBuf(&self.inSymSeed, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.inDuplicate.initFromTpm(buf)?; + self.name = buf.readSizedByteBuf(2); + self.inSymSeed = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_Rewrap_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_Rewrap_REQUEST { + fn num_handles(&self) -> u16 { 2 } + +} + +impl ReqStructure for TPM2_Rewrap_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.oldParent.clone(), self.newParent.clone()] } +} + +/// This command allows the TPM to serve in the role as a Duplication Authority. If proper +/// authorization for use of the oldParent is provided, then an HMAC key and a symmetric +/// key are recovered from inSymSeed and used to integrity check and decrypt inDuplicate. +/// A new protection seed value is generated according to the methods appropriate for +/// newParent and the blob is re-encrypted and a new integrity value is computed. The +/// re-encrypted blob is returned in outDuplicate and the symmetric key returned in outSymKey. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct RewrapResponse { + /// An object encrypted using symmetric key derived from outSymSeed + pub outDuplicate: TPM2B_PRIVATE, + + /// Seed for a symmetric key protected by newParent asymmetric key + pub outSymSeed: Vec, +} + +impl RewrapResponse { +} + +impl TpmStructure for RewrapResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + self.outDuplicate.toTpm(buf)?; + buf.writeSizedByteBuf(&self.outSymSeed, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.outDuplicate.initFromTpm(buf)?; + self.outSymSeed = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for RewrapResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for RewrapResponse { + fn num_handles(&self) -> u16 { 0 } + +} + +impl RespStructure for RewrapResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// This command allows an object to be encrypted using the symmetric encryption values of +/// a Storage Key. After encryption, the object may be loaded and used in the new +/// hierarchy. The imported object (duplicate) may be singly encrypted, multiply +/// encrypted, or unencrypted. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_Import_REQUEST { + /// The handle of the new parent for the object + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub parentHandle: TPM_HANDLE, + + /// The optional symmetric encryption key used as the inner wrapper for duplicate + /// If symmetricAlg is TPM_ALG_NULL, then this parameter shall be the Empty Buffer. + pub encryptionKey: Vec, + + /// The public area of the object to be imported + /// This is provided so that the integrity value for duplicate and the object attributes + /// can be checked. + /// NOTE Even if the integrity value of the object is not checked on input, the object + /// Name is required to create the integrity value for the imported object. + pub objectPublic: TPMT_PUBLIC, + + /// The symmetrically encrypted duplicate object that may contain an inner symmetric wrapper + pub duplicate: TPM2B_PRIVATE, + + /// The seed for the symmetric key and HMAC key + /// inSymSeed is encrypted/encoded using the algorithms of newParent. + pub inSymSeed: Vec, + + /// Definition for the symmetric algorithm to use for the inner wrapper + /// If this algorithm is TPM_ALG_NULL, no inner wrapper is present and encryptionKey shall + /// be the Empty Buffer. + pub symmetricAlg: TPMT_SYM_DEF_OBJECT, +} + +impl TPM2_Import_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + parentHandle: &TPM_HANDLE, + encryptionKey: &Vec, + objectPublic: &TPMT_PUBLIC, + duplicate: &TPM2B_PRIVATE, + inSymSeed: &Vec, + symmetricAlg: &TPMT_SYM_DEF_OBJECT, + ) -> Self { + Self { + parentHandle: parentHandle.clone(), + encryptionKey: encryptionKey.clone(), + objectPublic: objectPublic.clone(), + duplicate: duplicate.clone(), + inSymSeed: inSymSeed.clone(), + symmetricAlg: symmetricAlg.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_Import_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.encryptionKey, 2); + buf.writeSizedObj(&self.objectPublic)?; + self.duplicate.toTpm(buf)?; + buf.writeSizedByteBuf(&self.inSymSeed, 2); + self.symmetricAlg.toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.encryptionKey = buf.readSizedByteBuf(2); + buf.readSizedObj(&mut self.objectPublic)?; + self.duplicate.initFromTpm(buf)?; + self.inSymSeed = buf.readSizedByteBuf(2); + self.symmetricAlg.initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_Import_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_Import_REQUEST { + fn num_handles(&self) -> u16 { 1 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_Import_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.parentHandle.clone()] } +} + +/// This command allows an object to be encrypted using the symmetric encryption values of +/// a Storage Key. After encryption, the object may be loaded and used in the new +/// hierarchy. The imported object (duplicate) may be singly encrypted, multiply +/// encrypted, or unencrypted. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct ImportResponse { + /// The sensitive area encrypted with the symmetric key of parentHandle + pub outPrivate: TPM2B_PRIVATE, +} + +impl ImportResponse { +} + +impl TpmStructure for ImportResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + self.outPrivate.toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.outPrivate.initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for ImportResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for ImportResponse { + fn num_handles(&self) -> u16 { 0 } + +} + +impl RespStructure for ImportResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// This command performs RSA encryption using the indicated padding scheme according to +/// IETF RFC 8017. If the scheme of keyHandle is TPM_ALG_NULL, then the caller may use +/// inScheme to specify the padding scheme. If scheme of keyHandle is not TPM_ALG_NULL, +/// then inScheme shall either be TPM_ALG_NULL or be the same as scheme (TPM_RC_SCHEME). +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_RSA_Encrypt_REQUEST { + /// Reference to public portion of RSA key to use for encryption + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub keyHandle: TPM_HANDLE, + + /// Message to be encrypted + /// NOTE 1 The data type was chosen because it limits the overall size of the input to no + /// greater than the size of the largest RSA public key. This may be larger than allowed + /// for keyHandle. + pub message: Vec, + + /// Scheme selector + + /// The padding scheme to use if scheme associated with keyHandle is TPM_ALG_NULL + /// One of: TPMS_KEY_SCHEME_ECDH, TPMS_KEY_SCHEME_ECMQV, TPMS_SIG_SCHEME_RSASSA, + /// TPMS_SIG_SCHEME_RSAPSS, TPMS_SIG_SCHEME_ECDSA, TPMS_SIG_SCHEME_ECDAA, + /// TPMS_SIG_SCHEME_SM2, TPMS_SIG_SCHEME_ECSCHNORR, TPMS_ENC_SCHEME_RSAES, + /// TPMS_ENC_SCHEME_OAEP, TPMS_SCHEME_HASH, TPMS_NULL_ASYM_SCHEME. + pub inScheme: Option, + + /// Optional label L to be associated with the message + /// Size of the buffer is zero if no label is present + /// NOTE 2 See description of label above. + pub label: Vec, +} + +impl TPM2_RSA_Encrypt_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + keyHandle: &TPM_HANDLE, + message: &Vec, + inScheme: &Option, + label: &Vec, + ) -> Self { + Self { + keyHandle: keyHandle.clone(), + message: message.clone(), + inScheme: inScheme.clone(), + label: label.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_RSA_Encrypt_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.message, 2); + buf.writeShort(self.inScheme.as_ref().unwrap().GetUnionSelector().into()); + self.inScheme.as_ref().unwrap().toTpm(buf)?; + buf.writeSizedByteBuf(&self.label, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.message = buf.readSizedByteBuf(2); + let r#inSchemeScheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); + self.inScheme = TPMU_ASYM_SCHEME::create(r#inSchemeScheme)?; + self.inScheme.as_mut().unwrap().initFromTpm(buf)?; + self.label = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_RSA_Encrypt_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_RSA_Encrypt_REQUEST { + fn num_handles(&self) -> u16 { 1 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_RSA_Encrypt_REQUEST { + fn num_auth_handles(&self) -> u16 { 0 } + + fn get_handles(&self) -> Vec { vec![self.keyHandle.clone()] } +} + +/// This command performs RSA encryption using the indicated padding scheme according to +/// IETF RFC 8017. If the scheme of keyHandle is TPM_ALG_NULL, then the caller may use +/// inScheme to specify the padding scheme. If scheme of keyHandle is not TPM_ALG_NULL, +/// then inScheme shall either be TPM_ALG_NULL or be the same as scheme (TPM_RC_SCHEME). +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct RSA_EncryptResponse { + /// Encrypted output + pub outData: Vec, +} + +impl RSA_EncryptResponse { +} + +impl TpmStructure for RSA_EncryptResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.outData, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.outData = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for RSA_EncryptResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for RSA_EncryptResponse { + fn num_handles(&self) -> u16 { 0 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl RespStructure for RSA_EncryptResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// This command performs RSA decryption using the indicated padding scheme according to +/// IETF RFC 8017 ((PKCS#1). +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_RSA_Decrypt_REQUEST { + /// RSA key to use for decryption + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub keyHandle: TPM_HANDLE, + + /// Cipher text to be decrypted + /// NOTE An encrypted RSA data block is the size of the public modulus. + pub cipherText: Vec, + + /// Scheme selector + + /// The padding scheme to use if scheme associated with keyHandle is TPM_ALG_NULL + /// One of: TPMS_KEY_SCHEME_ECDH, TPMS_KEY_SCHEME_ECMQV, TPMS_SIG_SCHEME_RSASSA, + /// TPMS_SIG_SCHEME_RSAPSS, TPMS_SIG_SCHEME_ECDSA, TPMS_SIG_SCHEME_ECDAA, + /// TPMS_SIG_SCHEME_SM2, TPMS_SIG_SCHEME_ECSCHNORR, TPMS_ENC_SCHEME_RSAES, + /// TPMS_ENC_SCHEME_OAEP, TPMS_SCHEME_HASH, TPMS_NULL_ASYM_SCHEME. + pub inScheme: Option, + + /// Label whose association with the message is to be verified + pub label: Vec, +} + +impl TPM2_RSA_Decrypt_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + keyHandle: &TPM_HANDLE, + cipherText: &Vec, + inScheme: &Option, + label: &Vec, + ) -> Self { + Self { + keyHandle: keyHandle.clone(), + cipherText: cipherText.clone(), + inScheme: inScheme.clone(), + label: label.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_RSA_Decrypt_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.cipherText, 2); + buf.writeShort(self.inScheme.as_ref().unwrap().GetUnionSelector().into()); + self.inScheme.as_ref().unwrap().toTpm(buf)?; + buf.writeSizedByteBuf(&self.label, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.cipherText = buf.readSizedByteBuf(2); + let r#inSchemeScheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); + self.inScheme = TPMU_ASYM_SCHEME::create(r#inSchemeScheme)?; + self.inScheme.as_mut().unwrap().initFromTpm(buf)?; + self.label = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_RSA_Decrypt_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_RSA_Decrypt_REQUEST { + fn num_handles(&self) -> u16 { 1 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_RSA_Decrypt_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.keyHandle.clone()] } +} + +/// This command performs RSA decryption using the indicated padding scheme according to +/// IETF RFC 8017 ((PKCS#1). +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct RSA_DecryptResponse { + /// Decrypted output + pub message: Vec, +} + +impl RSA_DecryptResponse { +} + +impl TpmStructure for RSA_DecryptResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.message, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.message = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for RSA_DecryptResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for RSA_DecryptResponse { + fn num_handles(&self) -> u16 { 0 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl RespStructure for RSA_DecryptResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// This command uses the TPM to generate an ephemeral key pair (de, Qe where Qe [de]G). +/// It uses the private ephemeral key and a loaded public key (QS) to compute the shared +/// secret value (P [hde]QS). +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_ECDH_KeyGen_REQUEST { + /// Handle of a loaded ECC key public area. + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub keyHandle: TPM_HANDLE, +} + +impl TPM2_ECDH_KeyGen_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + keyHandle: &TPM_HANDLE, + ) -> Self { + Self { + keyHandle: keyHandle.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_ECDH_KeyGen_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_ECDH_KeyGen_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_ECDH_KeyGen_REQUEST { + fn num_handles(&self) -> u16 { 1 } + +} + +impl ReqStructure for TPM2_ECDH_KeyGen_REQUEST { + fn num_auth_handles(&self) -> u16 { 0 } + + fn get_handles(&self) -> Vec { vec![self.keyHandle.clone()] } +} + +/// This command uses the TPM to generate an ephemeral key pair (de, Qe where Qe [de]G). +/// It uses the private ephemeral key and a loaded public key (QS) to compute the shared +/// secret value (P [hde]QS). +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct ECDH_KeyGenResponse { + /// Results of P h[de]Qs + pub zPoint: TPMS_ECC_POINT, + + /// Generated ephemeral public point (Qe) + pub pubPoint: TPMS_ECC_POINT, +} + +impl ECDH_KeyGenResponse { +} + +impl TpmStructure for ECDH_KeyGenResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedObj(&self.zPoint)?; + buf.writeSizedObj(&self.pubPoint)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readSizedObj(&mut self.zPoint)?; + buf.readSizedObj(&mut self.pubPoint)?; + Ok(()) + } + +} + +impl TpmMarshaller for ECDH_KeyGenResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for ECDH_KeyGenResponse { + fn num_handles(&self) -> u16 { 0 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl RespStructure for ECDH_KeyGenResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// This command uses the TPM to recover the Z value from a public point (QB) and a +/// private key (ds). It will perform the multiplication of the provided inPoint (QB) with +/// the private key (ds) and return the coordinates of the resultant point (Z = (xZ , yZ) +/// [hds]QB; where h is the cofactor of the curve). +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_ECDH_ZGen_REQUEST { + /// Handle of a loaded ECC key + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub keyHandle: TPM_HANDLE, + + /// A public key + pub inPoint: TPMS_ECC_POINT, +} + +impl TPM2_ECDH_ZGen_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + keyHandle: &TPM_HANDLE, + inPoint: &TPMS_ECC_POINT, + ) -> Self { + Self { + keyHandle: keyHandle.clone(), + inPoint: inPoint.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_ECDH_ZGen_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedObj(&self.inPoint)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readSizedObj(&mut self.inPoint)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_ECDH_ZGen_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_ECDH_ZGen_REQUEST { + fn num_handles(&self) -> u16 { 1 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_ECDH_ZGen_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.keyHandle.clone()] } +} + +/// This command uses the TPM to recover the Z value from a public point (QB) and a +/// private key (ds). It will perform the multiplication of the provided inPoint (QB) with +/// the private key (ds) and return the coordinates of the resultant point (Z = (xZ , yZ) +/// [hds]QB; where h is the cofactor of the curve). +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct ECDH_ZGenResponse { + /// X and Y coordinates of the product of the multiplication Z = (xZ , yZ) [hdS]QB + pub outPoint: TPMS_ECC_POINT, +} + +impl ECDH_ZGenResponse { +} + +impl TpmStructure for ECDH_ZGenResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedObj(&self.outPoint)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readSizedObj(&mut self.outPoint)?; + Ok(()) + } + +} + +impl TpmMarshaller for ECDH_ZGenResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for ECDH_ZGenResponse { + fn num_handles(&self) -> u16 { 0 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl RespStructure for ECDH_ZGenResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// This command returns the parameters of an ECC curve identified by its TCG-assigned curveID. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_ECC_Parameters_REQUEST { + /// Parameter set selector + pub curveID: TPM_ECC_CURVE, +} + +impl TPM2_ECC_Parameters_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + curveID: TPM_ECC_CURVE, + ) -> Self { + Self { + curveID: curveID.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_ECC_Parameters_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeShort(self.curveID.into()); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.curveID = TPM_ECC_CURVE(buf.readShort() as u16); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_ECC_Parameters_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_ECC_Parameters_REQUEST { + fn num_handles(&self) -> u16 { 0 } + +} + +impl ReqStructure for TPM2_ECC_Parameters_REQUEST { + fn num_auth_handles(&self) -> u16 { 0 } + + fn get_handles(&self) -> Vec { vec![] } +} + +/// This command returns the parameters of an ECC curve identified by its TCG-assigned curveID. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct ECC_ParametersResponse { + /// ECC parameters for the selected curve + pub parameters: TPMS_ALGORITHM_DETAIL_ECC, +} + +impl ECC_ParametersResponse { +} + +impl TpmStructure for ECC_ParametersResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + self.parameters.toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.parameters.initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for ECC_ParametersResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for ECC_ParametersResponse { + fn num_handles(&self) -> u16 { 0 } + +} + +impl RespStructure for ECC_ParametersResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// This command supports two-phase key exchange protocols. The command is used in +/// combination with TPM2_EC_Ephemeral(). TPM2_EC_Ephemeral() generates an ephemeral key +/// and returns the public point of that ephemeral key along with a numeric value that +/// allows the TPM to regenerate the associated private key. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_ZGen_2Phase_REQUEST { + /// Handle of an unrestricted decryption key ECC + /// The private key referenced by this handle is used as dS,A + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub keyA: TPM_HANDLE, + + /// Other partys static public key (Qs,B = (Xs,B, Ys,B)) + pub inQsB: TPMS_ECC_POINT, + + /// Other party's ephemeral public key (Qe,B = (Xe,B, Ye,B)) + pub inQeB: TPMS_ECC_POINT, + + /// The key exchange scheme + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub inScheme: TPM_ALG_ID, + + /// Value returned by TPM2_EC_Ephemeral() + pub counter: u16, +} + +impl TPM2_ZGen_2Phase_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + keyA: &TPM_HANDLE, + inQsB: &TPMS_ECC_POINT, + inQeB: &TPMS_ECC_POINT, + inScheme: TPM_ALG_ID, + counter: u16, + ) -> Self { + Self { + keyA: keyA.clone(), + inQsB: inQsB.clone(), + inQeB: inQeB.clone(), + inScheme: inScheme.clone(), + counter: counter.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_ZGen_2Phase_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedObj(&self.inQsB)?; + buf.writeSizedObj(&self.inQeB)?; + buf.writeShort(self.inScheme.into()); + buf.writeShort(self.counter as u16); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readSizedObj(&mut self.inQsB)?; + buf.readSizedObj(&mut self.inQeB)?; + self.inScheme = TPM_ALG_ID(buf.readShort() as u16); + self.counter = buf.readShort() as u16; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_ZGen_2Phase_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_ZGen_2Phase_REQUEST { + fn num_handles(&self) -> u16 { 1 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_ZGen_2Phase_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.keyA.clone()] } +} + +/// This command supports two-phase key exchange protocols. The command is used in +/// combination with TPM2_EC_Ephemeral(). TPM2_EC_Ephemeral() generates an ephemeral key +/// and returns the public point of that ephemeral key along with a numeric value that +/// allows the TPM to regenerate the associated private key. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct ZGen_2PhaseResponse { + /// X and Y coordinates of the computed value (scheme dependent) + pub outZ1: TPMS_ECC_POINT, + + /// X and Y coordinates of the second computed value (scheme dependent) + pub outZ2: TPMS_ECC_POINT, +} + +impl ZGen_2PhaseResponse { +} + +impl TpmStructure for ZGen_2PhaseResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedObj(&self.outZ1)?; + buf.writeSizedObj(&self.outZ2)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readSizedObj(&mut self.outZ1)?; + buf.readSizedObj(&mut self.outZ2)?; + Ok(()) + } + +} + +impl TpmMarshaller for ZGen_2PhaseResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for ZGen_2PhaseResponse { + fn num_handles(&self) -> u16 { 0 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl RespStructure for ZGen_2PhaseResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// This command performs ECC encryption as described in Part 1, Annex D. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_ECC_Encrypt_REQUEST { + /// Reference to public portion of ECC key to use for encryption + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub keyHandle: TPM_HANDLE, + + /// Plaintext to be encrypted + pub plainText: Vec, + + /// Scheme selector + + /// The KDF to use if scheme associated with keyHandle is TPM_ALG_NULL + /// One of: TPMS_KDF_SCHEME_MGF1, TPMS_KDF_SCHEME_KDF1_SP800_56A, TPMS_KDF_SCHEME_KDF2, + /// TPMS_KDF_SCHEME_KDF1_SP800_108, TPMS_SCHEME_HASH, TPMS_NULL_KDF_SCHEME. + pub inScheme: Option, +} + +impl TPM2_ECC_Encrypt_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + keyHandle: &TPM_HANDLE, + plainText: &Vec, + inScheme: &Option, + ) -> Self { + Self { + keyHandle: keyHandle.clone(), + plainText: plainText.clone(), + inScheme: inScheme.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_ECC_Encrypt_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.plainText, 2); + buf.writeShort(self.inScheme.as_ref().unwrap().GetUnionSelector().into()); + self.inScheme.as_ref().unwrap().toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.plainText = buf.readSizedByteBuf(2); + let r#inSchemeScheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); + self.inScheme = TPMU_KDF_SCHEME::create(r#inSchemeScheme)?; + self.inScheme.as_mut().unwrap().initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_ECC_Encrypt_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_ECC_Encrypt_REQUEST { + fn num_handles(&self) -> u16 { 1 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_ECC_Encrypt_REQUEST { + fn num_auth_handles(&self) -> u16 { 0 } + + fn get_handles(&self) -> Vec { vec![self.keyHandle.clone()] } +} + +/// This command performs ECC encryption as described in Part 1, Annex D. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct ECC_EncryptResponse { + /// The public ephemeral key used for ECDH + pub C1: TPMS_ECC_POINT, + + /// The data block produced by the XOR process + pub C2: Vec, + + /// The integrity value + pub C3: Vec, +} + +impl ECC_EncryptResponse { +} + +impl TpmStructure for ECC_EncryptResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedObj(&self.C1)?; + buf.writeSizedByteBuf(&self.C2, 2); + buf.writeSizedByteBuf(&self.C3, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readSizedObj(&mut self.C1)?; + self.C2 = buf.readSizedByteBuf(2); + self.C3 = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for ECC_EncryptResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for ECC_EncryptResponse { + fn num_handles(&self) -> u16 { 0 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl RespStructure for ECC_EncryptResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// This command performs ECC decryption. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_ECC_Decrypt_REQUEST { + /// ECC key to use for decryption + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub keyHandle: TPM_HANDLE, + + /// The public ephemeral key used for ECDH + pub C1: TPMS_ECC_POINT, + + /// The data block produced by the XOR process + pub C2: Vec, + + /// The integrity value + pub C3: Vec, + + /// Scheme selector + + /// The KDF to use if scheme associated with keyHandle is TPM_ALG_NULL + /// One of: TPMS_KDF_SCHEME_MGF1, TPMS_KDF_SCHEME_KDF1_SP800_56A, TPMS_KDF_SCHEME_KDF2, + /// TPMS_KDF_SCHEME_KDF1_SP800_108, TPMS_SCHEME_HASH, TPMS_NULL_KDF_SCHEME. + pub inScheme: Option, +} + +impl TPM2_ECC_Decrypt_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + keyHandle: &TPM_HANDLE, + C1: &TPMS_ECC_POINT, + C2: &Vec, + C3: &Vec, + inScheme: &Option, + ) -> Self { + Self { + keyHandle: keyHandle.clone(), + C1: C1.clone(), + C2: C2.clone(), + C3: C3.clone(), + inScheme: inScheme.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_ECC_Decrypt_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedObj(&self.C1)?; + buf.writeSizedByteBuf(&self.C2, 2); + buf.writeSizedByteBuf(&self.C3, 2); + buf.writeShort(self.inScheme.as_ref().unwrap().GetUnionSelector().into()); + self.inScheme.as_ref().unwrap().toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readSizedObj(&mut self.C1)?; + self.C2 = buf.readSizedByteBuf(2); + self.C3 = buf.readSizedByteBuf(2); + let r#inSchemeScheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); + self.inScheme = TPMU_KDF_SCHEME::create(r#inSchemeScheme)?; + self.inScheme.as_mut().unwrap().initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_ECC_Decrypt_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_ECC_Decrypt_REQUEST { + fn num_handles(&self) -> u16 { 1 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_ECC_Decrypt_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.keyHandle.clone()] } +} + +/// This command performs ECC decryption. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct ECC_DecryptResponse { + /// Decrypted output + pub plainText: Vec, +} + +impl ECC_DecryptResponse { +} + +impl TpmStructure for ECC_DecryptResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.plainText, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.plainText = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for ECC_DecryptResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for ECC_DecryptResponse { + fn num_handles(&self) -> u16 { 0 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl RespStructure for ECC_DecryptResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// NOTE 1 This command is deprecated, and TPM2_EncryptDecrypt2() is preferred. This +/// should be reflected in platform-specific specifications. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_EncryptDecrypt_REQUEST { + /// The symmetric key used for the operation + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub keyHandle: TPM_HANDLE, + + /// If YES, then the operation is decryption; if NO, the operation is encryption + pub decrypt: u8, + + /// Symmetric encryption/decryption mode + /// this field shall match the default mode of the key or be TPM_ALG_NULL. + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub mode: TPM_ALG_ID, + + /// An initial value as required by the algorithm + pub ivIn: Vec, + + /// The data to be encrypted/decrypted + pub inData: Vec, +} + +impl TPM2_EncryptDecrypt_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + keyHandle: &TPM_HANDLE, + decrypt: u8, + mode: TPM_ALG_ID, + ivIn: &Vec, + inData: &Vec, + ) -> Self { + Self { + keyHandle: keyHandle.clone(), + decrypt: decrypt.clone(), + mode: mode.clone(), + ivIn: ivIn.clone(), + inData: inData.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_EncryptDecrypt_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeByte(self.decrypt as u8); + buf.writeShort(self.mode.into()); + buf.writeSizedByteBuf(&self.ivIn, 2); + buf.writeSizedByteBuf(&self.inData, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.decrypt = buf.readByte() as u8; + self.mode = TPM_ALG_ID(buf.readShort() as u16); + self.ivIn = buf.readSizedByteBuf(2); + self.inData = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_EncryptDecrypt_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_EncryptDecrypt_REQUEST { + fn num_handles(&self) -> u16 { 1 } + +} + +impl ReqStructure for TPM2_EncryptDecrypt_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.keyHandle.clone()] } +} + +/// NOTE 1 This command is deprecated, and TPM2_EncryptDecrypt2() is preferred. This +/// should be reflected in platform-specific specifications. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct EncryptDecryptResponse { + /// Encrypted or decrypted output + pub outData: Vec, + + /// Chaining value to use for IV in next round + pub ivOut: Vec, +} + +impl EncryptDecryptResponse { +} + +impl TpmStructure for EncryptDecryptResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.outData, 2); + buf.writeSizedByteBuf(&self.ivOut, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.outData = buf.readSizedByteBuf(2); + self.ivOut = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for EncryptDecryptResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for EncryptDecryptResponse { + fn num_handles(&self) -> u16 { 0 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl RespStructure for EncryptDecryptResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// This command is identical to TPM2_EncryptDecrypt(), except that the inData parameter +/// is the first parameter. This permits inData to be parameter encrypted. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_EncryptDecrypt2_REQUEST { + /// The symmetric key used for the operation + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub keyHandle: TPM_HANDLE, + + /// The data to be encrypted/decrypted + pub inData: Vec, + + /// If YES, then the operation is decryption; if NO, the operation is encryption + pub decrypt: u8, + + /// Symmetric mode + /// this field shall match the default mode of the key or be TPM_ALG_NULL. + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub mode: TPM_ALG_ID, + + /// An initial value as required by the algorithm + pub ivIn: Vec, +} + +impl TPM2_EncryptDecrypt2_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + keyHandle: &TPM_HANDLE, + inData: &Vec, + decrypt: u8, + mode: TPM_ALG_ID, + ivIn: &Vec, + ) -> Self { + Self { + keyHandle: keyHandle.clone(), + inData: inData.clone(), + decrypt: decrypt.clone(), + mode: mode.clone(), + ivIn: ivIn.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_EncryptDecrypt2_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.inData, 2); + buf.writeByte(self.decrypt as u8); + buf.writeShort(self.mode.into()); + buf.writeSizedByteBuf(&self.ivIn, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.inData = buf.readSizedByteBuf(2); + self.decrypt = buf.readByte() as u8; + self.mode = TPM_ALG_ID(buf.readShort() as u16); + self.ivIn = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_EncryptDecrypt2_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_EncryptDecrypt2_REQUEST { + fn num_handles(&self) -> u16 { 1 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_EncryptDecrypt2_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.keyHandle.clone()] } +} + +/// This command is identical to TPM2_EncryptDecrypt(), except that the inData parameter +/// is the first parameter. This permits inData to be parameter encrypted. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct EncryptDecrypt2Response { + /// Encrypted or decrypted output + pub outData: Vec, + + /// Chaining value to use for IV in next round + pub ivOut: Vec, +} + +impl EncryptDecrypt2Response { +} + +impl TpmStructure for EncryptDecrypt2Response { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.outData, 2); + buf.writeSizedByteBuf(&self.ivOut, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.outData = buf.readSizedByteBuf(2); + self.ivOut = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for EncryptDecrypt2Response { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for EncryptDecrypt2Response { + fn num_handles(&self) -> u16 { 0 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl RespStructure for EncryptDecrypt2Response { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// This command performs a hash operation on a data buffer and returns the results. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_Hash_REQUEST { + /// Data to be hashed + pub data: Vec, + + /// Algorithm for the hash being computed shall not be TPM_ALG_NULL + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub hashAlg: TPM_ALG_ID, + + /// Hierarchy to use for the ticket (TPM_RH_NULL allowed) + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub hierarchy: TPM_HANDLE, +} + +impl TPM2_Hash_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + data: &Vec, + hashAlg: TPM_ALG_ID, + hierarchy: &TPM_HANDLE, + ) -> Self { + Self { + data: data.clone(), + hashAlg: hashAlg.clone(), + hierarchy: hierarchy.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_Hash_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.data, 2); + buf.writeShort(self.hashAlg.into()); + self.hierarchy.toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.data = buf.readSizedByteBuf(2); + self.hashAlg = TPM_ALG_ID(buf.readShort() as u16); + self.hierarchy.initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_Hash_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_Hash_REQUEST { + fn num_handles(&self) -> u16 { 0 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_Hash_REQUEST { + fn num_auth_handles(&self) -> u16 { 0 } + + fn get_handles(&self) -> Vec { vec![] } +} + +/// This command performs a hash operation on a data buffer and returns the results. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct HashResponse { + /// Results + pub outHash: Vec, + + /// Ticket indicating that the sequence of octets used to compute outDigest did not start + /// with TPM_GENERATED_VALUE + /// will be a NULL ticket if the digest may not be signed with a restricted key + pub validation: TPMT_TK_HASHCHECK, +} + +impl HashResponse { +} + +impl TpmStructure for HashResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.outHash, 2); + self.validation.toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.outHash = buf.readSizedByteBuf(2); + self.validation.initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for HashResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for HashResponse { + fn num_handles(&self) -> u16 { 0 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl RespStructure for HashResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// This command performs an HMAC on the supplied data using the indicated hash algorithm. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_HMAC_REQUEST { + /// Handle for the symmetric signing key providing the HMAC key + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub handle: TPM_HANDLE, + + /// HMAC data + pub buffer: Vec, + + /// Algorithm to use for HMAC + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub hashAlg: TPM_ALG_ID, +} + +impl TPM2_HMAC_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + handle: &TPM_HANDLE, + buffer: &Vec, + hashAlg: TPM_ALG_ID, + ) -> Self { + Self { + handle: handle.clone(), + buffer: buffer.clone(), + hashAlg: hashAlg.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_HMAC_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.buffer, 2); + buf.writeShort(self.hashAlg.into()); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.buffer = buf.readSizedByteBuf(2); + self.hashAlg = TPM_ALG_ID(buf.readShort() as u16); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_HMAC_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_HMAC_REQUEST { + fn num_handles(&self) -> u16 { 1 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_HMAC_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.handle.clone()] } +} + +/// This command performs an HMAC on the supplied data using the indicated hash algorithm. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct HMACResponse { + /// The returned HMAC in a sized buffer + pub outHMAC: Vec, +} + +impl HMACResponse { +} + +impl TpmStructure for HMACResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.outHMAC, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.outHMAC = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for HMACResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for HMACResponse { + fn num_handles(&self) -> u16 { 0 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl RespStructure for HMACResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// This command performs an HMAC or a block cipher MAC on the supplied data using the +/// indicated algorithm. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_MAC_REQUEST { + /// Handle for the symmetric signing key providing the MAC key + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub handle: TPM_HANDLE, + + /// MAC data + pub buffer: Vec, + + /// Algorithm to use for MAC + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub inScheme: TPM_ALG_ID, +} + +impl TPM2_MAC_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + handle: &TPM_HANDLE, + buffer: &Vec, + inScheme: TPM_ALG_ID, + ) -> Self { + Self { + handle: handle.clone(), + buffer: buffer.clone(), + inScheme: inScheme.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_MAC_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.buffer, 2); + buf.writeShort(self.inScheme.into()); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.buffer = buf.readSizedByteBuf(2); + self.inScheme = TPM_ALG_ID(buf.readShort() as u16); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_MAC_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_MAC_REQUEST { + fn num_handles(&self) -> u16 { 1 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_MAC_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.handle.clone()] } +} + +/// This command performs an HMAC or a block cipher MAC on the supplied data using the +/// indicated algorithm. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct MACResponse { + /// The returned MAC in a sized buffer + pub outMAC: Vec, +} + +impl MACResponse { +} + +impl TpmStructure for MACResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.outMAC, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.outMAC = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for MACResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for MACResponse { + fn num_handles(&self) -> u16 { 0 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl RespStructure for MACResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// This command returns the next bytesRequested octets from the random number generator (RNG). +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_GetRandom_REQUEST { + /// Number of octets to return + pub bytesRequested: u16, +} + +impl TPM2_GetRandom_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + bytesRequested: u16, + ) -> Self { + Self { + bytesRequested: bytesRequested.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_GetRandom_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeShort(self.bytesRequested as u16); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.bytesRequested = buf.readShort() as u16; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_GetRandom_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_GetRandom_REQUEST { + fn num_handles(&self) -> u16 { 0 } + +} + +impl ReqStructure for TPM2_GetRandom_REQUEST { + fn num_auth_handles(&self) -> u16 { 0 } + + fn get_handles(&self) -> Vec { vec![] } +} + +/// This command returns the next bytesRequested octets from the random number generator (RNG). +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct GetRandomResponse { + /// The random octets + pub randomBytes: Vec, +} + +impl GetRandomResponse { +} + +impl TpmStructure for GetRandomResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.randomBytes, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.randomBytes = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for GetRandomResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for GetRandomResponse { + fn num_handles(&self) -> u16 { 0 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl RespStructure for GetRandomResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// This command is used to add "additional information" to the RNG state. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_StirRandom_REQUEST { + /// Additional information + pub inData: Vec, +} + +impl TPM2_StirRandom_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + inData: &Vec, + ) -> Self { + Self { + inData: inData.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_StirRandom_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.inData, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.inData = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_StirRandom_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_StirRandom_REQUEST { + fn num_handles(&self) -> u16 { 0 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_StirRandom_REQUEST { + fn num_auth_handles(&self) -> u16 { 0 } + + fn get_handles(&self) -> Vec { vec![] } +} + +/// This command starts an HMAC sequence. The TPM will create and initialize an HMAC +/// sequence structure, assign a handle to the sequence, and set the authValue of the +/// sequence object to the value in auth. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_HMAC_Start_REQUEST { + /// Handle of an HMAC key + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub handle: TPM_HANDLE, + + /// Authorization value for subsequent use of the sequence + pub auth: Vec, + + /// The hash algorithm to use for the HMAC + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub hashAlg: TPM_ALG_ID, +} + +impl TPM2_HMAC_Start_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + handle: &TPM_HANDLE, + auth: &Vec, + hashAlg: TPM_ALG_ID, + ) -> Self { + Self { + handle: handle.clone(), + auth: auth.clone(), + hashAlg: hashAlg.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_HMAC_Start_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.auth, 2); + buf.writeShort(self.hashAlg.into()); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.auth = buf.readSizedByteBuf(2); + self.hashAlg = TPM_ALG_ID(buf.readShort() as u16); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_HMAC_Start_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_HMAC_Start_REQUEST { + fn num_handles(&self) -> u16 { 1 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_HMAC_Start_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.handle.clone()] } +} + +/// This command starts an HMAC sequence. The TPM will create and initialize an HMAC +/// sequence structure, assign a handle to the sequence, and set the authValue of the +/// sequence object to the value in auth. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct HMAC_StartResponse { + /// A handle to reference the sequence + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub handle: TPM_HANDLE, +} + +impl HMAC_StartResponse { +} + +impl TpmStructure for HMAC_StartResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + Ok(()) + } + +} + +impl TpmMarshaller for HMAC_StartResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for HMAC_StartResponse { + fn num_handles(&self) -> u16 { 1 } + +} + +impl RespStructure for HMAC_StartResponse { + fn get_handle(&self) -> TPM_HANDLE { self.handle.clone() } + + fn set_handle(&mut self, handle: &TPM_HANDLE) { self.handle = handle.clone(); } +} + +/// This command starts a MAC sequence. The TPM will create and initialize a MAC sequence +/// structure, assign a handle to the sequence, and set the authValue of the sequence +/// object to the value in auth. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_MAC_Start_REQUEST { + /// Handle of a MAC key + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub handle: TPM_HANDLE, + + /// Authorization value for subsequent use of the sequence + pub auth: Vec, + + /// The algorithm to use for the MAC + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub inScheme: TPM_ALG_ID, +} + +impl TPM2_MAC_Start_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + handle: &TPM_HANDLE, + auth: &Vec, + inScheme: TPM_ALG_ID, + ) -> Self { + Self { + handle: handle.clone(), + auth: auth.clone(), + inScheme: inScheme.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_MAC_Start_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.auth, 2); + buf.writeShort(self.inScheme.into()); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.auth = buf.readSizedByteBuf(2); + self.inScheme = TPM_ALG_ID(buf.readShort() as u16); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_MAC_Start_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_MAC_Start_REQUEST { + fn num_handles(&self) -> u16 { 1 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_MAC_Start_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.handle.clone()] } +} + +/// This command starts a MAC sequence. The TPM will create and initialize a MAC sequence +/// structure, assign a handle to the sequence, and set the authValue of the sequence +/// object to the value in auth. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct MAC_StartResponse { + /// A handle to reference the sequence + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub handle: TPM_HANDLE, +} + +impl MAC_StartResponse { +} + +impl TpmStructure for MAC_StartResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + Ok(()) + } + +} + +impl TpmMarshaller for MAC_StartResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for MAC_StartResponse { + fn num_handles(&self) -> u16 { 1 } + +} + +impl RespStructure for MAC_StartResponse { + fn get_handle(&self) -> TPM_HANDLE { self.handle.clone() } + + fn set_handle(&mut self, handle: &TPM_HANDLE) { self.handle = handle.clone(); } +} + +/// This command starts a hash or an Event Sequence. If hashAlg is an implemented hash, +/// then a hash sequence is started. If hashAlg is TPM_ALG_NULL, then an Event Sequence is +/// started. If hashAlg is neither an implemented algorithm nor TPM_ALG_NULL, then the TPM +/// shall return TPM_RC_HASH. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_HashSequenceStart_REQUEST { + /// Authorization value for subsequent use of the sequence + pub auth: Vec, + + /// The hash algorithm to use for the hash sequence + /// An Event Sequence starts if this is TPM_ALG_NULL. + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub hashAlg: TPM_ALG_ID, +} + +impl TPM2_HashSequenceStart_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + auth: &Vec, + hashAlg: TPM_ALG_ID, + ) -> Self { + Self { + auth: auth.clone(), + hashAlg: hashAlg.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_HashSequenceStart_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.auth, 2); + buf.writeShort(self.hashAlg.into()); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.auth = buf.readSizedByteBuf(2); + self.hashAlg = TPM_ALG_ID(buf.readShort() as u16); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_HashSequenceStart_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_HashSequenceStart_REQUEST { + fn num_handles(&self) -> u16 { 0 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_HashSequenceStart_REQUEST { + fn num_auth_handles(&self) -> u16 { 0 } + + fn get_handles(&self) -> Vec { vec![] } +} + +/// This command starts a hash or an Event Sequence. If hashAlg is an implemented hash, +/// then a hash sequence is started. If hashAlg is TPM_ALG_NULL, then an Event Sequence is +/// started. If hashAlg is neither an implemented algorithm nor TPM_ALG_NULL, then the TPM +/// shall return TPM_RC_HASH. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct HashSequenceStartResponse { + /// A handle to reference the sequence + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub handle: TPM_HANDLE, +} + +impl HashSequenceStartResponse { +} + +impl TpmStructure for HashSequenceStartResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + Ok(()) + } + +} + +impl TpmMarshaller for HashSequenceStartResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for HashSequenceStartResponse { + fn num_handles(&self) -> u16 { 1 } + +} + +impl RespStructure for HashSequenceStartResponse { + fn get_handle(&self) -> TPM_HANDLE { self.handle.clone() } + + fn set_handle(&mut self, handle: &TPM_HANDLE) { self.handle = handle.clone(); } +} + +/// This command is used to add data to a hash or HMAC sequence. The amount of data in +/// buffer may be any size up to the limits of the TPM. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_SequenceUpdate_REQUEST { + /// Handle for the sequence object + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub sequenceHandle: TPM_HANDLE, + + /// Data to be added to hash + pub buffer: Vec, +} + +impl TPM2_SequenceUpdate_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + sequenceHandle: &TPM_HANDLE, + buffer: &Vec, + ) -> Self { + Self { + sequenceHandle: sequenceHandle.clone(), + buffer: buffer.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_SequenceUpdate_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.buffer, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.buffer = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_SequenceUpdate_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_SequenceUpdate_REQUEST { + fn num_handles(&self) -> u16 { 1 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_SequenceUpdate_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.sequenceHandle.clone()] } +} + +/// This command adds the last part of data, if any, to a hash/HMAC sequence and returns +/// the result. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_SequenceComplete_REQUEST { + /// Authorization for the sequence + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub sequenceHandle: TPM_HANDLE, + + /// Data to be added to the hash/HMAC + pub buffer: Vec, + + /// Hierarchy of the ticket for a hash + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub hierarchy: TPM_HANDLE, +} + +impl TPM2_SequenceComplete_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + sequenceHandle: &TPM_HANDLE, + buffer: &Vec, + hierarchy: &TPM_HANDLE, + ) -> Self { + Self { + sequenceHandle: sequenceHandle.clone(), + buffer: buffer.clone(), + hierarchy: hierarchy.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_SequenceComplete_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.buffer, 2); + self.hierarchy.toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.buffer = buf.readSizedByteBuf(2); + self.hierarchy.initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_SequenceComplete_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_SequenceComplete_REQUEST { + fn num_handles(&self) -> u16 { 1 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_SequenceComplete_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.sequenceHandle.clone()] } +} + +/// This command adds the last part of data, if any, to a hash/HMAC sequence and returns +/// the result. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct SequenceCompleteResponse { + /// The returned HMAC or digest in a sized buffer + pub result: Vec, + + /// Ticket indicating that the sequence of octets used to compute outDigest did not start + /// with TPM_GENERATED_VALUE + /// This is a NULL Ticket when the sequence is HMAC. + pub validation: TPMT_TK_HASHCHECK, +} + +impl SequenceCompleteResponse { +} + +impl TpmStructure for SequenceCompleteResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.result, 2); + self.validation.toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.result = buf.readSizedByteBuf(2); + self.validation.initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for SequenceCompleteResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for SequenceCompleteResponse { + fn num_handles(&self) -> u16 { 0 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl RespStructure for SequenceCompleteResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// This command adds the last part of data, if any, to an Event Sequence and returns the +/// result in a digest list. If pcrHandle references a PCR and not TPM_RH_NULL, then the +/// returned digest list is processed in the same manner as the digest list input +/// parameter to TPM2_PCR_Extend(). That is, if a bank contains a PCR associated with +/// pcrHandle, it is extended with the associated digest value from the list. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_EventSequenceComplete_REQUEST { + /// PCR to be extended with the Event data + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub pcrHandle: TPM_HANDLE, + + /// Authorization for the sequence + /// Auth Index: 2 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub sequenceHandle: TPM_HANDLE, + + /// Data to be added to the Event + pub buffer: Vec, +} + +impl TPM2_EventSequenceComplete_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + pcrHandle: &TPM_HANDLE, + sequenceHandle: &TPM_HANDLE, + buffer: &Vec, + ) -> Self { + Self { + pcrHandle: pcrHandle.clone(), + sequenceHandle: sequenceHandle.clone(), + buffer: buffer.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_EventSequenceComplete_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.buffer, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.buffer = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_EventSequenceComplete_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_EventSequenceComplete_REQUEST { + fn num_handles(&self) -> u16 { 2 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_EventSequenceComplete_REQUEST { + fn num_auth_handles(&self) -> u16 { 2 } + + fn get_handles(&self) -> Vec { vec![self.pcrHandle.clone(), self.sequenceHandle.clone()] } +} + +/// This command adds the last part of data, if any, to an Event Sequence and returns the +/// result in a digest list. If pcrHandle references a PCR and not TPM_RH_NULL, then the +/// returned digest list is processed in the same manner as the digest list input +/// parameter to TPM2_PCR_Extend(). That is, if a bank contains a PCR associated with +/// pcrHandle, it is extended with the associated digest value from the list. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct EventSequenceCompleteResponse { + /// List of digests computed for the PCR + pub results: Vec, +} + +impl EventSequenceCompleteResponse { +} + +impl TpmStructure for EventSequenceCompleteResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeObjArr(self.results.as_ref())?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readObjArr(self.results.as_mut())?; + Ok(()) + } + +} + +impl TpmMarshaller for EventSequenceCompleteResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for EventSequenceCompleteResponse { + fn num_handles(&self) -> u16 { 0 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 4, val_len: 66 } } +} + +impl RespStructure for EventSequenceCompleteResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// The purpose of this command is to prove that an object with a specific Name is loaded +/// in the TPM. By certifying that the object is loaded, the TPM warrants that a public +/// area with a given Name is self-consistent and associated with a valid sensitive area. +/// If a relying party has a public area that has the same Name as a Name certified with +/// this command, then the values in that public area are correct. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_Certify_REQUEST { + /// Handle of the object to be certified + /// Auth Index: 1 + /// Auth Role: ADMIN + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub objectHandle: TPM_HANDLE, + + /// Handle of the key used to sign the attestation structure + /// Auth Index: 2 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub signHandle: TPM_HANDLE, + + /// User provided qualifying data + pub qualifyingData: Vec, + + /// Scheme selector + + /// Signing scheme to use if the scheme for signHandle is TPM_ALG_NULL + /// One of: TPMS_SIG_SCHEME_RSASSA, TPMS_SIG_SCHEME_RSAPSS, TPMS_SIG_SCHEME_ECDSA, + /// TPMS_SIG_SCHEME_ECDAA, TPMS_SIG_SCHEME_SM2, TPMS_SIG_SCHEME_ECSCHNORR, + /// TPMS_SCHEME_HMAC, TPMS_SCHEME_HASH, TPMS_NULL_SIG_SCHEME. + pub inScheme: Option, +} + +impl TPM2_Certify_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + objectHandle: &TPM_HANDLE, + signHandle: &TPM_HANDLE, + qualifyingData: &Vec, + inScheme: &Option, + ) -> Self { + Self { + objectHandle: objectHandle.clone(), + signHandle: signHandle.clone(), + qualifyingData: qualifyingData.clone(), + inScheme: inScheme.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_Certify_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.qualifyingData, 2); + buf.writeShort(self.inScheme.as_ref().unwrap().GetUnionSelector().into()); + self.inScheme.as_ref().unwrap().toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.qualifyingData = buf.readSizedByteBuf(2); + let r#inSchemeScheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); + self.inScheme = TPMU_SIG_SCHEME::create(r#inSchemeScheme)?; + self.inScheme.as_mut().unwrap().initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_Certify_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_Certify_REQUEST { + fn num_handles(&self) -> u16 { 2 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_Certify_REQUEST { + fn num_auth_handles(&self) -> u16 { 2 } + + fn get_handles(&self) -> Vec { vec![self.objectHandle.clone(), self.signHandle.clone()] } +} + +/// The purpose of this command is to prove that an object with a specific Name is loaded +/// in the TPM. By certifying that the object is loaded, the TPM warrants that a public +/// area with a given Name is self-consistent and associated with a valid sensitive area. +/// If a relying party has a public area that has the same Name as a Name certified with +/// this command, then the values in that public area are correct. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct CertifyResponse { + /// The structure that was signed + pub certifyInfo: TPMS_ATTEST, + + /// Selector of the algorithm used to construct the signature + + /// The asymmetric signature over certifyInfo using the key referenced by signHandle + /// One of: TPMS_SIGNATURE_RSASSA, TPMS_SIGNATURE_RSAPSS, TPMS_SIGNATURE_ECDSA, + /// TPMS_SIGNATURE_ECDAA, TPMS_SIGNATURE_SM2, TPMS_SIGNATURE_ECSCHNORR, TPMT_HA, + /// TPMS_SCHEME_HASH, TPMS_NULL_SIGNATURE. + pub signature: Option, +} + +impl CertifyResponse { +} + +impl TpmStructure for CertifyResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedObj(&self.certifyInfo)?; + buf.writeShort(self.signature.as_ref().unwrap().GetUnionSelector().into()); + self.signature.as_ref().unwrap().toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readSizedObj(&mut self.certifyInfo)?; + let r#signatureSigAlg: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); + self.signature = TPMU_SIGNATURE::create(r#signatureSigAlg)?; + self.signature.as_mut().unwrap().initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for CertifyResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for CertifyResponse { + fn num_handles(&self) -> u16 { 0 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl RespStructure for CertifyResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// This command is used to prove the association between an object and its creation data. +/// The TPM will validate that the ticket was produced by the TPM and that the ticket +/// validates the association between a loaded public area and the provided hash of the +/// creation data (creationHash). +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_CertifyCreation_REQUEST { + /// Handle of the key that will sign the attestation block + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub signHandle: TPM_HANDLE, + + /// The object associated with the creation data + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub objectHandle: TPM_HANDLE, + + /// User-provided qualifying data + pub qualifyingData: Vec, + + /// Hash of the creation data produced by TPM2_Create() or TPM2_CreatePrimary() + pub creationHash: Vec, + + /// Scheme selector + + /// Signing scheme to use if the scheme for signHandle is TPM_ALG_NULL + /// One of: TPMS_SIG_SCHEME_RSASSA, TPMS_SIG_SCHEME_RSAPSS, TPMS_SIG_SCHEME_ECDSA, + /// TPMS_SIG_SCHEME_ECDAA, TPMS_SIG_SCHEME_SM2, TPMS_SIG_SCHEME_ECSCHNORR, + /// TPMS_SCHEME_HMAC, TPMS_SCHEME_HASH, TPMS_NULL_SIG_SCHEME. + pub inScheme: Option, + + /// Ticket produced by TPM2_Create() or TPM2_CreatePrimary() + pub creationTicket: TPMT_TK_CREATION, +} + +impl TPM2_CertifyCreation_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + signHandle: &TPM_HANDLE, + objectHandle: &TPM_HANDLE, + qualifyingData: &Vec, + creationHash: &Vec, + inScheme: &Option, + creationTicket: &TPMT_TK_CREATION, + ) -> Self { + Self { + signHandle: signHandle.clone(), + objectHandle: objectHandle.clone(), + qualifyingData: qualifyingData.clone(), + creationHash: creationHash.clone(), + inScheme: inScheme.clone(), + creationTicket: creationTicket.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_CertifyCreation_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.qualifyingData, 2); + buf.writeSizedByteBuf(&self.creationHash, 2); + buf.writeShort(self.inScheme.as_ref().unwrap().GetUnionSelector().into()); + self.inScheme.as_ref().unwrap().toTpm(buf)?; + self.creationTicket.toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.qualifyingData = buf.readSizedByteBuf(2); + self.creationHash = buf.readSizedByteBuf(2); + let r#inSchemeScheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); + self.inScheme = TPMU_SIG_SCHEME::create(r#inSchemeScheme)?; + self.inScheme.as_mut().unwrap().initFromTpm(buf)?; + self.creationTicket.initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_CertifyCreation_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_CertifyCreation_REQUEST { + fn num_handles(&self) -> u16 { 2 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_CertifyCreation_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.signHandle.clone(), self.objectHandle.clone()] } +} + +/// This command is used to prove the association between an object and its creation data. +/// The TPM will validate that the ticket was produced by the TPM and that the ticket +/// validates the association between a loaded public area and the provided hash of the +/// creation data (creationHash). +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct CertifyCreationResponse { + /// The structure that was signed + pub certifyInfo: TPMS_ATTEST, + + /// Selector of the algorithm used to construct the signature + + /// The signature over certifyInfo + /// One of: TPMS_SIGNATURE_RSASSA, TPMS_SIGNATURE_RSAPSS, TPMS_SIGNATURE_ECDSA, + /// TPMS_SIGNATURE_ECDAA, TPMS_SIGNATURE_SM2, TPMS_SIGNATURE_ECSCHNORR, TPMT_HA, + /// TPMS_SCHEME_HASH, TPMS_NULL_SIGNATURE. + pub signature: Option, +} + +impl CertifyCreationResponse { +} + +impl TpmStructure for CertifyCreationResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedObj(&self.certifyInfo)?; + buf.writeShort(self.signature.as_ref().unwrap().GetUnionSelector().into()); + self.signature.as_ref().unwrap().toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readSizedObj(&mut self.certifyInfo)?; + let r#signatureSigAlg: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); + self.signature = TPMU_SIGNATURE::create(r#signatureSigAlg)?; + self.signature.as_mut().unwrap().initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for CertifyCreationResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for CertifyCreationResponse { + fn num_handles(&self) -> u16 { 0 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl RespStructure for CertifyCreationResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// This command is used to quote PCR values. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_Quote_REQUEST { + /// Handle of key that will perform signature + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub signHandle: TPM_HANDLE, + + /// Data supplied by the caller + pub qualifyingData: Vec, + + /// Scheme selector + + /// Signing scheme to use if the scheme for signHandle is TPM_ALG_NULL + /// One of: TPMS_SIG_SCHEME_RSASSA, TPMS_SIG_SCHEME_RSAPSS, TPMS_SIG_SCHEME_ECDSA, + /// TPMS_SIG_SCHEME_ECDAA, TPMS_SIG_SCHEME_SM2, TPMS_SIG_SCHEME_ECSCHNORR, + /// TPMS_SCHEME_HMAC, TPMS_SCHEME_HASH, TPMS_NULL_SIG_SCHEME. + pub inScheme: Option, + + /// PCR set to quote + pub PCRselect: Vec, +} + +impl TPM2_Quote_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + signHandle: &TPM_HANDLE, + qualifyingData: &Vec, + inScheme: &Option, + PCRselect: &Vec, + ) -> Self { + Self { + signHandle: signHandle.clone(), + qualifyingData: qualifyingData.clone(), + inScheme: inScheme.clone(), + PCRselect: PCRselect.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_Quote_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.qualifyingData, 2); + buf.writeShort(self.inScheme.as_ref().unwrap().GetUnionSelector().into()); + self.inScheme.as_ref().unwrap().toTpm(buf)?; + buf.writeObjArr(self.PCRselect.as_ref())?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.qualifyingData = buf.readSizedByteBuf(2); + let r#inSchemeScheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); + self.inScheme = TPMU_SIG_SCHEME::create(r#inSchemeScheme)?; + self.inScheme.as_mut().unwrap().initFromTpm(buf)?; + buf.readObjArr(self.PCRselect.as_mut())?; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_Quote_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_Quote_REQUEST { + fn num_handles(&self) -> u16 { 1 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_Quote_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.signHandle.clone()] } +} + +/// This command is used to quote PCR values. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct QuoteResponse { + /// The quoted information + pub quoted: TPMS_ATTEST, + + /// Selector of the algorithm used to construct the signature + + /// The signature over quoted + /// One of: TPMS_SIGNATURE_RSASSA, TPMS_SIGNATURE_RSAPSS, TPMS_SIGNATURE_ECDSA, + /// TPMS_SIGNATURE_ECDAA, TPMS_SIGNATURE_SM2, TPMS_SIGNATURE_ECSCHNORR, TPMT_HA, + /// TPMS_SCHEME_HASH, TPMS_NULL_SIGNATURE. + pub signature: Option, +} + +impl QuoteResponse { +} + +impl TpmStructure for QuoteResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedObj(&self.quoted)?; + buf.writeShort(self.signature.as_ref().unwrap().GetUnionSelector().into()); + self.signature.as_ref().unwrap().toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readSizedObj(&mut self.quoted)?; + let r#signatureSigAlg: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); + self.signature = TPMU_SIGNATURE::create(r#signatureSigAlg)?; + self.signature.as_mut().unwrap().initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for QuoteResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for QuoteResponse { + fn num_handles(&self) -> u16 { 0 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl RespStructure for QuoteResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// This command returns a digital signature of the audit session digest. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_GetSessionAuditDigest_REQUEST { + /// Handle of the privacy administrator (TPM_RH_ENDORSEMENT) + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub privacyAdminHandle: TPM_HANDLE, + + /// Handle of the signing key + /// Auth Index: 2 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub signHandle: TPM_HANDLE, + + /// Handle of the audit session + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub sessionHandle: TPM_HANDLE, + + /// User-provided qualifying data may be zero-length + pub qualifyingData: Vec, + + /// Scheme selector + + /// Signing scheme to use if the scheme for signHandle is TPM_ALG_NULL + /// One of: TPMS_SIG_SCHEME_RSASSA, TPMS_SIG_SCHEME_RSAPSS, TPMS_SIG_SCHEME_ECDSA, + /// TPMS_SIG_SCHEME_ECDAA, TPMS_SIG_SCHEME_SM2, TPMS_SIG_SCHEME_ECSCHNORR, + /// TPMS_SCHEME_HMAC, TPMS_SCHEME_HASH, TPMS_NULL_SIG_SCHEME. + pub inScheme: Option, +} + +impl TPM2_GetSessionAuditDigest_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + privacyAdminHandle: &TPM_HANDLE, + signHandle: &TPM_HANDLE, + sessionHandle: &TPM_HANDLE, + qualifyingData: &Vec, + inScheme: &Option, + ) -> Self { + Self { + privacyAdminHandle: privacyAdminHandle.clone(), + signHandle: signHandle.clone(), + sessionHandle: sessionHandle.clone(), + qualifyingData: qualifyingData.clone(), + inScheme: inScheme.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_GetSessionAuditDigest_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.qualifyingData, 2); + buf.writeShort(self.inScheme.as_ref().unwrap().GetUnionSelector().into()); + self.inScheme.as_ref().unwrap().toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.qualifyingData = buf.readSizedByteBuf(2); + let r#inSchemeScheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); + self.inScheme = TPMU_SIG_SCHEME::create(r#inSchemeScheme)?; + self.inScheme.as_mut().unwrap().initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_GetSessionAuditDigest_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_GetSessionAuditDigest_REQUEST { + fn num_handles(&self) -> u16 { 3 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_GetSessionAuditDigest_REQUEST { + fn num_auth_handles(&self) -> u16 { 2 } + + fn get_handles(&self) -> Vec { vec![self.privacyAdminHandle.clone(), self.signHandle.clone(), self.sessionHandle.clone()] } +} + +/// This command returns a digital signature of the audit session digest. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct GetSessionAuditDigestResponse { + /// The audit information that was signed + pub auditInfo: TPMS_ATTEST, + + /// Selector of the algorithm used to construct the signature + + /// The signature over auditInfo + /// One of: TPMS_SIGNATURE_RSASSA, TPMS_SIGNATURE_RSAPSS, TPMS_SIGNATURE_ECDSA, + /// TPMS_SIGNATURE_ECDAA, TPMS_SIGNATURE_SM2, TPMS_SIGNATURE_ECSCHNORR, TPMT_HA, + /// TPMS_SCHEME_HASH, TPMS_NULL_SIGNATURE. + pub signature: Option, +} + +impl GetSessionAuditDigestResponse { +} + +impl TpmStructure for GetSessionAuditDigestResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedObj(&self.auditInfo)?; + buf.writeShort(self.signature.as_ref().unwrap().GetUnionSelector().into()); + self.signature.as_ref().unwrap().toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readSizedObj(&mut self.auditInfo)?; + let r#signatureSigAlg: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); + self.signature = TPMU_SIGNATURE::create(r#signatureSigAlg)?; + self.signature.as_mut().unwrap().initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for GetSessionAuditDigestResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for GetSessionAuditDigestResponse { + fn num_handles(&self) -> u16 { 0 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl RespStructure for GetSessionAuditDigestResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// This command returns the current value of the command audit digest, a digest of the +/// commands being audited, and the audit hash algorithm. These values are placed in an +/// attestation structure and signed with the key referenced by signHandle. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_GetCommandAuditDigest_REQUEST { + /// Handle of the privacy administrator (TPM_RH_ENDORSEMENT) + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub privacyHandle: TPM_HANDLE, + + /// The handle of the signing key + /// Auth Index: 2 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub signHandle: TPM_HANDLE, + + /// Other data to associate with this audit digest + pub qualifyingData: Vec, + + /// Scheme selector + + /// Signing scheme to use if the scheme for signHandle is TPM_ALG_NULL + /// One of: TPMS_SIG_SCHEME_RSASSA, TPMS_SIG_SCHEME_RSAPSS, TPMS_SIG_SCHEME_ECDSA, + /// TPMS_SIG_SCHEME_ECDAA, TPMS_SIG_SCHEME_SM2, TPMS_SIG_SCHEME_ECSCHNORR, + /// TPMS_SCHEME_HMAC, TPMS_SCHEME_HASH, TPMS_NULL_SIG_SCHEME. + pub inScheme: Option, +} + +impl TPM2_GetCommandAuditDigest_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + privacyHandle: &TPM_HANDLE, + signHandle: &TPM_HANDLE, + qualifyingData: &Vec, + inScheme: &Option, + ) -> Self { + Self { + privacyHandle: privacyHandle.clone(), + signHandle: signHandle.clone(), + qualifyingData: qualifyingData.clone(), + inScheme: inScheme.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_GetCommandAuditDigest_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.qualifyingData, 2); + buf.writeShort(self.inScheme.as_ref().unwrap().GetUnionSelector().into()); + self.inScheme.as_ref().unwrap().toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.qualifyingData = buf.readSizedByteBuf(2); + let r#inSchemeScheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); + self.inScheme = TPMU_SIG_SCHEME::create(r#inSchemeScheme)?; + self.inScheme.as_mut().unwrap().initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_GetCommandAuditDigest_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_GetCommandAuditDigest_REQUEST { + fn num_handles(&self) -> u16 { 2 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_GetCommandAuditDigest_REQUEST { + fn num_auth_handles(&self) -> u16 { 2 } + + fn get_handles(&self) -> Vec { vec![self.privacyHandle.clone(), self.signHandle.clone()] } +} + +/// This command returns the current value of the command audit digest, a digest of the +/// commands being audited, and the audit hash algorithm. These values are placed in an +/// attestation structure and signed with the key referenced by signHandle. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct GetCommandAuditDigestResponse { + /// The auditInfo that was signed + pub auditInfo: TPMS_ATTEST, + + /// Selector of the algorithm used to construct the signature + + /// The signature over auditInfo + /// One of: TPMS_SIGNATURE_RSASSA, TPMS_SIGNATURE_RSAPSS, TPMS_SIGNATURE_ECDSA, + /// TPMS_SIGNATURE_ECDAA, TPMS_SIGNATURE_SM2, TPMS_SIGNATURE_ECSCHNORR, TPMT_HA, + /// TPMS_SCHEME_HASH, TPMS_NULL_SIGNATURE. + pub signature: Option, +} + +impl GetCommandAuditDigestResponse { +} + +impl TpmStructure for GetCommandAuditDigestResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedObj(&self.auditInfo)?; + buf.writeShort(self.signature.as_ref().unwrap().GetUnionSelector().into()); + self.signature.as_ref().unwrap().toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readSizedObj(&mut self.auditInfo)?; + let r#signatureSigAlg: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); + self.signature = TPMU_SIGNATURE::create(r#signatureSigAlg)?; + self.signature.as_mut().unwrap().initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for GetCommandAuditDigestResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for GetCommandAuditDigestResponse { + fn num_handles(&self) -> u16 { 0 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl RespStructure for GetCommandAuditDigestResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// This command returns the current values of Time and Clock. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_GetTime_REQUEST { + /// Handle of the privacy administrator (TPM_RH_ENDORSEMENT) + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub privacyAdminHandle: TPM_HANDLE, + + /// The keyHandle identifier of a loaded key that can perform digital signatures + /// Auth Index: 2 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub signHandle: TPM_HANDLE, + + /// Data to tick stamp + pub qualifyingData: Vec, + + /// Scheme selector + + /// Signing scheme to use if the scheme for signHandle is TPM_ALG_NULL + /// One of: TPMS_SIG_SCHEME_RSASSA, TPMS_SIG_SCHEME_RSAPSS, TPMS_SIG_SCHEME_ECDSA, + /// TPMS_SIG_SCHEME_ECDAA, TPMS_SIG_SCHEME_SM2, TPMS_SIG_SCHEME_ECSCHNORR, + /// TPMS_SCHEME_HMAC, TPMS_SCHEME_HASH, TPMS_NULL_SIG_SCHEME. + pub inScheme: Option, +} + +impl TPM2_GetTime_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + privacyAdminHandle: &TPM_HANDLE, + signHandle: &TPM_HANDLE, + qualifyingData: &Vec, + inScheme: &Option, + ) -> Self { + Self { + privacyAdminHandle: privacyAdminHandle.clone(), + signHandle: signHandle.clone(), + qualifyingData: qualifyingData.clone(), + inScheme: inScheme.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_GetTime_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.qualifyingData, 2); + buf.writeShort(self.inScheme.as_ref().unwrap().GetUnionSelector().into()); + self.inScheme.as_ref().unwrap().toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.qualifyingData = buf.readSizedByteBuf(2); + let r#inSchemeScheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); + self.inScheme = TPMU_SIG_SCHEME::create(r#inSchemeScheme)?; + self.inScheme.as_mut().unwrap().initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_GetTime_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_GetTime_REQUEST { + fn num_handles(&self) -> u16 { 2 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_GetTime_REQUEST { + fn num_auth_handles(&self) -> u16 { 2 } + + fn get_handles(&self) -> Vec { vec![self.privacyAdminHandle.clone(), self.signHandle.clone()] } +} + +/// This command returns the current values of Time and Clock. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct GetTimeResponse { + /// Standard TPM-generated attestation block + pub timeInfo: TPMS_ATTEST, + + /// Selector of the algorithm used to construct the signature + + /// The signature over timeInfo + /// One of: TPMS_SIGNATURE_RSASSA, TPMS_SIGNATURE_RSAPSS, TPMS_SIGNATURE_ECDSA, + /// TPMS_SIGNATURE_ECDAA, TPMS_SIGNATURE_SM2, TPMS_SIGNATURE_ECSCHNORR, TPMT_HA, + /// TPMS_SCHEME_HASH, TPMS_NULL_SIGNATURE. + pub signature: Option, +} + +impl GetTimeResponse { +} + +impl TpmStructure for GetTimeResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedObj(&self.timeInfo)?; + buf.writeShort(self.signature.as_ref().unwrap().GetUnionSelector().into()); + self.signature.as_ref().unwrap().toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readSizedObj(&mut self.timeInfo)?; + let r#signatureSigAlg: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); + self.signature = TPMU_SIGNATURE::create(r#signatureSigAlg)?; + self.signature.as_mut().unwrap().initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for GetTimeResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for GetTimeResponse { + fn num_handles(&self) -> u16 { 0 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl RespStructure for GetTimeResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// The purpose of this command is to generate an X.509 certificate that proves an object +/// with a specific public key and attributes is loaded in the TPM. In contrast to +/// TPM2_Certify, which uses a TCG-defined data structure to convey attestation +/// information, TPM2_CertifyX509 encodes the attestation information in a DER-encoded +/// X.509 certificate that is compliant with RFC5280 Internet X.509 Public Key +/// Infrastructure Certificate and Certificate Revocation List (CRL) Profile. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_CertifyX509_REQUEST { + /// Handle of the object to be certified + /// Auth Index: 1 + /// Auth Role: ADMIN + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub objectHandle: TPM_HANDLE, + + /// Handle of the key used to sign the attestation structure + /// Auth Index: 2 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub signHandle: TPM_HANDLE, + + /// Shall be an Empty Buffer + pub reserved: Vec, + + /// Scheme selector + + /// Signing scheme to use if the scheme for signHandle is TPM_ALG_NULL + /// One of: TPMS_SIG_SCHEME_RSASSA, TPMS_SIG_SCHEME_RSAPSS, TPMS_SIG_SCHEME_ECDSA, + /// TPMS_SIG_SCHEME_ECDAA, TPMS_SIG_SCHEME_SM2, TPMS_SIG_SCHEME_ECSCHNORR, + /// TPMS_SCHEME_HMAC, TPMS_SCHEME_HASH, TPMS_NULL_SIG_SCHEME. + pub inScheme: Option, + + /// A DER encoded partial certificate + pub partialCertificate: Vec, +} + +impl TPM2_CertifyX509_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + objectHandle: &TPM_HANDLE, + signHandle: &TPM_HANDLE, + reserved: &Vec, + inScheme: &Option, + partialCertificate: &Vec, + ) -> Self { + Self { + objectHandle: objectHandle.clone(), + signHandle: signHandle.clone(), + reserved: reserved.clone(), + inScheme: inScheme.clone(), + partialCertificate: partialCertificate.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_CertifyX509_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.reserved, 2); + buf.writeShort(self.inScheme.as_ref().unwrap().GetUnionSelector().into()); + self.inScheme.as_ref().unwrap().toTpm(buf)?; + buf.writeSizedByteBuf(&self.partialCertificate, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.reserved = buf.readSizedByteBuf(2); + let r#inSchemeScheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); + self.inScheme = TPMU_SIG_SCHEME::create(r#inSchemeScheme)?; + self.inScheme.as_mut().unwrap().initFromTpm(buf)?; + self.partialCertificate = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_CertifyX509_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_CertifyX509_REQUEST { + fn num_handles(&self) -> u16 { 2 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_CertifyX509_REQUEST { + fn num_auth_handles(&self) -> u16 { 2 } + + fn get_handles(&self) -> Vec { vec![self.objectHandle.clone(), self.signHandle.clone()] } +} + +/// The purpose of this command is to generate an X.509 certificate that proves an object +/// with a specific public key and attributes is loaded in the TPM. In contrast to +/// TPM2_Certify, which uses a TCG-defined data structure to convey attestation +/// information, TPM2_CertifyX509 encodes the attestation information in a DER-encoded +/// X.509 certificate that is compliant with RFC5280 Internet X.509 Public Key +/// Infrastructure Certificate and Certificate Revocation List (CRL) Profile. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct CertifyX509Response { + /// A DER encoded SEQUENCE containing the DER encoded fields added to partialCertificate + /// to make it a complete RFC5280 TBSCertificate. + pub addedToCertificate: Vec, + + /// The digest that was signed + pub tbsDigest: Vec, + + /// Selector of the algorithm used to construct the signature + + /// The signature over tbsDigest + /// One of: TPMS_SIGNATURE_RSASSA, TPMS_SIGNATURE_RSAPSS, TPMS_SIGNATURE_ECDSA, + /// TPMS_SIGNATURE_ECDAA, TPMS_SIGNATURE_SM2, TPMS_SIGNATURE_ECSCHNORR, TPMT_HA, + /// TPMS_SCHEME_HASH, TPMS_NULL_SIGNATURE. + pub signature: Option, +} + +impl CertifyX509Response { +} + +impl TpmStructure for CertifyX509Response { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.addedToCertificate, 2); + buf.writeSizedByteBuf(&self.tbsDigest, 2); + buf.writeShort(self.signature.as_ref().unwrap().GetUnionSelector().into()); + self.signature.as_ref().unwrap().toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.addedToCertificate = buf.readSizedByteBuf(2); + self.tbsDigest = buf.readSizedByteBuf(2); + let r#signatureSigAlg: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); + self.signature = TPMU_SIGNATURE::create(r#signatureSigAlg)?; + self.signature.as_mut().unwrap().initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for CertifyX509Response { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for CertifyX509Response { + fn num_handles(&self) -> u16 { 0 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl RespStructure for CertifyX509Response { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// TPM2_Commit() performs the first part of an ECC anonymous signing operation. The TPM +/// will perform the point multiplications on the provided points and return intermediate +/// signing values. The signHandle parameter shall refer to an ECC key and the signing +/// scheme must be anonymous (TPM_RC_SCHEME). +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_Commit_REQUEST { + /// Handle of the key that will be used in the signing operation + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub signHandle: TPM_HANDLE, + + /// A point (M) on the curve used by signHandle + pub P1: TPMS_ECC_POINT, + + /// Octet array used to derive x-coordinate of a base point + pub s2: Vec, + + /// Y coordinate of the point associated with s2 + pub y2: Vec, +} + +impl TPM2_Commit_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + signHandle: &TPM_HANDLE, + P1: &TPMS_ECC_POINT, + s2: &Vec, + y2: &Vec, + ) -> Self { + Self { + signHandle: signHandle.clone(), + P1: P1.clone(), + s2: s2.clone(), + y2: y2.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_Commit_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedObj(&self.P1)?; + buf.writeSizedByteBuf(&self.s2, 2); + buf.writeSizedByteBuf(&self.y2, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readSizedObj(&mut self.P1)?; + self.s2 = buf.readSizedByteBuf(2); + self.y2 = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_Commit_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_Commit_REQUEST { + fn num_handles(&self) -> u16 { 1 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_Commit_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.signHandle.clone()] } +} + +/// TPM2_Commit() performs the first part of an ECC anonymous signing operation. The TPM +/// will perform the point multiplications on the provided points and return intermediate +/// signing values. The signHandle parameter shall refer to an ECC key and the signing +/// scheme must be anonymous (TPM_RC_SCHEME). +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct CommitResponse { + /// ECC point K [ds](x2, y2) + pub K: TPMS_ECC_POINT, + + /// ECC point L [r](x2, y2) + pub L: TPMS_ECC_POINT, + + /// ECC point E [r]P1 + pub E: TPMS_ECC_POINT, + + /// Least-significant 16 bits of commitCount + pub counter: u16, +} + +impl CommitResponse { +} + +impl TpmStructure for CommitResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedObj(&self.K)?; + buf.writeSizedObj(&self.L)?; + buf.writeSizedObj(&self.E)?; + buf.writeShort(self.counter as u16); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readSizedObj(&mut self.K)?; + buf.readSizedObj(&mut self.L)?; + buf.readSizedObj(&mut self.E)?; + self.counter = buf.readShort() as u16; + Ok(()) + } + +} + +impl TpmMarshaller for CommitResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for CommitResponse { + fn num_handles(&self) -> u16 { 0 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl RespStructure for CommitResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// TPM2_EC_Ephemeral() creates an ephemeral key for use in a two-phase key exchange protocol. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_EC_Ephemeral_REQUEST { + /// The curve for the computed ephemeral point + pub curveID: TPM_ECC_CURVE, +} + +impl TPM2_EC_Ephemeral_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + curveID: TPM_ECC_CURVE, + ) -> Self { + Self { + curveID: curveID.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_EC_Ephemeral_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeShort(self.curveID.into()); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.curveID = TPM_ECC_CURVE(buf.readShort() as u16); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_EC_Ephemeral_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_EC_Ephemeral_REQUEST { + fn num_handles(&self) -> u16 { 0 } + +} + +impl ReqStructure for TPM2_EC_Ephemeral_REQUEST { + fn num_auth_handles(&self) -> u16 { 0 } + + fn get_handles(&self) -> Vec { vec![] } +} + +/// TPM2_EC_Ephemeral() creates an ephemeral key for use in a two-phase key exchange protocol. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct EC_EphemeralResponse { + /// Ephemeral public key Q [r]G + pub Q: TPMS_ECC_POINT, + + /// Least-significant 16 bits of commitCount + pub counter: u16, +} + +impl EC_EphemeralResponse { +} + +impl TpmStructure for EC_EphemeralResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedObj(&self.Q)?; + buf.writeShort(self.counter as u16); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readSizedObj(&mut self.Q)?; + self.counter = buf.readShort() as u16; + Ok(()) + } + +} + +impl TpmMarshaller for EC_EphemeralResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for EC_EphemeralResponse { + fn num_handles(&self) -> u16 { 0 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl RespStructure for EC_EphemeralResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// This command uses loaded keys to validate a signature on a message with the message +/// digest passed to the TPM. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_VerifySignature_REQUEST { + /// Handle of public key that will be used in the validation + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub keyHandle: TPM_HANDLE, + + /// Digest of the signed message + pub digest: Vec, + + /// Selector of the algorithm used to construct the signature + + /// Signature to be tested + /// One of: TPMS_SIGNATURE_RSASSA, TPMS_SIGNATURE_RSAPSS, TPMS_SIGNATURE_ECDSA, + /// TPMS_SIGNATURE_ECDAA, TPMS_SIGNATURE_SM2, TPMS_SIGNATURE_ECSCHNORR, TPMT_HA, + /// TPMS_SCHEME_HASH, TPMS_NULL_SIGNATURE. + pub signature: Option, +} + +impl TPM2_VerifySignature_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + keyHandle: &TPM_HANDLE, + digest: &Vec, + signature: &Option, + ) -> Self { + Self { + keyHandle: keyHandle.clone(), + digest: digest.clone(), + signature: signature.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_VerifySignature_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.digest, 2); + buf.writeShort(self.signature.as_ref().unwrap().GetUnionSelector().into()); + self.signature.as_ref().unwrap().toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.digest = buf.readSizedByteBuf(2); + let r#signatureSigAlg: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); + self.signature = TPMU_SIGNATURE::create(r#signatureSigAlg)?; + self.signature.as_mut().unwrap().initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_VerifySignature_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_VerifySignature_REQUEST { + fn num_handles(&self) -> u16 { 1 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_VerifySignature_REQUEST { + fn num_auth_handles(&self) -> u16 { 0 } + + fn get_handles(&self) -> Vec { vec![self.keyHandle.clone()] } +} + +/// This command uses loaded keys to validate a signature on a message with the message +/// digest passed to the TPM. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct VerifySignatureResponse { + pub validation: TPMT_TK_VERIFIED, +} + +impl VerifySignatureResponse { +} + +impl TpmStructure for VerifySignatureResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + self.validation.toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.validation.initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for VerifySignatureResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for VerifySignatureResponse { + fn num_handles(&self) -> u16 { 0 } + +} + +impl RespStructure for VerifySignatureResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// This command causes the TPM to sign an externally provided hash with the specified +/// symmetric or asymmetric signing key. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_Sign_REQUEST { + /// Handle of key that will perform signing + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub keyHandle: TPM_HANDLE, + + /// Digest to be signed + pub digest: Vec, + + /// Scheme selector + + /// Signing scheme to use if the scheme for keyHandle is TPM_ALG_NULL + /// One of: TPMS_SIG_SCHEME_RSASSA, TPMS_SIG_SCHEME_RSAPSS, TPMS_SIG_SCHEME_ECDSA, + /// TPMS_SIG_SCHEME_ECDAA, TPMS_SIG_SCHEME_SM2, TPMS_SIG_SCHEME_ECSCHNORR, + /// TPMS_SCHEME_HMAC, TPMS_SCHEME_HASH, TPMS_NULL_SIG_SCHEME. + pub inScheme: Option, + + /// Proof that digest was created by the TPM + /// If keyHandle is not a restricted signing key, then this may be a NULL Ticket with tag + /// = TPM_ST_CHECKHASH. + pub validation: TPMT_TK_HASHCHECK, +} + +impl TPM2_Sign_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + keyHandle: &TPM_HANDLE, + digest: &Vec, + inScheme: &Option, + validation: &TPMT_TK_HASHCHECK, + ) -> Self { + Self { + keyHandle: keyHandle.clone(), + digest: digest.clone(), + inScheme: inScheme.clone(), + validation: validation.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_Sign_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.digest, 2); + buf.writeShort(self.inScheme.as_ref().unwrap().GetUnionSelector().into()); + self.inScheme.as_ref().unwrap().toTpm(buf)?; + self.validation.toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.digest = buf.readSizedByteBuf(2); + let r#inSchemeScheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); + self.inScheme = TPMU_SIG_SCHEME::create(r#inSchemeScheme)?; + self.inScheme.as_mut().unwrap().initFromTpm(buf)?; + self.validation.initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_Sign_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_Sign_REQUEST { + fn num_handles(&self) -> u16 { 1 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_Sign_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.keyHandle.clone()] } +} + +/// This command causes the TPM to sign an externally provided hash with the specified +/// symmetric or asymmetric signing key. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct SignResponse { + /// Selector of the algorithm used to construct the signature + + /// The signature + /// One of: TPMS_SIGNATURE_RSASSA, TPMS_SIGNATURE_RSAPSS, TPMS_SIGNATURE_ECDSA, + /// TPMS_SIGNATURE_ECDAA, TPMS_SIGNATURE_SM2, TPMS_SIGNATURE_ECSCHNORR, TPMT_HA, + /// TPMS_SCHEME_HASH, TPMS_NULL_SIGNATURE. + pub signature: Option, +} + +impl SignResponse { +} + +impl TpmStructure for SignResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + if (self.signature.is_none()) { return Ok(()) }; + buf.writeShort(self.signature.as_ref().unwrap().GetUnionSelector().into()); + self.signature.as_ref().unwrap().toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + let r#signatureSigAlg: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); + self.signature = TPMU_SIGNATURE::create(r#signatureSigAlg)?; + self.signature.as_mut().unwrap().initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for SignResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for SignResponse { + fn num_handles(&self) -> u16 { 0 } + +} + +impl RespStructure for SignResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// This command may be used by the Privacy Administrator or platform to change the audit +/// status of a command or to set the hash algorithm used for the audit digest, but not +/// both at the same time. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_SetCommandCodeAuditStatus_REQUEST { + /// TPM_RH_OWNER or TPM_RH_PLATFORM+{PP} + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub auth: TPM_HANDLE, + + /// Hash algorithm for the audit digest; if TPM_ALG_NULL, then the hash is not changed + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub auditAlg: TPM_ALG_ID, + + /// List of commands that will be added to those that will be audited + pub setList: Vec, + + /// List of commands that will no longer be audited + pub clearList: Vec, +} + +impl TPM2_SetCommandCodeAuditStatus_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + auth: &TPM_HANDLE, + auditAlg: TPM_ALG_ID, + setList: &Vec, + clearList: &Vec, + ) -> Self { + Self { + auth: auth.clone(), + auditAlg: auditAlg.clone(), + setList: setList.clone(), + clearList: clearList.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_SetCommandCodeAuditStatus_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeShort(self.auditAlg.into()); + buf.writeValArr(self.setList.as_ref(), 4); + buf.writeValArr(self.clearList.as_ref(), 4); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.auditAlg = TPM_ALG_ID(buf.readShort() as u16); + buf.readValArr(self.setList.as_mut(), 4)?; + buf.readValArr(self.clearList.as_mut(), 4)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_SetCommandCodeAuditStatus_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_SetCommandCodeAuditStatus_REQUEST { + fn num_handles(&self) -> u16 { 1 } + +} + +impl ReqStructure for TPM2_SetCommandCodeAuditStatus_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.auth.clone()] } +} + +/// This command is used to cause an update to the indicated PCR. The digests parameter +/// contains one or more tagged digest values identified by an algorithm ID. For each +/// digest, the PCR associated with pcrHandle is Extended into the bank identified by the +/// tag (hashAlg). +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_PCR_Extend_REQUEST { + /// Handle of the PCR + /// Auth Handle: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub pcrHandle: TPM_HANDLE, + + /// List of tagged digest values to be extended + pub digests: Vec, +} + +impl TPM2_PCR_Extend_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + pcrHandle: &TPM_HANDLE, + digests: &Vec, + ) -> Self { + Self { + pcrHandle: pcrHandle.clone(), + digests: digests.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_PCR_Extend_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeObjArr(self.digests.as_ref())?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readObjArr(self.digests.as_mut())?; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_PCR_Extend_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_PCR_Extend_REQUEST { + fn num_handles(&self) -> u16 { 1 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 4, val_len: 66 } } +} + +impl ReqStructure for TPM2_PCR_Extend_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.pcrHandle.clone()] } +} + +/// This command is used to cause an update to the indicated PCR. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_PCR_Event_REQUEST { + /// Handle of the PCR + /// Auth Handle: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub pcrHandle: TPM_HANDLE, + + /// Event data in sized buffer + pub eventData: Vec, +} + +impl TPM2_PCR_Event_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + pcrHandle: &TPM_HANDLE, + eventData: &Vec, + ) -> Self { + Self { + pcrHandle: pcrHandle.clone(), + eventData: eventData.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_PCR_Event_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.eventData, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.eventData = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_PCR_Event_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_PCR_Event_REQUEST { + fn num_handles(&self) -> u16 { 1 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_PCR_Event_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.pcrHandle.clone()] } +} + +/// This command is used to cause an update to the indicated PCR. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct PCR_EventResponse { + pub digests: Vec, +} + +impl PCR_EventResponse { +} + +impl TpmStructure for PCR_EventResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeObjArr(self.digests.as_ref())?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readObjArr(self.digests.as_mut())?; + Ok(()) + } + +} + +impl TpmMarshaller for PCR_EventResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for PCR_EventResponse { + fn num_handles(&self) -> u16 { 0 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 4, val_len: 66 } } +} + +impl RespStructure for PCR_EventResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// This command returns the values of all PCR specified in pcrSelectionIn. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_PCR_Read_REQUEST { + /// The selection of PCR to read + pub pcrSelectionIn: Vec, +} + +impl TPM2_PCR_Read_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + pcrSelectionIn: &Vec, + ) -> Self { + Self { + pcrSelectionIn: pcrSelectionIn.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_PCR_Read_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeObjArr(self.pcrSelectionIn.as_ref())?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readObjArr(self.pcrSelectionIn.as_mut())?; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_PCR_Read_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_PCR_Read_REQUEST { + fn num_handles(&self) -> u16 { 0 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 4, val_len: 3 } } +} + +impl ReqStructure for TPM2_PCR_Read_REQUEST { + fn num_auth_handles(&self) -> u16 { 0 } + + fn get_handles(&self) -> Vec { vec![] } +} + +/// This command returns the values of all PCR specified in pcrSelectionIn. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct PCR_ReadResponse { + /// The current value of the PCR update counter + pub pcrUpdateCounter: u32, + + /// The PCR in the returned list + pub pcrSelectionOut: Vec, + + /// The contents of the PCR indicated in pcrSelectOut-˃ pcrSelection[] as tagged digests + pub pcrValues: Vec, +} + +impl PCR_ReadResponse { +} + +impl TpmStructure for PCR_ReadResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeInt(self.pcrUpdateCounter as u32); + buf.writeObjArr(self.pcrSelectionOut.as_ref())?; + buf.writeObjArr(self.pcrValues.as_ref())?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.pcrUpdateCounter = buf.readInt() as u32; + buf.readObjArr(self.pcrSelectionOut.as_mut())?; + buf.readObjArr(self.pcrValues.as_mut())?; + Ok(()) + } + +} + +impl TpmMarshaller for PCR_ReadResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for PCR_ReadResponse { + fn num_handles(&self) -> u16 { 0 } + +} + +impl RespStructure for PCR_ReadResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// This command is used to set the desired PCR allocation of PCR and algorithms. This +/// command requires Platform Authorization. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_PCR_Allocate_REQUEST { + /// TPM_RH_PLATFORM+{PP} + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub authHandle: TPM_HANDLE, + + /// The requested allocation + pub pcrAllocation: Vec, +} + +impl TPM2_PCR_Allocate_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + authHandle: &TPM_HANDLE, + pcrAllocation: &Vec, + ) -> Self { + Self { + authHandle: authHandle.clone(), + pcrAllocation: pcrAllocation.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_PCR_Allocate_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeObjArr(self.pcrAllocation.as_ref())?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readObjArr(self.pcrAllocation.as_mut())?; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_PCR_Allocate_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_PCR_Allocate_REQUEST { + fn num_handles(&self) -> u16 { 1 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 4, val_len: 3 } } +} + +impl ReqStructure for TPM2_PCR_Allocate_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.authHandle.clone()] } +} + +/// This command is used to set the desired PCR allocation of PCR and algorithms. This +/// command requires Platform Authorization. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct PCR_AllocateResponse { + /// YES if the allocation succeeded + pub allocationSuccess: u8, + + /// Maximum number of PCR that may be in a bank + pub maxPCR: u32, + + /// Number of octets required to satisfy the request + pub sizeNeeded: u32, + + /// Number of octets available. Computed before the allocation. + pub sizeAvailable: u32, +} + +impl PCR_AllocateResponse { +} + +impl TpmStructure for PCR_AllocateResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeByte(self.allocationSuccess as u8); + buf.writeInt(self.maxPCR as u32); + buf.writeInt(self.sizeNeeded as u32); + buf.writeInt(self.sizeAvailable as u32); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.allocationSuccess = buf.readByte() as u8; + self.maxPCR = buf.readInt() as u32; + self.sizeNeeded = buf.readInt() as u32; + self.sizeAvailable = buf.readInt() as u32; + Ok(()) + } + +} + +impl TpmMarshaller for PCR_AllocateResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for PCR_AllocateResponse { + fn num_handles(&self) -> u16 { 0 } + +} + +impl RespStructure for PCR_AllocateResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// This command is used to associate a policy with a PCR or group of PCR. The policy +/// determines the conditions under which a PCR may be extended or reset. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_PCR_SetAuthPolicy_REQUEST { + /// TPM_RH_PLATFORM+{PP} + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub authHandle: TPM_HANDLE, + + /// The desired authPolicy + pub authPolicy: Vec, + + /// The hash algorithm of the policy + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub hashAlg: TPM_ALG_ID, + + /// The PCR for which the policy is to be set + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub pcrNum: TPM_HANDLE, +} + +impl TPM2_PCR_SetAuthPolicy_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + authHandle: &TPM_HANDLE, + authPolicy: &Vec, + hashAlg: TPM_ALG_ID, + pcrNum: &TPM_HANDLE, + ) -> Self { + Self { + authHandle: authHandle.clone(), + authPolicy: authPolicy.clone(), + hashAlg: hashAlg.clone(), + pcrNum: pcrNum.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_PCR_SetAuthPolicy_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.authPolicy, 2); + buf.writeShort(self.hashAlg.into()); + self.pcrNum.toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.authPolicy = buf.readSizedByteBuf(2); + self.hashAlg = TPM_ALG_ID(buf.readShort() as u16); + self.pcrNum.initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_PCR_SetAuthPolicy_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_PCR_SetAuthPolicy_REQUEST { + fn num_handles(&self) -> u16 { 1 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_PCR_SetAuthPolicy_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.authHandle.clone()] } +} + +/// This command changes the authValue of a PCR or group of PCR. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_PCR_SetAuthValue_REQUEST { + /// Handle for a PCR that may have an authorization value set + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub pcrHandle: TPM_HANDLE, + + /// The desired authorization value + pub auth: Vec, +} + +impl TPM2_PCR_SetAuthValue_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + pcrHandle: &TPM_HANDLE, + auth: &Vec, + ) -> Self { + Self { + pcrHandle: pcrHandle.clone(), + auth: auth.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_PCR_SetAuthValue_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.auth, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.auth = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_PCR_SetAuthValue_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_PCR_SetAuthValue_REQUEST { + fn num_handles(&self) -> u16 { 1 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_PCR_SetAuthValue_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.pcrHandle.clone()] } +} + +/// If the attribute of a PCR allows the PCR to be reset and proper authorization is +/// provided, then this command may be used to set the PCR in all banks to zero. The +/// attributes of the PCR may restrict the locality that can perform the reset operation. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_PCR_Reset_REQUEST { + /// The PCR to reset + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub pcrHandle: TPM_HANDLE, +} + +impl TPM2_PCR_Reset_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + pcrHandle: &TPM_HANDLE, + ) -> Self { + Self { + pcrHandle: pcrHandle.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_PCR_Reset_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_PCR_Reset_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_PCR_Reset_REQUEST { + fn num_handles(&self) -> u16 { 1 } + +} + +impl ReqStructure for TPM2_PCR_Reset_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.pcrHandle.clone()] } +} + +/// This command includes a signed authorization in a policy. The command ties the policy +/// to a signing key by including the Name of the signing key in the policyDigest +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_PolicySigned_REQUEST { + /// Handle for a key that will validate the signature + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub authObject: TPM_HANDLE, + + /// Handle for the policy session being extended + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub policySession: TPM_HANDLE, + + /// The policy nonce for the session + /// This can be the Empty Buffer. + pub nonceTPM: Vec, + + /// Digest of the command parameters to which this authorization is limited + /// This is not the cpHash for this command but the cpHash for the command to which this + /// policy session will be applied. If it is not limited, the parameter will be the Empty Buffer. + pub cpHashA: Vec, + + /// A reference to a policy relating to the authorization may be the Empty Buffer + /// Size is limited to be no larger than the nonce size supported on the TPM. + pub policyRef: Vec, + + /// Time when authorization will expire, measured in seconds from the time that nonceTPM + /// was generated + /// If expiration is non-negative, a NULL Ticket is returned. See 23.2.5. + pub expiration: i32, + + /// Selector of the algorithm used to construct the signature + + /// Signed authorization (not optional) + /// One of: TPMS_SIGNATURE_RSASSA, TPMS_SIGNATURE_RSAPSS, TPMS_SIGNATURE_ECDSA, + /// TPMS_SIGNATURE_ECDAA, TPMS_SIGNATURE_SM2, TPMS_SIGNATURE_ECSCHNORR, TPMT_HA, + /// TPMS_SCHEME_HASH, TPMS_NULL_SIGNATURE. + pub auth: Option, +} + +impl TPM2_PolicySigned_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + authObject: &TPM_HANDLE, + policySession: &TPM_HANDLE, + nonceTPM: &Vec, + cpHashA: &Vec, + policyRef: &Vec, + expiration: i32, + auth: &Option, + ) -> Self { + Self { + authObject: authObject.clone(), + policySession: policySession.clone(), + nonceTPM: nonceTPM.clone(), + cpHashA: cpHashA.clone(), + policyRef: policyRef.clone(), + expiration: expiration.clone(), + auth: auth.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_PolicySigned_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.nonceTPM, 2); + buf.writeSizedByteBuf(&self.cpHashA, 2); + buf.writeSizedByteBuf(&self.policyRef, 2); + buf.writeInt(self.expiration as u32); + buf.writeShort(self.auth.as_ref().unwrap().GetUnionSelector().into()); + self.auth.as_ref().unwrap().toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.nonceTPM = buf.readSizedByteBuf(2); + self.cpHashA = buf.readSizedByteBuf(2); + self.policyRef = buf.readSizedByteBuf(2); + self.expiration = buf.readInt() as i32; + let r#authSigAlg: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); + self.auth = TPMU_SIGNATURE::create(r#authSigAlg)?; + self.auth.as_mut().unwrap().initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_PolicySigned_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_PolicySigned_REQUEST { + fn num_handles(&self) -> u16 { 2 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_PolicySigned_REQUEST { + fn num_auth_handles(&self) -> u16 { 0 } + + fn get_handles(&self) -> Vec { vec![self.authObject.clone(), self.policySession.clone()] } +} + +/// This command includes a signed authorization in a policy. The command ties the policy +/// to a signing key by including the Name of the signing key in the policyDigest +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct PolicySignedResponse { + /// Implementation-specific time value, used to indicate to the TPM when the ticket expires + /// NOTE If policyTicket is a NULL Ticket, then this shall be the Empty Buffer. + pub timeout: Vec, + + /// Produced if the command succeeds and expiration in the command was non-zero; this + /// ticket will use the TPMT_ST_AUTH_SIGNED structure tag. See 23.2.5 + pub policyTicket: TPMT_TK_AUTH, +} + +impl PolicySignedResponse { +} + +impl TpmStructure for PolicySignedResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.timeout, 2); + self.policyTicket.toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.timeout = buf.readSizedByteBuf(2); + self.policyTicket.initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for PolicySignedResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for PolicySignedResponse { + fn num_handles(&self) -> u16 { 0 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl RespStructure for PolicySignedResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// This command includes a secret-based authorization to a policy. The caller proves +/// knowledge of the secret value using an authorization session using the authValue +/// associated with authHandle. A password session, an HMAC session, or a policy session +/// containing TPM2_PolicyAuthValue() or TPM2_PolicyPassword() will satisfy this requirement. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_PolicySecret_REQUEST { + /// Handle for an entity providing the authorization + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub authHandle: TPM_HANDLE, + + /// Handle for the policy session being extended + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub policySession: TPM_HANDLE, + + /// The policy nonce for the session + /// This can be the Empty Buffer. + pub nonceTPM: Vec, + + /// Digest of the command parameters to which this authorization is limited + /// This not the cpHash for this command but the cpHash for the command to which this + /// policy session will be applied. If it is not limited, the parameter will be the Empty Buffer. + pub cpHashA: Vec, + + /// A reference to a policy relating to the authorization may be the Empty Buffer + /// Size is limited to be no larger than the nonce size supported on the TPM. + pub policyRef: Vec, + + /// Time when authorization will expire, measured in seconds from the time that nonceTPM + /// was generated + /// If expiration is non-negative, a NULL Ticket is returned. See 23.2.5. + pub expiration: i32, +} + +impl TPM2_PolicySecret_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + authHandle: &TPM_HANDLE, + policySession: &TPM_HANDLE, + nonceTPM: &Vec, + cpHashA: &Vec, + policyRef: &Vec, + expiration: i32, + ) -> Self { + Self { + authHandle: authHandle.clone(), + policySession: policySession.clone(), + nonceTPM: nonceTPM.clone(), + cpHashA: cpHashA.clone(), + policyRef: policyRef.clone(), + expiration: expiration.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_PolicySecret_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.nonceTPM, 2); + buf.writeSizedByteBuf(&self.cpHashA, 2); + buf.writeSizedByteBuf(&self.policyRef, 2); + buf.writeInt(self.expiration as u32); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.nonceTPM = buf.readSizedByteBuf(2); + self.cpHashA = buf.readSizedByteBuf(2); + self.policyRef = buf.readSizedByteBuf(2); + self.expiration = buf.readInt() as i32; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_PolicySecret_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_PolicySecret_REQUEST { + fn num_handles(&self) -> u16 { 2 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_PolicySecret_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.authHandle.clone(), self.policySession.clone()] } +} + +/// This command includes a secret-based authorization to a policy. The caller proves +/// knowledge of the secret value using an authorization session using the authValue +/// associated with authHandle. A password session, an HMAC session, or a policy session +/// containing TPM2_PolicyAuthValue() or TPM2_PolicyPassword() will satisfy this requirement. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct PolicySecretResponse { + /// Implementation-specific time value used to indicate to the TPM when the ticket expires + pub timeout: Vec, + + /// Produced if the command succeeds and expiration in the command was non-zero ( See + /// 23.2.5). This ticket will use the TPMT_ST_AUTH_SECRET structure tag + pub policyTicket: TPMT_TK_AUTH, +} + +impl PolicySecretResponse { +} + +impl TpmStructure for PolicySecretResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.timeout, 2); + self.policyTicket.toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.timeout = buf.readSizedByteBuf(2); + self.policyTicket.initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for PolicySecretResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for PolicySecretResponse { + fn num_handles(&self) -> u16 { 0 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl RespStructure for PolicySecretResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// This command is similar to TPM2_PolicySigned() except that it takes a ticket instead +/// of a signed authorization. The ticket represents a validated authorization that had an +/// expiration time associated with it. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_PolicyTicket_REQUEST { + /// Handle for the policy session being extended + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub policySession: TPM_HANDLE, + + /// Time when authorization will expire + /// The contents are TPM specific. This shall be the value returned when ticket was produced. + pub timeout: Vec, + + /// Digest of the command parameters to which this authorization is limited + /// If it is not limited, the parameter will be the Empty Buffer. + pub cpHashA: Vec, + + /// Reference to a qualifier for the policy may be the Empty Buffer + pub policyRef: Vec, + + /// Name of the object that provided the authorization + pub authName: Vec, + + /// An authorization ticket returned by the TPM in response to a TPM2_PolicySigned() or + /// TPM2_PolicySecret() + pub ticket: TPMT_TK_AUTH, +} + +impl TPM2_PolicyTicket_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + policySession: &TPM_HANDLE, + timeout: &Vec, + cpHashA: &Vec, + policyRef: &Vec, + authName: &Vec, + ticket: &TPMT_TK_AUTH, + ) -> Self { + Self { + policySession: policySession.clone(), + timeout: timeout.clone(), + cpHashA: cpHashA.clone(), + policyRef: policyRef.clone(), + authName: authName.clone(), + ticket: ticket.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_PolicyTicket_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.timeout, 2); + buf.writeSizedByteBuf(&self.cpHashA, 2); + buf.writeSizedByteBuf(&self.policyRef, 2); + buf.writeSizedByteBuf(&self.authName, 2); + self.ticket.toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.timeout = buf.readSizedByteBuf(2); + self.cpHashA = buf.readSizedByteBuf(2); + self.policyRef = buf.readSizedByteBuf(2); + self.authName = buf.readSizedByteBuf(2); + self.ticket.initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_PolicyTicket_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_PolicyTicket_REQUEST { + fn num_handles(&self) -> u16 { 1 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_PolicyTicket_REQUEST { + fn num_auth_handles(&self) -> u16 { 0 } + + fn get_handles(&self) -> Vec { vec![self.policySession.clone()] } +} + +/// This command allows options in authorizations without requiring that the TPM evaluate +/// all of the options. If a policy may be satisfied by different sets of conditions, the +/// TPM need only evaluate one set that satisfies the policy. This command will indicate +/// that one of the required sets of conditions has been satisfied. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_PolicyOR_REQUEST { + /// Handle for the policy session being extended + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub policySession: TPM_HANDLE, + + /// The list of hashes to check for a match + pub pHashList: Vec, +} + +impl TPM2_PolicyOR_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + policySession: &TPM_HANDLE, + pHashList: &Vec, + ) -> Self { + Self { + policySession: policySession.clone(), + pHashList: pHashList.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_PolicyOR_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeObjArr(self.pHashList.as_ref())?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readObjArr(self.pHashList.as_mut())?; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_PolicyOR_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_PolicyOR_REQUEST { + fn num_handles(&self) -> u16 { 1 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 4, val_len: 2 } } +} + +impl ReqStructure for TPM2_PolicyOR_REQUEST { + fn num_auth_handles(&self) -> u16 { 0 } + + fn get_handles(&self) -> Vec { vec![self.policySession.clone()] } +} + +/// This command is used to cause conditional gating of a policy based on PCR. This +/// command together with TPM2_PolicyOR() allows one group of authorizations to occur when +/// PCR are in one state and a different set of authorizations when the PCR are in a +/// different state. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_PolicyPCR_REQUEST { + /// Handle for the policy session being extended + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub policySession: TPM_HANDLE, + + /// Expected digest value of the selected PCR using the hash algorithm of the session; may + /// be zero length + pub pcrDigest: Vec, + + /// The PCR to include in the check digest + pub pcrs: Vec, +} + +impl TPM2_PolicyPCR_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + policySession: &TPM_HANDLE, + pcrDigest: &Vec, + pcrs: &Vec, + ) -> Self { + Self { + policySession: policySession.clone(), + pcrDigest: pcrDigest.clone(), + pcrs: pcrs.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_PolicyPCR_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.pcrDigest, 2); + buf.writeObjArr(self.pcrs.as_ref())?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.pcrDigest = buf.readSizedByteBuf(2); + buf.readObjArr(self.pcrs.as_mut())?; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_PolicyPCR_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_PolicyPCR_REQUEST { + fn num_handles(&self) -> u16 { 1 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_PolicyPCR_REQUEST { + fn num_auth_handles(&self) -> u16 { 0 } + + fn get_handles(&self) -> Vec { vec![self.policySession.clone()] } +} + +/// This command indicates that the authorization will be limited to a specific locality. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_PolicyLocality_REQUEST { + /// Handle for the policy session being extended + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub policySession: TPM_HANDLE, + + /// The allowed localities for the policy + pub locality: TPMA_LOCALITY, +} + +impl TPM2_PolicyLocality_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + policySession: &TPM_HANDLE, + locality: TPMA_LOCALITY, + ) -> Self { + Self { + policySession: policySession.clone(), + locality: locality.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_PolicyLocality_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeByte(self.locality.into()); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.locality = TPMA_LOCALITY(buf.readByte() as u8); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_PolicyLocality_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_PolicyLocality_REQUEST { + fn num_handles(&self) -> u16 { 1 } + +} + +impl ReqStructure for TPM2_PolicyLocality_REQUEST { + fn num_auth_handles(&self) -> u16 { 0 } + + fn get_handles(&self) -> Vec { vec![self.policySession.clone()] } +} + +/// This command is used to cause conditional gating of a policy based on the contents of +/// an NV Index. It is an immediate assertion. The NV index is validated during the +/// TPM2_PolicyNV() command, not when the session is used for authorization. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_PolicyNV_REQUEST { + /// Handle indicating the source of the authorization value + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub authHandle: TPM_HANDLE, + + /// The NV Index of the area to read + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub nvIndex: TPM_HANDLE, + + /// Handle for the policy session being extended + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub policySession: TPM_HANDLE, + + /// The second operand + pub operandB: Vec, + + /// The octet offset in the NV Index for the start of operand A + pub offset: u16, + + /// The comparison to make + pub operation: TPM_EO, +} + +impl TPM2_PolicyNV_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + authHandle: &TPM_HANDLE, + nvIndex: &TPM_HANDLE, + policySession: &TPM_HANDLE, + operandB: &Vec, + offset: u16, + operation: TPM_EO, + ) -> Self { + Self { + authHandle: authHandle.clone(), + nvIndex: nvIndex.clone(), + policySession: policySession.clone(), + operandB: operandB.clone(), + offset: offset.clone(), + operation: operation.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_PolicyNV_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.operandB, 2); + buf.writeShort(self.offset as u16); + buf.writeShort(self.operation.into()); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.operandB = buf.readSizedByteBuf(2); + self.offset = buf.readShort() as u16; + self.operation = TPM_EO(buf.readShort() as u16); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_PolicyNV_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_PolicyNV_REQUEST { + fn num_handles(&self) -> u16 { 3 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_PolicyNV_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.authHandle.clone(), self.nvIndex.clone(), self.policySession.clone()] } +} + +/// This command is used to cause conditional gating of a policy based on the contents of +/// the TPMS_TIME_INFO structure. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_PolicyCounterTimer_REQUEST { + /// Handle for the policy session being extended + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub policySession: TPM_HANDLE, + + /// The second operand + pub operandB: Vec, + + /// The octet offset in the TPMS_TIME_INFO structure for the start of operand A + pub offset: u16, + + /// The comparison to make + pub operation: TPM_EO, +} + +impl TPM2_PolicyCounterTimer_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + policySession: &TPM_HANDLE, + operandB: &Vec, + offset: u16, + operation: TPM_EO, + ) -> Self { + Self { + policySession: policySession.clone(), + operandB: operandB.clone(), + offset: offset.clone(), + operation: operation.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_PolicyCounterTimer_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.operandB, 2); + buf.writeShort(self.offset as u16); + buf.writeShort(self.operation.into()); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.operandB = buf.readSizedByteBuf(2); + self.offset = buf.readShort() as u16; + self.operation = TPM_EO(buf.readShort() as u16); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_PolicyCounterTimer_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_PolicyCounterTimer_REQUEST { + fn num_handles(&self) -> u16 { 1 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_PolicyCounterTimer_REQUEST { + fn num_auth_handles(&self) -> u16 { 0 } + + fn get_handles(&self) -> Vec { vec![self.policySession.clone()] } +} + +/// This command indicates that the authorization will be limited to a specific command code. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_PolicyCommandCode_REQUEST { + /// Handle for the policy session being extended + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub policySession: TPM_HANDLE, + + /// The allowed commandCode + pub code: TPM_CC, +} + +impl TPM2_PolicyCommandCode_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + policySession: &TPM_HANDLE, + code: TPM_CC, + ) -> Self { + Self { + policySession: policySession.clone(), + code: code.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_PolicyCommandCode_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeInt(self.code.into()); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.code = TPM_CC(buf.readInt() as u32); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_PolicyCommandCode_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_PolicyCommandCode_REQUEST { + fn num_handles(&self) -> u16 { 1 } + +} + +impl ReqStructure for TPM2_PolicyCommandCode_REQUEST { + fn num_auth_handles(&self) -> u16 { 0 } + + fn get_handles(&self) -> Vec { vec![self.policySession.clone()] } +} + +/// This command indicates that physical presence will need to be asserted at the time the +/// authorization is performed. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_PolicyPhysicalPresence_REQUEST { + /// Handle for the policy session being extended + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub policySession: TPM_HANDLE, +} + +impl TPM2_PolicyPhysicalPresence_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + policySession: &TPM_HANDLE, + ) -> Self { + Self { + policySession: policySession.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_PolicyPhysicalPresence_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_PolicyPhysicalPresence_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_PolicyPhysicalPresence_REQUEST { + fn num_handles(&self) -> u16 { 1 } + +} + +impl ReqStructure for TPM2_PolicyPhysicalPresence_REQUEST { + fn num_auth_handles(&self) -> u16 { 0 } + + fn get_handles(&self) -> Vec { vec![self.policySession.clone()] } +} + +/// This command is used to allow a policy to be bound to a specific command and command parameters. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_PolicyCpHash_REQUEST { + /// Handle for the policy session being extended + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub policySession: TPM_HANDLE, + + /// The cpHash added to the policy + pub cpHashA: Vec, +} + +impl TPM2_PolicyCpHash_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + policySession: &TPM_HANDLE, + cpHashA: &Vec, + ) -> Self { + Self { + policySession: policySession.clone(), + cpHashA: cpHashA.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_PolicyCpHash_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.cpHashA, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.cpHashA = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_PolicyCpHash_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_PolicyCpHash_REQUEST { + fn num_handles(&self) -> u16 { 1 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_PolicyCpHash_REQUEST { + fn num_auth_handles(&self) -> u16 { 0 } + + fn get_handles(&self) -> Vec { vec![self.policySession.clone()] } +} + +/// This command allows a policy to be bound to a specific set of TPM entities without +/// being bound to the parameters of the command. This is most useful for commands such as +/// TPM2_Duplicate() and for TPM2_PCR_Event() when the referenced PCR requires a policy. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_PolicyNameHash_REQUEST { + /// Handle for the policy session being extended + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub policySession: TPM_HANDLE, + + /// The digest to be added to the policy + pub nameHash: Vec, +} + +impl TPM2_PolicyNameHash_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + policySession: &TPM_HANDLE, + nameHash: &Vec, + ) -> Self { + Self { + policySession: policySession.clone(), + nameHash: nameHash.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_PolicyNameHash_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.nameHash, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.nameHash = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_PolicyNameHash_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_PolicyNameHash_REQUEST { + fn num_handles(&self) -> u16 { 1 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_PolicyNameHash_REQUEST { + fn num_auth_handles(&self) -> u16 { 0 } + + fn get_handles(&self) -> Vec { vec![self.policySession.clone()] } +} + +/// This command allows qualification of duplication to allow duplication to a selected +/// new parent. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_PolicyDuplicationSelect_REQUEST { + /// Handle for the policy session being extended + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub policySession: TPM_HANDLE, + + /// The Name of the object to be duplicated + pub objectName: Vec, + + /// The Name of the new parent + pub newParentName: Vec, + + /// If YES, the objectName will be included in the value in policySessionpolicyDigest + pub includeObject: u8, +} + +impl TPM2_PolicyDuplicationSelect_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + policySession: &TPM_HANDLE, + objectName: &Vec, + newParentName: &Vec, + includeObject: u8, + ) -> Self { + Self { + policySession: policySession.clone(), + objectName: objectName.clone(), + newParentName: newParentName.clone(), + includeObject: includeObject.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_PolicyDuplicationSelect_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.objectName, 2); + buf.writeSizedByteBuf(&self.newParentName, 2); + buf.writeByte(self.includeObject as u8); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.objectName = buf.readSizedByteBuf(2); + self.newParentName = buf.readSizedByteBuf(2); + self.includeObject = buf.readByte() as u8; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_PolicyDuplicationSelect_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_PolicyDuplicationSelect_REQUEST { + fn num_handles(&self) -> u16 { 1 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_PolicyDuplicationSelect_REQUEST { + fn num_auth_handles(&self) -> u16 { 0 } + + fn get_handles(&self) -> Vec { vec![self.policySession.clone()] } +} + +/// This command allows policies to change. If a policy were static, then it would be +/// difficult to add users to a policy. This command lets a policy authority sign a new +/// policy so that it may be used in an existing policy. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_PolicyAuthorize_REQUEST { + /// Handle for the policy session being extended + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub policySession: TPM_HANDLE, + + /// Digest of the policy being approved + pub approvedPolicy: Vec, + + /// A policy qualifier + pub policyRef: Vec, + + /// Name of a key that can sign a policy addition + pub keySign: Vec, + + /// Ticket validating that approvedPolicy and policyRef were signed by keySign + pub checkTicket: TPMT_TK_VERIFIED, +} + +impl TPM2_PolicyAuthorize_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + policySession: &TPM_HANDLE, + approvedPolicy: &Vec, + policyRef: &Vec, + keySign: &Vec, + checkTicket: &TPMT_TK_VERIFIED, + ) -> Self { + Self { + policySession: policySession.clone(), + approvedPolicy: approvedPolicy.clone(), + policyRef: policyRef.clone(), + keySign: keySign.clone(), + checkTicket: checkTicket.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_PolicyAuthorize_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.approvedPolicy, 2); + buf.writeSizedByteBuf(&self.policyRef, 2); + buf.writeSizedByteBuf(&self.keySign, 2); + self.checkTicket.toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.approvedPolicy = buf.readSizedByteBuf(2); + self.policyRef = buf.readSizedByteBuf(2); + self.keySign = buf.readSizedByteBuf(2); + self.checkTicket.initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_PolicyAuthorize_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_PolicyAuthorize_REQUEST { + fn num_handles(&self) -> u16 { 1 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_PolicyAuthorize_REQUEST { + fn num_auth_handles(&self) -> u16 { 0 } + + fn get_handles(&self) -> Vec { vec![self.policySession.clone()] } +} + +/// This command allows a policy to be bound to the authorization value of the authorized entity. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_PolicyAuthValue_REQUEST { + /// Handle for the policy session being extended + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub policySession: TPM_HANDLE, +} + +impl TPM2_PolicyAuthValue_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + policySession: &TPM_HANDLE, + ) -> Self { + Self { + policySession: policySession.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_PolicyAuthValue_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_PolicyAuthValue_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_PolicyAuthValue_REQUEST { + fn num_handles(&self) -> u16 { 1 } + +} + +impl ReqStructure for TPM2_PolicyAuthValue_REQUEST { + fn num_auth_handles(&self) -> u16 { 0 } + + fn get_handles(&self) -> Vec { vec![self.policySession.clone()] } +} + +/// This command allows a policy to be bound to the authorization value of the authorized object. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_PolicyPassword_REQUEST { + /// Handle for the policy session being extended + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub policySession: TPM_HANDLE, +} + +impl TPM2_PolicyPassword_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + policySession: &TPM_HANDLE, + ) -> Self { + Self { + policySession: policySession.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_PolicyPassword_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_PolicyPassword_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_PolicyPassword_REQUEST { + fn num_handles(&self) -> u16 { 1 } + +} + +impl ReqStructure for TPM2_PolicyPassword_REQUEST { + fn num_auth_handles(&self) -> u16 { 0 } + + fn get_handles(&self) -> Vec { vec![self.policySession.clone()] } +} + +/// This command returns the current policyDigest of the session. This command allows the +/// TPM to be used to perform the actions required to pre-compute the authPolicy for an object. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_PolicyGetDigest_REQUEST { + /// Handle for the policy session + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub policySession: TPM_HANDLE, +} + +impl TPM2_PolicyGetDigest_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + policySession: &TPM_HANDLE, + ) -> Self { + Self { + policySession: policySession.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_PolicyGetDigest_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_PolicyGetDigest_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_PolicyGetDigest_REQUEST { + fn num_handles(&self) -> u16 { 1 } + +} + +impl ReqStructure for TPM2_PolicyGetDigest_REQUEST { + fn num_auth_handles(&self) -> u16 { 0 } + + fn get_handles(&self) -> Vec { vec![self.policySession.clone()] } +} + +/// This command returns the current policyDigest of the session. This command allows the +/// TPM to be used to perform the actions required to pre-compute the authPolicy for an object. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct PolicyGetDigestResponse { + /// The current value of the policySessionpolicyDigest + pub policyDigest: Vec, +} + +impl PolicyGetDigestResponse { +} + +impl TpmStructure for PolicyGetDigestResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.policyDigest, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.policyDigest = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for PolicyGetDigestResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for PolicyGetDigestResponse { + fn num_handles(&self) -> u16 { 0 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl RespStructure for PolicyGetDigestResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// This command allows a policy to be bound to the TPMA_NV_WRITTEN attributes. This is a +/// deferred assertion. Values are stored in the policy session context and checked when +/// the policy is used for authorization. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_PolicyNvWritten_REQUEST { + /// Handle for the policy session being extended + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub policySession: TPM_HANDLE, + + /// YES if NV Index is required to have been written + /// NO if NV Index is required not to have been written + pub writtenSet: u8, +} + +impl TPM2_PolicyNvWritten_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + policySession: &TPM_HANDLE, + writtenSet: u8, + ) -> Self { + Self { + policySession: policySession.clone(), + writtenSet: writtenSet.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_PolicyNvWritten_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeByte(self.writtenSet as u8); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.writtenSet = buf.readByte() as u8; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_PolicyNvWritten_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_PolicyNvWritten_REQUEST { + fn num_handles(&self) -> u16 { 1 } + +} + +impl ReqStructure for TPM2_PolicyNvWritten_REQUEST { + fn num_auth_handles(&self) -> u16 { 0 } + + fn get_handles(&self) -> Vec { vec![self.policySession.clone()] } +} + +/// This command allows a policy to be bound to a specific creation template. This is most +/// useful for an object creation command such as TPM2_Create(), TPM2_CreatePrimary(), or +/// TPM2_CreateLoaded(). +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_PolicyTemplate_REQUEST { + /// Handle for the policy session being extended + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub policySession: TPM_HANDLE, + + /// The digest to be added to the policy + pub templateHash: Vec, +} + +impl TPM2_PolicyTemplate_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + policySession: &TPM_HANDLE, + templateHash: &Vec, + ) -> Self { + Self { + policySession: policySession.clone(), + templateHash: templateHash.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_PolicyTemplate_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.templateHash, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.templateHash = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_PolicyTemplate_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_PolicyTemplate_REQUEST { + fn num_handles(&self) -> u16 { 1 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_PolicyTemplate_REQUEST { + fn num_auth_handles(&self) -> u16 { 0 } + + fn get_handles(&self) -> Vec { vec![self.policySession.clone()] } +} + +/// This command provides a capability that is the equivalent of a revocable policy. With +/// TPM2_PolicyAuthorize(), the authorization ticket never expires, so the authorization +/// may not be withdrawn. With this command, the approved policy is kept in an NV Index +/// location so that the policy may be changed as needed to render the old policy unusable. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_PolicyAuthorizeNV_REQUEST { + /// Handle indicating the source of the authorization value + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub authHandle: TPM_HANDLE, + + /// The NV Index of the area to read + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub nvIndex: TPM_HANDLE, + + /// Handle for the policy session being extended + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub policySession: TPM_HANDLE, +} + +impl TPM2_PolicyAuthorizeNV_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + authHandle: &TPM_HANDLE, + nvIndex: &TPM_HANDLE, + policySession: &TPM_HANDLE, + ) -> Self { + Self { + authHandle: authHandle.clone(), + nvIndex: nvIndex.clone(), + policySession: policySession.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_PolicyAuthorizeNV_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_PolicyAuthorizeNV_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_PolicyAuthorizeNV_REQUEST { + fn num_handles(&self) -> u16 { 3 } + +} + +impl ReqStructure for TPM2_PolicyAuthorizeNV_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.authHandle.clone(), self.nvIndex.clone(), self.policySession.clone()] } +} + +/// This command is used to create a Primary Object under one of the Primary Seeds or a +/// Temporary Object under TPM_RH_NULL. The command uses a TPM2B_PUBLIC as a template for +/// the object to be created. The size of the unique field shall not be checked for +/// consistency with the other object parameters. The command will create and load a +/// Primary Object. The sensitive area is not returned. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_CreatePrimary_REQUEST { + /// TPM_RH_ENDORSEMENT, TPM_RH_OWNER, TPM_RH_PLATFORM+{PP}, or TPM_RH_NULL + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub primaryHandle: TPM_HANDLE, + + /// The sensitive data, see TPM 2.0 Part 1 Sensitive Values + pub inSensitive: TPMS_SENSITIVE_CREATE, + + /// The public template + pub inPublic: TPMT_PUBLIC, + + /// Data that will be included in the creation data for this object to provide permanent, + /// verifiable linkage between this object and some object owner data + pub outsideInfo: Vec, + + /// PCR that will be used in creation data + pub creationPCR: Vec, +} + +impl TPM2_CreatePrimary_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + primaryHandle: &TPM_HANDLE, + inSensitive: &TPMS_SENSITIVE_CREATE, + inPublic: &TPMT_PUBLIC, + outsideInfo: &Vec, + creationPCR: &Vec, + ) -> Self { + Self { + primaryHandle: primaryHandle.clone(), + inSensitive: inSensitive.clone(), + inPublic: inPublic.clone(), + outsideInfo: outsideInfo.clone(), + creationPCR: creationPCR.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_CreatePrimary_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedObj(&self.inSensitive)?; + buf.writeSizedObj(&self.inPublic)?; + buf.writeSizedByteBuf(&self.outsideInfo, 2); + buf.writeObjArr(self.creationPCR.as_ref())?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readSizedObj(&mut self.inSensitive)?; + buf.readSizedObj(&mut self.inPublic)?; + self.outsideInfo = buf.readSizedByteBuf(2); + buf.readObjArr(self.creationPCR.as_mut())?; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_CreatePrimary_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_CreatePrimary_REQUEST { + fn num_handles(&self) -> u16 { 1 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_CreatePrimary_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.primaryHandle.clone()] } +} + +/// This command is used to create a Primary Object under one of the Primary Seeds or a +/// Temporary Object under TPM_RH_NULL. The command uses a TPM2B_PUBLIC as a template for +/// the object to be created. The size of the unique field shall not be checked for +/// consistency with the other object parameters. The command will create and load a +/// Primary Object. The sensitive area is not returned. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct CreatePrimaryResponse { + /// Handle of type TPM_HT_TRANSIENT for created Primary Object + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub handle: TPM_HANDLE, + + /// The public portion of the created object + pub outPublic: TPMT_PUBLIC, + + /// Contains a TPMT_CREATION_DATA + pub creationData: TPMS_CREATION_DATA, + + /// Digest of creationData using nameAlg of outPublic + pub creationHash: Vec, + + /// Ticket used by TPM2_CertifyCreation() to validate that the creation data was produced + /// by the TPM + pub creationTicket: TPMT_TK_CREATION, + + /// The name of the created object + pub name: Vec, +} + +impl CreatePrimaryResponse { +} + +impl TpmStructure for CreatePrimaryResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedObj(&self.outPublic)?; + buf.writeSizedObj(&self.creationData)?; + buf.writeSizedByteBuf(&self.creationHash, 2); + self.creationTicket.toTpm(buf)?; + buf.writeSizedByteBuf(&self.name, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readSizedObj(&mut self.outPublic)?; + buf.readSizedObj(&mut self.creationData)?; + self.creationHash = buf.readSizedByteBuf(2); + self.creationTicket.initFromTpm(buf)?; + self.name = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for CreatePrimaryResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for CreatePrimaryResponse { + fn num_handles(&self) -> u16 { 1 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl RespStructure for CreatePrimaryResponse { + fn get_handle(&self) -> TPM_HANDLE { self.handle.clone() } + + fn set_handle(&mut self, handle: &TPM_HANDLE) { self.handle = handle.clone(); } + + fn get_resp_name(&self) -> Vec { self.name.clone() } +} + +/// This command enables and disables use of a hierarchy and its associated NV storage. +/// The command allows phEnable, phEnableNV, shEnable, and ehEnable to be changed when the +/// proper authorization is provided. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_HierarchyControl_REQUEST { + /// TPM_RH_ENDORSEMENT, TPM_RH_OWNER or TPM_RH_PLATFORM+{PP} + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub authHandle: TPM_HANDLE, + + /// The enable being modified + /// TPM_RH_ENDORSEMENT, TPM_RH_OWNER, TPM_RH_PLATFORM, or TPM_RH_PLATFORM_NV + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub enable: TPM_HANDLE, + + /// YES if the enable should be SET, NO if the enable should be CLEAR + pub state: u8, +} + +impl TPM2_HierarchyControl_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + authHandle: &TPM_HANDLE, + enable: &TPM_HANDLE, + state: u8, + ) -> Self { + Self { + authHandle: authHandle.clone(), + enable: enable.clone(), + state: state.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_HierarchyControl_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + self.enable.toTpm(buf)?; + buf.writeByte(self.state as u8); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.enable.initFromTpm(buf)?; + self.state = buf.readByte() as u8; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_HierarchyControl_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_HierarchyControl_REQUEST { + fn num_handles(&self) -> u16 { 1 } + +} + +impl ReqStructure for TPM2_HierarchyControl_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.authHandle.clone()] } +} + +/// This command allows setting of the authorization policy for the lockout +/// (lockoutPolicy), the platform hierarchy (platformPolicy), the storage hierarchy +/// (ownerPolicy), and the endorsement hierarchy (endorsementPolicy). On TPMs implementing +/// Authenticated Countdown Timers (ACT), this command may also be used to set the +/// authorization policy for an ACT. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_SetPrimaryPolicy_REQUEST { + /// TPM_RH_LOCKOUT, TPM_RH_ENDORSEMENT, TPM_RH_OWNER, TPMI_RH_ACT or TPM_RH_PLATFORM+{PP} + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub authHandle: TPM_HANDLE, + + /// An authorization policy digest; may be the Empty Buffer + /// If hashAlg is TPM_ALG_NULL, then this shall be an Empty Buffer. + pub authPolicy: Vec, + + /// The hash algorithm to use for the policy + /// If the authPolicy is an Empty Buffer, then this field shall be TPM_ALG_NULL. + #[derivative(Default(value="TPM_ALG_ID::NULL"))] + pub hashAlg: TPM_ALG_ID, +} + +impl TPM2_SetPrimaryPolicy_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + authHandle: &TPM_HANDLE, + authPolicy: &Vec, + hashAlg: TPM_ALG_ID, + ) -> Self { + Self { + authHandle: authHandle.clone(), + authPolicy: authPolicy.clone(), + hashAlg: hashAlg.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_SetPrimaryPolicy_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.authPolicy, 2); + buf.writeShort(self.hashAlg.into()); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.authPolicy = buf.readSizedByteBuf(2); + self.hashAlg = TPM_ALG_ID(buf.readShort() as u16); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_SetPrimaryPolicy_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_SetPrimaryPolicy_REQUEST { + fn num_handles(&self) -> u16 { 1 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_SetPrimaryPolicy_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.authHandle.clone()] } +} + +/// This replaces the current platform primary seed (PPS) with a value from the RNG and +/// sets platformPolicy to the default initialization value (the Empty Buffer). +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_ChangePPS_REQUEST { + /// TPM_RH_PLATFORM+{PP} + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub authHandle: TPM_HANDLE, +} + +impl TPM2_ChangePPS_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + authHandle: &TPM_HANDLE, + ) -> Self { + Self { + authHandle: authHandle.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_ChangePPS_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_ChangePPS_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_ChangePPS_REQUEST { + fn num_handles(&self) -> u16 { 1 } + +} + +impl ReqStructure for TPM2_ChangePPS_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.authHandle.clone()] } +} + +/// This replaces the current endorsement primary seed (EPS) with a value from the RNG and +/// sets the Endorsement hierarchy controls to their default initialization values: +/// ehEnable is SET, endorsementAuth and endorsementPolicy are both set to the Empty +/// Buffer. It will flush any resident objects (transient or persistent) in the +/// Endorsement hierarchy and not allow objects in the hierarchy associated with the +/// previous EPS to be loaded. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_ChangeEPS_REQUEST { + /// TPM_RH_PLATFORM+{PP} + /// Auth Handle: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub authHandle: TPM_HANDLE, +} + +impl TPM2_ChangeEPS_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + authHandle: &TPM_HANDLE, + ) -> Self { + Self { + authHandle: authHandle.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_ChangeEPS_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_ChangeEPS_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_ChangeEPS_REQUEST { + fn num_handles(&self) -> u16 { 1 } + +} + +impl ReqStructure for TPM2_ChangeEPS_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.authHandle.clone()] } +} + +/// This command removes all TPM context associated with a specific Owner. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_Clear_REQUEST { + /// TPM_RH_LOCKOUT or TPM_RH_PLATFORM+{PP} + /// Auth Handle: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub authHandle: TPM_HANDLE, +} + +impl TPM2_Clear_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + authHandle: &TPM_HANDLE, + ) -> Self { + Self { + authHandle: authHandle.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_Clear_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_Clear_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_Clear_REQUEST { + fn num_handles(&self) -> u16 { 1 } + +} + +impl ReqStructure for TPM2_Clear_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.authHandle.clone()] } +} + +/// TPM2_ClearControl() disables and enables the execution of TPM2_Clear(). +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_ClearControl_REQUEST { + /// TPM_RH_LOCKOUT or TPM_RH_PLATFORM+{PP} + /// Auth Handle: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub auth: TPM_HANDLE, + + /// YES if the disableOwnerClear flag is to be SET, NO if the flag is to be CLEAR. + pub disable: u8, +} + +impl TPM2_ClearControl_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + auth: &TPM_HANDLE, + disable: u8, + ) -> Self { + Self { + auth: auth.clone(), + disable: disable.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_ClearControl_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeByte(self.disable as u8); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.disable = buf.readByte() as u8; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_ClearControl_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_ClearControl_REQUEST { + fn num_handles(&self) -> u16 { 1 } + +} + +impl ReqStructure for TPM2_ClearControl_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.auth.clone()] } +} + +/// This command allows the authorization secret for a hierarchy or lockout to be changed +/// using the current authorization value as the command authorization. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_HierarchyChangeAuth_REQUEST { + /// TPM_RH_LOCKOUT, TPM_RH_ENDORSEMENT, TPM_RH_OWNER or TPM_RH_PLATFORM+{PP} + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub authHandle: TPM_HANDLE, + + /// New authorization value + pub newAuth: Vec, +} + +impl TPM2_HierarchyChangeAuth_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + authHandle: &TPM_HANDLE, + newAuth: &Vec, + ) -> Self { + Self { + authHandle: authHandle.clone(), + newAuth: newAuth.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_HierarchyChangeAuth_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.newAuth, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.newAuth = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_HierarchyChangeAuth_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_HierarchyChangeAuth_REQUEST { + fn num_handles(&self) -> u16 { 1 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_HierarchyChangeAuth_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.authHandle.clone()] } +} + +/// This command cancels the effect of a TPM lockout due to a number of successive +/// authorization failures. If this command is properly authorized, the lockout counter is +/// set to zero. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_DictionaryAttackLockReset_REQUEST { + /// TPM_RH_LOCKOUT + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub lockHandle: TPM_HANDLE, +} + +impl TPM2_DictionaryAttackLockReset_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + lockHandle: &TPM_HANDLE, + ) -> Self { + Self { + lockHandle: lockHandle.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_DictionaryAttackLockReset_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_DictionaryAttackLockReset_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_DictionaryAttackLockReset_REQUEST { + fn num_handles(&self) -> u16 { 1 } + +} + +impl ReqStructure for TPM2_DictionaryAttackLockReset_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.lockHandle.clone()] } +} + +/// This command changes the lockout parameters. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_DictionaryAttackParameters_REQUEST { + /// TPM_RH_LOCKOUT + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub lockHandle: TPM_HANDLE, + + /// Count of authorization failures before the lockout is imposed + pub newMaxTries: u32, + + /// Time in seconds before the authorization failure count is automatically decremented + /// A value of zero indicates that DA protection is disabled. + pub newRecoveryTime: u32, + + /// Time in seconds after a lockoutAuth failure before use of lockoutAuth is allowed + /// A value of zero indicates that a reboot is required. + pub lockoutRecovery: u32, +} + +impl TPM2_DictionaryAttackParameters_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + lockHandle: &TPM_HANDLE, + newMaxTries: u32, + newRecoveryTime: u32, + lockoutRecovery: u32, + ) -> Self { + Self { + lockHandle: lockHandle.clone(), + newMaxTries: newMaxTries.clone(), + newRecoveryTime: newRecoveryTime.clone(), + lockoutRecovery: lockoutRecovery.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_DictionaryAttackParameters_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeInt(self.newMaxTries as u32); + buf.writeInt(self.newRecoveryTime as u32); + buf.writeInt(self.lockoutRecovery as u32); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.newMaxTries = buf.readInt() as u32; + self.newRecoveryTime = buf.readInt() as u32; + self.lockoutRecovery = buf.readInt() as u32; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_DictionaryAttackParameters_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_DictionaryAttackParameters_REQUEST { + fn num_handles(&self) -> u16 { 1 } + +} + +impl ReqStructure for TPM2_DictionaryAttackParameters_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.lockHandle.clone()] } +} + +/// This command is used to determine which commands require assertion of Physical +/// Presence (PP) in addition to platformAuth/platformPolicy. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_PP_Commands_REQUEST { + /// TPM_RH_PLATFORM+PP + /// Auth Index: 1 + /// Auth Role: USER + Physical Presence + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub auth: TPM_HANDLE, + + /// List of commands to be added to those that will require that Physical Presence be asserted + pub setList: Vec, + + /// List of commands that will no longer require that Physical Presence be asserted + pub clearList: Vec, +} + +impl TPM2_PP_Commands_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + auth: &TPM_HANDLE, + setList: &Vec, + clearList: &Vec, + ) -> Self { + Self { + auth: auth.clone(), + setList: setList.clone(), + clearList: clearList.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_PP_Commands_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeValArr(self.setList.as_ref(), 4); + buf.writeValArr(self.clearList.as_ref(), 4); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readValArr(self.setList.as_mut(), 4)?; + buf.readValArr(self.clearList.as_mut(), 4)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_PP_Commands_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_PP_Commands_REQUEST { + fn num_handles(&self) -> u16 { 1 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 4, val_len: 4 } } +} + +impl ReqStructure for TPM2_PP_Commands_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.auth.clone()] } +} + +/// This command allows the platform to change the set of algorithms that are used by the +/// TPM. The algorithmSet setting is a vendor-dependent value. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_SetAlgorithmSet_REQUEST { + /// TPM_RH_PLATFORM + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub authHandle: TPM_HANDLE, + + /// A TPM vendor-dependent value indicating the algorithm set selection + pub algorithmSet: u32, +} + +impl TPM2_SetAlgorithmSet_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + authHandle: &TPM_HANDLE, + algorithmSet: u32, + ) -> Self { + Self { + authHandle: authHandle.clone(), + algorithmSet: algorithmSet.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_SetAlgorithmSet_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeInt(self.algorithmSet as u32); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.algorithmSet = buf.readInt() as u32; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_SetAlgorithmSet_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_SetAlgorithmSet_REQUEST { + fn num_handles(&self) -> u16 { 1 } + +} + +impl ReqStructure for TPM2_SetAlgorithmSet_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.authHandle.clone()] } +} + +/// This command uses platformPolicy and a TPM Vendor Authorization Key to authorize a +/// Field Upgrade Manifest. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_FieldUpgradeStart_REQUEST { + /// TPM_RH_PLATFORM+{PP} + /// Auth Index:1 + /// Auth Role: ADMIN + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub authorization: TPM_HANDLE, + + /// Handle of a public area that contains the TPM Vendor Authorization Key that will be + /// used to validate manifestSignature + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub keyHandle: TPM_HANDLE, + + /// Digest of the first block in the field upgrade sequence + pub fuDigest: Vec, + + /// Selector of the algorithm used to construct the signature + + /// Signature over fuDigest using the key associated with keyHandle (not optional) + /// One of: TPMS_SIGNATURE_RSASSA, TPMS_SIGNATURE_RSAPSS, TPMS_SIGNATURE_ECDSA, + /// TPMS_SIGNATURE_ECDAA, TPMS_SIGNATURE_SM2, TPMS_SIGNATURE_ECSCHNORR, TPMT_HA, + /// TPMS_SCHEME_HASH, TPMS_NULL_SIGNATURE. + pub manifestSignature: Option, +} + +impl TPM2_FieldUpgradeStart_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + authorization: &TPM_HANDLE, + keyHandle: &TPM_HANDLE, + fuDigest: &Vec, + manifestSignature: &Option, + ) -> Self { + Self { + authorization: authorization.clone(), + keyHandle: keyHandle.clone(), + fuDigest: fuDigest.clone(), + manifestSignature: manifestSignature.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_FieldUpgradeStart_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.fuDigest, 2); + buf.writeShort(self.manifestSignature.as_ref().unwrap().GetUnionSelector().into()); + self.manifestSignature.as_ref().unwrap().toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.fuDigest = buf.readSizedByteBuf(2); + let r#manifestSignatureSigAlg: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); + self.manifestSignature = TPMU_SIGNATURE::create(r#manifestSignatureSigAlg)?; + self.manifestSignature.as_mut().unwrap().initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_FieldUpgradeStart_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_FieldUpgradeStart_REQUEST { + fn num_handles(&self) -> u16 { 2 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_FieldUpgradeStart_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.authorization.clone(), self.keyHandle.clone()] } +} + +/// This command will take the actual field upgrade image to be installed on the TPM. The +/// exact format of fuData is vendor-specific. This command is only possible following a +/// successful TPM2_FieldUpgradeStart(). If the TPM has not received a properly authorized +/// TPM2_FieldUpgradeStart(), then the TPM shall return TPM_RC_FIELDUPGRADE. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_FieldUpgradeData_REQUEST { + /// Field upgrade image data + pub fuData: Vec, +} + +impl TPM2_FieldUpgradeData_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + fuData: &Vec, + ) -> Self { + Self { + fuData: fuData.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_FieldUpgradeData_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.fuData, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.fuData = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_FieldUpgradeData_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_FieldUpgradeData_REQUEST { + fn num_handles(&self) -> u16 { 0 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_FieldUpgradeData_REQUEST { + fn num_auth_handles(&self) -> u16 { 0 } + + fn get_handles(&self) -> Vec { vec![] } +} + +/// This command will take the actual field upgrade image to be installed on the TPM. The +/// exact format of fuData is vendor-specific. This command is only possible following a +/// successful TPM2_FieldUpgradeStart(). If the TPM has not received a properly authorized +/// TPM2_FieldUpgradeStart(), then the TPM shall return TPM_RC_FIELDUPGRADE. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct FieldUpgradeDataResponse { + /// Tagged digest of the next block + /// TPM_ALG_NULL if field update is complete + pub nextDigest: TPMT_HA, + + /// Tagged digest of the first block of the sequence + pub firstDigest: TPMT_HA, +} + +impl FieldUpgradeDataResponse { +} + +impl TpmStructure for FieldUpgradeDataResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + self.nextDigest.toTpm(buf)?; + self.firstDigest.toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.nextDigest.initFromTpm(buf)?; + self.firstDigest.initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for FieldUpgradeDataResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for FieldUpgradeDataResponse { + fn num_handles(&self) -> u16 { 0 } + +} + +impl RespStructure for FieldUpgradeDataResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// This command is used to read a copy of the current firmware installed in the TPM. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_FirmwareRead_REQUEST { + /// The number of previous calls to this command in this sequence + /// set to 0 on the first call + pub sequenceNumber: u32, +} + +impl TPM2_FirmwareRead_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + sequenceNumber: u32, + ) -> Self { + Self { + sequenceNumber: sequenceNumber.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_FirmwareRead_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeInt(self.sequenceNumber as u32); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.sequenceNumber = buf.readInt() as u32; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_FirmwareRead_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_FirmwareRead_REQUEST { + fn num_handles(&self) -> u16 { 0 } + +} + +impl ReqStructure for TPM2_FirmwareRead_REQUEST { + fn num_auth_handles(&self) -> u16 { 0 } + + fn get_handles(&self) -> Vec { vec![] } +} + +/// This command is used to read a copy of the current firmware installed in the TPM. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct FirmwareReadResponse { + /// Field upgrade image data + pub fuData: Vec, +} + +impl FirmwareReadResponse { +} + +impl TpmStructure for FirmwareReadResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.fuData, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.fuData = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for FirmwareReadResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for FirmwareReadResponse { + fn num_handles(&self) -> u16 { 0 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl RespStructure for FirmwareReadResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// This command saves a session context, object context, or sequence object context +/// outside the TPM. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_ContextSave_REQUEST { + /// Handle of the resource to save + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub saveHandle: TPM_HANDLE, +} + +impl TPM2_ContextSave_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + saveHandle: &TPM_HANDLE, + ) -> Self { + Self { + saveHandle: saveHandle.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_ContextSave_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_ContextSave_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_ContextSave_REQUEST { + fn num_handles(&self) -> u16 { 1 } + +} + +impl ReqStructure for TPM2_ContextSave_REQUEST { + fn num_auth_handles(&self) -> u16 { 0 } + + fn get_handles(&self) -> Vec { vec![self.saveHandle.clone()] } +} + +/// This command saves a session context, object context, or sequence object context +/// outside the TPM. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct ContextSaveResponse { + pub context: TPMS_CONTEXT, +} + +impl ContextSaveResponse { +} + +impl TpmStructure for ContextSaveResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + self.context.toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.context.initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for ContextSaveResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for ContextSaveResponse { + fn num_handles(&self) -> u16 { 0 } + +} + +impl RespStructure for ContextSaveResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// This command is used to reload a context that has been saved by TPM2_ContextSave(). +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_ContextLoad_REQUEST { + /// The context blob + pub context: TPMS_CONTEXT, +} + +impl TPM2_ContextLoad_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + context: &TPMS_CONTEXT, + ) -> Self { + Self { + context: context.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_ContextLoad_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + self.context.toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.context.initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_ContextLoad_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_ContextLoad_REQUEST { + fn num_handles(&self) -> u16 { 0 } + +} + +impl ReqStructure for TPM2_ContextLoad_REQUEST { + fn num_auth_handles(&self) -> u16 { 0 } + + fn get_handles(&self) -> Vec { vec![] } +} + +/// This command is used to reload a context that has been saved by TPM2_ContextSave(). +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct ContextLoadResponse { + /// The handle assigned to the resource after it has been successfully loaded + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub handle: TPM_HANDLE, +} + +impl ContextLoadResponse { +} + +impl TpmStructure for ContextLoadResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + Ok(()) + } + +} + +impl TpmMarshaller for ContextLoadResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for ContextLoadResponse { + fn num_handles(&self) -> u16 { 1 } + +} + +impl RespStructure for ContextLoadResponse { + fn get_handle(&self) -> TPM_HANDLE { self.handle.clone() } + + fn set_handle(&mut self, handle: &TPM_HANDLE) { self.handle = handle.clone(); } +} + +/// This command causes all context associated with a loaded object, sequence object, or +/// session to be removed from TPM memory. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_FlushContext_REQUEST { + /// The handle of the item to flush + /// NOTE This is a use of a handle as a parameter. + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub flushHandle: TPM_HANDLE, +} + +impl TPM2_FlushContext_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + flushHandle: &TPM_HANDLE, + ) -> Self { + Self { + flushHandle: flushHandle.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_FlushContext_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + self.flushHandle.toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.flushHandle.initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_FlushContext_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_FlushContext_REQUEST { + fn num_handles(&self) -> u16 { 0 } + +} + +impl ReqStructure for TPM2_FlushContext_REQUEST { + fn num_auth_handles(&self) -> u16 { 0 } + + fn get_handles(&self) -> Vec { vec![] } +} + +/// This command allows certain Transient Objects to be made persistent or a persistent +/// object to be evicted. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_EvictControl_REQUEST { + /// TPM_RH_OWNER or TPM_RH_PLATFORM+{PP} + /// Auth Handle: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub auth: TPM_HANDLE, + + /// The handle of a loaded object + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub objectHandle: TPM_HANDLE, + + /// If objectHandle is a transient object handle, then this is the persistent handle for + /// the object + /// if objectHandle is a persistent object handle, then it shall be the same value as + /// persistentHandle + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub persistentHandle: TPM_HANDLE, +} + +impl TPM2_EvictControl_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + auth: &TPM_HANDLE, + objectHandle: &TPM_HANDLE, + persistentHandle: &TPM_HANDLE, + ) -> Self { + Self { + auth: auth.clone(), + objectHandle: objectHandle.clone(), + persistentHandle: persistentHandle.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_EvictControl_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + self.persistentHandle.toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.persistentHandle.initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_EvictControl_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_EvictControl_REQUEST { + fn num_handles(&self) -> u16 { 2 } + +} + +impl ReqStructure for TPM2_EvictControl_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.auth.clone(), self.objectHandle.clone()] } +} + +/// This command reads the current TPMS_TIME_INFO structure that contains the current +/// setting of Time, Clock, resetCount, and restartCount. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_ReadClock_REQUEST { +} + +impl TPM2_ReadClock_REQUEST { +} + +impl TpmStructure for TPM2_ReadClock_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_ReadClock_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_ReadClock_REQUEST { + fn num_handles(&self) -> u16 { 0 } + +} + +impl ReqStructure for TPM2_ReadClock_REQUEST { + fn num_auth_handles(&self) -> u16 { 0 } + + fn get_handles(&self) -> Vec { vec![] } +} + +/// This command reads the current TPMS_TIME_INFO structure that contains the current +/// setting of Time, Clock, resetCount, and restartCount. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct ReadClockResponse { + pub currentTime: TPMS_TIME_INFO, +} + +impl ReadClockResponse { +} + +impl TpmStructure for ReadClockResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + self.currentTime.toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.currentTime.initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for ReadClockResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for ReadClockResponse { + fn num_handles(&self) -> u16 { 0 } + +} + +impl RespStructure for ReadClockResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// This command is used to advance the value of the TPMs Clock. The command will fail if +/// newTime is less than the current value of Clock or if the new time is greater than +/// FFFF00000000000016. If both of these checks succeed, Clock is set to newTime. If +/// either of these checks fails, the TPM shall return TPM_RC_VALUE and make no change to Clock. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_ClockSet_REQUEST { + /// TPM_RH_OWNER or TPM_RH_PLATFORM+{PP} + /// Auth Handle: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub auth: TPM_HANDLE, + + /// New Clock setting in milliseconds + pub newTime: u64, +} + +impl TPM2_ClockSet_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + auth: &TPM_HANDLE, + newTime: u64, + ) -> Self { + Self { + auth: auth.clone(), + newTime: newTime.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_ClockSet_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeInt64(self.newTime as u64); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.newTime = buf.readInt64() as u64; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_ClockSet_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_ClockSet_REQUEST { + fn num_handles(&self) -> u16 { 1 } + +} + +impl ReqStructure for TPM2_ClockSet_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.auth.clone()] } +} + +/// This command adjusts the rate of advance of Clock and Time to provide a better +/// approximation to real time. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_ClockRateAdjust_REQUEST { + /// TPM_RH_OWNER or TPM_RH_PLATFORM+{PP} + /// Auth Handle: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub auth: TPM_HANDLE, + + /// Adjustment to current Clock update rate + pub rateAdjust: TPM_CLOCK_ADJUST, +} + +impl TPM2_ClockRateAdjust_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + auth: &TPM_HANDLE, + rateAdjust: TPM_CLOCK_ADJUST, + ) -> Self { + Self { + auth: auth.clone(), + rateAdjust: rateAdjust.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_ClockRateAdjust_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeByte(self.rateAdjust.into()); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.rateAdjust = TPM_CLOCK_ADJUST(buf.readByte() as i8); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_ClockRateAdjust_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_ClockRateAdjust_REQUEST { + fn num_handles(&self) -> u16 { 1 } + +} + +impl ReqStructure for TPM2_ClockRateAdjust_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.auth.clone()] } +} + +/// This command returns various information regarding the TPM and its current state. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_GetCapability_REQUEST { + /// Group selection; determines the format of the response + pub capability: TPM_CAP, + + /// Further definition of information + pub property: u32, + + /// Number of properties of the indicated type to return + pub propertyCount: u32, +} + +impl TPM2_GetCapability_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + capability: TPM_CAP, + property: u32, + propertyCount: u32, + ) -> Self { + Self { + capability: capability.clone(), + property: property.clone(), + propertyCount: propertyCount.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_GetCapability_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeInt(self.capability.into()); + buf.writeInt(self.property as u32); + buf.writeInt(self.propertyCount as u32); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.capability = TPM_CAP(buf.readInt() as u32); + self.property = buf.readInt() as u32; + self.propertyCount = buf.readInt() as u32; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_GetCapability_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_GetCapability_REQUEST { + fn num_handles(&self) -> u16 { 0 } + +} + +impl ReqStructure for TPM2_GetCapability_REQUEST { + fn num_auth_handles(&self) -> u16 { 0 } + + fn get_handles(&self) -> Vec { vec![] } +} + +/// This command returns various information regarding the TPM and its current state. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct GetCapabilityResponse { + /// Flag to indicate if there are more values of this type + pub moreData: u8, + + /// The capability + + /// The capability data + /// One of: TPML_ALG_PROPERTY, TPML_HANDLE, TPML_CCA, TPML_CC, TPML_PCR_SELECTION, + /// TPML_TAGGED_TPM_PROPERTY, TPML_TAGGED_PCR_PROPERTY, TPML_ECC_CURVE, + /// TPML_TAGGED_POLICY, TPML_ACT_DATA. + pub capabilityData: Option, +} + +impl GetCapabilityResponse { +} + +impl TpmStructure for GetCapabilityResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeByte(self.moreData as u8); + buf.writeInt(self.capabilityData.as_ref().unwrap().GetUnionSelector().into()); + self.capabilityData.as_ref().unwrap().toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.moreData = buf.readByte() as u8; + let r#capabilityDataCapability: TPM_CAP = TPM_CAP(buf.readInt() as u32); + self.capabilityData = TPMU_CAPABILITIES::create(r#capabilityDataCapability)?; + self.capabilityData.as_mut().unwrap().initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for GetCapabilityResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for GetCapabilityResponse { + fn num_handles(&self) -> u16 { 0 } + +} + +impl RespStructure for GetCapabilityResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// This command is used to check to see if specific combinations of algorithm parameters +/// are supported. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_TestParms_REQUEST { + /// The algorithm to be tested + + /// Algorithm parameters to be validated + /// One of: TPMS_KEYEDHASH_PARMS, TPMS_SYMCIPHER_PARMS, TPMS_RSA_PARMS, TPMS_ECC_PARMS, + /// TPMS_ASYM_PARMS. + pub parameters: Option, +} + +impl TPM2_TestParms_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + parameters: &Option, + ) -> Self { + Self { + parameters: parameters.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_TestParms_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + if (self.parameters.is_none()) { return Ok(()) }; + buf.writeShort(self.parameters.as_ref().unwrap().GetUnionSelector().into()); + self.parameters.as_ref().unwrap().toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + let r#parametersType: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); + self.parameters = TPMU_PUBLIC_PARMS::create(r#parametersType)?; + self.parameters.as_mut().unwrap().initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_TestParms_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_TestParms_REQUEST { + fn num_handles(&self) -> u16 { 0 } + +} + +impl ReqStructure for TPM2_TestParms_REQUEST { + fn num_auth_handles(&self) -> u16 { 0 } + + fn get_handles(&self) -> Vec { vec![] } +} + +/// This command defines the attributes of an NV Index and causes the TPM to reserve space +/// to hold the data associated with the NV Index. If a definition already exists at the +/// NV Index, the TPM will return TPM_RC_NV_DEFINED. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_NV_DefineSpace_REQUEST { + /// TPM_RH_OWNER or TPM_RH_PLATFORM+{PP} + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub authHandle: TPM_HANDLE, + + /// The authorization value + pub auth: Vec, + + /// The public parameters of the NV area + pub publicInfo: TPMS_NV_PUBLIC, +} + +impl TPM2_NV_DefineSpace_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + authHandle: &TPM_HANDLE, + auth: &Vec, + publicInfo: &TPMS_NV_PUBLIC, + ) -> Self { + Self { + authHandle: authHandle.clone(), + auth: auth.clone(), + publicInfo: publicInfo.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_NV_DefineSpace_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.auth, 2); + buf.writeSizedObj(&self.publicInfo)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.auth = buf.readSizedByteBuf(2); + buf.readSizedObj(&mut self.publicInfo)?; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_NV_DefineSpace_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_NV_DefineSpace_REQUEST { + fn num_handles(&self) -> u16 { 1 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_NV_DefineSpace_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.authHandle.clone()] } +} + +/// This command removes an Index from the TPM. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_NV_UndefineSpace_REQUEST { + /// TPM_RH_OWNER or TPM_RH_PLATFORM+{PP} + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub authHandle: TPM_HANDLE, + + /// The NV Index to remove from NV space + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub nvIndex: TPM_HANDLE, +} + +impl TPM2_NV_UndefineSpace_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + authHandle: &TPM_HANDLE, + nvIndex: &TPM_HANDLE, + ) -> Self { + Self { + authHandle: authHandle.clone(), + nvIndex: nvIndex.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_NV_UndefineSpace_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_NV_UndefineSpace_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_NV_UndefineSpace_REQUEST { + fn num_handles(&self) -> u16 { 2 } + +} + +impl ReqStructure for TPM2_NV_UndefineSpace_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.authHandle.clone(), self.nvIndex.clone()] } +} + +/// This command allows removal of a platform-created NV Index that has +/// TPMA_NV_POLICY_DELETE SET. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_NV_UndefineSpaceSpecial_REQUEST { + /// Index to be deleted + /// Auth Index: 1 + /// Auth Role: ADMIN + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub nvIndex: TPM_HANDLE, + + /// TPM_RH_PLATFORM + {PP} + /// Auth Index: 2 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub platform: TPM_HANDLE, +} + +impl TPM2_NV_UndefineSpaceSpecial_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + nvIndex: &TPM_HANDLE, + platform: &TPM_HANDLE, + ) -> Self { + Self { + nvIndex: nvIndex.clone(), + platform: platform.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_NV_UndefineSpaceSpecial_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_NV_UndefineSpaceSpecial_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_NV_UndefineSpaceSpecial_REQUEST { + fn num_handles(&self) -> u16 { 2 } + +} + +impl ReqStructure for TPM2_NV_UndefineSpaceSpecial_REQUEST { + fn num_auth_handles(&self) -> u16 { 2 } + + fn get_handles(&self) -> Vec { vec![self.nvIndex.clone(), self.platform.clone()] } +} + +/// This command is used to read the public area and Name of an NV Index. The public area +/// of an Index is not privacy-sensitive and no authorization is required to read this data. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_NV_ReadPublic_REQUEST { + /// The NV Index + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub nvIndex: TPM_HANDLE, +} + +impl TPM2_NV_ReadPublic_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + nvIndex: &TPM_HANDLE, + ) -> Self { + Self { + nvIndex: nvIndex.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_NV_ReadPublic_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_NV_ReadPublic_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_NV_ReadPublic_REQUEST { + fn num_handles(&self) -> u16 { 1 } + +} + +impl ReqStructure for TPM2_NV_ReadPublic_REQUEST { + fn num_auth_handles(&self) -> u16 { 0 } + + fn get_handles(&self) -> Vec { vec![self.nvIndex.clone()] } +} + +/// This command is used to read the public area and Name of an NV Index. The public area +/// of an Index is not privacy-sensitive and no authorization is required to read this data. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct NV_ReadPublicResponse { + /// The public area of the NV Index + pub nvPublic: TPMS_NV_PUBLIC, + + /// The Name of the nvIndex + pub nvName: Vec, +} + +impl NV_ReadPublicResponse { +} + +impl TpmStructure for NV_ReadPublicResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedObj(&self.nvPublic)?; + buf.writeSizedByteBuf(&self.nvName, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readSizedObj(&mut self.nvPublic)?; + self.nvName = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for NV_ReadPublicResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for NV_ReadPublicResponse { + fn num_handles(&self) -> u16 { 0 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl RespStructure for NV_ReadPublicResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// This command writes a value to an area in NV memory that was previously defined by +/// TPM2_NV_DefineSpace(). +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_NV_Write_REQUEST { + /// Handle indicating the source of the authorization value + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub authHandle: TPM_HANDLE, + + /// The NV Index of the area to write + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub nvIndex: TPM_HANDLE, + + /// The data to write + pub data: Vec, + + /// The octet offset into the NV Area + pub offset: u16, +} + +impl TPM2_NV_Write_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + authHandle: &TPM_HANDLE, + nvIndex: &TPM_HANDLE, + data: &Vec, + offset: u16, + ) -> Self { + Self { + authHandle: authHandle.clone(), + nvIndex: nvIndex.clone(), + data: data.clone(), + offset: offset.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_NV_Write_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.data, 2); + buf.writeShort(self.offset as u16); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.data = buf.readSizedByteBuf(2); + self.offset = buf.readShort() as u16; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_NV_Write_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_NV_Write_REQUEST { + fn num_handles(&self) -> u16 { 2 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_NV_Write_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.authHandle.clone(), self.nvIndex.clone()] } +} + +/// This command is used to increment the value in an NV Index that has the TPM_NT_COUNTER +/// attribute. The data value of the NV Index is incremented by one. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_NV_Increment_REQUEST { + /// Handle indicating the source of the authorization value + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub authHandle: TPM_HANDLE, + + /// The NV Index to increment + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub nvIndex: TPM_HANDLE, +} + +impl TPM2_NV_Increment_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + authHandle: &TPM_HANDLE, + nvIndex: &TPM_HANDLE, + ) -> Self { + Self { + authHandle: authHandle.clone(), + nvIndex: nvIndex.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_NV_Increment_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_NV_Increment_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_NV_Increment_REQUEST { + fn num_handles(&self) -> u16 { 2 } + +} + +impl ReqStructure for TPM2_NV_Increment_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.authHandle.clone(), self.nvIndex.clone()] } +} + +/// This command extends a value to an area in NV memory that was previously defined by +/// TPM2_NV_DefineSpace. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_NV_Extend_REQUEST { + /// Handle indicating the source of the authorization value + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub authHandle: TPM_HANDLE, + + /// The NV Index to extend + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub nvIndex: TPM_HANDLE, + + /// The data to extend + pub data: Vec, +} + +impl TPM2_NV_Extend_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + authHandle: &TPM_HANDLE, + nvIndex: &TPM_HANDLE, + data: &Vec, + ) -> Self { + Self { + authHandle: authHandle.clone(), + nvIndex: nvIndex.clone(), + data: data.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_NV_Extend_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.data, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.data = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_NV_Extend_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_NV_Extend_REQUEST { + fn num_handles(&self) -> u16 { 2 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_NV_Extend_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.authHandle.clone(), self.nvIndex.clone()] } +} + +/// This command is used to SET bits in an NV Index that was created as a bit field. Any +/// number of bits from 0 to 64 may be SET. The contents of bits are ORed with the current +/// contents of the NV Index. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_NV_SetBits_REQUEST { + /// Handle indicating the source of the authorization value + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub authHandle: TPM_HANDLE, + + /// NV Index of the area in which the bit is to be set + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub nvIndex: TPM_HANDLE, + + /// The data to OR with the current contents + pub bits: u64, +} + +impl TPM2_NV_SetBits_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + authHandle: &TPM_HANDLE, + nvIndex: &TPM_HANDLE, + bits: u64, + ) -> Self { + Self { + authHandle: authHandle.clone(), + nvIndex: nvIndex.clone(), + bits: bits.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_NV_SetBits_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeInt64(self.bits as u64); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.bits = buf.readInt64() as u64; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_NV_SetBits_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_NV_SetBits_REQUEST { + fn num_handles(&self) -> u16 { 2 } + +} + +impl ReqStructure for TPM2_NV_SetBits_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.authHandle.clone(), self.nvIndex.clone()] } +} + +/// If the TPMA_NV_WRITEDEFINE or TPMA_NV_WRITE_STCLEAR attributes of an NV location are +/// SET, then this command may be used to inhibit further writes of the NV Index. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_NV_WriteLock_REQUEST { + /// Handle indicating the source of the authorization value + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub authHandle: TPM_HANDLE, + + /// The NV Index of the area to lock + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub nvIndex: TPM_HANDLE, +} + +impl TPM2_NV_WriteLock_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + authHandle: &TPM_HANDLE, + nvIndex: &TPM_HANDLE, + ) -> Self { + Self { + authHandle: authHandle.clone(), + nvIndex: nvIndex.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_NV_WriteLock_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_NV_WriteLock_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_NV_WriteLock_REQUEST { + fn num_handles(&self) -> u16 { 2 } + +} + +impl ReqStructure for TPM2_NV_WriteLock_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.authHandle.clone(), self.nvIndex.clone()] } +} + +/// The command will SET TPMA_NV_WRITELOCKED for all indexes that have their +/// TPMA_NV_GLOBALLOCK attribute SET. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_NV_GlobalWriteLock_REQUEST { + /// TPM_RH_OWNER or TPM_RH_PLATFORM+{PP} + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub authHandle: TPM_HANDLE, +} + +impl TPM2_NV_GlobalWriteLock_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + authHandle: &TPM_HANDLE, + ) -> Self { + Self { + authHandle: authHandle.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_NV_GlobalWriteLock_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_NV_GlobalWriteLock_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_NV_GlobalWriteLock_REQUEST { + fn num_handles(&self) -> u16 { 1 } + +} + +impl ReqStructure for TPM2_NV_GlobalWriteLock_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.authHandle.clone()] } +} + +/// This command reads a value from an area in NV memory previously defined by TPM2_NV_DefineSpace(). +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_NV_Read_REQUEST { + /// The handle indicating the source of the authorization value + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub authHandle: TPM_HANDLE, + + /// The NV Index to be read + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub nvIndex: TPM_HANDLE, + + /// Number of octets to read + pub size: u16, + + /// Octet offset into the NV area + /// This value shall be less than or equal to the size of the nvIndex data. + pub offset: u16, +} + +impl TPM2_NV_Read_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + authHandle: &TPM_HANDLE, + nvIndex: &TPM_HANDLE, + size: u16, + offset: u16, + ) -> Self { + Self { + authHandle: authHandle.clone(), + nvIndex: nvIndex.clone(), + size: size.clone(), + offset: offset.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_NV_Read_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeShort(self.size as u16); + buf.writeShort(self.offset as u16); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.size = buf.readShort() as u16; + self.offset = buf.readShort() as u16; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_NV_Read_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_NV_Read_REQUEST { + fn num_handles(&self) -> u16 { 2 } + +} + +impl ReqStructure for TPM2_NV_Read_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.authHandle.clone(), self.nvIndex.clone()] } +} + +/// This command reads a value from an area in NV memory previously defined by TPM2_NV_DefineSpace(). +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct NV_ReadResponse { + /// The data read + pub data: Vec, +} + +impl NV_ReadResponse { +} + +impl TpmStructure for NV_ReadResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.data, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.data = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for NV_ReadResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for NV_ReadResponse { + fn num_handles(&self) -> u16 { 0 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl RespStructure for NV_ReadResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// If TPMA_NV_READ_STCLEAR is SET in an Index, then this command may be used to prevent +/// further reads of the NV Index until the next TPM2_Startup (TPM_SU_CLEAR). +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_NV_ReadLock_REQUEST { + /// The handle indicating the source of the authorization value + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub authHandle: TPM_HANDLE, + + /// The NV Index to be locked + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub nvIndex: TPM_HANDLE, +} + +impl TPM2_NV_ReadLock_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + authHandle: &TPM_HANDLE, + nvIndex: &TPM_HANDLE, + ) -> Self { + Self { + authHandle: authHandle.clone(), + nvIndex: nvIndex.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_NV_ReadLock_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_NV_ReadLock_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_NV_ReadLock_REQUEST { + fn num_handles(&self) -> u16 { 2 } + +} + +impl ReqStructure for TPM2_NV_ReadLock_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.authHandle.clone(), self.nvIndex.clone()] } +} + +/// This command allows the authorization secret for an NV Index to be changed. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_NV_ChangeAuth_REQUEST { + /// Handle of the entity + /// Auth Index: 1 + /// Auth Role: ADMIN + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub nvIndex: TPM_HANDLE, + + /// New authorization value + pub newAuth: Vec, +} + +impl TPM2_NV_ChangeAuth_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + nvIndex: &TPM_HANDLE, + newAuth: &Vec, + ) -> Self { + Self { + nvIndex: nvIndex.clone(), + newAuth: newAuth.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_NV_ChangeAuth_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.newAuth, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.newAuth = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_NV_ChangeAuth_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_NV_ChangeAuth_REQUEST { + fn num_handles(&self) -> u16 { 1 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_NV_ChangeAuth_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.nvIndex.clone()] } +} + +/// The purpose of this command is to certify the contents of an NV Index or portion of an +/// NV Index. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_NV_Certify_REQUEST { + /// Handle of the key used to sign the attestation structure + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub signHandle: TPM_HANDLE, + + /// Handle indicating the source of the authorization value for the NV Index + /// Auth Index: 2 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub authHandle: TPM_HANDLE, + + /// Index for the area to be certified + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub nvIndex: TPM_HANDLE, + + /// User-provided qualifying data + pub qualifyingData: Vec, + + /// Scheme selector + + /// Signing scheme to use if the scheme for signHandle is TPM_ALG_NULL + /// One of: TPMS_SIG_SCHEME_RSASSA, TPMS_SIG_SCHEME_RSAPSS, TPMS_SIG_SCHEME_ECDSA, + /// TPMS_SIG_SCHEME_ECDAA, TPMS_SIG_SCHEME_SM2, TPMS_SIG_SCHEME_ECSCHNORR, + /// TPMS_SCHEME_HMAC, TPMS_SCHEME_HASH, TPMS_NULL_SIG_SCHEME. + pub inScheme: Option, + + /// Number of octets to certify + pub size: u16, + + /// Octet offset into the NV area + /// This value shall be less than or equal to the size of the nvIndex data. + pub offset: u16, +} + +impl TPM2_NV_Certify_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + signHandle: &TPM_HANDLE, + authHandle: &TPM_HANDLE, + nvIndex: &TPM_HANDLE, + qualifyingData: &Vec, + inScheme: &Option, + size: u16, + offset: u16, + ) -> Self { + Self { + signHandle: signHandle.clone(), + authHandle: authHandle.clone(), + nvIndex: nvIndex.clone(), + qualifyingData: qualifyingData.clone(), + inScheme: inScheme.clone(), + size: size.clone(), + offset: offset.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_NV_Certify_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.qualifyingData, 2); + buf.writeShort(self.inScheme.as_ref().unwrap().GetUnionSelector().into()); + self.inScheme.as_ref().unwrap().toTpm(buf)?; + buf.writeShort(self.size as u16); + buf.writeShort(self.offset as u16); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.qualifyingData = buf.readSizedByteBuf(2); + let r#inSchemeScheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); + self.inScheme = TPMU_SIG_SCHEME::create(r#inSchemeScheme)?; + self.inScheme.as_mut().unwrap().initFromTpm(buf)?; + self.size = buf.readShort() as u16; + self.offset = buf.readShort() as u16; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_NV_Certify_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_NV_Certify_REQUEST { + fn num_handles(&self) -> u16 { 3 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_NV_Certify_REQUEST { + fn num_auth_handles(&self) -> u16 { 2 } + + fn get_handles(&self) -> Vec { vec![self.signHandle.clone(), self.authHandle.clone(), self.nvIndex.clone()] } +} + +/// The purpose of this command is to certify the contents of an NV Index or portion of an +/// NV Index. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct NV_CertifyResponse { + /// The structure that was signed + pub certifyInfo: TPMS_ATTEST, + + /// Selector of the algorithm used to construct the signature + + /// The asymmetric signature over certifyInfo using the key referenced by signHandle + /// One of: TPMS_SIGNATURE_RSASSA, TPMS_SIGNATURE_RSAPSS, TPMS_SIGNATURE_ECDSA, + /// TPMS_SIGNATURE_ECDAA, TPMS_SIGNATURE_SM2, TPMS_SIGNATURE_ECSCHNORR, TPMT_HA, + /// TPMS_SCHEME_HASH, TPMS_NULL_SIGNATURE. + pub signature: Option, +} + +impl NV_CertifyResponse { +} + +impl TpmStructure for NV_CertifyResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedObj(&self.certifyInfo)?; + buf.writeShort(self.signature.as_ref().unwrap().GetUnionSelector().into()); + self.signature.as_ref().unwrap().toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + buf.readSizedObj(&mut self.certifyInfo)?; + let r#signatureSigAlg: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); + self.signature = TPMU_SIGNATURE::create(r#signatureSigAlg)?; + self.signature.as_mut().unwrap().initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for NV_CertifyResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for NV_CertifyResponse { + fn num_handles(&self) -> u16 { 0 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl RespStructure for NV_CertifyResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// The purpose of this command is to obtain information about an Attached Component +/// referenced by an AC handle. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_AC_GetCapability_REQUEST { + /// Handle indicating the Attached Component + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub ac: TPM_HANDLE, + + /// Starting info type + pub capability: TPM_AT, + + /// Maximum number of values to return + pub count: u32, +} + +impl TPM2_AC_GetCapability_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + ac: &TPM_HANDLE, + capability: TPM_AT, + count: u32, + ) -> Self { + Self { + ac: ac.clone(), + capability: capability.clone(), + count: count.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_AC_GetCapability_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeInt(self.capability.into()); + buf.writeInt(self.count as u32); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.capability = TPM_AT(buf.readInt() as u32); + self.count = buf.readInt() as u32; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_AC_GetCapability_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_AC_GetCapability_REQUEST { + fn num_handles(&self) -> u16 { 1 } + +} + +impl ReqStructure for TPM2_AC_GetCapability_REQUEST { + fn num_auth_handles(&self) -> u16 { 0 } + + fn get_handles(&self) -> Vec { vec![self.ac.clone()] } +} + +/// The purpose of this command is to obtain information about an Attached Component +/// referenced by an AC handle. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct AC_GetCapabilityResponse { + /// Flag to indicate whether there are more values + pub moreData: u8, + + /// List of capabilities + pub capabilitiesData: Vec, +} + +impl AC_GetCapabilityResponse { +} + +impl TpmStructure for AC_GetCapabilityResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeByte(self.moreData as u8); + buf.writeObjArr(self.capabilitiesData.as_ref())?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.moreData = buf.readByte() as u8; + buf.readObjArr(self.capabilitiesData.as_mut())?; + Ok(()) + } + +} + +impl TpmMarshaller for AC_GetCapabilityResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for AC_GetCapabilityResponse { + fn num_handles(&self) -> u16 { 0 } + +} + +impl RespStructure for AC_GetCapabilityResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// The purpose of this command is to send (copy) a loaded object from the TPM to an +/// Attached Component. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_AC_Send_REQUEST { + /// Handle of the object being sent to ac + /// Auth Index: 1 + /// Auth Role: DUP + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub sendObject: TPM_HANDLE, + + /// The handle indicating the source of the authorization value + /// Auth Index: 2 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub authHandle: TPM_HANDLE, + + /// Handle indicating the Attached Component to which the object will be sent + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub ac: TPM_HANDLE, + + /// Optional non sensitive information related to the object + pub acDataIn: Vec, +} + +impl TPM2_AC_Send_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + sendObject: &TPM_HANDLE, + authHandle: &TPM_HANDLE, + ac: &TPM_HANDLE, + acDataIn: &Vec, + ) -> Self { + Self { + sendObject: sendObject.clone(), + authHandle: authHandle.clone(), + ac: ac.clone(), + acDataIn: acDataIn.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_AC_Send_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.acDataIn, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.acDataIn = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_AC_Send_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_AC_Send_REQUEST { + fn num_handles(&self) -> u16 { 3 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_AC_Send_REQUEST { + fn num_auth_handles(&self) -> u16 { 2 } + + fn get_handles(&self) -> Vec { vec![self.sendObject.clone(), self.authHandle.clone(), self.ac.clone()] } +} + +/// The purpose of this command is to send (copy) a loaded object from the TPM to an +/// Attached Component. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct AC_SendResponse { + /// May include AC specific data or information about an error. + pub acDataOut: TPMS_AC_OUTPUT, +} + +impl AC_SendResponse { +} + +impl TpmStructure for AC_SendResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + self.acDataOut.toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.acDataOut.initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for AC_SendResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for AC_SendResponse { + fn num_handles(&self) -> u16 { 0 } + +} + +impl RespStructure for AC_SendResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// This command allows qualification of the sending (copying) of an Object to an Attached +/// Component (AC). Qualification includes selection of the receiving AC and the method of +/// authentication for the AC, and, in certain circumstances, the Object to be sent may be +/// specified. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_Policy_AC_SendSelect_REQUEST { + /// Handle for the policy session being extended + /// Auth Index: None + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub policySession: TPM_HANDLE, + + /// The Name of the Object to be sent + pub objectName: Vec, + + /// The Name associated with authHandle used in the TPM2_AC_Send() command + pub authHandleName: Vec, + + /// The Name of the Attached Component to which the Object will be sent + pub acName: Vec, + + /// If SET, objectName will be included in the value in policySessionpolicyDigest + pub includeObject: u8, +} + +impl TPM2_Policy_AC_SendSelect_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + policySession: &TPM_HANDLE, + objectName: &Vec, + authHandleName: &Vec, + acName: &Vec, + includeObject: u8, + ) -> Self { + Self { + policySession: policySession.clone(), + objectName: objectName.clone(), + authHandleName: authHandleName.clone(), + acName: acName.clone(), + includeObject: includeObject.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_Policy_AC_SendSelect_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.objectName, 2); + buf.writeSizedByteBuf(&self.authHandleName, 2); + buf.writeSizedByteBuf(&self.acName, 2); + buf.writeByte(self.includeObject as u8); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.objectName = buf.readSizedByteBuf(2); + self.authHandleName = buf.readSizedByteBuf(2); + self.acName = buf.readSizedByteBuf(2); + self.includeObject = buf.readByte() as u8; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_Policy_AC_SendSelect_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_Policy_AC_SendSelect_REQUEST { + fn num_handles(&self) -> u16 { 1 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_Policy_AC_SendSelect_REQUEST { + fn num_auth_handles(&self) -> u16 { 0 } + + fn get_handles(&self) -> Vec { vec![self.policySession.clone()] } +} + +/// This command is used to set the time remaining before an Authenticated Countdown Timer +/// (ACT) expires. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_ACT_SetTimeout_REQUEST { + /// Handle of the selected ACT + /// Auth Index: 1 + /// Auth Role: USER + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub actHandle: TPM_HANDLE, + + /// The start timeout value for the ACT in seconds + pub startTimeout: u32, +} + +impl TPM2_ACT_SetTimeout_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + actHandle: &TPM_HANDLE, + startTimeout: u32, + ) -> Self { + Self { + actHandle: actHandle.clone(), + startTimeout: startTimeout.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_ACT_SetTimeout_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeInt(self.startTimeout as u32); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.startTimeout = buf.readInt() as u32; + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_ACT_SetTimeout_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_ACT_SetTimeout_REQUEST { + fn num_handles(&self) -> u16 { 1 } + +} + +impl ReqStructure for TPM2_ACT_SetTimeout_REQUEST { + fn num_auth_handles(&self) -> u16 { 1 } + + fn get_handles(&self) -> Vec { vec![self.actHandle.clone()] } +} + +/// This is a placeholder to allow testing of the dispatch code. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2_Vendor_TCG_Test_REQUEST { + /// Dummy data + pub inputData: Vec, +} + +impl TPM2_Vendor_TCG_Test_REQUEST { + /// Creates a new instance with the specified values + pub fn new( + inputData: &Vec, + ) -> Self { + Self { + inputData: inputData.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TPM2_Vendor_TCG_Test_REQUEST { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.inputData, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.inputData = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2_Vendor_TCG_Test_REQUEST { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for TPM2_Vendor_TCG_Test_REQUEST { + fn num_handles(&self) -> u16 { 0 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl ReqStructure for TPM2_Vendor_TCG_Test_REQUEST { + fn num_auth_handles(&self) -> u16 { 0 } + + fn get_handles(&self) -> Vec { vec![] } +} + +/// This is a placeholder to allow testing of the dispatch code. +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct Vendor_TCG_TestResponse { + /// Dummy data + pub outputData: Vec, +} + +impl Vendor_TCG_TestResponse { +} + +impl TpmStructure for Vendor_TCG_TestResponse { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.outputData, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.outputData = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for Vendor_TCG_TestResponse { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +impl CmdStructure for Vendor_TCG_TestResponse { + fn num_handles(&self) -> u16 { 0 } + + fn sess_enc_info(&self) -> SessEncInfo { SessEncInfo { size_len: 2, val_len: 1 } } +} + +impl RespStructure for Vendor_TCG_TestResponse { + fn get_handle(&self) -> TPM_HANDLE { TPM_HANDLE::default() } + + fn set_handle(&mut self, _handle: &TPM_HANDLE) { } +} + +/// These are the RSA schemes that only need a hash algorithm as a scheme parameter. +pub type TPMS_SCHEME_RSASSA = TPMS_SIG_SCHEME_RSASSA; + +/// These are the RSA schemes that only need a hash algorithm as a scheme parameter. +pub type TPMS_SCHEME_RSAPSS = TPMS_SIG_SCHEME_RSAPSS; + +/// Most of the ECC signature schemes only require a hash algorithm to complete the +/// definition and can be typed as TPMS_SCHEME_HASH. Anonymous algorithms also require a +/// count value so they are typed to be TPMS_SCHEME_ECDAA. +pub type TPMS_SCHEME_ECDSA = TPMS_SIG_SCHEME_ECDSA; + +/// Most of the ECC signature schemes only require a hash algorithm to complete the +/// definition and can be typed as TPMS_SCHEME_HASH. Anonymous algorithms also require a +/// count value so they are typed to be TPMS_SCHEME_ECDAA. +pub type TPMS_SCHEME_SM2 = TPMS_SIG_SCHEME_SM2; + +/// Most of the ECC signature schemes only require a hash algorithm to complete the +/// definition and can be typed as TPMS_SCHEME_HASH. Anonymous algorithms also require a +/// count value so they are typed to be TPMS_SCHEME_ECDAA. +pub type TPMS_SCHEME_ECSCHNORR = TPMS_SIG_SCHEME_ECSCHNORR; + +/// These are the RSA encryption schemes that only need a hash algorithm as a controlling parameter. +pub type TPMS_SCHEME_OAEP = TPMS_ENC_SCHEME_OAEP; + +/// These are the RSA encryption schemes that only need a hash algorithm as a controlling parameter. +pub type TPMS_SCHEME_RSAES = TPMS_ENC_SCHEME_RSAES; + +/// These are the ECC schemes that only need a hash algorithm as a controlling parameter. +pub type TPMS_SCHEME_ECDH = TPMS_KEY_SCHEME_ECDH; + +/// These are the ECC schemes that only need a hash algorithm as a controlling parameter. +pub type TPMS_SCHEME_ECMQV = TPMS_KEY_SCHEME_ECMQV; + +/// These structures are used to define the key derivation for symmetric secret sharing +/// using asymmetric methods. A secret sharing scheme is required in any asymmetric key +/// with the decrypt attribute SET. +pub type TPMS_SCHEME_MGF1 = TPMS_KDF_SCHEME_MGF1; + +/// These structures are used to define the key derivation for symmetric secret sharing +/// using asymmetric methods. A secret sharing scheme is required in any asymmetric key +/// with the decrypt attribute SET. +pub type TPMS_SCHEME_KDF1_SP800_56A = TPMS_KDF_SCHEME_KDF1_SP800_56A; + +/// These structures are used to define the key derivation for symmetric secret sharing +/// using asymmetric methods. A secret sharing scheme is required in any asymmetric key +/// with the decrypt attribute SET. +pub type TPMS_SCHEME_KDF2 = TPMS_KDF_SCHEME_KDF2; + +/// These structures are used to define the key derivation for symmetric secret sharing +/// using asymmetric methods. A secret sharing scheme is required in any asymmetric key +/// with the decrypt attribute SET. +pub type TPMS_SCHEME_KDF1_SP800_108 = TPMS_KDF_SCHEME_KDF1_SP800_108; + +/// Contains the public and the plaintext-sensitive and/or encrypted private part of a TPM +/// key (or other object) +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TssObject { + /// Public part of key + pub Public: TPMT_PUBLIC, + + /// Sensitive part of key + pub Sensitive: TPMT_SENSITIVE, + + /// Private part is the encrypted sensitive part of key + pub Private: TPM2B_PRIVATE, +} + +impl TssObject { + /// Creates a new instance with the specified values + pub fn new( + Public: &TPMT_PUBLIC, + Sensitive: &TPMT_SENSITIVE, + Private: &TPM2B_PRIVATE, + ) -> Self { + Self { + Public: Public.clone(), + Sensitive: Sensitive.clone(), + Private: Private.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TssObject { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + self.Public.toTpm(buf)?; + self.Sensitive.toTpm(buf)?; + self.Private.toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.Public.initFromTpm(buf)?; + self.Sensitive.initFromTpm(buf)?; + self.Private.initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for TssObject { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// Contains a PCR index and associated hash(pcr-value) [TSS] +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct PcrValue { + /// PCR Index + pub index: u32, + + /// PCR Value + pub value: TPMT_HA, +} + +impl PcrValue { + /// Creates a new instance with the specified values + pub fn new( + index: u32, + value: &TPMT_HA, + ) -> Self { + Self { + index: index.clone(), + value: value.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for PcrValue { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeInt(self.index as u32); + self.value.toTpm(buf)?; + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.index = buf.readInt() as u32; + self.value.initFromTpm(buf)?; + Ok(()) + } + +} + +impl TpmMarshaller for PcrValue { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// Structure representing a session block in a command buffer [TSS] +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct SessionIn { + /// Session handle + #[derivative(Default(value="TPM_HANDLE::default()"))] + pub handle: TPM_HANDLE, + + /// Caller nonce + pub nonceCaller: Vec, + + /// Session attributes + pub attributes: TPMA_SESSION, + + /// AuthValue (or HMAC) + pub auth: Vec, +} + +impl SessionIn { + /// Creates a new instance with the specified values + pub fn new( + handle: &TPM_HANDLE, + nonceCaller: &Vec, + attributes: TPMA_SESSION, + auth: &Vec, + ) -> Self { + Self { + handle: handle.clone(), + nonceCaller: nonceCaller.clone(), + attributes: attributes.clone(), + auth: auth.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for SessionIn { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + self.handle.toTpm(buf)?; + buf.writeSizedByteBuf(&self.nonceCaller, 2); + buf.writeByte(self.attributes.into()); + buf.writeSizedByteBuf(&self.auth, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.handle.initFromTpm(buf)?; + self.nonceCaller = buf.readSizedByteBuf(2); + self.attributes = TPMA_SESSION(buf.readByte() as u8); + self.auth = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for SessionIn { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// Structure representing a session block in a response buffer [TSS] +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct SessionOut { + /// TPM nonce + pub nonceTpm: Vec, + + /// Session attributes + pub attributes: TPMA_SESSION, + + /// HMAC value + pub auth: Vec, +} + +impl SessionOut { + /// Creates a new instance with the specified values + pub fn new( + nonceTpm: &Vec, + attributes: TPMA_SESSION, + auth: &Vec, + ) -> Self { + Self { + nonceTpm: nonceTpm.clone(), + attributes: attributes.clone(), + auth: auth.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for SessionOut { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.nonceTpm, 2); + buf.writeByte(self.attributes.into()); + buf.writeSizedByteBuf(&self.auth, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.nonceTpm = buf.readSizedByteBuf(2); + self.attributes = TPMA_SESSION(buf.readByte() as u8); + self.auth = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for SessionOut { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// Command header [TSS] +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct CommandHeader { + /// Command tag (sessions, or no sessions) + pub Tag: TPM_ST, + + /// Total command buffer length + pub CommandSize: u32, + + /// Command code + pub CommandCode: TPM_CC, +} + +impl CommandHeader { + /// Creates a new instance with the specified values + pub fn new( + Tag: TPM_ST, + CommandSize: u32, + CommandCode: TPM_CC, + ) -> Self { + Self { + Tag: Tag.clone(), + CommandSize: CommandSize.clone(), + CommandCode: CommandCode.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for CommandHeader { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeShort(self.Tag.into()); + buf.writeInt(self.CommandSize as u32); + buf.writeInt(self.CommandCode.into()); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.Tag = TPM_ST(buf.readShort() as u16); + self.CommandSize = buf.readInt() as u32; + self.CommandCode = TPM_CC(buf.readInt() as u32); + Ok(()) + } + +} + +impl TpmMarshaller for CommandHeader { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// Contains the public and private part of a TPM key +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TSS_KEY { + /// Public part of key + pub publicPart: TPMT_PUBLIC, + + /// Private part is the encrypted sensitive part of key + pub privatePart: Vec, +} + +impl TSS_KEY { + /// Creates a new instance with the specified values + pub fn new( + publicPart: &TPMT_PUBLIC, + privatePart: &Vec, + ) -> Self { + Self { + publicPart: publicPart.clone(), + privatePart: privatePart.clone(), + ..Default::default() + } + } + +} + +impl TpmStructure for TSS_KEY { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + self.publicPart.toTpm(buf)?; + buf.writeSizedByteBuf(&self.privatePart, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.publicPart.initFromTpm(buf)?; + self.privatePart = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TSS_KEY { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// Auto-derived from TPM2B_DIGEST to provide unique GetUnionSelector() implementation +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2B_DIGEST_SYMCIPHER { + /// The buffer area that can be no larger than a digest + pub buffer: Vec, +} + +impl TPM2B_DIGEST_SYMCIPHER { + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::SYMCIPHER + } +} + +impl TpmStructure for TPM2B_DIGEST_SYMCIPHER { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.buffer, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.buffer = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2B_DIGEST_SYMCIPHER { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +/// Auto-derived from TPM2B_DIGEST +#[derive(Debug, Clone, Derivative)] +#[derivative(Default)] +pub struct TPM2B_DIGEST_KEYEDHASH { + /// The buffer area that can be no larger than a digest + pub buffer: Vec, +} + +impl TPM2B_DIGEST_KEYEDHASH { + fn GetUnionSelector() -> TPM_ALG_ID { + TPM_ALG_ID::KEYEDHASH + } +} + +impl TpmStructure for TPM2B_DIGEST_KEYEDHASH { + fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.createObj::()?; + Ok(()) + } + + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer) + } + + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeSizedByteBuf(&self.buffer, 2); + Ok(()) + } + + fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Deserialize fields + self.buffer = buf.readSizedByteBuf(2); + Ok(()) + } + +} + +impl TpmMarshaller for TPM2B_DIGEST_KEYEDHASH { + /// Serialize this structure to a TPM buffer + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.serialize(buffer) + } + + /// Deserialize this structure from a TPM buffer + fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.deserialize(buffer) + } + +} + +lazy_static::lazy_static! { + /// Maps enum type IDs to a map of values to string representations + pub static ref ENUM_TO_STR_MAP: HashMap> = { + let mut map = HashMap::new(); + let mut TPM_ALG_ID_map: HashMap = HashMap::new(); + TPM_ALG_ID_map.insert(0x0, "ERROR"); + TPM_ALG_ID_map.insert(0x1, "FIRST"); + TPM_ALG_ID_map.insert(0x1, "RSA"); + TPM_ALG_ID_map.insert(0x3, "TDES"); + TPM_ALG_ID_map.insert(0x4, "SHA"); + TPM_ALG_ID_map.insert(0x4, "SHA1"); + TPM_ALG_ID_map.insert(0x5, "HMAC"); + TPM_ALG_ID_map.insert(0x6, "AES"); + TPM_ALG_ID_map.insert(0x7, "MGF1"); + TPM_ALG_ID_map.insert(0x8, "KEYEDHASH"); + TPM_ALG_ID_map.insert(0xA, "XOR"); + TPM_ALG_ID_map.insert(0xB, "SHA256"); + TPM_ALG_ID_map.insert(0xC, "SHA384"); + TPM_ALG_ID_map.insert(0xD, "SHA512"); + TPM_ALG_ID_map.insert(0x10, "NULL"); + TPM_ALG_ID_map.insert(0x12, "SM3_256"); + TPM_ALG_ID_map.insert(0x13, "SM4"); + TPM_ALG_ID_map.insert(0x14, "RSASSA"); + TPM_ALG_ID_map.insert(0x15, "RSAES"); + TPM_ALG_ID_map.insert(0x16, "RSAPSS"); + TPM_ALG_ID_map.insert(0x17, "OAEP"); + TPM_ALG_ID_map.insert(0x18, "ECDSA"); + TPM_ALG_ID_map.insert(0x19, "ECDH"); + TPM_ALG_ID_map.insert(0x1A, "ECDAA"); + TPM_ALG_ID_map.insert(0x1B, "SM2"); + TPM_ALG_ID_map.insert(0x1C, "ECSCHNORR"); + TPM_ALG_ID_map.insert(0x1D, "ECMQV"); + TPM_ALG_ID_map.insert(0x20, "KDF1_SP800_56A"); + TPM_ALG_ID_map.insert(0x21, "KDF2"); + TPM_ALG_ID_map.insert(0x22, "KDF1_SP800_108"); + TPM_ALG_ID_map.insert(0x23, "ECC"); + TPM_ALG_ID_map.insert(0x25, "SYMCIPHER"); + TPM_ALG_ID_map.insert(0x26, "CAMELLIA"); + TPM_ALG_ID_map.insert(0x27, "SHA3_256"); + TPM_ALG_ID_map.insert(0x28, "SHA3_384"); + TPM_ALG_ID_map.insert(0x29, "SHA3_512"); + TPM_ALG_ID_map.insert(0x3F, "CMAC"); + TPM_ALG_ID_map.insert(0x40, "CTR"); + TPM_ALG_ID_map.insert(0x41, "OFB"); + TPM_ALG_ID_map.insert(0x42, "CBC"); + TPM_ALG_ID_map.insert(0x43, "CFB"); + TPM_ALG_ID_map.insert(0x44, "ECB"); + TPM_ALG_ID_map.insert(0x44, "LAST"); + TPM_ALG_ID_map.insert(0x7FFF, "ANY"); + TPM_ALG_ID_map.insert(0x7FFE, "ANY2"); + map.insert(std::any::TypeId::of::(), TPM_ALG_ID_map); + + let mut TPM_ECC_CURVE_map: HashMap = HashMap::new(); + TPM_ECC_CURVE_map.insert(0x0, "NONE"); + TPM_ECC_CURVE_map.insert(0x1, "NIST_P192"); + TPM_ECC_CURVE_map.insert(0x2, "NIST_P224"); + TPM_ECC_CURVE_map.insert(0x3, "NIST_P256"); + TPM_ECC_CURVE_map.insert(0x4, "NIST_P384"); + TPM_ECC_CURVE_map.insert(0x5, "NIST_P521"); + TPM_ECC_CURVE_map.insert(0x10, "BN_P256"); + TPM_ECC_CURVE_map.insert(0x11, "BN_P638"); + TPM_ECC_CURVE_map.insert(0x20, "SM2_P256"); + TPM_ECC_CURVE_map.insert(0x21, "TEST_P192"); + map.insert(std::any::TypeId::of::(), TPM_ECC_CURVE_map); + + let mut SHA1_map: HashMap = HashMap::new(); + SHA1_map.insert(0x14, "DIGEST_SIZE"); + SHA1_map.insert(0x40, "BLOCK_SIZE"); + map.insert(std::any::TypeId::of::(), SHA1_map); + + let mut SHA256_map: HashMap = HashMap::new(); + SHA256_map.insert(0x20, "DIGEST_SIZE"); + SHA256_map.insert(0x40, "BLOCK_SIZE"); + map.insert(std::any::TypeId::of::(), SHA256_map); + + let mut SHA384_map: HashMap = HashMap::new(); + SHA384_map.insert(0x30, "DIGEST_SIZE"); + SHA384_map.insert(0x80, "BLOCK_SIZE"); + map.insert(std::any::TypeId::of::(), SHA384_map); + + let mut SHA512_map: HashMap = HashMap::new(); + SHA512_map.insert(0x40, "DIGEST_SIZE"); + SHA512_map.insert(0x80, "BLOCK_SIZE"); + map.insert(std::any::TypeId::of::(), SHA512_map); + + let mut SM3_256_map: HashMap = HashMap::new(); + SM3_256_map.insert(0x20, "DIGEST_SIZE"); + SM3_256_map.insert(0x40, "BLOCK_SIZE"); + map.insert(std::any::TypeId::of::(), SM3_256_map); + + let mut SHA3_256_map: HashMap = HashMap::new(); + SHA3_256_map.insert(0x20, "DIGEST_SIZE"); + SHA3_256_map.insert(0x88, "BLOCK_SIZE"); + map.insert(std::any::TypeId::of::(), SHA3_256_map); + + let mut SHA3_384_map: HashMap = HashMap::new(); + SHA3_384_map.insert(0x30, "DIGEST_SIZE"); + SHA3_384_map.insert(0x68, "BLOCK_SIZE"); + map.insert(std::any::TypeId::of::(), SHA3_384_map); + + let mut SHA3_512_map: HashMap = HashMap::new(); + SHA3_512_map.insert(0x40, "DIGEST_SIZE"); + SHA3_512_map.insert(0x48, "BLOCK_SIZE"); + map.insert(std::any::TypeId::of::(), SHA3_512_map); + + let mut Logic_map: HashMap = HashMap::new(); + Logic_map.insert(0x1, "TRUE"); + Logic_map.insert(0x0, "FALSE"); + Logic_map.insert(0x1, "YES"); + Logic_map.insert(0x0, "NO"); + Logic_map.insert(0x1, "SET"); + Logic_map.insert(0x0, "CLEAR"); + map.insert(std::any::TypeId::of::(), Logic_map); + + let mut TPM_SPEC_map: HashMap = HashMap::new(); + TPM_SPEC_map.insert(0x322E3000, "FAMILY"); + TPM_SPEC_map.insert(0x0, "LEVEL"); + TPM_SPEC_map.insert(0xA2, "VERSION"); + TPM_SPEC_map.insert(0x7E3, "YEAR"); + TPM_SPEC_map.insert(0x168, "DAY_OF_YEAR"); + map.insert(std::any::TypeId::of::(), TPM_SPEC_map); + + let mut TPM_GENERATED_map: HashMap = HashMap::new(); + TPM_GENERATED_map.insert(0xFF544347, "VALUE"); + map.insert(std::any::TypeId::of::(), TPM_GENERATED_map); + + let mut TPM_CC_map: HashMap = HashMap::new(); + TPM_CC_map.insert(0x11F, "FIRST"); + TPM_CC_map.insert(0x11F, "NV_UndefineSpaceSpecial"); + TPM_CC_map.insert(0x120, "EvictControl"); + TPM_CC_map.insert(0x121, "HierarchyControl"); + TPM_CC_map.insert(0x122, "NV_UndefineSpace"); + TPM_CC_map.insert(0x124, "ChangeEPS"); + TPM_CC_map.insert(0x125, "ChangePPS"); + TPM_CC_map.insert(0x126, "Clear"); + TPM_CC_map.insert(0x127, "ClearControl"); + TPM_CC_map.insert(0x128, "ClockSet"); + TPM_CC_map.insert(0x129, "HierarchyChangeAuth"); + TPM_CC_map.insert(0x12A, "NV_DefineSpace"); + TPM_CC_map.insert(0x12B, "PCR_Allocate"); + TPM_CC_map.insert(0x12C, "PCR_SetAuthPolicy"); + TPM_CC_map.insert(0x12D, "PP_Commands"); + TPM_CC_map.insert(0x12E, "SetPrimaryPolicy"); + TPM_CC_map.insert(0x12F, "FieldUpgradeStart"); + TPM_CC_map.insert(0x130, "ClockRateAdjust"); + TPM_CC_map.insert(0x131, "CreatePrimary"); + TPM_CC_map.insert(0x132, "NV_GlobalWriteLock"); + TPM_CC_map.insert(0x133, "GetCommandAuditDigest"); + TPM_CC_map.insert(0x134, "NV_Increment"); + TPM_CC_map.insert(0x135, "NV_SetBits"); + TPM_CC_map.insert(0x136, "NV_Extend"); + TPM_CC_map.insert(0x137, "NV_Write"); + TPM_CC_map.insert(0x138, "NV_WriteLock"); + TPM_CC_map.insert(0x139, "DictionaryAttackLockReset"); + TPM_CC_map.insert(0x13A, "DictionaryAttackParameters"); + TPM_CC_map.insert(0x13B, "NV_ChangeAuth"); + TPM_CC_map.insert(0x13C, "PCR_Event"); + TPM_CC_map.insert(0x13D, "PCR_Reset"); + TPM_CC_map.insert(0x13E, "SequenceComplete"); + TPM_CC_map.insert(0x13F, "SetAlgorithmSet"); + TPM_CC_map.insert(0x140, "SetCommandCodeAuditStatus"); + TPM_CC_map.insert(0x141, "FieldUpgradeData"); + TPM_CC_map.insert(0x142, "IncrementalSelfTest"); + TPM_CC_map.insert(0x143, "SelfTest"); + TPM_CC_map.insert(0x144, "Startup"); + TPM_CC_map.insert(0x145, "Shutdown"); + TPM_CC_map.insert(0x146, "StirRandom"); + TPM_CC_map.insert(0x147, "ActivateCredential"); + TPM_CC_map.insert(0x148, "Certify"); + TPM_CC_map.insert(0x149, "PolicyNV"); + TPM_CC_map.insert(0x14A, "CertifyCreation"); + TPM_CC_map.insert(0x14B, "Duplicate"); + TPM_CC_map.insert(0x14C, "GetTime"); + TPM_CC_map.insert(0x14D, "GetSessionAuditDigest"); + TPM_CC_map.insert(0x14E, "NV_Read"); + TPM_CC_map.insert(0x14F, "NV_ReadLock"); + TPM_CC_map.insert(0x150, "ObjectChangeAuth"); + TPM_CC_map.insert(0x151, "PolicySecret"); + TPM_CC_map.insert(0x152, "Rewrap"); + TPM_CC_map.insert(0x153, "Create"); + TPM_CC_map.insert(0x154, "ECDH_ZGen"); + TPM_CC_map.insert(0x155, "HMAC"); + TPM_CC_map.insert(0x155, "MAC"); + TPM_CC_map.insert(0x156, "Import"); + TPM_CC_map.insert(0x157, "Load"); + TPM_CC_map.insert(0x158, "Quote"); + TPM_CC_map.insert(0x159, "RSA_Decrypt"); + TPM_CC_map.insert(0x15B, "HMAC_Start"); + TPM_CC_map.insert(0x15B, "MAC_Start"); + TPM_CC_map.insert(0x15C, "SequenceUpdate"); + TPM_CC_map.insert(0x15D, "Sign"); + TPM_CC_map.insert(0x15E, "Unseal"); + TPM_CC_map.insert(0x160, "PolicySigned"); + TPM_CC_map.insert(0x161, "ContextLoad"); + TPM_CC_map.insert(0x162, "ContextSave"); + TPM_CC_map.insert(0x163, "ECDH_KeyGen"); + TPM_CC_map.insert(0x164, "EncryptDecrypt"); + TPM_CC_map.insert(0x165, "FlushContext"); + TPM_CC_map.insert(0x167, "LoadExternal"); + TPM_CC_map.insert(0x168, "MakeCredential"); + TPM_CC_map.insert(0x169, "NV_ReadPublic"); + TPM_CC_map.insert(0x16A, "PolicyAuthorize"); + TPM_CC_map.insert(0x16B, "PolicyAuthValue"); + TPM_CC_map.insert(0x16C, "PolicyCommandCode"); + TPM_CC_map.insert(0x16D, "PolicyCounterTimer"); + TPM_CC_map.insert(0x16E, "PolicyCpHash"); + TPM_CC_map.insert(0x16F, "PolicyLocality"); + TPM_CC_map.insert(0x170, "PolicyNameHash"); + TPM_CC_map.insert(0x171, "PolicyOR"); + TPM_CC_map.insert(0x172, "PolicyTicket"); + TPM_CC_map.insert(0x173, "ReadPublic"); + TPM_CC_map.insert(0x174, "RSA_Encrypt"); + TPM_CC_map.insert(0x176, "StartAuthSession"); + TPM_CC_map.insert(0x177, "VerifySignature"); + TPM_CC_map.insert(0x178, "ECC_Parameters"); + TPM_CC_map.insert(0x179, "FirmwareRead"); + TPM_CC_map.insert(0x17A, "GetCapability"); + TPM_CC_map.insert(0x17B, "GetRandom"); + TPM_CC_map.insert(0x17C, "GetTestResult"); + TPM_CC_map.insert(0x17D, "Hash"); + TPM_CC_map.insert(0x17E, "PCR_Read"); + TPM_CC_map.insert(0x17F, "PolicyPCR"); + TPM_CC_map.insert(0x180, "PolicyRestart"); + TPM_CC_map.insert(0x181, "ReadClock"); + TPM_CC_map.insert(0x182, "PCR_Extend"); + TPM_CC_map.insert(0x183, "PCR_SetAuthValue"); + TPM_CC_map.insert(0x184, "NV_Certify"); + TPM_CC_map.insert(0x185, "EventSequenceComplete"); + TPM_CC_map.insert(0x186, "HashSequenceStart"); + TPM_CC_map.insert(0x187, "PolicyPhysicalPresence"); + TPM_CC_map.insert(0x188, "PolicyDuplicationSelect"); + TPM_CC_map.insert(0x189, "PolicyGetDigest"); + TPM_CC_map.insert(0x18A, "TestParms"); + TPM_CC_map.insert(0x18B, "Commit"); + TPM_CC_map.insert(0x18C, "PolicyPassword"); + TPM_CC_map.insert(0x18D, "ZGen_2Phase"); + TPM_CC_map.insert(0x18E, "EC_Ephemeral"); + TPM_CC_map.insert(0x18F, "PolicyNvWritten"); + TPM_CC_map.insert(0x190, "PolicyTemplate"); + TPM_CC_map.insert(0x191, "CreateLoaded"); + TPM_CC_map.insert(0x192, "PolicyAuthorizeNV"); + TPM_CC_map.insert(0x193, "EncryptDecrypt2"); + TPM_CC_map.insert(0x194, "AC_GetCapability"); + TPM_CC_map.insert(0x195, "AC_Send"); + TPM_CC_map.insert(0x196, "Policy_AC_SendSelect"); + TPM_CC_map.insert(0x197, "CertifyX509"); + TPM_CC_map.insert(0x198, "ACT_SetTimeout"); + TPM_CC_map.insert(0x199, "ECC_Encrypt"); + TPM_CC_map.insert(0x19A, "ECC_Decrypt"); + TPM_CC_map.insert(0x19A, "LAST"); + TPM_CC_map.insert(0x20000000, "CC_VEND"); + TPM_CC_map.insert(0x20000000, "Vendor_TCG_Test"); + map.insert(std::any::TypeId::of::(), TPM_CC_map); + + let mut ImplementationConstants_map: HashMap = HashMap::new(); + ImplementationConstants_map.insert(0x1, "Ossl"); + ImplementationConstants_map.insert(0x2, "Ltc"); + ImplementationConstants_map.insert(0x3, "Msbn"); + ImplementationConstants_map.insert(0x4, "Symcrypt"); + ImplementationConstants_map.insert(0x3, "HASH_COUNT"); + ImplementationConstants_map.insert(0x100, "MAX_SYM_KEY_BITS"); + ImplementationConstants_map.insert(0x20, "MAX_SYM_KEY_BYTES"); + ImplementationConstants_map.insert(0x10, "MAX_SYM_BLOCK_SIZE"); + ImplementationConstants_map.insert(0x19A, "MAX_CAP_CC"); + ImplementationConstants_map.insert(0x100, "MAX_RSA_KEY_BYTES"); + ImplementationConstants_map.insert(0x20, "MAX_AES_KEY_BYTES"); + ImplementationConstants_map.insert(0x30, "MAX_ECC_KEY_BYTES"); + ImplementationConstants_map.insert(0x20, "LABEL_MAX_BUFFER"); + ImplementationConstants_map.insert(0x4, "_TPM_CAP_SIZE"); + ImplementationConstants_map.insert(0x3F8, "MAX_CAP_DATA"); + ImplementationConstants_map.insert(0xA9, "MAX_CAP_ALGS"); + ImplementationConstants_map.insert(0xFE, "MAX_CAP_HANDLES"); + ImplementationConstants_map.insert(0x7F, "MAX_TPM_PROPERTIES"); + ImplementationConstants_map.insert(0xCB, "MAX_PCR_PROPERTIES"); + ImplementationConstants_map.insert(0x1FC, "MAX_ECC_CURVES"); + ImplementationConstants_map.insert(0xE, "MAX_TAGGED_POLICIES"); + ImplementationConstants_map.insert(0x7F, "MAX_AC_CAPABILITIES"); + ImplementationConstants_map.insert(0x54, "MAX_ACT_DATA"); + map.insert(std::any::TypeId::of::(), ImplementationConstants_map); + + let mut TPM_RC_map: HashMap = HashMap::new(); + TPM_RC_map.insert(0x0, "SUCCESS"); + TPM_RC_map.insert(0x1E, "BAD_TAG"); + TPM_RC_map.insert(0x100, "RC_VER1"); + TPM_RC_map.insert(0x100, "INITIALIZE"); + TPM_RC_map.insert(0x101, "FAILURE"); + TPM_RC_map.insert(0x103, "SEQUENCE"); + TPM_RC_map.insert(0x10B, "PRIVATE"); + TPM_RC_map.insert(0x119, "HMAC"); + TPM_RC_map.insert(0x120, "DISABLED"); + TPM_RC_map.insert(0x121, "EXCLUSIVE"); + TPM_RC_map.insert(0x124, "AUTH_TYPE"); + TPM_RC_map.insert(0x125, "AUTH_MISSING"); + TPM_RC_map.insert(0x126, "POLICY"); + TPM_RC_map.insert(0x127, "PCR"); + TPM_RC_map.insert(0x128, "PCR_CHANGED"); + TPM_RC_map.insert(0x12D, "UPGRADE"); + TPM_RC_map.insert(0x12E, "TOO_MANY_CONTEXTS"); + TPM_RC_map.insert(0x12F, "AUTH_UNAVAILABLE"); + TPM_RC_map.insert(0x130, "REBOOT"); + TPM_RC_map.insert(0x131, "UNBALANCED"); + TPM_RC_map.insert(0x142, "COMMAND_SIZE"); + TPM_RC_map.insert(0x143, "COMMAND_CODE"); + TPM_RC_map.insert(0x144, "AUTHSIZE"); + TPM_RC_map.insert(0x145, "AUTH_CONTEXT"); + TPM_RC_map.insert(0x146, "NV_RANGE"); + TPM_RC_map.insert(0x147, "NV_SIZE"); + TPM_RC_map.insert(0x148, "NV_LOCKED"); + TPM_RC_map.insert(0x149, "NV_AUTHORIZATION"); + TPM_RC_map.insert(0x14A, "NV_UNINITIALIZED"); + TPM_RC_map.insert(0x14B, "NV_SPACE"); + TPM_RC_map.insert(0x14C, "NV_DEFINED"); + TPM_RC_map.insert(0x150, "BAD_CONTEXT"); + TPM_RC_map.insert(0x151, "CPHASH"); + TPM_RC_map.insert(0x152, "PARENT"); + TPM_RC_map.insert(0x153, "NEEDS_TEST"); + TPM_RC_map.insert(0x154, "NO_RESULT"); + TPM_RC_map.insert(0x155, "SENSITIVE"); + TPM_RC_map.insert(0x17F, "RC_MAX_FM0"); + TPM_RC_map.insert(0x80, "RC_FMT1"); + TPM_RC_map.insert(0x81, "ASYMMETRIC"); + TPM_RC_map.insert(0x82, "ATTRIBUTES"); + TPM_RC_map.insert(0x83, "HASH"); + TPM_RC_map.insert(0x84, "VALUE"); + TPM_RC_map.insert(0x85, "HIERARCHY"); + TPM_RC_map.insert(0x87, "KEY_SIZE"); + TPM_RC_map.insert(0x88, "MGF"); + TPM_RC_map.insert(0x89, "MODE"); + TPM_RC_map.insert(0x8A, "TYPE"); + TPM_RC_map.insert(0x8B, "HANDLE"); + TPM_RC_map.insert(0x8C, "KDF"); + TPM_RC_map.insert(0x8D, "RANGE"); + TPM_RC_map.insert(0x8E, "AUTH_FAIL"); + TPM_RC_map.insert(0x8F, "NONCE"); + TPM_RC_map.insert(0x90, "PP"); + TPM_RC_map.insert(0x92, "SCHEME"); + TPM_RC_map.insert(0x95, "SIZE"); + TPM_RC_map.insert(0x96, "SYMMETRIC"); + TPM_RC_map.insert(0x97, "TAG"); + TPM_RC_map.insert(0x98, "SELECTOR"); + TPM_RC_map.insert(0x9A, "INSUFFICIENT"); + TPM_RC_map.insert(0x9B, "SIGNATURE"); + TPM_RC_map.insert(0x9C, "KEY"); + TPM_RC_map.insert(0x9D, "POLICY_FAIL"); + TPM_RC_map.insert(0x9F, "INTEGRITY"); + TPM_RC_map.insert(0xA0, "TICKET"); + TPM_RC_map.insert(0xA1, "RESERVED_BITS"); + TPM_RC_map.insert(0xA2, "BAD_AUTH"); + TPM_RC_map.insert(0xA3, "EXPIRED"); + TPM_RC_map.insert(0xA4, "POLICY_CC"); + TPM_RC_map.insert(0xA5, "BINDING"); + TPM_RC_map.insert(0xA6, "CURVE"); + TPM_RC_map.insert(0xA7, "ECC_POINT"); + TPM_RC_map.insert(0x900, "RC_WARN"); + TPM_RC_map.insert(0x901, "CONTEXT_GAP"); + TPM_RC_map.insert(0x902, "OBJECT_MEMORY"); + TPM_RC_map.insert(0x903, "SESSION_MEMORY"); + TPM_RC_map.insert(0x904, "MEMORY"); + TPM_RC_map.insert(0x905, "SESSION_HANDLES"); + TPM_RC_map.insert(0x906, "OBJECT_HANDLES"); + TPM_RC_map.insert(0x907, "LOCALITY"); + TPM_RC_map.insert(0x908, "YIELDED"); + TPM_RC_map.insert(0x909, "CANCELED"); + TPM_RC_map.insert(0x90A, "TESTING"); + TPM_RC_map.insert(0x910, "REFERENCE_H0"); + TPM_RC_map.insert(0x911, "REFERENCE_H1"); + TPM_RC_map.insert(0x912, "REFERENCE_H2"); + TPM_RC_map.insert(0x913, "REFERENCE_H3"); + TPM_RC_map.insert(0x914, "REFERENCE_H4"); + TPM_RC_map.insert(0x915, "REFERENCE_H5"); + TPM_RC_map.insert(0x916, "REFERENCE_H6"); + TPM_RC_map.insert(0x918, "REFERENCE_S0"); + TPM_RC_map.insert(0x919, "REFERENCE_S1"); + TPM_RC_map.insert(0x91A, "REFERENCE_S2"); + TPM_RC_map.insert(0x91B, "REFERENCE_S3"); + TPM_RC_map.insert(0x91C, "REFERENCE_S4"); + TPM_RC_map.insert(0x91D, "REFERENCE_S5"); + TPM_RC_map.insert(0x91E, "REFERENCE_S6"); + TPM_RC_map.insert(0x920, "NV_RATE"); + TPM_RC_map.insert(0x921, "LOCKOUT"); + TPM_RC_map.insert(0x922, "RETRY"); + TPM_RC_map.insert(0x923, "NV_UNAVAILABLE"); + TPM_RC_map.insert(0x97F, "NOT_USED"); + TPM_RC_map.insert(0x0, "H"); + TPM_RC_map.insert(0x40, "P"); + TPM_RC_map.insert(0x800, "S"); + TPM_RC_map.insert(0x100, "_1"); + TPM_RC_map.insert(0x200, "_2"); + TPM_RC_map.insert(0x300, "_3"); + TPM_RC_map.insert(0x400, "_4"); + TPM_RC_map.insert(0x500, "_5"); + TPM_RC_map.insert(0x600, "_6"); + TPM_RC_map.insert(0x700, "_7"); + TPM_RC_map.insert(0x800, "_8"); + TPM_RC_map.insert(0x900, "_9"); + TPM_RC_map.insert(0xA00, "A"); + TPM_RC_map.insert(0xB00, "B"); + TPM_RC_map.insert(0xC00, "C"); + TPM_RC_map.insert(0xD00, "D"); + TPM_RC_map.insert(0xE00, "E"); + TPM_RC_map.insert(0xF00, "F"); + TPM_RC_map.insert(0xF00, "N_MASK"); + TPM_RC_map.insert(0x40280001, "TSS_TCP_BAD_HANDSHAKE_RESP"); + TPM_RC_map.insert(0x40280002, "TSS_TCP_SERVER_TOO_OLD"); + TPM_RC_map.insert(0x40280003, "TSS_TCP_BAD_ACK"); + TPM_RC_map.insert(0x40280004, "TSS_TCP_BAD_RESP_LEN"); + TPM_RC_map.insert(0x40280005, "TSS_TCP_UNEXPECTED_STARTUP_RESP"); + TPM_RC_map.insert(0x40280006, "TSS_TCP_INVALID_SIZE_TAG"); + TPM_RC_map.insert(0x40280007, "TSS_TCP_DISCONNECTED"); + TPM_RC_map.insert(0x40280010, "TSS_DISPATCH_FAILED"); + TPM_RC_map.insert(0x40280011, "TSS_SEND_OP_FAILED"); + TPM_RC_map.insert(0x40280021, "TSS_RESP_BUF_TOO_SHORT"); + TPM_RC_map.insert(0x40280022, "TSS_RESP_BUF_INVALID_SESSION_TAG"); + TPM_RC_map.insert(0x40280023, "TSS_RESP_BUF_INVALID_SIZE"); + TPM_RC_map.insert(0x80280400, "TBS_COMMAND_BLOCKED"); + TPM_RC_map.insert(0x80280401, "TBS_INVALID_HANDLE"); + TPM_RC_map.insert(0x80280402, "TBS_DUPLICATE_V_HANDLE"); + TPM_RC_map.insert(0x80280403, "TBS_EMBEDDED_COMMAND_BLOCKED"); + TPM_RC_map.insert(0x80280404, "TBS_EMBEDDED_COMMAND_UNSUPPORTED"); + TPM_RC_map.insert(0x80284000, "TBS_UNKNOWN_ERROR"); + TPM_RC_map.insert(0x80284001, "TBS_INTERNAL_ERROR"); + TPM_RC_map.insert(0x80284002, "TBS_BAD_PARAMETER"); + TPM_RC_map.insert(0x80284003, "TBS_INVALID_OUTPUT_POINTER"); + TPM_RC_map.insert(0x80284004, "TBS_INVALID_CONTEXT"); + TPM_RC_map.insert(0x80284005, "TBS_INSUFFICIENT_BUFFER"); + TPM_RC_map.insert(0x80284006, "TBS_IO_ERROR"); + TPM_RC_map.insert(0x80284007, "TBS_INVALID_CONTEXT_PARAM"); + TPM_RC_map.insert(0x80284008, "TBS_SERVICE_NOT_RUNNING"); + TPM_RC_map.insert(0x80284009, "TBS_TOO_MANY_CONTEXTS"); + TPM_RC_map.insert(0x8028400A, "TBS_TOO_MANY_RESOURCES"); + TPM_RC_map.insert(0x8028400B, "TBS_SERVICE_START_PENDING"); + TPM_RC_map.insert(0x8028400C, "TBS_PPI_NOT_SUPPORTED"); + TPM_RC_map.insert(0x8028400D, "TBS_COMMAND_CANCELED"); + TPM_RC_map.insert(0x8028400E, "TBS_BUFFER_TOO_LARGE"); + TPM_RC_map.insert(0x8028400F, "TBS_TPM_NOT_FOUND"); + TPM_RC_map.insert(0x80284010, "TBS_SERVICE_DISABLED"); + TPM_RC_map.insert(0x80284012, "TBS_ACCESS_DENIED"); + TPM_RC_map.insert(0x80284014, "TBS_PPI_FUNCTION_NOT_SUPPORTED"); + TPM_RC_map.insert(0x80284015, "TBS_OWNER_AUTH_NOT_FOUND"); + map.insert(std::any::TypeId::of::(), TPM_RC_map); + + let mut TPM_CLOCK_ADJUST_map: HashMap = HashMap::new(); + TPM_CLOCK_ADJUST_map.insert(0xFFFFFFFD, "COARSE_SLOWER"); + TPM_CLOCK_ADJUST_map.insert(0xFFFFFFFE, "MEDIUM_SLOWER"); + TPM_CLOCK_ADJUST_map.insert(0xFFFFFFFF, "FINE_SLOWER"); + TPM_CLOCK_ADJUST_map.insert(0x0, "NO_CHANGE"); + TPM_CLOCK_ADJUST_map.insert(0x1, "FINE_FASTER"); + TPM_CLOCK_ADJUST_map.insert(0x2, "MEDIUM_FASTER"); + TPM_CLOCK_ADJUST_map.insert(0x3, "COARSE_FASTER"); + map.insert(std::any::TypeId::of::(), TPM_CLOCK_ADJUST_map); + + let mut TPM_EO_map: HashMap = HashMap::new(); + TPM_EO_map.insert(0x0, "EQ"); + TPM_EO_map.insert(0x1, "NEQ"); + TPM_EO_map.insert(0x2, "SIGNED_GT"); + TPM_EO_map.insert(0x3, "UNSIGNED_GT"); + TPM_EO_map.insert(0x4, "SIGNED_LT"); + TPM_EO_map.insert(0x5, "UNSIGNED_LT"); + TPM_EO_map.insert(0x6, "SIGNED_GE"); + TPM_EO_map.insert(0x7, "UNSIGNED_GE"); + TPM_EO_map.insert(0x8, "SIGNED_LE"); + TPM_EO_map.insert(0x9, "UNSIGNED_LE"); + TPM_EO_map.insert(0xA, "BITSET"); + TPM_EO_map.insert(0xB, "BITCLEAR"); + map.insert(std::any::TypeId::of::(), TPM_EO_map); + + let mut TPM_ST_map: HashMap = HashMap::new(); + TPM_ST_map.insert(0xC4, "RSP_COMMAND"); + TPM_ST_map.insert(0x8000, "NULL"); + TPM_ST_map.insert(0x8001, "NO_SESSIONS"); + TPM_ST_map.insert(0x8002, "SESSIONS"); + TPM_ST_map.insert(0x8014, "ATTEST_NV"); + TPM_ST_map.insert(0x8015, "ATTEST_COMMAND_AUDIT"); + TPM_ST_map.insert(0x8016, "ATTEST_SESSION_AUDIT"); + TPM_ST_map.insert(0x8017, "ATTEST_CERTIFY"); + TPM_ST_map.insert(0x8018, "ATTEST_QUOTE"); + TPM_ST_map.insert(0x8019, "ATTEST_TIME"); + TPM_ST_map.insert(0x801A, "ATTEST_CREATION"); + TPM_ST_map.insert(0x801C, "ATTEST_NV_DIGEST"); + TPM_ST_map.insert(0x8021, "CREATION"); + TPM_ST_map.insert(0x8022, "VERIFIED"); + TPM_ST_map.insert(0x8023, "AUTH_SECRET"); + TPM_ST_map.insert(0x8024, "HASHCHECK"); + TPM_ST_map.insert(0x8025, "AUTH_SIGNED"); + TPM_ST_map.insert(0x8029, "FU_MANIFEST"); + map.insert(std::any::TypeId::of::(), TPM_ST_map); + + let mut TPM_SU_map: HashMap = HashMap::new(); + TPM_SU_map.insert(0x0, "CLEAR"); + TPM_SU_map.insert(0x1, "STATE"); + map.insert(std::any::TypeId::of::(), TPM_SU_map); + + let mut TPM_SE_map: HashMap = HashMap::new(); + TPM_SE_map.insert(0x0, "HMAC"); + TPM_SE_map.insert(0x1, "POLICY"); + TPM_SE_map.insert(0x3, "TRIAL"); + map.insert(std::any::TypeId::of::(), TPM_SE_map); + + let mut TPM_CAP_map: HashMap = HashMap::new(); + TPM_CAP_map.insert(0x0, "FIRST"); + TPM_CAP_map.insert(0x0, "ALGS"); + TPM_CAP_map.insert(0x1, "HANDLES"); + TPM_CAP_map.insert(0x2, "COMMANDS"); + TPM_CAP_map.insert(0x3, "PP_COMMANDS"); + TPM_CAP_map.insert(0x4, "AUDIT_COMMANDS"); + TPM_CAP_map.insert(0x5, "PCRS"); + TPM_CAP_map.insert(0x6, "TPM_PROPERTIES"); + TPM_CAP_map.insert(0x7, "PCR_PROPERTIES"); + TPM_CAP_map.insert(0x8, "ECC_CURVES"); + TPM_CAP_map.insert(0x9, "AUTH_POLICIES"); + TPM_CAP_map.insert(0xA, "ACT"); + TPM_CAP_map.insert(0xA, "LAST"); + TPM_CAP_map.insert(0x100, "VENDOR_PROPERTY"); + map.insert(std::any::TypeId::of::(), TPM_CAP_map); + + let mut TPM_PT_map: HashMap = HashMap::new(); + TPM_PT_map.insert(0x0, "NONE"); + TPM_PT_map.insert(0x100, "PT_GROUP"); + TPM_PT_map.insert(0x100, "PT_FIXED"); + TPM_PT_map.insert(0x100, "FAMILY_INDICATOR"); + TPM_PT_map.insert(0x101, "LEVEL"); + TPM_PT_map.insert(0x102, "REVISION"); + TPM_PT_map.insert(0x103, "DAY_OF_YEAR"); + TPM_PT_map.insert(0x104, "YEAR"); + TPM_PT_map.insert(0x105, "MANUFACTURER"); + TPM_PT_map.insert(0x106, "VENDOR_STRING_1"); + TPM_PT_map.insert(0x107, "VENDOR_STRING_2"); + TPM_PT_map.insert(0x108, "VENDOR_STRING_3"); + TPM_PT_map.insert(0x109, "VENDOR_STRING_4"); + TPM_PT_map.insert(0x10A, "VENDOR_TPM_TYPE"); + TPM_PT_map.insert(0x10B, "FIRMWARE_VERSION_1"); + TPM_PT_map.insert(0x10C, "FIRMWARE_VERSION_2"); + TPM_PT_map.insert(0x10D, "INPUT_BUFFER"); + TPM_PT_map.insert(0x10E, "HR_TRANSIENT_MIN"); + TPM_PT_map.insert(0x10F, "HR_PERSISTENT_MIN"); + TPM_PT_map.insert(0x110, "HR_LOADED_MIN"); + TPM_PT_map.insert(0x111, "ACTIVE_SESSIONS_MAX"); + TPM_PT_map.insert(0x112, "PCR_COUNT"); + TPM_PT_map.insert(0x113, "PCR_SELECT_MIN"); + TPM_PT_map.insert(0x114, "CONTEXT_GAP_MAX"); + TPM_PT_map.insert(0x116, "NV_COUNTERS_MAX"); + TPM_PT_map.insert(0x117, "NV_INDEX_MAX"); + TPM_PT_map.insert(0x118, "MEMORY"); + TPM_PT_map.insert(0x119, "CLOCK_UPDATE"); + TPM_PT_map.insert(0x11A, "CONTEXT_HASH"); + TPM_PT_map.insert(0x11B, "CONTEXT_SYM"); + TPM_PT_map.insert(0x11C, "CONTEXT_SYM_SIZE"); + TPM_PT_map.insert(0x11D, "ORDERLY_COUNT"); + TPM_PT_map.insert(0x11E, "MAX_COMMAND_SIZE"); + TPM_PT_map.insert(0x11F, "MAX_RESPONSE_SIZE"); + TPM_PT_map.insert(0x120, "MAX_DIGEST"); + TPM_PT_map.insert(0x121, "MAX_OBJECT_CONTEXT"); + TPM_PT_map.insert(0x122, "MAX_SESSION_CONTEXT"); + TPM_PT_map.insert(0x123, "PS_FAMILY_INDICATOR"); + TPM_PT_map.insert(0x124, "PS_LEVEL"); + TPM_PT_map.insert(0x125, "PS_REVISION"); + TPM_PT_map.insert(0x126, "PS_DAY_OF_YEAR"); + TPM_PT_map.insert(0x127, "PS_YEAR"); + TPM_PT_map.insert(0x128, "SPLIT_MAX"); + TPM_PT_map.insert(0x129, "TOTAL_COMMANDS"); + TPM_PT_map.insert(0x12A, "LIBRARY_COMMANDS"); + TPM_PT_map.insert(0x12B, "VENDOR_COMMANDS"); + TPM_PT_map.insert(0x12C, "NV_BUFFER_MAX"); + TPM_PT_map.insert(0x12D, "MODES"); + TPM_PT_map.insert(0x12E, "MAX_CAP_BUFFER"); + TPM_PT_map.insert(0x200, "PT_VAR"); + TPM_PT_map.insert(0x200, "PERMANENT"); + TPM_PT_map.insert(0x201, "STARTUP_CLEAR"); + TPM_PT_map.insert(0x202, "HR_NV_INDEX"); + TPM_PT_map.insert(0x203, "HR_LOADED"); + TPM_PT_map.insert(0x204, "HR_LOADED_AVAIL"); + TPM_PT_map.insert(0x205, "HR_ACTIVE"); + TPM_PT_map.insert(0x206, "HR_ACTIVE_AVAIL"); + TPM_PT_map.insert(0x207, "HR_TRANSIENT_AVAIL"); + TPM_PT_map.insert(0x208, "HR_PERSISTENT"); + TPM_PT_map.insert(0x209, "HR_PERSISTENT_AVAIL"); + TPM_PT_map.insert(0x20A, "NV_COUNTERS"); + TPM_PT_map.insert(0x20B, "NV_COUNTERS_AVAIL"); + TPM_PT_map.insert(0x20C, "ALGORITHM_SET"); + TPM_PT_map.insert(0x20D, "LOADED_CURVES"); + TPM_PT_map.insert(0x20E, "LOCKOUT_COUNTER"); + TPM_PT_map.insert(0x20F, "MAX_AUTH_FAIL"); + TPM_PT_map.insert(0x210, "LOCKOUT_INTERVAL"); + TPM_PT_map.insert(0x211, "LOCKOUT_RECOVERY"); + TPM_PT_map.insert(0x212, "NV_WRITE_RECOVERY"); + TPM_PT_map.insert(0x213, "AUDIT_COUNTER_0"); + TPM_PT_map.insert(0x214, "AUDIT_COUNTER_1"); + map.insert(std::any::TypeId::of::(), TPM_PT_map); + + let mut TPM_PT_PCR_map: HashMap = HashMap::new(); + TPM_PT_PCR_map.insert(0x0, "FIRST"); + TPM_PT_PCR_map.insert(0x0, "SAVE"); + TPM_PT_PCR_map.insert(0x1, "EXTEND_L0"); + TPM_PT_PCR_map.insert(0x2, "RESET_L0"); + TPM_PT_PCR_map.insert(0x3, "EXTEND_L1"); + TPM_PT_PCR_map.insert(0x4, "RESET_L1"); + TPM_PT_PCR_map.insert(0x5, "EXTEND_L2"); + TPM_PT_PCR_map.insert(0x6, "RESET_L2"); + TPM_PT_PCR_map.insert(0x7, "EXTEND_L3"); + TPM_PT_PCR_map.insert(0x8, "RESET_L3"); + TPM_PT_PCR_map.insert(0x9, "EXTEND_L4"); + TPM_PT_PCR_map.insert(0xA, "RESET_L4"); + TPM_PT_PCR_map.insert(0x11, "NO_INCREMENT"); + TPM_PT_PCR_map.insert(0x12, "DRTM_RESET"); + TPM_PT_PCR_map.insert(0x13, "POLICY"); + TPM_PT_PCR_map.insert(0x14, "AUTH"); + TPM_PT_PCR_map.insert(0x14, "LAST"); + map.insert(std::any::TypeId::of::(), TPM_PT_PCR_map); + + let mut TPM_PS_map: HashMap = HashMap::new(); + TPM_PS_map.insert(0x0, "MAIN"); + TPM_PS_map.insert(0x1, "PC"); + TPM_PS_map.insert(0x2, "PDA"); + TPM_PS_map.insert(0x3, "CELL_PHONE"); + TPM_PS_map.insert(0x4, "SERVER"); + TPM_PS_map.insert(0x5, "PERIPHERAL"); + TPM_PS_map.insert(0x6, "TSS"); + TPM_PS_map.insert(0x7, "STORAGE"); + TPM_PS_map.insert(0x8, "AUTHENTICATION"); + TPM_PS_map.insert(0x9, "EMBEDDED"); + TPM_PS_map.insert(0xA, "HARDCOPY"); + TPM_PS_map.insert(0xB, "INFRASTRUCTURE"); + TPM_PS_map.insert(0xC, "VIRTUALIZATION"); + TPM_PS_map.insert(0xD, "TNC"); + TPM_PS_map.insert(0xE, "MULTI_TENANT"); + TPM_PS_map.insert(0xF, "TC"); + map.insert(std::any::TypeId::of::(), TPM_PS_map); + + let mut TPM_HT_map: HashMap = HashMap::new(); + TPM_HT_map.insert(0x0, "PCR"); + TPM_HT_map.insert(0x1, "NV_INDEX"); + TPM_HT_map.insert(0x2, "HMAC_SESSION"); + TPM_HT_map.insert(0x2, "LOADED_SESSION"); + TPM_HT_map.insert(0x3, "POLICY_SESSION"); + TPM_HT_map.insert(0x3, "SAVED_SESSION"); + TPM_HT_map.insert(0x40, "PERMANENT"); + TPM_HT_map.insert(0x80, "TRANSIENT"); + TPM_HT_map.insert(0x81, "PERSISTENT"); + TPM_HT_map.insert(0x90, "AC"); + map.insert(std::any::TypeId::of::(), TPM_HT_map); + + let mut TPM_RH_map: HashMap = HashMap::new(); + TPM_RH_map.insert(0x40000000, "FIRST"); + TPM_RH_map.insert(0x40000000, "SRK"); + TPM_RH_map.insert(0x40000001, "OWNER"); + TPM_RH_map.insert(0x40000002, "REVOKE"); + TPM_RH_map.insert(0x40000003, "TRANSPORT"); + TPM_RH_map.insert(0x40000004, "OPERATOR"); + TPM_RH_map.insert(0x40000005, "ADMIN"); + TPM_RH_map.insert(0x40000006, "EK"); + TPM_RH_map.insert(0x40000007, "NULL"); + TPM_RH_map.insert(0x40000008, "UNASSIGNED"); + TPM_RH_map.insert(0x40000009, "PW"); + TPM_RH_map.insert(0x4000000A, "LOCKOUT"); + TPM_RH_map.insert(0x4000000B, "ENDORSEMENT"); + TPM_RH_map.insert(0x4000000C, "PLATFORM"); + TPM_RH_map.insert(0x4000000D, "PLATFORM_NV"); + TPM_RH_map.insert(0x40000010, "AUTH_00"); + TPM_RH_map.insert(0x4000010F, "AUTH_FF"); + TPM_RH_map.insert(0x40000110, "ACT_0"); + TPM_RH_map.insert(0x4000011F, "ACT_F"); + TPM_RH_map.insert(0x4000011F, "LAST"); + map.insert(std::any::TypeId::of::(), TPM_RH_map); + + let mut TPM_NT_map: HashMap = HashMap::new(); + TPM_NT_map.insert(0x0, "ORDINARY"); + TPM_NT_map.insert(0x1, "COUNTER"); + TPM_NT_map.insert(0x2, "BITS"); + TPM_NT_map.insert(0x4, "EXTEND"); + TPM_NT_map.insert(0x8, "PIN_FAIL"); + TPM_NT_map.insert(0x9, "PIN_PASS"); + map.insert(std::any::TypeId::of::(), TPM_NT_map); + + let mut TPM_AT_map: HashMap = HashMap::new(); + TPM_AT_map.insert(0x0, "ANY"); + TPM_AT_map.insert(0x1, "ERROR"); + TPM_AT_map.insert(0x2, "PV1"); + TPM_AT_map.insert(0x80000000, "VEND"); + map.insert(std::any::TypeId::of::(), TPM_AT_map); + + let mut TPM_AE_map: HashMap = HashMap::new(); + TPM_AE_map.insert(0x0, "NONE"); + map.insert(std::any::TypeId::of::(), TPM_AE_map); + + let mut PLATFORM_map: HashMap = HashMap::new(); + PLATFORM_map.insert(0x322E3000, "FAMILY"); + PLATFORM_map.insert(0x0, "LEVEL"); + PLATFORM_map.insert(0xA2, "VERSION"); + PLATFORM_map.insert(0x7E3, "YEAR"); + PLATFORM_map.insert(0x168, "DAY_OF_YEAR"); + map.insert(std::any::TypeId::of::(), PLATFORM_map); + + let mut Implementation_map: HashMap = HashMap::new(); + Implementation_map.insert(0x0, "FIELD_UPGRADE_IMPLEMENTED"); + Implementation_map.insert(0x1, "HASH_LIB"); + Implementation_map.insert(0x1, "SYM_LIB"); + Implementation_map.insert(0x1, "MATH_LIB"); + Implementation_map.insert(0x18, "IMPLEMENTATION_PCR"); + Implementation_map.insert(0x3, "PCR_SELECT_MAX"); + Implementation_map.insert(0x18, "PLATFORM_PCR"); + Implementation_map.insert(0x3, "PCR_SELECT_MIN"); + Implementation_map.insert(0x11, "DRTM_PCR"); + Implementation_map.insert(0x0, "HCRTM_PCR"); + Implementation_map.insert(0x5, "NUM_LOCALITIES"); + Implementation_map.insert(0x3, "MAX_HANDLE_NUM"); + Implementation_map.insert(0x40, "MAX_ACTIVE_SESSIONS"); + Implementation_map.insert(0x3, "MAX_LOADED_SESSIONS"); + Implementation_map.insert(0x3, "MAX_SESSION_NUM"); + Implementation_map.insert(0x3, "MAX_LOADED_OBJECTS"); + Implementation_map.insert(0x2, "MIN_EVICT_OBJECTS"); + Implementation_map.insert(0x1, "NUM_POLICY_PCR_GROUP"); + Implementation_map.insert(0x1, "NUM_AUTHVALUE_PCR_GROUP"); + Implementation_map.insert(0x4F0, "MAX_CONTEXT_SIZE"); + Implementation_map.insert(0x400, "MAX_DIGEST_BUFFER"); + Implementation_map.insert(0x800, "MAX_NV_INDEX_SIZE"); + Implementation_map.insert(0x400, "MAX_NV_BUFFER_SIZE"); + Implementation_map.insert(0x400, "MAX_CAP_BUFFER"); + Implementation_map.insert(0x4000, "NV_MEMORY_SIZE"); + Implementation_map.insert(0x8, "MIN_COUNTER_INDICES"); + Implementation_map.insert(0x10, "NUM_STATIC_PCR"); + Implementation_map.insert(0x40, "MAX_ALG_LIST_SIZE"); + Implementation_map.insert(0x20, "PRIMARY_SEED_SIZE"); + Implementation_map.insert(0x6, "CONTEXT_ENCRYPT_ALGORITHM"); + Implementation_map.insert(0xC, "NV_CLOCK_UPDATE_INTERVAL"); + Implementation_map.insert(0x1, "NUM_POLICY_PCR"); + Implementation_map.insert(0x1000, "MAX_COMMAND_SIZE"); + Implementation_map.insert(0x1000, "MAX_RESPONSE_SIZE"); + Implementation_map.insert(0x8, "ORDERLY_BITS"); + Implementation_map.insert(0x80, "MAX_SYM_DATA"); + Implementation_map.insert(0x40, "MAX_RNG_ENTROPY_SIZE"); + Implementation_map.insert(0x200, "RAM_INDEX_SPACE"); + Implementation_map.insert(0x10001, "RSA_DEFAULT_PUBLIC_EXPONENT"); + Implementation_map.insert(0x1, "ENABLE_PCR_NO_INCREMENT"); + Implementation_map.insert(0x1, "CRT_FORMAT_RSA"); + Implementation_map.insert(0x0, "VENDOR_COMMAND_COUNT"); + Implementation_map.insert(0x400, "MAX_VENDOR_BUFFER_SIZE"); + Implementation_map.insert(0x2000, "MAX_DERIVATION_BITS"); + Implementation_map.insert(0x80, "RSA_MAX_PRIME"); + Implementation_map.insert(0x280, "RSA_PRIVATE_SIZE"); + Implementation_map.insert(0x14, "SIZE_OF_X509_SERIAL_NUMBER"); + Implementation_map.insert(0x280, "PRIVATE_VENDOR_SPECIFIC_BYTES"); + map.insert(std::any::TypeId::of::(), Implementation_map); + + let mut TPM_HC_map: HashMap = HashMap::new(); + TPM_HC_map.insert(0xFFFFFF, "HR_HANDLE_MASK"); + TPM_HC_map.insert(0xFF000000, "HR_RANGE_MASK"); + TPM_HC_map.insert(0x18, "HR_SHIFT"); + TPM_HC_map.insert(0x0, "HR_PCR"); + TPM_HC_map.insert(0x2000000, "HR_HMAC_SESSION"); + TPM_HC_map.insert(0x3000000, "HR_POLICY_SESSION"); + TPM_HC_map.insert(0x80000000, "HR_TRANSIENT"); + TPM_HC_map.insert(0x81000000, "HR_PERSISTENT"); + TPM_HC_map.insert(0x1000000, "HR_NV_INDEX"); + TPM_HC_map.insert(0x40000000, "HR_PERMANENT"); + TPM_HC_map.insert(0x0, "PCR_FIRST"); + TPM_HC_map.insert(0x17, "PCR_LAST"); + TPM_HC_map.insert(0x2000000, "HMAC_SESSION_FIRST"); + TPM_HC_map.insert(0x200003F, "HMAC_SESSION_LAST"); + TPM_HC_map.insert(0x2000000, "LOADED_SESSION_FIRST"); + TPM_HC_map.insert(0x200003F, "LOADED_SESSION_LAST"); + TPM_HC_map.insert(0x3000000, "POLICY_SESSION_FIRST"); + TPM_HC_map.insert(0x300003F, "POLICY_SESSION_LAST"); + TPM_HC_map.insert(0x80000000, "TRANSIENT_FIRST"); + TPM_HC_map.insert(0x3000000, "ACTIVE_SESSION_FIRST"); + TPM_HC_map.insert(0x300003F, "ACTIVE_SESSION_LAST"); + TPM_HC_map.insert(0x80000002, "TRANSIENT_LAST"); + TPM_HC_map.insert(0x81000000, "PERSISTENT_FIRST"); + TPM_HC_map.insert(0x81FFFFFF, "PERSISTENT_LAST"); + TPM_HC_map.insert(0x81800000, "PLATFORM_PERSISTENT"); + TPM_HC_map.insert(0x1000000, "NV_INDEX_FIRST"); + TPM_HC_map.insert(0x1FFFFFF, "NV_INDEX_LAST"); + TPM_HC_map.insert(0x40000000, "PERMANENT_FIRST"); + TPM_HC_map.insert(0x4000011F, "PERMANENT_LAST"); + TPM_HC_map.insert(0x1D00000, "HR_NV_AC"); + TPM_HC_map.insert(0x1D00000, "NV_AC_FIRST"); + TPM_HC_map.insert(0x1D0FFFF, "NV_AC_LAST"); + TPM_HC_map.insert(0x90000000, "HR_AC"); + TPM_HC_map.insert(0x90000000, "AC_FIRST"); + TPM_HC_map.insert(0x9000FFFF, "AC_LAST"); + map.insert(std::any::TypeId::of::(), TPM_HC_map); + + let mut TPMA_ALGORITHM_map: HashMap = HashMap::new(); + TPMA_ALGORITHM_map.insert(0x1, "asymmetric"); + TPMA_ALGORITHM_map.insert(0x2, "symmetric"); + TPMA_ALGORITHM_map.insert(0x4, "hash"); + TPMA_ALGORITHM_map.insert(0x8, "object"); + TPMA_ALGORITHM_map.insert(0x100, "signing"); + TPMA_ALGORITHM_map.insert(0x200, "encrypting"); + TPMA_ALGORITHM_map.insert(0x400, "method"); + map.insert(std::any::TypeId::of::(), TPMA_ALGORITHM_map); + + let mut TPMA_OBJECT_map: HashMap = HashMap::new(); + TPMA_OBJECT_map.insert(0x2, "fixedTPM"); + TPMA_OBJECT_map.insert(0x4, "stClear"); + TPMA_OBJECT_map.insert(0x10, "fixedParent"); + TPMA_OBJECT_map.insert(0x20, "sensitiveDataOrigin"); + TPMA_OBJECT_map.insert(0x40, "userWithAuth"); + TPMA_OBJECT_map.insert(0x80, "adminWithPolicy"); + TPMA_OBJECT_map.insert(0x400, "noDA"); + TPMA_OBJECT_map.insert(0x800, "encryptedDuplication"); + TPMA_OBJECT_map.insert(0x10000, "restricted"); + TPMA_OBJECT_map.insert(0x20000, "decrypt"); + TPMA_OBJECT_map.insert(0x40000, "sign"); + TPMA_OBJECT_map.insert(0x40000, "encrypt"); + TPMA_OBJECT_map.insert(0x80000, "x509sign"); + map.insert(std::any::TypeId::of::(), TPMA_OBJECT_map); + + let mut TPMA_SESSION_map: HashMap = HashMap::new(); + TPMA_SESSION_map.insert(0x1, "continueSession"); + TPMA_SESSION_map.insert(0x2, "auditExclusive"); + TPMA_SESSION_map.insert(0x4, "auditReset"); + TPMA_SESSION_map.insert(0x20, "decrypt"); + TPMA_SESSION_map.insert(0x40, "encrypt"); + TPMA_SESSION_map.insert(0x80, "audit"); + map.insert(std::any::TypeId::of::(), TPMA_SESSION_map); + + let mut TPMA_LOCALITY_map: HashMap = HashMap::new(); + TPMA_LOCALITY_map.insert(0x1, "LOC_ZERO"); + TPMA_LOCALITY_map.insert(0x2, "LOC_ONE"); + TPMA_LOCALITY_map.insert(0x4, "LOC_TWO"); + TPMA_LOCALITY_map.insert(0x8, "LOC_THREE"); + TPMA_LOCALITY_map.insert(0x10, "LOC_FOUR"); + map.insert(std::any::TypeId::of::(), TPMA_LOCALITY_map); + + let mut TPMA_PERMANENT_map: HashMap = HashMap::new(); + TPMA_PERMANENT_map.insert(0x1, "ownerAuthSet"); + TPMA_PERMANENT_map.insert(0x2, "endorsementAuthSet"); + TPMA_PERMANENT_map.insert(0x4, "lockoutAuthSet"); + TPMA_PERMANENT_map.insert(0x100, "disableClear"); + TPMA_PERMANENT_map.insert(0x200, "inLockout"); + TPMA_PERMANENT_map.insert(0x400, "tpmGeneratedEPS"); + map.insert(std::any::TypeId::of::(), TPMA_PERMANENT_map); + + let mut TPMA_STARTUP_CLEAR_map: HashMap = HashMap::new(); + TPMA_STARTUP_CLEAR_map.insert(0x1, "phEnable"); + TPMA_STARTUP_CLEAR_map.insert(0x2, "shEnable"); + TPMA_STARTUP_CLEAR_map.insert(0x4, "ehEnable"); + TPMA_STARTUP_CLEAR_map.insert(0x8, "phEnableNV"); + TPMA_STARTUP_CLEAR_map.insert(0x80000000, "orderly"); + map.insert(std::any::TypeId::of::(), TPMA_STARTUP_CLEAR_map); + + let mut TPMA_MEMORY_map: HashMap = HashMap::new(); + TPMA_MEMORY_map.insert(0x1, "sharedRAM"); + TPMA_MEMORY_map.insert(0x2, "sharedNV"); + TPMA_MEMORY_map.insert(0x4, "objectCopiedToRam"); + map.insert(std::any::TypeId::of::(), TPMA_MEMORY_map); + + let mut TPMA_CC_map: HashMap = HashMap::new(); + TPMA_CC_map.insert(0x400000, "nv"); + TPMA_CC_map.insert(0x800000, "extensive"); + TPMA_CC_map.insert(0x1000000, "flushed"); + TPMA_CC_map.insert(0x10000000, "rHandle"); + TPMA_CC_map.insert(0x20000000, "V"); + map.insert(std::any::TypeId::of::(), TPMA_CC_map); + + let mut TPMA_MODES_map: HashMap = HashMap::new(); + TPMA_MODES_map.insert(0x1, "FIPS_140_2"); + map.insert(std::any::TypeId::of::(), TPMA_MODES_map); + + let mut TPMA_X509_KEY_USAGE_map: HashMap = HashMap::new(); + TPMA_X509_KEY_USAGE_map.insert(0x800000, "decipherOnly"); + TPMA_X509_KEY_USAGE_map.insert(0x1000000, "encipherOnly"); + TPMA_X509_KEY_USAGE_map.insert(0x2000000, "cRLSign"); + TPMA_X509_KEY_USAGE_map.insert(0x4000000, "keyCertSign"); + TPMA_X509_KEY_USAGE_map.insert(0x8000000, "keyAgreement"); + TPMA_X509_KEY_USAGE_map.insert(0x10000000, "dataEncipherment"); + TPMA_X509_KEY_USAGE_map.insert(0x20000000, "keyEncipherment"); + TPMA_X509_KEY_USAGE_map.insert(0x40000000, "nonrepudiation"); + TPMA_X509_KEY_USAGE_map.insert(0x40000000, "contentCommitment"); + TPMA_X509_KEY_USAGE_map.insert(0x80000000, "digitalSignature"); + map.insert(std::any::TypeId::of::(), TPMA_X509_KEY_USAGE_map); + + let mut TPMA_ACT_map: HashMap = HashMap::new(); + TPMA_ACT_map.insert(0x1, "signaled"); + TPMA_ACT_map.insert(0x2, "preserveSignaled"); + map.insert(std::any::TypeId::of::(), TPMA_ACT_map); + + let TPM_NV_INDEX_map: HashMap = HashMap::new(); + map.insert(std::any::TypeId::of::(), TPM_NV_INDEX_map); + + let mut TPMA_NV_map: HashMap = HashMap::new(); + TPMA_NV_map.insert(0x1, "PPWRITE"); + TPMA_NV_map.insert(0x2, "OWNERWRITE"); + TPMA_NV_map.insert(0x4, "AUTHWRITE"); + TPMA_NV_map.insert(0x8, "POLICYWRITE"); + TPMA_NV_map.insert(0x0, "ORDINARY"); + TPMA_NV_map.insert(0x10, "COUNTER"); + TPMA_NV_map.insert(0x20, "BITS"); + TPMA_NV_map.insert(0x40, "EXTEND"); + TPMA_NV_map.insert(0x80, "PIN_FAIL"); + TPMA_NV_map.insert(0x90, "PIN_PASS"); + TPMA_NV_map.insert(0x400, "POLICY_DELETE"); + TPMA_NV_map.insert(0x800, "WRITELOCKED"); + TPMA_NV_map.insert(0x1000, "WRITEALL"); + TPMA_NV_map.insert(0x2000, "WRITEDEFINE"); + TPMA_NV_map.insert(0x4000, "WRITE_STCLEAR"); + TPMA_NV_map.insert(0x8000, "GLOBALLOCK"); + TPMA_NV_map.insert(0x10000, "PPREAD"); + TPMA_NV_map.insert(0x20000, "OWNERREAD"); + TPMA_NV_map.insert(0x40000, "AUTHREAD"); + TPMA_NV_map.insert(0x80000, "POLICYREAD"); + TPMA_NV_map.insert(0x2000000, "NO_DA"); + TPMA_NV_map.insert(0x4000000, "ORDERLY"); + TPMA_NV_map.insert(0x8000000, "CLEAR_STCLEAR"); + TPMA_NV_map.insert(0x10000000, "READLOCKED"); + TPMA_NV_map.insert(0x20000000, "WRITTEN"); + TPMA_NV_map.insert(0x40000000, "PLATFORMCREATE"); + TPMA_NV_map.insert(0x80000000, "READ_STCLEAR"); + map.insert(std::any::TypeId::of::(), TPMA_NV_map); + + map + }; + + /// Maps enum type IDs to a map of string representations to values + static ref STR_TO_ENUM_MAP: HashMap> = { + let mut map = HashMap::new(); + let mut TPM_ALG_ID_map: HashMap<&'static str, u64> = HashMap::new(); + TPM_ALG_ID_map.insert("ERROR", 0x0); + TPM_ALG_ID_map.insert("FIRST", 0x1); + TPM_ALG_ID_map.insert("RSA", 0x1); + TPM_ALG_ID_map.insert("TDES", 0x3); + TPM_ALG_ID_map.insert("SHA", 0x4); + TPM_ALG_ID_map.insert("SHA1", 0x4); + TPM_ALG_ID_map.insert("HMAC", 0x5); + TPM_ALG_ID_map.insert("AES", 0x6); + TPM_ALG_ID_map.insert("MGF1", 0x7); + TPM_ALG_ID_map.insert("KEYEDHASH", 0x8); + TPM_ALG_ID_map.insert("XOR", 0xA); + TPM_ALG_ID_map.insert("SHA256", 0xB); + TPM_ALG_ID_map.insert("SHA384", 0xC); + TPM_ALG_ID_map.insert("SHA512", 0xD); + TPM_ALG_ID_map.insert("NULL", 0x10); + TPM_ALG_ID_map.insert("SM3_256", 0x12); + TPM_ALG_ID_map.insert("SM4", 0x13); + TPM_ALG_ID_map.insert("RSASSA", 0x14); + TPM_ALG_ID_map.insert("RSAES", 0x15); + TPM_ALG_ID_map.insert("RSAPSS", 0x16); + TPM_ALG_ID_map.insert("OAEP", 0x17); + TPM_ALG_ID_map.insert("ECDSA", 0x18); + TPM_ALG_ID_map.insert("ECDH", 0x19); + TPM_ALG_ID_map.insert("ECDAA", 0x1A); + TPM_ALG_ID_map.insert("SM2", 0x1B); + TPM_ALG_ID_map.insert("ECSCHNORR", 0x1C); + TPM_ALG_ID_map.insert("ECMQV", 0x1D); + TPM_ALG_ID_map.insert("KDF1_SP800_56A", 0x20); + TPM_ALG_ID_map.insert("KDF2", 0x21); + TPM_ALG_ID_map.insert("KDF1_SP800_108", 0x22); + TPM_ALG_ID_map.insert("ECC", 0x23); + TPM_ALG_ID_map.insert("SYMCIPHER", 0x25); + TPM_ALG_ID_map.insert("CAMELLIA", 0x26); + TPM_ALG_ID_map.insert("SHA3_256", 0x27); + TPM_ALG_ID_map.insert("SHA3_384", 0x28); + TPM_ALG_ID_map.insert("SHA3_512", 0x29); + TPM_ALG_ID_map.insert("CMAC", 0x3F); + TPM_ALG_ID_map.insert("CTR", 0x40); + TPM_ALG_ID_map.insert("OFB", 0x41); + TPM_ALG_ID_map.insert("CBC", 0x42); + TPM_ALG_ID_map.insert("CFB", 0x43); + TPM_ALG_ID_map.insert("ECB", 0x44); + TPM_ALG_ID_map.insert("LAST", 0x44); + TPM_ALG_ID_map.insert("ANY", 0x7FFF); + TPM_ALG_ID_map.insert("ANY2", 0x7FFE); + map.insert(std::any::TypeId::of::(), TPM_ALG_ID_map); + + let mut TPM_ECC_CURVE_map: HashMap<&'static str, u64> = HashMap::new(); + TPM_ECC_CURVE_map.insert("NONE", 0x0); + TPM_ECC_CURVE_map.insert("NIST_P192", 0x1); + TPM_ECC_CURVE_map.insert("NIST_P224", 0x2); + TPM_ECC_CURVE_map.insert("NIST_P256", 0x3); + TPM_ECC_CURVE_map.insert("NIST_P384", 0x4); + TPM_ECC_CURVE_map.insert("NIST_P521", 0x5); + TPM_ECC_CURVE_map.insert("BN_P256", 0x10); + TPM_ECC_CURVE_map.insert("BN_P638", 0x11); + TPM_ECC_CURVE_map.insert("SM2_P256", 0x20); + TPM_ECC_CURVE_map.insert("TEST_P192", 0x21); + map.insert(std::any::TypeId::of::(), TPM_ECC_CURVE_map); + + let mut SHA1_map: HashMap<&'static str, u64> = HashMap::new(); + SHA1_map.insert("DIGEST_SIZE", 0x14); + SHA1_map.insert("BLOCK_SIZE", 0x40); + map.insert(std::any::TypeId::of::(), SHA1_map); + + let mut SHA256_map: HashMap<&'static str, u64> = HashMap::new(); + SHA256_map.insert("DIGEST_SIZE", 0x20); + SHA256_map.insert("BLOCK_SIZE", 0x40); + map.insert(std::any::TypeId::of::(), SHA256_map); + + let mut SHA384_map: HashMap<&'static str, u64> = HashMap::new(); + SHA384_map.insert("DIGEST_SIZE", 0x30); + SHA384_map.insert("BLOCK_SIZE", 0x80); + map.insert(std::any::TypeId::of::(), SHA384_map); + + let mut SHA512_map: HashMap<&'static str, u64> = HashMap::new(); + SHA512_map.insert("DIGEST_SIZE", 0x40); + SHA512_map.insert("BLOCK_SIZE", 0x80); + map.insert(std::any::TypeId::of::(), SHA512_map); + + let mut SM3_256_map: HashMap<&'static str, u64> = HashMap::new(); + SM3_256_map.insert("DIGEST_SIZE", 0x20); + SM3_256_map.insert("BLOCK_SIZE", 0x40); + map.insert(std::any::TypeId::of::(), SM3_256_map); + + let mut SHA3_256_map: HashMap<&'static str, u64> = HashMap::new(); + SHA3_256_map.insert("DIGEST_SIZE", 0x20); + SHA3_256_map.insert("BLOCK_SIZE", 0x88); + map.insert(std::any::TypeId::of::(), SHA3_256_map); + + let mut SHA3_384_map: HashMap<&'static str, u64> = HashMap::new(); + SHA3_384_map.insert("DIGEST_SIZE", 0x30); + SHA3_384_map.insert("BLOCK_SIZE", 0x68); + map.insert(std::any::TypeId::of::(), SHA3_384_map); + + let mut SHA3_512_map: HashMap<&'static str, u64> = HashMap::new(); + SHA3_512_map.insert("DIGEST_SIZE", 0x40); + SHA3_512_map.insert("BLOCK_SIZE", 0x48); + map.insert(std::any::TypeId::of::(), SHA3_512_map); + + let mut Logic_map: HashMap<&'static str, u64> = HashMap::new(); + Logic_map.insert("TRUE", 0x1); + Logic_map.insert("FALSE", 0x0); + Logic_map.insert("YES", 0x1); + Logic_map.insert("NO", 0x0); + Logic_map.insert("SET", 0x1); + Logic_map.insert("CLEAR", 0x0); + map.insert(std::any::TypeId::of::(), Logic_map); + + let mut TPM_SPEC_map: HashMap<&'static str, u64> = HashMap::new(); + TPM_SPEC_map.insert("FAMILY", 0x322E3000); + TPM_SPEC_map.insert("LEVEL", 0x0); + TPM_SPEC_map.insert("VERSION", 0xA2); + TPM_SPEC_map.insert("YEAR", 0x7E3); + TPM_SPEC_map.insert("DAY_OF_YEAR", 0x168); + map.insert(std::any::TypeId::of::(), TPM_SPEC_map); + + let mut TPM_GENERATED_map: HashMap<&'static str, u64> = HashMap::new(); + TPM_GENERATED_map.insert("VALUE", 0xFF544347); + map.insert(std::any::TypeId::of::(), TPM_GENERATED_map); + + let mut TPM_CC_map: HashMap<&'static str, u64> = HashMap::new(); + TPM_CC_map.insert("FIRST", 0x11F); + TPM_CC_map.insert("NV_UndefineSpaceSpecial", 0x11F); + TPM_CC_map.insert("EvictControl", 0x120); + TPM_CC_map.insert("HierarchyControl", 0x121); + TPM_CC_map.insert("NV_UndefineSpace", 0x122); + TPM_CC_map.insert("ChangeEPS", 0x124); + TPM_CC_map.insert("ChangePPS", 0x125); + TPM_CC_map.insert("Clear", 0x126); + TPM_CC_map.insert("ClearControl", 0x127); + TPM_CC_map.insert("ClockSet", 0x128); + TPM_CC_map.insert("HierarchyChangeAuth", 0x129); + TPM_CC_map.insert("NV_DefineSpace", 0x12A); + TPM_CC_map.insert("PCR_Allocate", 0x12B); + TPM_CC_map.insert("PCR_SetAuthPolicy", 0x12C); + TPM_CC_map.insert("PP_Commands", 0x12D); + TPM_CC_map.insert("SetPrimaryPolicy", 0x12E); + TPM_CC_map.insert("FieldUpgradeStart", 0x12F); + TPM_CC_map.insert("ClockRateAdjust", 0x130); + TPM_CC_map.insert("CreatePrimary", 0x131); + TPM_CC_map.insert("NV_GlobalWriteLock", 0x132); + TPM_CC_map.insert("GetCommandAuditDigest", 0x133); + TPM_CC_map.insert("NV_Increment", 0x134); + TPM_CC_map.insert("NV_SetBits", 0x135); + TPM_CC_map.insert("NV_Extend", 0x136); + TPM_CC_map.insert("NV_Write", 0x137); + TPM_CC_map.insert("NV_WriteLock", 0x138); + TPM_CC_map.insert("DictionaryAttackLockReset", 0x139); + TPM_CC_map.insert("DictionaryAttackParameters", 0x13A); + TPM_CC_map.insert("NV_ChangeAuth", 0x13B); + TPM_CC_map.insert("PCR_Event", 0x13C); + TPM_CC_map.insert("PCR_Reset", 0x13D); + TPM_CC_map.insert("SequenceComplete", 0x13E); + TPM_CC_map.insert("SetAlgorithmSet", 0x13F); + TPM_CC_map.insert("SetCommandCodeAuditStatus", 0x140); + TPM_CC_map.insert("FieldUpgradeData", 0x141); + TPM_CC_map.insert("IncrementalSelfTest", 0x142); + TPM_CC_map.insert("SelfTest", 0x143); + TPM_CC_map.insert("Startup", 0x144); + TPM_CC_map.insert("Shutdown", 0x145); + TPM_CC_map.insert("StirRandom", 0x146); + TPM_CC_map.insert("ActivateCredential", 0x147); + TPM_CC_map.insert("Certify", 0x148); + TPM_CC_map.insert("PolicyNV", 0x149); + TPM_CC_map.insert("CertifyCreation", 0x14A); + TPM_CC_map.insert("Duplicate", 0x14B); + TPM_CC_map.insert("GetTime", 0x14C); + TPM_CC_map.insert("GetSessionAuditDigest", 0x14D); + TPM_CC_map.insert("NV_Read", 0x14E); + TPM_CC_map.insert("NV_ReadLock", 0x14F); + TPM_CC_map.insert("ObjectChangeAuth", 0x150); + TPM_CC_map.insert("PolicySecret", 0x151); + TPM_CC_map.insert("Rewrap", 0x152); + TPM_CC_map.insert("Create", 0x153); + TPM_CC_map.insert("ECDH_ZGen", 0x154); + TPM_CC_map.insert("HMAC", 0x155); + TPM_CC_map.insert("MAC", 0x155); + TPM_CC_map.insert("Import", 0x156); + TPM_CC_map.insert("Load", 0x157); + TPM_CC_map.insert("Quote", 0x158); + TPM_CC_map.insert("RSA_Decrypt", 0x159); + TPM_CC_map.insert("HMAC_Start", 0x15B); + TPM_CC_map.insert("MAC_Start", 0x15B); + TPM_CC_map.insert("SequenceUpdate", 0x15C); + TPM_CC_map.insert("Sign", 0x15D); + TPM_CC_map.insert("Unseal", 0x15E); + TPM_CC_map.insert("PolicySigned", 0x160); + TPM_CC_map.insert("ContextLoad", 0x161); + TPM_CC_map.insert("ContextSave", 0x162); + TPM_CC_map.insert("ECDH_KeyGen", 0x163); + TPM_CC_map.insert("EncryptDecrypt", 0x164); + TPM_CC_map.insert("FlushContext", 0x165); + TPM_CC_map.insert("LoadExternal", 0x167); + TPM_CC_map.insert("MakeCredential", 0x168); + TPM_CC_map.insert("NV_ReadPublic", 0x169); + TPM_CC_map.insert("PolicyAuthorize", 0x16A); + TPM_CC_map.insert("PolicyAuthValue", 0x16B); + TPM_CC_map.insert("PolicyCommandCode", 0x16C); + TPM_CC_map.insert("PolicyCounterTimer", 0x16D); + TPM_CC_map.insert("PolicyCpHash", 0x16E); + TPM_CC_map.insert("PolicyLocality", 0x16F); + TPM_CC_map.insert("PolicyNameHash", 0x170); + TPM_CC_map.insert("PolicyOR", 0x171); + TPM_CC_map.insert("PolicyTicket", 0x172); + TPM_CC_map.insert("ReadPublic", 0x173); + TPM_CC_map.insert("RSA_Encrypt", 0x174); + TPM_CC_map.insert("StartAuthSession", 0x176); + TPM_CC_map.insert("VerifySignature", 0x177); + TPM_CC_map.insert("ECC_Parameters", 0x178); + TPM_CC_map.insert("FirmwareRead", 0x179); + TPM_CC_map.insert("GetCapability", 0x17A); + TPM_CC_map.insert("GetRandom", 0x17B); + TPM_CC_map.insert("GetTestResult", 0x17C); + TPM_CC_map.insert("Hash", 0x17D); + TPM_CC_map.insert("PCR_Read", 0x17E); + TPM_CC_map.insert("PolicyPCR", 0x17F); + TPM_CC_map.insert("PolicyRestart", 0x180); + TPM_CC_map.insert("ReadClock", 0x181); + TPM_CC_map.insert("PCR_Extend", 0x182); + TPM_CC_map.insert("PCR_SetAuthValue", 0x183); + TPM_CC_map.insert("NV_Certify", 0x184); + TPM_CC_map.insert("EventSequenceComplete", 0x185); + TPM_CC_map.insert("HashSequenceStart", 0x186); + TPM_CC_map.insert("PolicyPhysicalPresence", 0x187); + TPM_CC_map.insert("PolicyDuplicationSelect", 0x188); + TPM_CC_map.insert("PolicyGetDigest", 0x189); + TPM_CC_map.insert("TestParms", 0x18A); + TPM_CC_map.insert("Commit", 0x18B); + TPM_CC_map.insert("PolicyPassword", 0x18C); + TPM_CC_map.insert("ZGen_2Phase", 0x18D); + TPM_CC_map.insert("EC_Ephemeral", 0x18E); + TPM_CC_map.insert("PolicyNvWritten", 0x18F); + TPM_CC_map.insert("PolicyTemplate", 0x190); + TPM_CC_map.insert("CreateLoaded", 0x191); + TPM_CC_map.insert("PolicyAuthorizeNV", 0x192); + TPM_CC_map.insert("EncryptDecrypt2", 0x193); + TPM_CC_map.insert("AC_GetCapability", 0x194); + TPM_CC_map.insert("AC_Send", 0x195); + TPM_CC_map.insert("Policy_AC_SendSelect", 0x196); + TPM_CC_map.insert("CertifyX509", 0x197); + TPM_CC_map.insert("ACT_SetTimeout", 0x198); + TPM_CC_map.insert("ECC_Encrypt", 0x199); + TPM_CC_map.insert("ECC_Decrypt", 0x19A); + TPM_CC_map.insert("LAST", 0x19A); + TPM_CC_map.insert("CC_VEND", 0x20000000); + TPM_CC_map.insert("Vendor_TCG_Test", 0x20000000); + map.insert(std::any::TypeId::of::(), TPM_CC_map); + + let mut ImplementationConstants_map: HashMap<&'static str, u64> = HashMap::new(); + ImplementationConstants_map.insert("Ossl", 0x1); + ImplementationConstants_map.insert("Ltc", 0x2); + ImplementationConstants_map.insert("Msbn", 0x3); + ImplementationConstants_map.insert("Symcrypt", 0x4); + ImplementationConstants_map.insert("HASH_COUNT", 0x3); + ImplementationConstants_map.insert("MAX_SYM_KEY_BITS", 0x100); + ImplementationConstants_map.insert("MAX_SYM_KEY_BYTES", 0x20); + ImplementationConstants_map.insert("MAX_SYM_BLOCK_SIZE", 0x10); + ImplementationConstants_map.insert("MAX_CAP_CC", 0x19A); + ImplementationConstants_map.insert("MAX_RSA_KEY_BYTES", 0x100); + ImplementationConstants_map.insert("MAX_AES_KEY_BYTES", 0x20); + ImplementationConstants_map.insert("MAX_ECC_KEY_BYTES", 0x30); + ImplementationConstants_map.insert("LABEL_MAX_BUFFER", 0x20); + ImplementationConstants_map.insert("_TPM_CAP_SIZE", 0x4); + ImplementationConstants_map.insert("MAX_CAP_DATA", 0x3F8); + ImplementationConstants_map.insert("MAX_CAP_ALGS", 0xA9); + ImplementationConstants_map.insert("MAX_CAP_HANDLES", 0xFE); + ImplementationConstants_map.insert("MAX_TPM_PROPERTIES", 0x7F); + ImplementationConstants_map.insert("MAX_PCR_PROPERTIES", 0xCB); + ImplementationConstants_map.insert("MAX_ECC_CURVES", 0x1FC); + ImplementationConstants_map.insert("MAX_TAGGED_POLICIES", 0xE); + ImplementationConstants_map.insert("MAX_AC_CAPABILITIES", 0x7F); + ImplementationConstants_map.insert("MAX_ACT_DATA", 0x54); + map.insert(std::any::TypeId::of::(), ImplementationConstants_map); + + let mut TPM_RC_map: HashMap<&'static str, u64> = HashMap::new(); + TPM_RC_map.insert("SUCCESS", 0x0); + TPM_RC_map.insert("BAD_TAG", 0x1E); + TPM_RC_map.insert("RC_VER1", 0x100); + TPM_RC_map.insert("INITIALIZE", 0x100); + TPM_RC_map.insert("FAILURE", 0x101); + TPM_RC_map.insert("SEQUENCE", 0x103); + TPM_RC_map.insert("PRIVATE", 0x10B); + TPM_RC_map.insert("HMAC", 0x119); + TPM_RC_map.insert("DISABLED", 0x120); + TPM_RC_map.insert("EXCLUSIVE", 0x121); + TPM_RC_map.insert("AUTH_TYPE", 0x124); + TPM_RC_map.insert("AUTH_MISSING", 0x125); + TPM_RC_map.insert("POLICY", 0x126); + TPM_RC_map.insert("PCR", 0x127); + TPM_RC_map.insert("PCR_CHANGED", 0x128); + TPM_RC_map.insert("UPGRADE", 0x12D); + TPM_RC_map.insert("TOO_MANY_CONTEXTS", 0x12E); + TPM_RC_map.insert("AUTH_UNAVAILABLE", 0x12F); + TPM_RC_map.insert("REBOOT", 0x130); + TPM_RC_map.insert("UNBALANCED", 0x131); + TPM_RC_map.insert("COMMAND_SIZE", 0x142); + TPM_RC_map.insert("COMMAND_CODE", 0x143); + TPM_RC_map.insert("AUTHSIZE", 0x144); + TPM_RC_map.insert("AUTH_CONTEXT", 0x145); + TPM_RC_map.insert("NV_RANGE", 0x146); + TPM_RC_map.insert("NV_SIZE", 0x147); + TPM_RC_map.insert("NV_LOCKED", 0x148); + TPM_RC_map.insert("NV_AUTHORIZATION", 0x149); + TPM_RC_map.insert("NV_UNINITIALIZED", 0x14A); + TPM_RC_map.insert("NV_SPACE", 0x14B); + TPM_RC_map.insert("NV_DEFINED", 0x14C); + TPM_RC_map.insert("BAD_CONTEXT", 0x150); + TPM_RC_map.insert("CPHASH", 0x151); + TPM_RC_map.insert("PARENT", 0x152); + TPM_RC_map.insert("NEEDS_TEST", 0x153); + TPM_RC_map.insert("NO_RESULT", 0x154); + TPM_RC_map.insert("SENSITIVE", 0x155); + TPM_RC_map.insert("RC_MAX_FM0", 0x17F); + TPM_RC_map.insert("RC_FMT1", 0x80); + TPM_RC_map.insert("ASYMMETRIC", 0x81); + TPM_RC_map.insert("ATTRIBUTES", 0x82); + TPM_RC_map.insert("HASH", 0x83); + TPM_RC_map.insert("VALUE", 0x84); + TPM_RC_map.insert("HIERARCHY", 0x85); + TPM_RC_map.insert("KEY_SIZE", 0x87); + TPM_RC_map.insert("MGF", 0x88); + TPM_RC_map.insert("MODE", 0x89); + TPM_RC_map.insert("TYPE", 0x8A); + TPM_RC_map.insert("HANDLE", 0x8B); + TPM_RC_map.insert("KDF", 0x8C); + TPM_RC_map.insert("RANGE", 0x8D); + TPM_RC_map.insert("AUTH_FAIL", 0x8E); + TPM_RC_map.insert("NONCE", 0x8F); + TPM_RC_map.insert("PP", 0x90); + TPM_RC_map.insert("SCHEME", 0x92); + TPM_RC_map.insert("SIZE", 0x95); + TPM_RC_map.insert("SYMMETRIC", 0x96); + TPM_RC_map.insert("TAG", 0x97); + TPM_RC_map.insert("SELECTOR", 0x98); + TPM_RC_map.insert("INSUFFICIENT", 0x9A); + TPM_RC_map.insert("SIGNATURE", 0x9B); + TPM_RC_map.insert("KEY", 0x9C); + TPM_RC_map.insert("POLICY_FAIL", 0x9D); + TPM_RC_map.insert("INTEGRITY", 0x9F); + TPM_RC_map.insert("TICKET", 0xA0); + TPM_RC_map.insert("RESERVED_BITS", 0xA1); + TPM_RC_map.insert("BAD_AUTH", 0xA2); + TPM_RC_map.insert("EXPIRED", 0xA3); + TPM_RC_map.insert("POLICY_CC", 0xA4); + TPM_RC_map.insert("BINDING", 0xA5); + TPM_RC_map.insert("CURVE", 0xA6); + TPM_RC_map.insert("ECC_POINT", 0xA7); + TPM_RC_map.insert("RC_WARN", 0x900); + TPM_RC_map.insert("CONTEXT_GAP", 0x901); + TPM_RC_map.insert("OBJECT_MEMORY", 0x902); + TPM_RC_map.insert("SESSION_MEMORY", 0x903); + TPM_RC_map.insert("MEMORY", 0x904); + TPM_RC_map.insert("SESSION_HANDLES", 0x905); + TPM_RC_map.insert("OBJECT_HANDLES", 0x906); + TPM_RC_map.insert("LOCALITY", 0x907); + TPM_RC_map.insert("YIELDED", 0x908); + TPM_RC_map.insert("CANCELED", 0x909); + TPM_RC_map.insert("TESTING", 0x90A); + TPM_RC_map.insert("REFERENCE_H0", 0x910); + TPM_RC_map.insert("REFERENCE_H1", 0x911); + TPM_RC_map.insert("REFERENCE_H2", 0x912); + TPM_RC_map.insert("REFERENCE_H3", 0x913); + TPM_RC_map.insert("REFERENCE_H4", 0x914); + TPM_RC_map.insert("REFERENCE_H5", 0x915); + TPM_RC_map.insert("REFERENCE_H6", 0x916); + TPM_RC_map.insert("REFERENCE_S0", 0x918); + TPM_RC_map.insert("REFERENCE_S1", 0x919); + TPM_RC_map.insert("REFERENCE_S2", 0x91A); + TPM_RC_map.insert("REFERENCE_S3", 0x91B); + TPM_RC_map.insert("REFERENCE_S4", 0x91C); + TPM_RC_map.insert("REFERENCE_S5", 0x91D); + TPM_RC_map.insert("REFERENCE_S6", 0x91E); + TPM_RC_map.insert("NV_RATE", 0x920); + TPM_RC_map.insert("LOCKOUT", 0x921); + TPM_RC_map.insert("RETRY", 0x922); + TPM_RC_map.insert("NV_UNAVAILABLE", 0x923); + TPM_RC_map.insert("NOT_USED", 0x97F); + TPM_RC_map.insert("H", 0x0); + TPM_RC_map.insert("P", 0x40); + TPM_RC_map.insert("S", 0x800); + TPM_RC_map.insert("_1", 0x100); + TPM_RC_map.insert("_2", 0x200); + TPM_RC_map.insert("_3", 0x300); + TPM_RC_map.insert("_4", 0x400); + TPM_RC_map.insert("_5", 0x500); + TPM_RC_map.insert("_6", 0x600); + TPM_RC_map.insert("_7", 0x700); + TPM_RC_map.insert("_8", 0x800); + TPM_RC_map.insert("_9", 0x900); + TPM_RC_map.insert("A", 0xA00); + TPM_RC_map.insert("B", 0xB00); + TPM_RC_map.insert("C", 0xC00); + TPM_RC_map.insert("D", 0xD00); + TPM_RC_map.insert("E", 0xE00); + TPM_RC_map.insert("F", 0xF00); + TPM_RC_map.insert("N_MASK", 0xF00); + TPM_RC_map.insert("TSS_TCP_BAD_HANDSHAKE_RESP", 0x40280001); + TPM_RC_map.insert("TSS_TCP_SERVER_TOO_OLD", 0x40280002); + TPM_RC_map.insert("TSS_TCP_BAD_ACK", 0x40280003); + TPM_RC_map.insert("TSS_TCP_BAD_RESP_LEN", 0x40280004); + TPM_RC_map.insert("TSS_TCP_UNEXPECTED_STARTUP_RESP", 0x40280005); + TPM_RC_map.insert("TSS_TCP_INVALID_SIZE_TAG", 0x40280006); + TPM_RC_map.insert("TSS_TCP_DISCONNECTED", 0x40280007); + TPM_RC_map.insert("TSS_DISPATCH_FAILED", 0x40280010); + TPM_RC_map.insert("TSS_SEND_OP_FAILED", 0x40280011); + TPM_RC_map.insert("TSS_RESP_BUF_TOO_SHORT", 0x40280021); + TPM_RC_map.insert("TSS_RESP_BUF_INVALID_SESSION_TAG", 0x40280022); + TPM_RC_map.insert("TSS_RESP_BUF_INVALID_SIZE", 0x40280023); + TPM_RC_map.insert("TBS_COMMAND_BLOCKED", 0x80280400); + TPM_RC_map.insert("TBS_INVALID_HANDLE", 0x80280401); + TPM_RC_map.insert("TBS_DUPLICATE_V_HANDLE", 0x80280402); + TPM_RC_map.insert("TBS_EMBEDDED_COMMAND_BLOCKED", 0x80280403); + TPM_RC_map.insert("TBS_EMBEDDED_COMMAND_UNSUPPORTED", 0x80280404); + TPM_RC_map.insert("TBS_UNKNOWN_ERROR", 0x80284000); + TPM_RC_map.insert("TBS_INTERNAL_ERROR", 0x80284001); + TPM_RC_map.insert("TBS_BAD_PARAMETER", 0x80284002); + TPM_RC_map.insert("TBS_INVALID_OUTPUT_POINTER", 0x80284003); + TPM_RC_map.insert("TBS_INVALID_CONTEXT", 0x80284004); + TPM_RC_map.insert("TBS_INSUFFICIENT_BUFFER", 0x80284005); + TPM_RC_map.insert("TBS_IO_ERROR", 0x80284006); + TPM_RC_map.insert("TBS_INVALID_CONTEXT_PARAM", 0x80284007); + TPM_RC_map.insert("TBS_SERVICE_NOT_RUNNING", 0x80284008); + TPM_RC_map.insert("TBS_TOO_MANY_CONTEXTS", 0x80284009); + TPM_RC_map.insert("TBS_TOO_MANY_RESOURCES", 0x8028400A); + TPM_RC_map.insert("TBS_SERVICE_START_PENDING", 0x8028400B); + TPM_RC_map.insert("TBS_PPI_NOT_SUPPORTED", 0x8028400C); + TPM_RC_map.insert("TBS_COMMAND_CANCELED", 0x8028400D); + TPM_RC_map.insert("TBS_BUFFER_TOO_LARGE", 0x8028400E); + TPM_RC_map.insert("TBS_TPM_NOT_FOUND", 0x8028400F); + TPM_RC_map.insert("TBS_SERVICE_DISABLED", 0x80284010); + TPM_RC_map.insert("TBS_ACCESS_DENIED", 0x80284012); + TPM_RC_map.insert("TBS_PPI_FUNCTION_NOT_SUPPORTED", 0x80284014); + TPM_RC_map.insert("TBS_OWNER_AUTH_NOT_FOUND", 0x80284015); + map.insert(std::any::TypeId::of::(), TPM_RC_map); + + let mut TPM_CLOCK_ADJUST_map: HashMap<&'static str, u64> = HashMap::new(); + TPM_CLOCK_ADJUST_map.insert("COARSE_SLOWER", 0xFFFFFFFD); + TPM_CLOCK_ADJUST_map.insert("MEDIUM_SLOWER", 0xFFFFFFFE); + TPM_CLOCK_ADJUST_map.insert("FINE_SLOWER", 0xFFFFFFFF); + TPM_CLOCK_ADJUST_map.insert("NO_CHANGE", 0x0); + TPM_CLOCK_ADJUST_map.insert("FINE_FASTER", 0x1); + TPM_CLOCK_ADJUST_map.insert("MEDIUM_FASTER", 0x2); + TPM_CLOCK_ADJUST_map.insert("COARSE_FASTER", 0x3); + map.insert(std::any::TypeId::of::(), TPM_CLOCK_ADJUST_map); + + let mut TPM_EO_map: HashMap<&'static str, u64> = HashMap::new(); + TPM_EO_map.insert("EQ", 0x0); + TPM_EO_map.insert("NEQ", 0x1); + TPM_EO_map.insert("SIGNED_GT", 0x2); + TPM_EO_map.insert("UNSIGNED_GT", 0x3); + TPM_EO_map.insert("SIGNED_LT", 0x4); + TPM_EO_map.insert("UNSIGNED_LT", 0x5); + TPM_EO_map.insert("SIGNED_GE", 0x6); + TPM_EO_map.insert("UNSIGNED_GE", 0x7); + TPM_EO_map.insert("SIGNED_LE", 0x8); + TPM_EO_map.insert("UNSIGNED_LE", 0x9); + TPM_EO_map.insert("BITSET", 0xA); + TPM_EO_map.insert("BITCLEAR", 0xB); + map.insert(std::any::TypeId::of::(), TPM_EO_map); + + let mut TPM_ST_map: HashMap<&'static str, u64> = HashMap::new(); + TPM_ST_map.insert("RSP_COMMAND", 0xC4); + TPM_ST_map.insert("NULL", 0x8000); + TPM_ST_map.insert("NO_SESSIONS", 0x8001); + TPM_ST_map.insert("SESSIONS", 0x8002); + TPM_ST_map.insert("ATTEST_NV", 0x8014); + TPM_ST_map.insert("ATTEST_COMMAND_AUDIT", 0x8015); + TPM_ST_map.insert("ATTEST_SESSION_AUDIT", 0x8016); + TPM_ST_map.insert("ATTEST_CERTIFY", 0x8017); + TPM_ST_map.insert("ATTEST_QUOTE", 0x8018); + TPM_ST_map.insert("ATTEST_TIME", 0x8019); + TPM_ST_map.insert("ATTEST_CREATION", 0x801A); + TPM_ST_map.insert("ATTEST_NV_DIGEST", 0x801C); + TPM_ST_map.insert("CREATION", 0x8021); + TPM_ST_map.insert("VERIFIED", 0x8022); + TPM_ST_map.insert("AUTH_SECRET", 0x8023); + TPM_ST_map.insert("HASHCHECK", 0x8024); + TPM_ST_map.insert("AUTH_SIGNED", 0x8025); + TPM_ST_map.insert("FU_MANIFEST", 0x8029); + map.insert(std::any::TypeId::of::(), TPM_ST_map); + + let mut TPM_SU_map: HashMap<&'static str, u64> = HashMap::new(); + TPM_SU_map.insert("CLEAR", 0x0); + TPM_SU_map.insert("STATE", 0x1); + map.insert(std::any::TypeId::of::(), TPM_SU_map); + + let mut TPM_SE_map: HashMap<&'static str, u64> = HashMap::new(); + TPM_SE_map.insert("HMAC", 0x0); + TPM_SE_map.insert("POLICY", 0x1); + TPM_SE_map.insert("TRIAL", 0x3); + map.insert(std::any::TypeId::of::(), TPM_SE_map); + + let mut TPM_CAP_map: HashMap<&'static str, u64> = HashMap::new(); + TPM_CAP_map.insert("FIRST", 0x0); + TPM_CAP_map.insert("ALGS", 0x0); + TPM_CAP_map.insert("HANDLES", 0x1); + TPM_CAP_map.insert("COMMANDS", 0x2); + TPM_CAP_map.insert("PP_COMMANDS", 0x3); + TPM_CAP_map.insert("AUDIT_COMMANDS", 0x4); + TPM_CAP_map.insert("PCRS", 0x5); + TPM_CAP_map.insert("TPM_PROPERTIES", 0x6); + TPM_CAP_map.insert("PCR_PROPERTIES", 0x7); + TPM_CAP_map.insert("ECC_CURVES", 0x8); + TPM_CAP_map.insert("AUTH_POLICIES", 0x9); + TPM_CAP_map.insert("ACT", 0xA); + TPM_CAP_map.insert("LAST", 0xA); + TPM_CAP_map.insert("VENDOR_PROPERTY", 0x100); + map.insert(std::any::TypeId::of::(), TPM_CAP_map); + + let mut TPM_PT_map: HashMap<&'static str, u64> = HashMap::new(); + TPM_PT_map.insert("NONE", 0x0); + TPM_PT_map.insert("PT_GROUP", 0x100); + TPM_PT_map.insert("PT_FIXED", 0x100); + TPM_PT_map.insert("FAMILY_INDICATOR", 0x100); + TPM_PT_map.insert("LEVEL", 0x101); + TPM_PT_map.insert("REVISION", 0x102); + TPM_PT_map.insert("DAY_OF_YEAR", 0x103); + TPM_PT_map.insert("YEAR", 0x104); + TPM_PT_map.insert("MANUFACTURER", 0x105); + TPM_PT_map.insert("VENDOR_STRING_1", 0x106); + TPM_PT_map.insert("VENDOR_STRING_2", 0x107); + TPM_PT_map.insert("VENDOR_STRING_3", 0x108); + TPM_PT_map.insert("VENDOR_STRING_4", 0x109); + TPM_PT_map.insert("VENDOR_TPM_TYPE", 0x10A); + TPM_PT_map.insert("FIRMWARE_VERSION_1", 0x10B); + TPM_PT_map.insert("FIRMWARE_VERSION_2", 0x10C); + TPM_PT_map.insert("INPUT_BUFFER", 0x10D); + TPM_PT_map.insert("HR_TRANSIENT_MIN", 0x10E); + TPM_PT_map.insert("HR_PERSISTENT_MIN", 0x10F); + TPM_PT_map.insert("HR_LOADED_MIN", 0x110); + TPM_PT_map.insert("ACTIVE_SESSIONS_MAX", 0x111); + TPM_PT_map.insert("PCR_COUNT", 0x112); + TPM_PT_map.insert("PCR_SELECT_MIN", 0x113); + TPM_PT_map.insert("CONTEXT_GAP_MAX", 0x114); + TPM_PT_map.insert("NV_COUNTERS_MAX", 0x116); + TPM_PT_map.insert("NV_INDEX_MAX", 0x117); + TPM_PT_map.insert("MEMORY", 0x118); + TPM_PT_map.insert("CLOCK_UPDATE", 0x119); + TPM_PT_map.insert("CONTEXT_HASH", 0x11A); + TPM_PT_map.insert("CONTEXT_SYM", 0x11B); + TPM_PT_map.insert("CONTEXT_SYM_SIZE", 0x11C); + TPM_PT_map.insert("ORDERLY_COUNT", 0x11D); + TPM_PT_map.insert("MAX_COMMAND_SIZE", 0x11E); + TPM_PT_map.insert("MAX_RESPONSE_SIZE", 0x11F); + TPM_PT_map.insert("MAX_DIGEST", 0x120); + TPM_PT_map.insert("MAX_OBJECT_CONTEXT", 0x121); + TPM_PT_map.insert("MAX_SESSION_CONTEXT", 0x122); + TPM_PT_map.insert("PS_FAMILY_INDICATOR", 0x123); + TPM_PT_map.insert("PS_LEVEL", 0x124); + TPM_PT_map.insert("PS_REVISION", 0x125); + TPM_PT_map.insert("PS_DAY_OF_YEAR", 0x126); + TPM_PT_map.insert("PS_YEAR", 0x127); + TPM_PT_map.insert("SPLIT_MAX", 0x128); + TPM_PT_map.insert("TOTAL_COMMANDS", 0x129); + TPM_PT_map.insert("LIBRARY_COMMANDS", 0x12A); + TPM_PT_map.insert("VENDOR_COMMANDS", 0x12B); + TPM_PT_map.insert("NV_BUFFER_MAX", 0x12C); + TPM_PT_map.insert("MODES", 0x12D); + TPM_PT_map.insert("MAX_CAP_BUFFER", 0x12E); + TPM_PT_map.insert("PT_VAR", 0x200); + TPM_PT_map.insert("PERMANENT", 0x200); + TPM_PT_map.insert("STARTUP_CLEAR", 0x201); + TPM_PT_map.insert("HR_NV_INDEX", 0x202); + TPM_PT_map.insert("HR_LOADED", 0x203); + TPM_PT_map.insert("HR_LOADED_AVAIL", 0x204); + TPM_PT_map.insert("HR_ACTIVE", 0x205); + TPM_PT_map.insert("HR_ACTIVE_AVAIL", 0x206); + TPM_PT_map.insert("HR_TRANSIENT_AVAIL", 0x207); + TPM_PT_map.insert("HR_PERSISTENT", 0x208); + TPM_PT_map.insert("HR_PERSISTENT_AVAIL", 0x209); + TPM_PT_map.insert("NV_COUNTERS", 0x20A); + TPM_PT_map.insert("NV_COUNTERS_AVAIL", 0x20B); + TPM_PT_map.insert("ALGORITHM_SET", 0x20C); + TPM_PT_map.insert("LOADED_CURVES", 0x20D); + TPM_PT_map.insert("LOCKOUT_COUNTER", 0x20E); + TPM_PT_map.insert("MAX_AUTH_FAIL", 0x20F); + TPM_PT_map.insert("LOCKOUT_INTERVAL", 0x210); + TPM_PT_map.insert("LOCKOUT_RECOVERY", 0x211); + TPM_PT_map.insert("NV_WRITE_RECOVERY", 0x212); + TPM_PT_map.insert("AUDIT_COUNTER_0", 0x213); + TPM_PT_map.insert("AUDIT_COUNTER_1", 0x214); + map.insert(std::any::TypeId::of::(), TPM_PT_map); + + let mut TPM_PT_PCR_map: HashMap<&'static str, u64> = HashMap::new(); + TPM_PT_PCR_map.insert("FIRST", 0x0); + TPM_PT_PCR_map.insert("SAVE", 0x0); + TPM_PT_PCR_map.insert("EXTEND_L0", 0x1); + TPM_PT_PCR_map.insert("RESET_L0", 0x2); + TPM_PT_PCR_map.insert("EXTEND_L1", 0x3); + TPM_PT_PCR_map.insert("RESET_L1", 0x4); + TPM_PT_PCR_map.insert("EXTEND_L2", 0x5); + TPM_PT_PCR_map.insert("RESET_L2", 0x6); + TPM_PT_PCR_map.insert("EXTEND_L3", 0x7); + TPM_PT_PCR_map.insert("RESET_L3", 0x8); + TPM_PT_PCR_map.insert("EXTEND_L4", 0x9); + TPM_PT_PCR_map.insert("RESET_L4", 0xA); + TPM_PT_PCR_map.insert("NO_INCREMENT", 0x11); + TPM_PT_PCR_map.insert("DRTM_RESET", 0x12); + TPM_PT_PCR_map.insert("POLICY", 0x13); + TPM_PT_PCR_map.insert("AUTH", 0x14); + TPM_PT_PCR_map.insert("LAST", 0x14); + map.insert(std::any::TypeId::of::(), TPM_PT_PCR_map); + + let mut TPM_PS_map: HashMap<&'static str, u64> = HashMap::new(); + TPM_PS_map.insert("MAIN", 0x0); + TPM_PS_map.insert("PC", 0x1); + TPM_PS_map.insert("PDA", 0x2); + TPM_PS_map.insert("CELL_PHONE", 0x3); + TPM_PS_map.insert("SERVER", 0x4); + TPM_PS_map.insert("PERIPHERAL", 0x5); + TPM_PS_map.insert("TSS", 0x6); + TPM_PS_map.insert("STORAGE", 0x7); + TPM_PS_map.insert("AUTHENTICATION", 0x8); + TPM_PS_map.insert("EMBEDDED", 0x9); + TPM_PS_map.insert("HARDCOPY", 0xA); + TPM_PS_map.insert("INFRASTRUCTURE", 0xB); + TPM_PS_map.insert("VIRTUALIZATION", 0xC); + TPM_PS_map.insert("TNC", 0xD); + TPM_PS_map.insert("MULTI_TENANT", 0xE); + TPM_PS_map.insert("TC", 0xF); + map.insert(std::any::TypeId::of::(), TPM_PS_map); + + let mut TPM_HT_map: HashMap<&'static str, u64> = HashMap::new(); + TPM_HT_map.insert("PCR", 0x0); + TPM_HT_map.insert("NV_INDEX", 0x1); + TPM_HT_map.insert("HMAC_SESSION", 0x2); + TPM_HT_map.insert("LOADED_SESSION", 0x2); + TPM_HT_map.insert("POLICY_SESSION", 0x3); + TPM_HT_map.insert("SAVED_SESSION", 0x3); + TPM_HT_map.insert("PERMANENT", 0x40); + TPM_HT_map.insert("TRANSIENT", 0x80); + TPM_HT_map.insert("PERSISTENT", 0x81); + TPM_HT_map.insert("AC", 0x90); + map.insert(std::any::TypeId::of::(), TPM_HT_map); + + let mut TPM_RH_map: HashMap<&'static str, u64> = HashMap::new(); + TPM_RH_map.insert("FIRST", 0x40000000); + TPM_RH_map.insert("SRK", 0x40000000); + TPM_RH_map.insert("OWNER", 0x40000001); + TPM_RH_map.insert("REVOKE", 0x40000002); + TPM_RH_map.insert("TRANSPORT", 0x40000003); + TPM_RH_map.insert("OPERATOR", 0x40000004); + TPM_RH_map.insert("ADMIN", 0x40000005); + TPM_RH_map.insert("EK", 0x40000006); + TPM_RH_map.insert("NULL", 0x40000007); + TPM_RH_map.insert("UNASSIGNED", 0x40000008); + TPM_RH_map.insert("PW", 0x40000009); + TPM_RH_map.insert("LOCKOUT", 0x4000000A); + TPM_RH_map.insert("ENDORSEMENT", 0x4000000B); + TPM_RH_map.insert("PLATFORM", 0x4000000C); + TPM_RH_map.insert("PLATFORM_NV", 0x4000000D); + TPM_RH_map.insert("AUTH_00", 0x40000010); + TPM_RH_map.insert("AUTH_FF", 0x4000010F); + TPM_RH_map.insert("ACT_0", 0x40000110); + TPM_RH_map.insert("ACT_F", 0x4000011F); + TPM_RH_map.insert("LAST", 0x4000011F); + map.insert(std::any::TypeId::of::(), TPM_RH_map); + + let mut TPM_NT_map: HashMap<&'static str, u64> = HashMap::new(); + TPM_NT_map.insert("ORDINARY", 0x0); + TPM_NT_map.insert("COUNTER", 0x1); + TPM_NT_map.insert("BITS", 0x2); + TPM_NT_map.insert("EXTEND", 0x4); + TPM_NT_map.insert("PIN_FAIL", 0x8); + TPM_NT_map.insert("PIN_PASS", 0x9); + map.insert(std::any::TypeId::of::(), TPM_NT_map); + + let mut TPM_AT_map: HashMap<&'static str, u64> = HashMap::new(); + TPM_AT_map.insert("ANY", 0x0); + TPM_AT_map.insert("ERROR", 0x1); + TPM_AT_map.insert("PV1", 0x2); + TPM_AT_map.insert("VEND", 0x80000000); + map.insert(std::any::TypeId::of::(), TPM_AT_map); + + let mut TPM_AE_map: HashMap<&'static str, u64> = HashMap::new(); + TPM_AE_map.insert("NONE", 0x0); + map.insert(std::any::TypeId::of::(), TPM_AE_map); + + let mut PLATFORM_map: HashMap<&'static str, u64> = HashMap::new(); + PLATFORM_map.insert("FAMILY", 0x322E3000); + PLATFORM_map.insert("LEVEL", 0x0); + PLATFORM_map.insert("VERSION", 0xA2); + PLATFORM_map.insert("YEAR", 0x7E3); + PLATFORM_map.insert("DAY_OF_YEAR", 0x168); + map.insert(std::any::TypeId::of::(), PLATFORM_map); + + let mut Implementation_map: HashMap<&'static str, u64> = HashMap::new(); + Implementation_map.insert("FIELD_UPGRADE_IMPLEMENTED", 0x0); + Implementation_map.insert("HASH_LIB", 0x1); + Implementation_map.insert("SYM_LIB", 0x1); + Implementation_map.insert("MATH_LIB", 0x1); + Implementation_map.insert("IMPLEMENTATION_PCR", 0x18); + Implementation_map.insert("PCR_SELECT_MAX", 0x3); + Implementation_map.insert("PLATFORM_PCR", 0x18); + Implementation_map.insert("PCR_SELECT_MIN", 0x3); + Implementation_map.insert("DRTM_PCR", 0x11); + Implementation_map.insert("HCRTM_PCR", 0x0); + Implementation_map.insert("NUM_LOCALITIES", 0x5); + Implementation_map.insert("MAX_HANDLE_NUM", 0x3); + Implementation_map.insert("MAX_ACTIVE_SESSIONS", 0x40); + Implementation_map.insert("MAX_LOADED_SESSIONS", 0x3); + Implementation_map.insert("MAX_SESSION_NUM", 0x3); + Implementation_map.insert("MAX_LOADED_OBJECTS", 0x3); + Implementation_map.insert("MIN_EVICT_OBJECTS", 0x2); + Implementation_map.insert("NUM_POLICY_PCR_GROUP", 0x1); + Implementation_map.insert("NUM_AUTHVALUE_PCR_GROUP", 0x1); + Implementation_map.insert("MAX_CONTEXT_SIZE", 0x4F0); + Implementation_map.insert("MAX_DIGEST_BUFFER", 0x400); + Implementation_map.insert("MAX_NV_INDEX_SIZE", 0x800); + Implementation_map.insert("MAX_NV_BUFFER_SIZE", 0x400); + Implementation_map.insert("MAX_CAP_BUFFER", 0x400); + Implementation_map.insert("NV_MEMORY_SIZE", 0x4000); + Implementation_map.insert("MIN_COUNTER_INDICES", 0x8); + Implementation_map.insert("NUM_STATIC_PCR", 0x10); + Implementation_map.insert("MAX_ALG_LIST_SIZE", 0x40); + Implementation_map.insert("PRIMARY_SEED_SIZE", 0x20); + Implementation_map.insert("CONTEXT_ENCRYPT_ALGORITHM", 0x6); + Implementation_map.insert("NV_CLOCK_UPDATE_INTERVAL", 0xC); + Implementation_map.insert("NUM_POLICY_PCR", 0x1); + Implementation_map.insert("MAX_COMMAND_SIZE", 0x1000); + Implementation_map.insert("MAX_RESPONSE_SIZE", 0x1000); + Implementation_map.insert("ORDERLY_BITS", 0x8); + Implementation_map.insert("MAX_SYM_DATA", 0x80); + Implementation_map.insert("MAX_RNG_ENTROPY_SIZE", 0x40); + Implementation_map.insert("RAM_INDEX_SPACE", 0x200); + Implementation_map.insert("RSA_DEFAULT_PUBLIC_EXPONENT", 0x10001); + Implementation_map.insert("ENABLE_PCR_NO_INCREMENT", 0x1); + Implementation_map.insert("CRT_FORMAT_RSA", 0x1); + Implementation_map.insert("VENDOR_COMMAND_COUNT", 0x0); + Implementation_map.insert("MAX_VENDOR_BUFFER_SIZE", 0x400); + Implementation_map.insert("MAX_DERIVATION_BITS", 0x2000); + Implementation_map.insert("RSA_MAX_PRIME", 0x80); + Implementation_map.insert("RSA_PRIVATE_SIZE", 0x280); + Implementation_map.insert("SIZE_OF_X509_SERIAL_NUMBER", 0x14); + Implementation_map.insert("PRIVATE_VENDOR_SPECIFIC_BYTES", 0x280); + map.insert(std::any::TypeId::of::(), Implementation_map); + + let mut TPM_HC_map: HashMap<&'static str, u64> = HashMap::new(); + TPM_HC_map.insert("HR_HANDLE_MASK", 0xFFFFFF); + TPM_HC_map.insert("HR_RANGE_MASK", 0xFF000000); + TPM_HC_map.insert("HR_SHIFT", 0x18); + TPM_HC_map.insert("HR_PCR", 0x0); + TPM_HC_map.insert("HR_HMAC_SESSION", 0x2000000); + TPM_HC_map.insert("HR_POLICY_SESSION", 0x3000000); + TPM_HC_map.insert("HR_TRANSIENT", 0x80000000); + TPM_HC_map.insert("HR_PERSISTENT", 0x81000000); + TPM_HC_map.insert("HR_NV_INDEX", 0x1000000); + TPM_HC_map.insert("HR_PERMANENT", 0x40000000); + TPM_HC_map.insert("PCR_FIRST", 0x0); + TPM_HC_map.insert("PCR_LAST", 0x17); + TPM_HC_map.insert("HMAC_SESSION_FIRST", 0x2000000); + TPM_HC_map.insert("HMAC_SESSION_LAST", 0x200003F); + TPM_HC_map.insert("LOADED_SESSION_FIRST", 0x2000000); + TPM_HC_map.insert("LOADED_SESSION_LAST", 0x200003F); + TPM_HC_map.insert("POLICY_SESSION_FIRST", 0x3000000); + TPM_HC_map.insert("POLICY_SESSION_LAST", 0x300003F); + TPM_HC_map.insert("TRANSIENT_FIRST", 0x80000000); + TPM_HC_map.insert("ACTIVE_SESSION_FIRST", 0x3000000); + TPM_HC_map.insert("ACTIVE_SESSION_LAST", 0x300003F); + TPM_HC_map.insert("TRANSIENT_LAST", 0x80000002); + TPM_HC_map.insert("PERSISTENT_FIRST", 0x81000000); + TPM_HC_map.insert("PERSISTENT_LAST", 0x81FFFFFF); + TPM_HC_map.insert("PLATFORM_PERSISTENT", 0x81800000); + TPM_HC_map.insert("NV_INDEX_FIRST", 0x1000000); + TPM_HC_map.insert("NV_INDEX_LAST", 0x1FFFFFF); + TPM_HC_map.insert("PERMANENT_FIRST", 0x40000000); + TPM_HC_map.insert("PERMANENT_LAST", 0x4000011F); + TPM_HC_map.insert("HR_NV_AC", 0x1D00000); + TPM_HC_map.insert("NV_AC_FIRST", 0x1D00000); + TPM_HC_map.insert("NV_AC_LAST", 0x1D0FFFF); + TPM_HC_map.insert("HR_AC", 0x90000000); + TPM_HC_map.insert("AC_FIRST", 0x90000000); + TPM_HC_map.insert("AC_LAST", 0x9000FFFF); + map.insert(std::any::TypeId::of::(), TPM_HC_map); + + let mut TPMA_ALGORITHM_map: HashMap<&'static str, u64> = HashMap::new(); + TPMA_ALGORITHM_map.insert("asymmetric", 0x1); + TPMA_ALGORITHM_map.insert("symmetric", 0x2); + TPMA_ALGORITHM_map.insert("hash", 0x4); + TPMA_ALGORITHM_map.insert("object", 0x8); + TPMA_ALGORITHM_map.insert("signing", 0x100); + TPMA_ALGORITHM_map.insert("encrypting", 0x200); + TPMA_ALGORITHM_map.insert("method", 0x400); + map.insert(std::any::TypeId::of::(), TPMA_ALGORITHM_map); + + let mut TPMA_OBJECT_map: HashMap<&'static str, u64> = HashMap::new(); + TPMA_OBJECT_map.insert("fixedTPM", 0x2); + TPMA_OBJECT_map.insert("stClear", 0x4); + TPMA_OBJECT_map.insert("fixedParent", 0x10); + TPMA_OBJECT_map.insert("sensitiveDataOrigin", 0x20); + TPMA_OBJECT_map.insert("userWithAuth", 0x40); + TPMA_OBJECT_map.insert("adminWithPolicy", 0x80); + TPMA_OBJECT_map.insert("noDA", 0x400); + TPMA_OBJECT_map.insert("encryptedDuplication", 0x800); + TPMA_OBJECT_map.insert("restricted", 0x10000); + TPMA_OBJECT_map.insert("decrypt", 0x20000); + TPMA_OBJECT_map.insert("sign", 0x40000); + TPMA_OBJECT_map.insert("encrypt", 0x40000); + TPMA_OBJECT_map.insert("x509sign", 0x80000); + map.insert(std::any::TypeId::of::(), TPMA_OBJECT_map); + + let mut TPMA_SESSION_map: HashMap<&'static str, u64> = HashMap::new(); + TPMA_SESSION_map.insert("continueSession", 0x1); + TPMA_SESSION_map.insert("auditExclusive", 0x2); + TPMA_SESSION_map.insert("auditReset", 0x4); + TPMA_SESSION_map.insert("decrypt", 0x20); + TPMA_SESSION_map.insert("encrypt", 0x40); + TPMA_SESSION_map.insert("audit", 0x80); + map.insert(std::any::TypeId::of::(), TPMA_SESSION_map); + + let mut TPMA_LOCALITY_map: HashMap<&'static str, u64> = HashMap::new(); + TPMA_LOCALITY_map.insert("LOC_ZERO", 0x1); + TPMA_LOCALITY_map.insert("LOC_ONE", 0x2); + TPMA_LOCALITY_map.insert("LOC_TWO", 0x4); + TPMA_LOCALITY_map.insert("LOC_THREE", 0x8); + TPMA_LOCALITY_map.insert("LOC_FOUR", 0x10); + map.insert(std::any::TypeId::of::(), TPMA_LOCALITY_map); + + let mut TPMA_PERMANENT_map: HashMap<&'static str, u64> = HashMap::new(); + TPMA_PERMANENT_map.insert("ownerAuthSet", 0x1); + TPMA_PERMANENT_map.insert("endorsementAuthSet", 0x2); + TPMA_PERMANENT_map.insert("lockoutAuthSet", 0x4); + TPMA_PERMANENT_map.insert("disableClear", 0x100); + TPMA_PERMANENT_map.insert("inLockout", 0x200); + TPMA_PERMANENT_map.insert("tpmGeneratedEPS", 0x400); + map.insert(std::any::TypeId::of::(), TPMA_PERMANENT_map); + + let mut TPMA_STARTUP_CLEAR_map: HashMap<&'static str, u64> = HashMap::new(); + TPMA_STARTUP_CLEAR_map.insert("phEnable", 0x1); + TPMA_STARTUP_CLEAR_map.insert("shEnable", 0x2); + TPMA_STARTUP_CLEAR_map.insert("ehEnable", 0x4); + TPMA_STARTUP_CLEAR_map.insert("phEnableNV", 0x8); + TPMA_STARTUP_CLEAR_map.insert("orderly", 0x80000000); + map.insert(std::any::TypeId::of::(), TPMA_STARTUP_CLEAR_map); + + let mut TPMA_MEMORY_map: HashMap<&'static str, u64> = HashMap::new(); + TPMA_MEMORY_map.insert("sharedRAM", 0x1); + TPMA_MEMORY_map.insert("sharedNV", 0x2); + TPMA_MEMORY_map.insert("objectCopiedToRam", 0x4); + map.insert(std::any::TypeId::of::(), TPMA_MEMORY_map); + + let mut TPMA_CC_map: HashMap<&'static str, u64> = HashMap::new(); + TPMA_CC_map.insert("nv", 0x400000); + TPMA_CC_map.insert("extensive", 0x800000); + TPMA_CC_map.insert("flushed", 0x1000000); + TPMA_CC_map.insert("rHandle", 0x10000000); + TPMA_CC_map.insert("V", 0x20000000); + map.insert(std::any::TypeId::of::(), TPMA_CC_map); + + let mut TPMA_MODES_map: HashMap<&'static str, u64> = HashMap::new(); + TPMA_MODES_map.insert("FIPS_140_2", 0x1); + map.insert(std::any::TypeId::of::(), TPMA_MODES_map); + + let mut TPMA_X509_KEY_USAGE_map: HashMap<&'static str, u64> = HashMap::new(); + TPMA_X509_KEY_USAGE_map.insert("decipherOnly", 0x800000); + TPMA_X509_KEY_USAGE_map.insert("encipherOnly", 0x1000000); + TPMA_X509_KEY_USAGE_map.insert("cRLSign", 0x2000000); + TPMA_X509_KEY_USAGE_map.insert("keyCertSign", 0x4000000); + TPMA_X509_KEY_USAGE_map.insert("keyAgreement", 0x8000000); + TPMA_X509_KEY_USAGE_map.insert("dataEncipherment", 0x10000000); + TPMA_X509_KEY_USAGE_map.insert("keyEncipherment", 0x20000000); + TPMA_X509_KEY_USAGE_map.insert("nonrepudiation", 0x40000000); + TPMA_X509_KEY_USAGE_map.insert("contentCommitment", 0x40000000); + TPMA_X509_KEY_USAGE_map.insert("digitalSignature", 0x80000000); + map.insert(std::any::TypeId::of::(), TPMA_X509_KEY_USAGE_map); + + let mut TPMA_ACT_map: HashMap<&'static str, u64> = HashMap::new(); + TPMA_ACT_map.insert("signaled", 0x1); + TPMA_ACT_map.insert("preserveSignaled", 0x2); + map.insert(std::any::TypeId::of::(), TPMA_ACT_map); + + let TPM_NV_INDEX_map: HashMap<&'static str, u64> = HashMap::new(); + map.insert(std::any::TypeId::of::(), TPM_NV_INDEX_map); + + let mut TPMA_NV_map: HashMap<&'static str, u64> = HashMap::new(); + TPMA_NV_map.insert("PPWRITE", 0x1); + TPMA_NV_map.insert("OWNERWRITE", 0x2); + TPMA_NV_map.insert("AUTHWRITE", 0x4); + TPMA_NV_map.insert("POLICYWRITE", 0x8); + TPMA_NV_map.insert("ORDINARY", 0x0); + TPMA_NV_map.insert("COUNTER", 0x10); + TPMA_NV_map.insert("BITS", 0x20); + TPMA_NV_map.insert("EXTEND", 0x40); + TPMA_NV_map.insert("PIN_FAIL", 0x80); + TPMA_NV_map.insert("PIN_PASS", 0x90); + TPMA_NV_map.insert("POLICY_DELETE", 0x400); + TPMA_NV_map.insert("WRITELOCKED", 0x800); + TPMA_NV_map.insert("WRITEALL", 0x1000); + TPMA_NV_map.insert("WRITEDEFINE", 0x2000); + TPMA_NV_map.insert("WRITE_STCLEAR", 0x4000); + TPMA_NV_map.insert("GLOBALLOCK", 0x8000); + TPMA_NV_map.insert("PPREAD", 0x10000); + TPMA_NV_map.insert("OWNERREAD", 0x20000); + TPMA_NV_map.insert("AUTHREAD", 0x40000); + TPMA_NV_map.insert("POLICYREAD", 0x80000); + TPMA_NV_map.insert("NO_DA", 0x2000000); + TPMA_NV_map.insert("ORDERLY", 0x4000000); + TPMA_NV_map.insert("CLEAR_STCLEAR", 0x8000000); + TPMA_NV_map.insert("READLOCKED", 0x10000000); + TPMA_NV_map.insert("WRITTEN", 0x20000000); + TPMA_NV_map.insert("PLATFORMCREATE", 0x40000000); + TPMA_NV_map.insert("READ_STCLEAR", 0x80000000); + map.insert(std::any::TypeId::of::(), TPMA_NV_map); + + map + }; + +} + diff --git a/TssCodeGen/README.md b/TssCodeGen/README.md index 8c389b89..fcbc3c55 100644 --- a/TssCodeGen/README.md +++ b/TssCodeGen/README.md @@ -3,7 +3,7 @@ # Purpose -This is the tool that automatically (re)generates the interface part of the TPM Software Stack (TSS) implementations for all supported programming languages/frameworks ([.Net][TSS.Net], [C++][TSS.CPP], [Java][TSS.Java], [Node.js][TSS.JS], [Python][TSS.Py]) based on the TCG's [TPM 2.0 specification] documents. +This is the tool that automatically (re)generates the interface part of the TPM Software Stack (TSS) implementations for all supported programming languages/frameworks ([.Net][TSS.Net], [C++][TSS.CPP], [Rust][TSS.Rust], [Java][TSS.Java], [Node.js][TSS.JS], [Python][TSS.Py]) based on the TCG's [TPM 2.0 specification] documents. Auto-generated code includes the following components of the TPM 2.0 interface: * constants (represented as enums); @@ -18,7 +18,7 @@ Auto-generated code includes the following components of the TPM 2.0 interface: When built and run in-place from a Visual Studio with no command line options provided, the tool will pick the TPM 2.0 specification data from the [TpmSpec](./TpmSpec) directory, and update TSS for all supported languages in this repo clone. -If the tool is used from a directory different from the one used by the Visual Studio build, you may need to use command line options to specify the location of the TPM 2.0 specification documents (`-spec`) and the target TSS implementations (`-dest`). You can also specify a subset of target TSS programming languages to update using a combination of options `-dotNet`, `-cpp`, `-java`, `-node`, `-py`. +If the tool is used from a directory different from the one used by the Visual Studio build, you may need to use command line options to specify the location of the TPM 2.0 specification documents (`-spec`) and the target TSS implementations (`-dest`). You can also specify a subset of target TSS programming languages to update using a combination of options `-dotNet`, `-cpp`, `-java`, `-node`, `-py`, `-rust`. Run the tool with the `-help` option to get more detailed information about its command line options. @@ -69,7 +69,7 @@ The tool works in three phases: 3) Code generation phase. - A specialized class for each of the target program language ([CGenDotNet](./src/CGenDotNet.cs), [CGenCpp](./src/CGenCpp.cs), [CGenJava](./src/CGenJava.cs), [CGenNode](./src/CGenNode.cs), [CGenPy](./src/CGenPy.cs)) produces the code based on the AST representation. + A specialized class for each of the target program language ([CGenDotNet](./src/CGenDotNet.cs), [CGenCpp](./src/CGenCpp.cs), [CGenRust](./src/CGenRust.cs), [CGenJava](./src/CGenJava.cs), [CGenNode](./src/CGenNode.cs), [CGenPy](./src/CGenPy.cs)) produces the code based on the AST representation. ## *Abstract Syntax Tree (AST) classes* @@ -155,7 +155,7 @@ The `CodeGenBase.Generate()` method implements the same generic workflow for all * TPM union factory implementation from the collection of the `UnionMember` and realted `UnionMember` instances. - Union factory is used to instantiate the correct union member (class implementing the given union interface) based on the union type and selector (tag) value. This is necessary while unmarshaling TPM structures with fields of a union type. * Class definitions from all `TpmStruct` instances. This includes field definitions, constructors, marshaling methods (except for [TSS.Net]), and on case-by-case basis additional interface methods. - - The set of automatically generated methods for a few TPM 2.0 structures is extended with custom additions via .snips files ([C++](../TSS.CPP/Src/TpmExtensions.cpp.snips), [Java](../TSS.Java/src/TpmExtensions.java.snips), [Node.js](../TSS.JS/src/TpmExtensions.js.snips), [Python](../TSS.Py/src/TpmExtensions.py.snips)). Snippet files contain fragments of the code that are appended to the auto-generated classes (class declarations in the case of C++) without any additional translations. Note that [TSS.Net] does not use this mechanism, as it custmizes its auto-generated classes using *partial classes* syntax. + - The set of automatically generated methods for a few TPM 2.0 structures is extended with custom additions via .snips files ([C++](../TSS.CPP/Src/TpmExtensions.cpp.snips), [Rust](../TSS.Rust/src/tpm_extensions.rs.snips), [Java](../TSS.Java/src/TpmExtensions.java.snips), [Node.js](../TSS.JS/src/TpmExtensions.js.snips), [Python](../TSS.Py/src/TpmExtensions.py.snips)). Snippet files contain fragments of the code that are appended to the auto-generated classes (class declarations in the case of C++) without any additional translations. Note that [TSS.Net] does not use this mechanism, as it custmizes its auto-generated classes using *partial classes* syntax. * TPM command definitions from the select `TpmStruct` instances representing command and response parameters. .Net code generator additionally creates a static class with marshaling metadata `CommandInformation`, and for C++ two maps for enum-to-string and string-to-enum conversions (`Enum2StrMap` and `Str2EnumMap`) are generated. @@ -166,12 +166,14 @@ Generated code is accumulated in an internal buffer and then is written out to a * [TSS.CPP] follows [TSS.JS]/[TSS.Py] in splitting the TPM data type and command *declarations* between two header files ([TpmTypes.h](../TSS.CPP/include/TpmTypes.h) and [Tpm2.h](../TSS.CPP/include/Tpm2.h)). Yet it additionally creates the third source file for the *definitions* of marshaling methods, union factory and enum names conversion maps ([TpmTypes.cpp](../TSS.CPP/Src/TpmTypes.cpp)). - Note also that in contrast to other languages the C++ output sources are not completely (re)created by the code generator, but are rather *updated* by means of replacing their sections marked by the `<>` comment with the new auto-generated code. * [TSS.Net] places all auto-generated definitions in the single source file ([X_TpmDefs.cs](../TSS.NET/TSS.NET/X_TpmDefs.cs)). +* [TSS.Rust] keeps all TPM data types in [tpm_types.rs](../TSS.Rust/src/tpm_types.rs) and TPM command definitions in [tpm2.rs](../TSS.Rust/src/tpm2.rs), similar to [TSS.JS]/[TSS.Py]. Rust unions are represented as enums with tuple variants. * Java keeps each definition in its own [separate source file](../TSS.Java/src/tss/tpm), plus [Tpm.java](../TSS.Java/src/tss/Tpm.java) for TPM command definitions. [TSS.Net]: ../TSS.NET [TSS.CPP]: ../TSS.CPP +[TSS.Rust]: ../TSS.Rust [TSS.Java]: ../TSS.Java [TSS.JS]: ../TSS.JS [TSS.Py]: ../TSS.Py diff --git a/TssCodeGen/src/CGenJava.cs b/TssCodeGen/src/CGenJava.cs index d04628f8..8a6b822a 100644 --- a/TssCodeGen/src/CGenJava.cs +++ b/TssCodeGen/src/CGenJava.cs @@ -69,7 +69,7 @@ internal static bool ConflictingEnumMember(string name, string typeName) /// Constants and bitfields are represented as classes derived /// from TpmEnum, and TpmAttribute correspondingly in Java - void GenEnum(TpmType e, List elements, int wireSize) + void GenEnum(TpmType e, List elements, long wireSize) { needsUtil = true; // Collection needs java.util.* diff --git a/TssCodeGen/src/CGenRust.cs b/TssCodeGen/src/CGenRust.cs new file mode 100644 index 00000000..7c681bdf --- /dev/null +++ b/TssCodeGen/src/CGenRust.cs @@ -0,0 +1,1064 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See the LICENSE file in the project root for full license information. + */ + +using System; +using System.Diagnostics; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; + +namespace CodeGen +{ + /// Rust TSS code generator + internal class CGenRust : CodeGenBase + { + static readonly (string, string)[] TpmStructureFunctions = new (string, string)[] { + ("serialize", "(&self, buffer: &mut TpmBuffer)"), + ("deserialize", "(&mut self, buffer: &mut TpmBuffer)"), + ("fromTpm", "(&self, buffer: &mut TpmBuffer)"), + ("fromBytes", "(&mut self, buffer: &mut Vec)"), + }; + + // Maps enum type to a map of enumerator names to values + Dictionary> EnumMap; + + public CGenRust(string rootDir) : base(rootDir, @"src\tpm_extensions.rs.snips") { } + + internal override void Generate() + { + EnumMap = new Dictionary>(); + + GenerateTpmTypesRs(); + UpdateExistingSource(@"src\tpm_types.rs"); + + GenerateTpmCommandPrototypes(); + UpdateExistingSource(@"src\tpm2.rs"); + } + + /// Determines whether this struct is represented as a type alias in Rust + static bool IsTypedefStruct(TpmStruct s) + { + return s.DerivedFrom != null && s.ContainingUnions.Count == 0; + } + + static string ParamForField(StructField f) { + if (f.IsArray() || !f.IsValueType()) + { + return $"&{TransType(f)}"; + } + else + { + return TransType(f); + } + } + + static string TransType(StructField f) + { + string typeName = f.TypeName; + + // Handle union object types + if (f.MarshalType == MarshalType.UnionObject) + { + return $"Option<{ToRustName(typeName)}>"; + } + + // Handle types with generics (containers like Vec, Option, etc.) + if (typeName.Contains("<") && typeName.Contains(">")) + { + int openBracketIndex = typeName.IndexOf('<'); + int closeBracketIndex = typeName.LastIndexOf('>'); + + string baseType = typeName.Substring(0, openBracketIndex); + string genericParams = typeName.Substring(openBracketIndex + 1, closeBracketIndex - openBracketIndex - 1); + + return $"{baseType}<{ToRustName(genericParams)}>"; + } + + // Standard type conversion + return ToRustName(typeName); + } + + string GetCommandReturnType(CommandFlavor gen, TpmStruct resp, string methodName, + out string returnFieldName) + { + returnFieldName = null; + if (gen == CommandFlavor.AsyncCommand) + return "Result<(), TpmError>"; + + string returnType = "Result<(), TpmError>"; + var respFields = resp.NonTagFields; + if (ForceJustOneReturnParm.Contains(methodName)) + { + respFields = respFields.Take(1).ToArray(); + } + + if (respFields.Count() > 1) + return $"Result<{resp.Name}, TpmError>"; + + if (respFields.Count() == 1) + { + returnFieldName = respFields[0].Name; + returnType = $"Result<{TransType(respFields[0])}, TpmError>"; + } + return returnType; + } + + void GenerateTpmTypesRs() + { + // Generate the enums, bitfields, unions, and structs + foreach (var e in TpmTypes.Get()) + GenEnum(e); + + foreach (var bf in TpmTypes.Get()) + GenBitfield(bf); + + foreach (var u in TpmTypes.Get()) + GenUnion(u); + + foreach (var s in TpmTypes.Get()) + GenStructDecl(s); + + // Generate the enum maps + GenEnumMap(); + } + + /// + /// Checks if an enum has duplicate values among its elements + /// + private bool HasDuplicateValues(List elements) + { + HashSet values = new HashSet(); + foreach (var element in elements) + { + if (!values.Add(element.NumericValue)) + { + return true; // Found a duplicate + } + } + return false; + } + + void GenEnum(TpmType e, List elements) + { + WriteComment(e); + + var enumVals = new Dictionary(); + + var enumUnderlyingType = e.GetFinalUnderlyingType(); + var sizeInBits = enumUnderlyingType.GetSize() * 8; + var enumUnderlyingTypeName = enumUnderlyingType.Name; + var enumUnderlyingTypeSigned = enumUnderlyingTypeName.StartsWith("i") ? true : false; + + // Generate a newtype struct with constants for enums with duplicates + Write($"#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]"); + Write($"pub struct {e.Name}(pub {enumUnderlyingTypeName});"); + Write(""); + + // Generate constants for each enum value + TabIn($"impl {e.Name} {{"); + + foreach (var elt in elements) + { + WriteComment(AsSummary(elt.Comment)); + var enumValue = ToRustEnumValue(elt, sizeInBits, enumUnderlyingTypeSigned); + var enumHexValue = enumUnderlyingTypeSigned ? enumValue.ToString() : ToHex(enumValue); + var originalValueComment = ""; + if (enumHexValue != elt.Value) + { + originalValueComment = $" // Original value: {elt.Value}"; + } + + Write($"pub const {elt.Name}: Self = Self({enumHexValue});{originalValueComment}"); + + // Do not include artificially added named constants into the name conversion maps + if (elt.SpecName != null) + enumVals[elt.Name] = e is TpmEnum ? ToHex(elt.NumericValue) : elt.Value; + } + + // Add TryFrom implementation for the newtype struct + Write(""); + TabIn($"pub fn try_from(value: {enumUnderlyingTypeName}) -> Result {{"); + TabIn("match value {"); + foreach (var elt in elements.GroupBy(x => x.NumericValue).Select(g => g.Last())) + { + var enumValue = ToRustEnumValue(elt, sizeInBits, enumUnderlyingTypeSigned); + + // Only include first occurrence of each value to avoid duplicate match arms + Write($"{enumValue} => Ok(Self::{elt.Name}), // Original value: {elt.Value}"); + } + Write("_ => Err(TpmError::InvalidEnumValue),"); + TabOut("}", false); + TabOut("}", false); + + TabOut("}"); + Write(""); + + // Implement TpmEnum trait for the struct + TabIn($"impl TpmEnum<{enumUnderlyingTypeName}> for {e.Name} {{"); + TabIn($"fn get_value(&self) -> {enumUnderlyingTypeName} {{"); + Write("self.0.into()"); + TabOut("}"); + TabIn("fn try_from_trait(value: u64) -> Result where Self: Sized {"); + Write($"{e.Name}::try_from(value as {enumUnderlyingTypeName})"); + TabOut("}"); + TabIn("fn new_from_trait(value: u64) -> Result where Self: Sized {"); + Write($"Ok({e.Name}(value as {enumUnderlyingTypeName}))"); + TabOut("}", false); + TabOut("}"); + Write(""); + + // Add numeric conversions + TabIn($"impl From<{e.Name}> for u{sizeInBits} {{"); + TabIn($"fn from(value: {e.Name}) -> Self {{"); + Write($"value.0 as u{sizeInBits}"); + TabOut("}", false); + TabOut("}"); + Write(""); + + TabIn($"impl From<{e.Name}> for i{sizeInBits} {{"); + TabIn($"fn from(value: {e.Name}) -> Self {{"); + Write($"value.0 as i{sizeInBits}"); + TabOut("}", false); + TabOut("}"); + Write(""); + + // Implement Display trait + TabIn($"impl fmt::Display for {e.Name} {{"); + TabIn("fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {"); + TabIn("match self.0 {"); + + // Since several enum variants can map to the same value, we need to group them and only print the last + // one in the match statement (the last is the most updated one) + var elementsToValues = elements.GroupBy(element => ToRustEnumValue(element, sizeInBits, enumUnderlyingTypeSigned)) + .Select(variants => (variants.Key, variants.Last().Name)); + foreach (var elementToValue in elementsToValues) + { + Write($"{elementToValue.Key} => write!(f, \"{elementToValue.Name}\"),"); + } + + Write($"_ => write!(f, \"{{}}\", enum_to_str(self.0 as u64, std::any::TypeId::of::<{e.Name}>())),"); + TabOut("}", false); + TabOut("}", false); + TabOut("}"); + Write(""); + + EnumMap[e.Name] = enumVals; + } + + void GenEnum(TpmEnum e) + { + GenEnum(e, e.Members); + } + + void GenBitfield(TpmBitfield bf) + { + var bitfieldElements = GetBifieldElements(bf); + // Generate the enum with constants approach + GenEnum(bf, bitfieldElements); + + // Add bitwise operations for flags using the newtype pattern + TabIn($"impl std::ops::BitOr for {bf.Name} {{"); + Write("type Output = Self;"); + Write(""); + TabIn("fn bitor(self, rhs: Self) -> Self::Output {"); + Write($"Self(self.0 | rhs.0)"); + TabOut("}"); + TabOut("}"); + Write(""); + + // From impl + TabIn($"impl From for {bf.Name} {{"); + TabIn($"fn from(value: u{bf.GetFinalUnderlyingType().GetSize() * 8}) -> Self {{"); + Write($"Self(value.into())"); + TabOut("}", false); + TabOut("}"); + Write(""); + + } + + void GenUnion(TpmUnion u) + { + if (!u.Implement) + return; + + var unionSelectorType = GetUnionSelectorType(u); + + WriteComment(u); + + Write($"#[derive(Clone)]"); + Write($"pub enum {u.Name} {{"); + TabIn(); + + foreach (var m in u.Members) + { + if (m.Type.IsElementary()) + { + Write($"{ToRustEnumName(m.Name)},"); + } + else + { + Write($"{ToRustEnumName(m.Name)}({m.Type.Name}),"); + } + } + + TabOut("}"); + Write(""); + + WriteComment("Union selector type"); + TabIn($"impl {u.Name} {{"); + TabIn($"pub fn GetUnionSelector(&self) -> {unionSelectorType} {{"); + TabIn("match self {"); + foreach (var m in u.Members) + { + string memberName = ToRustEnumName(m.Name); + if (m.Type.IsElementary()) + { + Write($"Self::{memberName} => {m.SelectorValue.QualifiedName}, "); + } + else + { + Write($"Self::{memberName}(_) => {m.Type.Name}::GetUnionSelector(),"); + } + } + TabOut("}", false); + TabOut("}"); + + TabIn($"pub fn create(selector: {unionSelectorType}) -> Result, TpmError> {{"); + TabIn("match selector {"); + foreach (var m in u.Members) + { + string memberName = ToRustEnumName(m.Name); + if (m.Type.IsElementary()) + { + Write($"{m.SelectorValue.QualifiedName} => Ok(None),"); + } + else + { + Write($"{m.SelectorValue.QualifiedName} => Ok(Some(Self::{memberName}({m.Type.Name}::default()))),"); + } + + } + Write("_ => Err(TpmError::InvalidUnion),"); + + TabOut("}", false); + TabOut("}", false); + + TabOut("}"); + + // Implement Debug trait + TabIn($"impl fmt::Debug for {u.Name} {{"); + TabIn("fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {"); + TabIn("match self {"); + foreach (var m in u.Members) + { + string memberName = ToRustEnumName(m.Name); + if (m.Type.IsElementary()) + { + Write($"Self::{memberName} => write!(f, \"{u.Name}::{memberName}\"),"); + } + else + { + Write($"Self::{memberName}(inner) => write!(f, \"{u.Name}::{memberName}({{:?}})\", inner),"); + } + } + TabOut("}", false); + TabOut("}", false); + TabOut("}", false); + + // Marshaling methods + TabIn($"impl TpmStructure for {u.Name} {{"); + + foreach (var functionNameAndParams in TpmStructureFunctions) + { + TabIn("fn " + functionNameAndParams.Item1 + functionNameAndParams.Item2 + " -> Result<(), TpmError> {"); + TabIn("match self {"); + foreach (var m in u.Members) + { + string memberName = ToRustEnumName(m.Name); + if (m.Type.IsElementary()) + { + Write($"Self::{memberName} => Ok(()),"); + } + else + { + Write($"Self::{memberName}(inner) => inner.{functionNameAndParams.Item1}(buffer),"); + } + } + TabOut("}", false); + TabOut("}"); + } + + TabOut("}"); + + TabIn($"impl TpmMarshaller for {u.Name} {{"); + var tpmMarshallerFunctions = new (string, string)[] { + ("toTpm", "(&self, buffer: &mut TpmBuffer)"), + ("initFromTpm", "(&mut self, buffer: &mut TpmBuffer)"), + }; + + foreach (var functionNameAndParams in tpmMarshallerFunctions) + { + TabIn("fn " + functionNameAndParams.Item1 + functionNameAndParams.Item2 + " -> Result<(), TpmError> {"); + TabIn("match self {"); + foreach (var m in u.Members) + { + string memberName = ToRustEnumName(m.Name); + if (m.Type.IsElementary()) + { + Write($"Self::{memberName} => Ok(()),"); + } + else + { + Write($"Self::{memberName}(inner) => inner.{functionNameAndParams.Item1}(buffer),"); + } + } + TabOut("}", false); + TabOut("}"); + } + + TabOut("}"); + + Write(""); + } + + void GenGetUnionSelector(TpmStruct s) + { + string selType = GetUnionMemberSelectorInfo(s, out string selVal); + if (selType == null) + { + return; + } + + TabIn($"fn GetUnionSelector() -> {selType} {{"); + Write($"{selVal}"); + TabOut("}", false); + } + + void GenStructDecl(TpmStruct s) + { + string structName = s.Name; + + if (IsTypedefStruct(s)) + { + Debug.Assert(s.Fields.Count == 0); + WriteComment(s); + Write($"pub type {structName} = {s.DerivedFrom.Name};"); + Write(""); + return; + } + + WriteComment(s); + Write($"#[derive(Debug, Clone, Derivative)]"); + Write("#[derivative(Default)]"); + Write($"pub struct {structName} {{"); + TabIn(); + + GenFields(s); + + TabOut("}"); + Write(""); + + // Implement struct methods + TabIn($"impl {structName} {{"); + + // Constructor + if (!s.Info.IsResponse() && s.NonTagFields.Count() > 0) + { + Write("/// Creates a new instance with the specified values"); + Write("pub fn new("); + TabIn(); + + GenConstructorFieldsDecl(s); + + Write($") -> Self {{"); + TabIn("Self {"); + + GenConstructorFieldsInit(s); + + Write("..Default::default()"); + + TabOut("}", false); + TabOut("}", false); + Write(""); + } + + GenGetUnionSelector(s); + + TabOut("}"); + + GenTpmStructureImplementation(s); + + GenTpmMarshallerImplementation(s); + + GenTpmCmdStructureImplementation(s); + + Write(""); + } + + // Generates the constructor fields initialization, supporting "derived" structs by containing the same fields + void GenConstructorFieldsInit(TpmStruct s) { + if (s.DerivedFrom != null) + { + GenConstructorFieldsInit(s.DerivedFrom); + } + + foreach (var f in s.NonTagFields) + { + if (f.MarshalType == MarshalType.ConstantValue || f.MarshalType == MarshalType.UnionSelector) + continue; + + var fieldName = ToRustName(f.Name); + Write($"{fieldName}: {fieldName}.clone(),"); + } + } + + // Generates the constructor fields declaration, supporting "derived" structs by containing the same fields + void GenConstructorFieldsDecl(TpmStruct s) { + if (s.DerivedFrom != null) { + GenConstructorFieldsDecl(s.DerivedFrom); + } + + foreach (var f in s.NonTagFields) + { + if (f.MarshalType == MarshalType.ConstantValue || f.MarshalType == MarshalType.UnionSelector) + continue; + + Write($"{ToRustName(f.Name)}: {ParamForField(f)},"); + } + } + + // Generates the struct's fields, supporting "derived" structs by containing the same fields + void GenFields(TpmStruct s) { + var fieldsToInit = s.NonDefaultInitFields.Select(f => f.Name).ToHashSet(); + + if (s.DerivedFrom != null) { + GenFields(s.DerivedFrom); + } + + // Fields + foreach (var f in s.NonSizeFields) + { + if (f.MarshalType == MarshalType.ConstantValue) + // No member field for a constant tag + continue; + + WriteComment(f); + if (f.MarshalType == MarshalType.UnionSelector) + { + // Selectors are handled through methods in Rust + continue; + } + + if (fieldsToInit.Contains(f.Name)) + { + Write($"#[derivative(Default(value=\"{f.GetInitVal()}\"))]"); + } + Write($"pub {ToRustName(f.Name)}: {TransType(f)},"); + } + + InsertSnip(s.Name); + } + + void GenTpmStructureImplementation(TpmStruct s) + { + // Marshaling methods + TabIn($"impl TpmStructure for {s.Name} {{"); + + TabIn("fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> {"); + Write($"buffer.createObj::<{s.Name}>()?;"); + Write("Ok(())"); + TabOut("}"); + + TabIn("fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> {"); + Write("let mut tpm_buffer = TpmBuffer::from(buffer);"); + Write($"self.initFromTpm(&mut tpm_buffer)"); + TabOut("}"); + + GenStructMarshalingImpl(s); + + TabOut("}"); + } + + void GenTpmMarshallerImplementation(TpmStruct s) + { + // Marshaling methods + TabIn($"impl TpmMarshaller for {s.Name} {{"); + + Write("/// Serialize this structure to a TPM buffer"); + TabIn("fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> {"); + Write("self.serialize(buffer)"); + TabOut("}"); + Write(""); + + Write("/// Deserialize this structure from a TPM buffer"); + TabIn("fn initFromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> {"); + Write("self.deserialize(buffer)"); + TabOut("}"); + + TabOut("}"); + } + + void GenTpmCmdStructureImplementation(TpmStruct s) + { + var info = s.IsCmdStruct() ? s.Info as CmdStructInfo : null; + + if (info == null) + { + return; + } + + TabIn($"impl CmdStructure for {s.Name} {{"); + + Write($"fn num_handles(&self) -> u16 {{ {info.NumHandles} }}"); + Write(""); + + if (info.SessEncSizeLen != 0) + { + Debug.Assert(info.SessEncValLen != 0); + Write($"fn sess_enc_info(&self) -> SessEncInfo {{ SessEncInfo {{ size_len: {info.SessEncSizeLen}, val_len: {info.SessEncValLen} }} }}"); + } + + TabOut("}"); + + if (info.IsRequest()) + { + GenReqStructureImplementation(s, info); + } + else + { + GenRespStructureImplementation(s, info); + } + } + + private void GenRespStructureImplementation(TpmStruct s, CmdStructInfo info) + { + TabIn($"impl RespStructure for {s.Name} {{"); + + if (info.NumHandles == 0) + { + Write($"fn get_handle(&self) -> TPM_HANDLE {{ TPM_HANDLE::default() }}"); + Write(""); + Write($"fn set_handle(&mut self, _handle: &TPM_HANDLE) {{ }}"); + } + else + { + // Per TPM spec, handles are always the first fields in a command/response struct, + // and Fields is guaranteed non-empty when NumHandles > 0. + Write($"fn get_handle(&self) -> TPM_HANDLE {{ self.{s.Fields[0].Name}.clone() }}"); + Write(""); + Write($"fn set_handle(&mut self, handle: &TPM_HANDLE) {{ self.{s.Fields[0].Name} = handle.clone(); }}"); + } + + // If the response struct has a "name" field, override get_resp_name() + var nameField = s.NonTagFields.FirstOrDefault(f => f.Name == "name"); + if (nameField != null) + { + Write(""); + Write($"fn get_resp_name(&self) -> Vec {{ self.name.clone() }}"); + } + + TabOut("}"); + } + + private void GenReqStructureImplementation(TpmStruct s, CmdStructInfo info) + { + string handles = string.Join(", ", s.Fields.Take(info.NumHandles).Select(f => "self." + f.Name + ".clone()")); + + TabIn($"impl ReqStructure for {s.Name} {{"); + + Write($"fn num_auth_handles(&self) -> u16 {{ {info.NumAuthHandles} }}"); + Write(""); + Write($"fn get_handles(&self) -> Vec {{ vec![{handles}] }}"); + + TabOut("}"); + } + + void GenerateTpmCommandPrototypes() + { + var commands = TpmTypes.Get().Where(s => s.Info.IsRequest()); + + TabIn("impl Tpm2 {"); + + foreach (TpmStruct s in commands) + GenCommand(s, CommandFlavor.Synch); + + TabOut("}"); + Write(""); + + Write("/// Asynchronous TPM2 command methods"); + TabIn("pub struct AsyncMethods<'a> {"); + Write("tpm: &'a mut Tpm2,"); + TabOut("}"); + Write(""); + + TabIn("impl<'a> AsyncMethods<'a> {"); + Write(""); + + foreach (TpmStruct s in commands) + GenCommand(s, CommandFlavor.AsyncCommand); + + foreach (TpmStruct s in commands) + GenCommand(s, CommandFlavor.AsyncResponse); + + TabOut("}"); + } + + enum CommandFlavor + { + Synch, AsyncCommand, AsyncResponse + } + + void GenCommand(TpmStruct req, CommandFlavor gen) + { + var resp = GetRespStruct(req); + + string cmdName = ToRustName(GetCommandName(req)); + + if (gen == CommandFlavor.AsyncCommand) + cmdName += "_async"; + else if (gen == CommandFlavor.AsyncResponse) + cmdName += "_complete"; + + string annotation = Helpers.WrapText(AsSummary(req.Comment)) + eol; + var reqFields = new StructField[0]; + if (gen != CommandFlavor.AsyncResponse) + { + reqFields = req.NonTagFields; + foreach (var f in reqFields) + annotation += GetParamComment(f) + eol; + } + WriteComment(annotation + (GetReturnComment(resp.NonTagFields)), false); + + string returnType = GetCommandReturnType(gen, resp, cmdName, out string returnFieldName); + + Write($"pub fn {cmdName}("); + TabIn(); + + Write($"&mut self,"); + + if (gen != CommandFlavor.AsyncResponse && reqFields.Length > 0) + { + foreach (var f in reqFields) + { + if (f.MarshalType == MarshalType.ConstantValue) + continue; + + Write($"{ToRustName(f.Name)}: {ParamForField(f)},"); + } + } + + TabOut($") -> {returnType} {{"); + TabIn(); + GenCommandImplementation(req, resp, reqFields, returnFieldName, gen); + TabOut("}"); + Write(""); + } + + private void GenCommandImplementation(TpmStruct req, TpmStruct resp, StructField[] reqFields, string returnFieldName, CommandFlavor gen) + { + // Create request structure + if (reqFields.Length > 0) + { + Write($"let req = {req.Name}::new("); + TabIn(); + foreach (var f in reqFields) + { + if (f.MarshalType == MarshalType.ConstantValue) + continue; + + Write($"{ToRustName(f.Name)},"); + } + TabOut(");"); + Write(""); + } + else if (gen != CommandFlavor.AsyncResponse) + { + Write($"let req = {req.Name}::default();"); + Write(""); + } + + var respFields = resp.NonTagFields; + if (gen != CommandFlavor.AsyncCommand) + { + // Create response structure (or empty if there is no response) + if (respFields.Length > 0) + { + Write($"let mut resp = {resp.Name}::default();"); + } + else + { + Write($"let mut resp = EmptyTpmResponse::default();"); + } + } + + // Call dispatch method + var cmdCode = "TPM_CC::" + ToRustName(GetCommandName(req)); + if (gen == CommandFlavor.AsyncCommand) + { + Write($"self.tpm.dispatch_command({cmdCode}, &req)?;"); + } + else if (gen == CommandFlavor.AsyncResponse) + { + Write($"self.tpm.process_response({cmdCode}, &mut resp)?;"); + } + else + { + Write($"self.dispatch({cmdCode}, req, &mut resp)?;"); + } + + if (gen == CommandFlavor.AsyncCommand) + { + Write("Ok(())"); + } + else + { + if (returnFieldName != null) + { + Write($"Ok(resp.{ToRustName(returnFieldName)})"); + } + else if (respFields.Length > 0) + { + Write("Ok(resp)"); + } + else + { + Write("Ok(())"); + } + } + } + + void GenEnumMap() + { + TabIn("lazy_static::lazy_static! {"); + Write("/// Maps enum type IDs to a map of values to string representations"); + Write("pub static ref ENUM_TO_STR_MAP: HashMap> = {"); + TabIn("let mut map = HashMap::new();"); + + foreach (var e in EnumMap) + { + var mutable = e.Value.Count > 0 ? "mut" : ""; + Write($"let {mutable} {ToRustName(e.Key)}_map: HashMap = HashMap::new();"); + foreach (var v in e.Value) + { + Write($"{ToRustName(e.Key)}_map.insert({v.Value}, \"{v.Key}\");"); + } + Write($"map.insert(std::any::TypeId::of::<{e.Key}>(), {ToRustName(e.Key)}_map);"); + Write(""); + } + + Write("map"); + TabOut("};"); + Write(""); + + Write("/// Maps enum type IDs to a map of string representations to values"); + Write("static ref STR_TO_ENUM_MAP: HashMap> = {"); + TabIn("let mut map = HashMap::new();"); + + foreach (var e in EnumMap) + { + var mutable = e.Value.Count > 0 ? "mut" : ""; + Write($"let {mutable} {ToRustName(e.Key)}_map: HashMap<&'static str, u64> = HashMap::new();"); + foreach (var v in e.Value) + { + Write($"{ToRustName(e.Key)}_map.insert(\"{v.Key}\", {v.Value});"); + } + Write($"map.insert(std::any::TypeId::of::<{e.Key}>(), {ToRustName(e.Key)}_map);"); + Write(""); + } + + Write("map"); + TabOut("};"); + TabOut("}"); + Write(""); + } + + void GenStructMarshalingImpl(TpmStruct s) + { + Write("// Implement serialization/deserialization"); + + // To TPM implementation + TabIn("fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> {"); + Write("// Serialize fields"); + var toTpmOps = GetFieldsMarshalOpsRecursive(s, GetToTpmFieldsMarshalOps); + + foreach (var op in toTpmOps) + { + Write(op + ";"); + } + Write("Ok(())"); + TabOut("}"); + Write(""); + + // From TPM implementation + TabIn("fn deserialize(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError> {"); + Write("// Deserialize fields"); + var fromTpmOps = GetFieldsMarshalOpsRecursive(s, GetFromTpmFieldsMarshalOps); + foreach (var op in fromTpmOps) + { + Write(op + ";"); + } + Write("Ok(())"); + TabOut("}"); + } + + // Recursively gets all marshal ops for the struct and its base classes (fields are contained in rust rather + // than derived) + List GetFieldsMarshalOpsRecursive(TpmStruct s, Func> getMarshalOpsFunc) { + var ops = new List(); + + if (s.DerivedFrom != null) { + ops.AddRange(GetFieldsMarshalOpsRecursive(s.DerivedFrom, getMarshalOpsFunc)); + } + + ops.AddRange(getMarshalOpsFunc(s.MarshalFields)); + + return ops; + } + + // Helper methods for Rust-specific formatting + + // Returns name as-is to keep TPM spec naming conventions consistent across all language bindings. + static string ToRustName(string name) => name; + + static long ToRustEnumValue(TpmNamedConstant element, int bits, bool signed) + { + return Convert.ToInt64(CastToNumberWithBitsAndSign(element.NumericValue, bits, signed)); + } + + // Returns name as-is to keep TPM spec naming conventions consistent across all language bindings. + static string ToRustEnumName(string name) => name; + + + string ConvertToRustInitVal(string cppInitVal) + { + // Handle common C++ init values + switch (cppInitVal) + { + case "nullptr": return "None"; + case "0": return "0"; + case "true": return "true"; + case "false": return "false"; + default: + return cppInitVal; + } + } + + protected override void WriteComment(string comment, bool wrap = true) + { + WriteComment(comment, "/// ", "/// ", "", wrap); + } + + // Helper methods for array handling and serialization + + /// + /// Determines if a field is a list (vector/collection) by checking the type name + /// + private bool IsList(StructField f) + { + if (!f.IsArray()) + return false; + + // Check if it's a dynamic array/list (not a fixed size array) + return f.Type.SpecName.StartsWith("TPML_") || + (f.SizeTagField != null && f.SizeTagField.MarshalType == MarshalType.ArrayCount); + } + + /// + /// Gets the element type name for lists/arrays + /// + private string GetElementTypeName(StructField f) + { + if (f.Type.SpecName.StartsWith("TPML_")) + { + // Extract the element type from TPML_X (list of X) + string elementTypeName = f.Type.SpecName.Substring(5); + return elementTypeName; + } + + // For regular arrays, use the base type + return f.Type.SpecName; + } + + private static object CastToNumberWithBitsAndSign(long number, int bits, bool sign) + { + if (sign) + { + // Cast to signed types + if (bits == 8) + { + return (sbyte)number; // Cast to signed byte (8 bits) + } + else if (bits == 16) + { + return (short)number; // Cast to short (16 bits) + } + else if (bits == 32) + { + return (int)number; // Cast to int (32 bits) + } + else if (bits == 64) + { + return (long)number; // Cast to long (64 bits) + } + } + else + { + // Cast to unsigned types + if (bits == 8) + { + return (byte)number; // Cast to unsigned byte (8 bits) + } + else if (bits == 16) + { + return (ushort)number; // Cast to unsigned short (16 bits) + } + else if (bits == 32) + { + return (uint)number; // Cast to unsigned int (32 bits) + } + else if (bits == 64) + { + return (ulong)number; // Cast to unsigned long (64 bits) + } + } + + throw new ArgumentException("Unsupported bit size or invalid number range"); + } + + /// + /// Gets the size of an array if it's fixed size, or 0 if dynamic + /// + private int GetArraySize(StructField f) + { + if (!f.IsArray()) + return 0; + + // If there's a size tag field, it's a dynamic array + if (f.SizeTagField != null && f.SizeTagField.MarshalType == MarshalType.ArrayCount) + return 0; + + // Try to extract size from constraints if available + if (f.MaxVal != null) + { + return (int)f.MaxVal.NumericValue; + } + + // Default size for byte arrays if nothing else specified + if (f.Type.SpecName == "BYTE") + return 64; // Common buffer size in TPM + + return 0; + } + + /// + /// Gets the base element type for use in lists/arrays + /// + private TpmType GetElementType(StructField f) + { + string elementTypeName = GetElementTypeName(f); + return TpmTypes.Lookup(elementTypeName) ?? f.Type; + } + } +} diff --git a/TssCodeGen/src/CodeGenBase.cs b/TssCodeGen/src/CodeGenBase.cs index 85a980d7..fcc873d9 100644 --- a/TssCodeGen/src/CodeGenBase.cs +++ b/TssCodeGen/src/CodeGenBase.cs @@ -41,17 +41,18 @@ protected CodeGenBase(string rootDir, string snipsFileName = null) LoadSnips(rootDir + snipsFileName); } - + internal abstract void Generate(); - static void AddBitfieldElt(List elements, string name, int val, + static void AddBitfieldElt(List elements, string name, long val, string comment = null, string oldStyleName = null, bool custom = false) { // Comment is null only for custom enumerators "XXX_BIT_OFFSET" and "XXX_BIT_LENGTH" - var nc = new TpmNamedConstant(null, custom ? null : name, null, comment); + var value = comment == null ? val.ToString() : ToHex(val); + var nc = new TpmNamedConstant(null, custom ? null : name, value, comment); nc.Name = name; - nc.Value = comment == null ? val.ToString() : ToHex(val); + nc.Value = value; nc.OldStyleName = oldStyleName ?? name; elements.Add(nc); } @@ -88,7 +89,7 @@ public static List GetBifieldElements(TpmBitfield bf) string nameBase = b.Name.Contains("_") ? TargetLang.NameToDotNet(b.Name) : b.Name; int len = b.StartBit - b.EndBit + 1; var suff = TargetLang.DotNet ? new string[] { "BitMask", "BitOffset", "BitLength" } - : new string[] { "_BIT_MASK" , "_BIT_OFFSET", "_BIT_LENGTH" }; + : new string[] { "_BIT_MASK", "_BIT_OFFSET", "_BIT_LENGTH" }; AddBitfieldElt(elements, nameBase + suff[0], ((1 << len) - 1) << b.EndBit, b.Comment, null, true); AddBitfieldElt(elements, nameBase + suff[1], b.EndBit, null, null, true); AddBitfieldElt(elements, nameBase + suff[2], len, null, null, true); @@ -106,6 +107,9 @@ public static List GetBifieldElements(TpmBitfield bf) public static List GetToTpmFieldsMarshalOps(StructField[] fields) { var marshalOps = new List(); + string fieldNamePrefix = TargetLang.Rust ? "&" : ""; + string resultSuffix = TargetLang.Rust ? "?" : ""; + foreach (StructField f in fields) { int size = f.Type.GetSize(); @@ -114,49 +118,60 @@ public static List GetToTpmFieldsMarshalOps(StructField[] fields) { case MarshalType.Normal: if (f.IsValueType()) - marshalOps.Add($"buf.write{WireNameForInt(size)}({fieldName})"); + marshalOps.Add($"buf.write{WireNameForInt(size)}({TargetLang.GetEnumValue(fieldName, f.TypeName, size)})"); else - marshalOps.Add($"{fieldName}.toTpm(buf)"); + marshalOps.Add($"{fieldName}.toTpm(buf){resultSuffix}"); if (f.Attrs.HasFlag(StructFieldAttr.TermOnNull)) - marshalOps.Add(TargetLang.If($"{fieldName} == {TpmTypes.AlgNull}") + " return"); + { + string earlyReturn = TargetLang.Rust ? " { return Ok(()) }" : " return"; + marshalOps.Add(TargetLang.If($"{fieldName} == {TpmTypes.AlgNull}") + earlyReturn); + } break; case MarshalType.ConstantValue: - marshalOps.Add($"buf.write{WireNameForInt(size)}({ConstTag(f)})"); + marshalOps.Add($"buf.write{WireNameForInt(size)}({TargetLang.GetEnumValue(ConstTag(f), f.TypeName, size)})"); break; case MarshalType.SizedStruct: Debug.Assert(f.SizeTagField != null); - marshalOps.Add($"buf.writeSizedObj({fieldName})"); + marshalOps.Add($"buf.writeSizedObj({fieldNamePrefix + fieldName}){resultSuffix}"); break; case MarshalType.EncryptedVariableLengthArray: case MarshalType.SpecialVariableLengthArray: // TPMT_HA size is tagged by its hash alg (the first field) - marshalOps.Add($"buf.writeByteBuf({fieldName})"); + marshalOps.Add($"buf.writeByteBuf({fieldNamePrefix + fieldName})"); break; case MarshalType.VariableLengthArray: var sizeTagLen = f.SizeTagField.Type.GetSize(); if (f.IsByteBuffer()) - marshalOps.Add($"buf.writeSizedByteBuf({fieldName}" + (sizeTagLen == 2 ? ")" : $", {sizeTagLen})")); + { + // Rust doesn't support default arguments for functions, so we need to pass the size tag length explicitly + bool shouldNotPassSizeTag = sizeTagLen == 2 && !TargetLang.Rust; + marshalOps.Add($"buf.writeSizedByteBuf({fieldNamePrefix}{fieldName}" + (shouldNotPassSizeTag ? ")" : $", {sizeTagLen})")); + } else if (f.IsValueType()) - marshalOps.Add($"buf.writeValArr({fieldName}, {size})"); + marshalOps.Add($"buf.writeValArr({fieldName + TargetLang.AsReference(true)}, {size})"); else - marshalOps.Add($"buf.writeObjArr({fieldName})"); + marshalOps.Add($"buf.writeObjArr({fieldName + TargetLang.AsReference(true)}){resultSuffix}"); break; case MarshalType.UnionSelector: // A trick to allow using default-constructed TPMT_SENSITIVE as an empty (non-marshaling) object string unionField = ThisMember + f.RelatedUnion.Name; if (f == fields.First()) - marshalOps.Add(TargetLang.If($"{unionField} == {TargetLang.Null}") + " return"); - marshalOps.Add($"buf.write{WireNameForInt(size)}({unionField}{TargetLang.Member}GetUnionSelector())"); + { + string earlyReturn = TargetLang.Rust ? " { return Ok(()) }" : " return"; + marshalOps.Add(TargetLang.IfNull(unionField) + earlyReturn); + } + + marshalOps.Add($"buf.write{WireNameForInt(size)}({unionField}{TargetLang.UnionMember(true)}GetUnionSelector(){TargetLang.GetUnionValue(size)})"); break; case MarshalType.UnionObject: - marshalOps.Add($"{fieldName}{TargetLang.Member}toTpm(buf)"); + marshalOps.Add($"{fieldName}{TargetLang.UnionMember(true)}toTpm(buf){resultSuffix}"); break; default: @@ -169,6 +184,8 @@ public static List GetToTpmFieldsMarshalOps(StructField[] fields) public static List GetFromTpmFieldsMarshalOps(StructField[] fields) { + string resultSuffix = TargetLang.Rust ? "?" : ""; + var marshalOps = new List(); foreach (StructField f in fields) { @@ -178,13 +195,16 @@ public static List GetFromTpmFieldsMarshalOps(StructField[] fields) { case MarshalType.Normal: if (f.IsValueType()) - marshalOps.Add($"{fieldName} = buf.read{WireNameForInt(size)}()"); + marshalOps.Add($"{fieldName} = {TargetLang.ParseEnum(f.TypeName, $"buf.read{WireNameForInt(size)}()", f.Type.GetFinalUnderlyingType().Name)}"); else - marshalOps.Add(TargetLang.Cpp ? $"{fieldName}.initFromTpm(buf)" - : $"{fieldName} = {f.TypeName}.fromTpm(buf)"); + marshalOps.Add(TargetLang.Cpp || TargetLang.Rust ? $"{fieldName}.initFromTpm(buf){resultSuffix}" + : $"{fieldName} = {f.TypeName}.fromTpm(buf){resultSuffix}"); if (f.Attrs.HasFlag(StructFieldAttr.TermOnNull)) - marshalOps.Add(TargetLang.If($"{fieldName} == {TpmTypes.AlgNull}") + " return"); + { + string earlyReturn = TargetLang.Rust ? " { return Ok(()) }" : " return"; + marshalOps.Add(TargetLang.If($"{fieldName} == {TpmTypes.AlgNull}") + earlyReturn); + } break; case MarshalType.ConstantValue: @@ -194,8 +214,9 @@ public static List GetFromTpmFieldsMarshalOps(StructField[] fields) case MarshalType.SizedStruct: Debug.Assert(f.SizeTagField != null); - marshalOps.Add(TargetLang.Cpp ? $"buf.readSizedObj({fieldName})" - : $"{fieldName} = buf.createSizedObj({TargetLang.TypeInfo(f.TypeName)})"); + marshalOps.Add(TargetLang.Cpp ? $"buf.readSizedObj({fieldName})" : + TargetLang.Rust ? $"buf.readSizedObj(&mut {fieldName})?" : + $"{fieldName} = buf.createSizedObj({TargetLang.TypeInfo(f.TypeName)})"); break; case MarshalType.EncryptedVariableLengthArray: @@ -211,26 +232,41 @@ public static List GetFromTpmFieldsMarshalOps(StructField[] fields) case MarshalType.VariableLengthArray: var sizeTagLen = f.SizeTagField.Type.GetSize(); if (f.IsByteBuffer()) - marshalOps.Add($"{fieldName} = buf.readSizedByteBuf(" + (sizeTagLen == 2 ? ")" : $"{sizeTagLen})")); + { + // Rust doesn't support default arguments for functions, so we need to pass the size tag length explicitly + bool shouldNotPassSizeTag = sizeTagLen == 2 && !TargetLang.Rust; + marshalOps.Add($"{fieldName} = buf.readSizedByteBuf(" + (shouldNotPassSizeTag ? ")" : $"{sizeTagLen})")); + } else if (f.IsValueType()) - marshalOps.Add(TargetLang.Cpp ? $"buf.readValArr({fieldName}, {f.Type.GetSize()})" - : $"{fieldName} = buf.readValArr({f.Type.GetSize()})"); + marshalOps.Add(TargetLang.Cpp ? $"buf.readValArr({fieldName}, {f.Type.GetSize()})" : + TargetLang.Rust ? $"buf.readValArr({fieldName + TargetLang.AsReference(false)}, {f.Type.GetSize()})?" : + $"{fieldName} = buf.readValArr({f.Type.GetSize()})"); else - marshalOps.Add(TargetLang.Cpp ? $"buf.readObjArr({fieldName})" + marshalOps.Add(TargetLang.Cpp || TargetLang.Rust ? $"buf.readObjArr({fieldName + TargetLang.AsReference(false)}){resultSuffix}" : $"{fieldName} = buf.readObjArr({TargetLang.TypeInfo(f.TypeName.TrimEnd('[', ']'))})"); break; case MarshalType.UnionSelector: var localVar = TargetLang.LocalVar(f.Name, f.TypeName); - marshalOps.Add($"{localVar} = " + - (f.IsValueType() ? $"buf.read{WireNameForInt(size)}()" : $"{f.TypeName}.fromTpm(buf)")); + if (f.IsValueType()) + { + marshalOps.Add($"{localVar} = {TargetLang.ParseEnum(f.TypeName, $"buf.read{WireNameForInt(size)}()", f.Type.GetFinalUnderlyingType().Name)}"); + } + else + marshalOps.Add($"{localVar} = {f.TypeName}.fromTpm(buf){resultSuffix}"); break; case MarshalType.UnionObject: - var selector = (f as UnionField).UnionSelector.Name; - marshalOps.Add(TargetLang.Cpp ? $"UnionFactory::Create({fieldName}, {selector})" - : $"{fieldName} = UnionFactory.create({TargetLang.Quote(f.TypeName)}, {selector})"); - marshalOps.Add($"{fieldName}{TargetLang.Member}initFromTpm(buf)"); + var selector = (f as UnionField).UnionSelector; + var selectorName = selector.Name; + if (TargetLang.Cpp) + marshalOps.Add($"UnionFactory::Create({fieldName}, {selectorName})"); + else if (TargetLang.Rust) + marshalOps.Add($"{fieldName} = {f.TypeName}::create(r#{selectorName})?"); + else + marshalOps.Add($"{fieldName} = UnionFactory.create({TargetLang.Quote(f.TypeName)}, {selectorName})"); + + marshalOps.Add($"{fieldName}{TargetLang.UnionMember(false)}initFromTpm(buf){resultSuffix}"); break; default: break; @@ -351,15 +387,17 @@ internal static string Separator(T elem, IEnumerable list, string sep = ", return Object.ReferenceEquals(list.Last(), elem) ? term : sep; } - internal static string ToHex(int value) + internal static string ToHex(long value) { - return "0x" + Convert.ToString(value, 16).ToUpper(); + // Cast to uint to avoid sign-extension of 32-bit values (e.g. 0x80000000) + return "0x" + Convert.ToString((uint)value, 16).ToUpper(); } - internal static string ToHex(uint value) { return ToHex((int)value); } + internal static string ToHex(ulong value) { return ToHex((long)value); } internal static string WireNameForInt(int size) { - switch(size){ + switch (size) + { case 1: return "Byte"; case 2: return "Short"; case 4: return "Int"; @@ -427,7 +465,7 @@ public static string GetUnionChoicesList(TpmType t) public static string AsSummary(string comment) { - return string.IsNullOrEmpty(comment) ? comment + return string.IsNullOrEmpty(comment) ? comment : (TargetLang.Cpp || TargetLang.DotNet) ? " " + comment + " " : comment; } @@ -519,12 +557,12 @@ protected void WriteComment(string comment, string beg, string mid, string end = if (!comment.Contains('\n')) { if (end.StartsWith("\n")) - end = end.Substring(1); + end = end.Substring(1); end = " " + end.TrimStart(' '); } comment += end; } - var lines = comment.Split(new char[] {'\n'}); + var lines = comment.Split(new char[] { '\n' }); for (int i = 0; i < lines.Length; ++i) Write(lines[i]); CommentWritten = true; @@ -552,12 +590,12 @@ protected void WriteComment(TpmNamedConstant nc) WriteComment(AsSummary(nc.Comment)); } - protected bool NewLine = true, + protected bool NewLine = true, EmptyLineWritten = false, CommentWritten = false; protected const int SpacesPerTab = 4; - protected int IndentLevel; + protected int IndentLevel; protected string CurIndent() { @@ -586,9 +624,9 @@ protected void Write(string str, bool newLine = true) NewLine = true; } - string curIndent = CurIndent(), + string curIndent = CurIndent(), indent = NewLine ? curIndent : ""; - var lines = str.Replace("\r", "").Split(new char[] {'\n'}); + var lines = str.Replace("\r", "").Split(new char[] { '\n' }); for (int i = 0; i < lines.Length; ++i) { GeneratedCode.Append(indent + lines[i]); diff --git a/TssCodeGen/src/Expression.cs b/TssCodeGen/src/Expression.cs index 024c4275..0fa963f4 100644 --- a/TssCodeGen/src/Expression.cs +++ b/TssCodeGen/src/Expression.cs @@ -16,26 +16,28 @@ class Token { } + // Uses long (64-bit) to correctly handle unsigned 32-bit TPM constants (e.g. 0x80000000) + // that would overflow a signed int. class Operand : Token { string _Value; - int? _NumValue; + long? _NumValue; public Operand (string val) { _Value = val; } - public Operand (int val) { _NumValue = val; } + public Operand (long val) { _NumValue = val; } public static implicit operator Operand (string val) { return new Operand(val); } - public static implicit operator Operand (int val) { return new Operand(val); } + public static implicit operator Operand (long val) { return new Operand(val); } public string Value { get { return _Value; } } - public int NumericValue + public long NumericValue { get { if (_NumValue == null) _NumValue = Expression.Eval(Value); - return (int)_NumValue; + return (long)_NumValue; } } } // class Operand @@ -87,7 +89,7 @@ public bool Is (OpCode op) return Op == op; } - public int Apply (int lhs, int rhs) + public long Apply (long lhs, long rhs) { switch(Op) { @@ -117,10 +119,10 @@ class Expression { public static bool IsNumber(string val) { - int numIs; - return Int32.TryParse(val, out numIs) || + long numIs; + return Int64.TryParse(val, out numIs) || val.ToLower().StartsWith("0x") && - Int32.TryParse(val.Substring(2), NumberStyles.HexNumber, + Int64.TryParse(val.Substring(2), NumberStyles.HexNumber, new NumberFormatInfo(), out numIs); } @@ -128,11 +130,11 @@ public static bool IsNumber(string val) /// the Part 2, or Vendor Specicfic part of the TPM 2.0 spec added a new constant /// value defined not in a table, but rather in a NOTE. In this case this definition /// needs to be manually added into the ImplementationConstants array. - public static int Eval(string val) + public static long Eval(string val) { if (IsNumber(val)) { - return Convert.ToInt32(val, val.ToLower().StartsWith("0x") ? 16 : 10); + return Convert.ToInt64(val, val.ToLower().StartsWith("0x") ? 16 : 10); } if (TpmTypes.ContainsConstant(val)) { @@ -193,7 +195,7 @@ public static int Eval(string val) ops.Pop().Apply(values); } Debug.Assert(values.Count == 1); - int res = values.Pop().NumericValue; + long res = values.Pop().NumericValue; return res; } diff --git a/TssCodeGen/src/TargetLang.cs b/TssCodeGen/src/TargetLang.cs index fac613ee..c1ac4819 100644 --- a/TssCodeGen/src/TargetLang.cs +++ b/TssCodeGen/src/TargetLang.cs @@ -19,7 +19,8 @@ public enum Lang CPP, Java, JS, - Py + Py, + Rust } /// Handles language specific syntax of the generated code and translations of names, types @@ -30,9 +31,15 @@ public enum Lang /// the current target language: Curent, DotNet, Cpp, Java, Node, Py. public static partial class TargetLang { - /// Lists code generators corresponding to the supported target languages - /// from the Lang enum (listed in the same order) - static Type[] CodeGenerators = { typeof(CGenCpp), typeof(CGenJava), typeof(CGenNode), typeof(CGenPy) }; + /// Maps each target language to its code generator class + static Dictionary CodeGenerators = new Dictionary + { + { Lang.CPP, typeof(CGenCpp) }, + { Lang.Java, typeof(CGenJava) }, + { Lang.JS, typeof(CGenNode) }, + { Lang.Py, typeof(CGenPy) }, + { Lang.Rust, typeof(CGenRust) } + }; static Lang _curLang = Lang.None; @@ -60,25 +67,27 @@ public ElementaryType(int size, params string[] nameList) } static Dictionary ElementaryTypes = new Dictionary { - // .Net C++ Java TypeScript Python - { "BYTE", new ElementaryType(1, "byte", "BYTE", "byte", "number", "int")}, - { "UINT8", new ElementaryType(1, "byte", "UINT8", "byte", "number", "int")}, - { "INT8", new ElementaryType(1, "sbyte", "INT8", "byte", "number", "int")}, - { "UINT16", new ElementaryType(2, "ushort", "UINT16", "int", "number", "int")}, - { "INT16", new ElementaryType(2, "short", "INT16", "int", "number", "int")}, - { "UINT32", new ElementaryType(4, "uint", "UINT32", "int", "number", "int")}, - { "INT32", new ElementaryType(4, "int", "INT32", "int", "number", "int")}, - { "UINT64", new ElementaryType(8, "ulong", "UINT64", "long", "number", "int")}, - { "INT64", new ElementaryType(8, "long", "INT64", "long", "number", "int")}, - { "BOOL", new ElementaryType(1, "bool", "BOOL", "boolean", "boolean", "bool")} + // .Net C++ Java TypeScript Python Rust + { "BYTE", new ElementaryType(1, "byte", "BYTE", "byte", "number", "int", "u8")}, + { "UINT8", new ElementaryType(1, "byte", "UINT8", "byte", "number", "int", "u8")}, + { "INT8", new ElementaryType(1, "sbyte", "INT8", "byte", "number", "int", "i8")}, + { "UINT16", new ElementaryType(2, "ushort", "UINT16", "int", "number", "int", "u16")}, + { "INT16", new ElementaryType(2, "short", "INT16", "int", "number", "int", "i16")}, + { "UINT32", new ElementaryType(4, "uint", "UINT32", "int", "number", "int", "u32")}, + { "INT32", new ElementaryType(4, "int", "INT32", "int", "number", "int", "i32")}, + { "UINT64", new ElementaryType(8, "ulong", "UINT64", "long", "number", "int", "u64")}, + { "INT64", new ElementaryType(8, "long", "INT64", "long", "number", "int", "i64")}, + { "BOOL", new ElementaryType(1, "bool", "BOOL", "boolean", "boolean", "bool", "bool")} }; + static HashSet ElementaryTypesCurrentLang => + ElementaryTypes.Select(et => et.Value.Names[(int)Current - 1]).ToHashSet(); + public static IEnumerable GetElementaryTypes() => ElementaryTypes.Select(et => new TpmValueType(et.Key, et.Value.Size)); public static string NameFor(string typeName) => ElementaryTypes[typeName].Names[(int)Current - 1]; - public static Lang Current => _curLang; public static bool DotNet => _curLang == Lang.DotNet; @@ -86,31 +95,64 @@ public static IEnumerable GetElementaryTypes() public static bool Java => _curLang == Lang.Java; public static bool Node => _curLang == Lang.JS; public static bool Py => _curLang == Lang.Py; + public static bool Rust => _curLang == Lang.Rust; public static bool IsOneOf(params Lang[] toCompare) => Current.IsOneOf(toCompare); // Standalone "this" reference (as used, e.g. to pass it as a function argument) - public static string This => Py ? "self" : "this"; + public static string This => (Py || Rust) ? "self" : "this"; public static string ThisMember => _thisQual; - public static string ClassMember => Cpp ? "::" : "."; + public static string ClassMember => (Cpp || Rust) ? "::" : "."; + + public static string AsReference(bool isConst) => Rust ? (isConst ? ".as_ref()" : ".as_mut()") : ""; + public static string UnionMember(bool isConst) => Rust ? AsReference(isConst) + ".unwrap()." : Member; public static string Member => Cpp ? "->" : "."; public static string Null => _null; public static string Neg => Py ? "not " : "!"; public static string LineComment => Py ? "#" : "//"; public static string If(string cond) => Py ? $"if {cond}:" : $"if ({cond})"; + + public static string IfNull(string obj) => TargetLang.If(Rust ? $"{obj}.is_none()" : $"{obj} == {TargetLang.Null}"); public static string Quote(string str) => _quote + str + _quote; - public static string TypeInfo(string typeName) => typeName + (Java ? ".class" : ""); + public static string TypeInfo(string typeName) => typeName + (Java ? ".class" : Rust ? "::type_id()" : ""); public static string LocalVar(string varName, string typeName) - => Py ? varName : Node ? $"let {varName}: {typeName}" : $"{typeName} {varName}"; + => Py ? varName : Node ? $"let {varName}: {typeName}" : Rust ? $"let r#{varName}: {typeName}" : $"{typeName} {varName}"; - public static string NewObject(string type) => $"{_new}{type}()"; + public static string NewObject(string type) => Rust ? $"{type}::default()" : $"{_new}{type}()"; public static string DigestSize(string hashAlgField) => $"{_digestSize}({_thisQual}{hashAlgField})"; + public static string GetUnionValue(int sizeInBytes) => Rust ? GetEnumValue("", $"u{sizeInBytes}") : ""; + + public static string GetEnumValue(string enumValue, string enumTypename, int valueSizeInBytes = 4) { + if (!Rust) return enumValue; + + // In Rust, if the enum type is a primitive type (such as i32), we need to get the unsigned version of it + // (e.g. u32) using the "as" operator, as into() isn't implemented for such conversions + if (ElementaryTypesCurrentLang.Contains(enumTypename)) { + return $"{enumValue} as u{valueSizeInBytes * 8}"; + } + + // Otherwise, we can use the into() method to convert the enum value to the target type + return $"{enumValue}.into()"; + } + + public static string ParseEnum(string selectorTypeName, string value, string underlyingType) { + if (!Rust) return value; + + if (ElementaryTypesCurrentLang.Contains(selectorTypeName)) + { + return $"{value} as {underlyingType}"; + } + + return $"{selectorTypeName}({value} as {underlyingType})"; + } + + public static int MaxCommentLine => TargetLang.Py ? 72 : 90; public static string EnumeratorAsUint(string name) @@ -120,22 +162,22 @@ public static string EnumeratorAsUint(string name) } public static CodeGenBase NewCodeGen (Lang lang, string rootDir) - => (CodeGenBase)Activator.CreateInstance(CodeGenerators[(int)lang - 2], rootDir); + => (CodeGenBase)Activator.CreateInstance(CodeGenerators[lang], rootDir); /// This method is called before code generation for the given target /// language begins public static void SetTargetLang(Lang lang) { // This assertion will fail if a new target language is added to the Lang enum - // without also adding the corresponding - Debug.Assert(Enum.GetValues(typeof(Lang)).Length == CodeGenerators.Length + 2); + // without also adding the corresponding code generator to CodeGenerators + Debug.Assert(Enum.GetValues(typeof(Lang)).Length == CodeGenerators.Count + 2); _curLang = lang; _thisQual = DotNet || Cpp || Java ? "" : This + "."; - _null = Py ? "None" : Cpp ? "nullptr" : "null"; - _new = DotNet || Java || Node ? "new " : ""; - _quote = Py || Node ? "'" : "\""; - _digestSize = Cpp ? "TPMT_HA::DigestSize" : "Crypto.digestSize"; + _null = Py ? "None" : Rust ? "Default::default()" : Cpp ? "nullptr" : "null"; + _new = DotNet || Java || Node ? "new " : Rust ? "" : ""; + _quote = Py || Node ? "'" : Rust ? "\"" : "\""; + _digestSize = Cpp ? "TPMT_HA::DigestSize" : Rust ? "Crypto::digestSize" : "Crypto.digestSize"; GeneratedEnums = new HashSet(); @@ -176,8 +218,8 @@ public static void SetTargetLang(Lang lang) static bool IsGenerated(TpmEnum e) { - // In Java mutual order of definitions is not important - return Java || (GeneratedEnums != null && GeneratedEnums.Contains(e)); + // In Java and Rust mutual order of definitions is not important + return Java || Rust || (GeneratedEnums != null && GeneratedEnums.Contains(e)); } } // static class TargetLang diff --git a/TssCodeGen/src/TpmTranslations.cs b/TssCodeGen/src/TpmTranslations.cs index d97fd965..9a064a7e 100644 --- a/TssCodeGen/src/TpmTranslations.cs +++ b/TssCodeGen/src/TpmTranslations.cs @@ -444,7 +444,7 @@ public static string TranslateConstExpr(TpmConstExpr ce, TpmEnum enclosingEnum = { var nameDelimiters = new char[] { ' ', ',', '{', '}', '(', ')', '+', '-', '<', '*', '/', '`' }; - string suffix = TargetLang.Java ? ".toInt()" : ""; + string suffix = TargetLang.Java ? ".toInt()" : TargetLang.Rust ? ".into()" : ""; string expr = ce.Expr; string[] tokens = expr.Split(nameDelimiters); bool sizeofOccurred = false, @@ -484,12 +484,12 @@ public static string TranslateConstExpr(TpmConstExpr ce, TpmEnum enclosingEnum = Debug.Assert(sizeofOccurred); sizeofOccurred = false; TpmType t = TpmTypes.Lookup(token); - if (t is TpmStruct || TargetLang.IsOneOf(Lang.Java, Lang.JS, Lang.Py)) + if (t is TpmStruct || TargetLang.IsOneOf(Lang.Java, Lang.JS, Lang.Py, Lang.Rust)) { string sizeofExpr = "sizeof(" + token + ")"; Debug.Assert(expr.Contains(sizeofExpr)); - commentNeeded = TargetLang.Py; - string origExpr = TargetLang.Py ? "" : $"/*{sizeofExpr}*/"; + commentNeeded = TargetLang.Py || TargetLang.Rust; + string origExpr = (TargetLang.Py || TargetLang.Rust) ? "" : $"/*{sizeofExpr}*/"; expr = expr.Replace(sizeofExpr, $"0x{t.GetSize():X}{origExpr}"); } else if (TargetLang.DotNet) @@ -504,7 +504,7 @@ public static string TranslateConstExpr(TpmConstExpr ce, TpmEnum enclosingEnum = if (!TargetLang.IsGenerated(nc.EnclosingEnum)) { translated = nc.NumericValue.ToString(); - if (!TargetLang.Py) + if (!TargetLang.Py && !TargetLang.Rust) translated += "/*" + token + "*/"; else commentNeeded = true; @@ -530,9 +530,15 @@ public static string TranslateConstExpr(TpmConstExpr ce, TpmEnum enclosingEnum = } while (true); expr = expr.Replace("<<", " << (int)"); } + + // For Rust, we might need to add type suffixes for literals + if (TargetLang.Rust && expr.Contains("<<")) + { + expr = expr.Replace("<<", " << "); + } if (commentNeeded) - expr += $" # {ce.Expr}"; + expr += TargetLang.Rust ? $" /* {ce.Expr} */" : $" # {ce.Expr}"; return expr; } // TranslateConstExpr() @@ -549,6 +555,8 @@ static string TranslateFieldType(StructField f) { if (TargetLang.Cpp) typeName = "ByteVec"; + else if (TargetLang.Rust) + return "Vec"; else { if (TargetLang.Node) @@ -562,12 +570,13 @@ static string TranslateFieldType(StructField f) { if (TargetLang.Cpp) typeName = $"vector<{typeName}>"; + else if (TargetLang.Rust) + typeName = $"Vec<{typeName}>"; else return typeName + "[]"; } return typeName; } - } // partial class TargetLang } // namespace CodeGen diff --git a/TssCodeGen/src/TpmTypes.cs b/TssCodeGen/src/TpmTypes.cs index 70d1fdff..1681bf76 100644 --- a/TssCodeGen/src/TpmTypes.cs +++ b/TssCodeGen/src/TpmTypes.cs @@ -564,12 +564,12 @@ public override int CalcSize() if (counter != null) { if (counter.MarshalType == MarshalType.LengthOfStruct) - size += counter.MaxVal.NumericValue; + size += (int)counter.MaxVal.NumericValue; else if (counter.MarshalType == MarshalType.Normal && counter.Type.IsAlgOrHashAlg()) size += 64; // corresponds to SHA512 digest size continue; } - size += f.Type.GetSize() * (counter != null ? counter.MaxVal.NumericValue : 1); + size += (int)f.Type.GetSize() * (counter != null ? (int)counter.MaxVal.NumericValue : 1); } return size; } @@ -601,7 +601,7 @@ public override int CalcSize() { int fieldSize = f.Type.GetSize(); if (f.ArraySize != null) - fieldSize *= f.ArraySize.NumericValue; + fieldSize *= (int)f.ArraySize.NumericValue; size = Math.Max(size, fieldSize); } return size; @@ -948,7 +948,7 @@ public static implicit operator TpmConstExpr(string s) } /// Result of computing the constant's value expression - public int NumericValue => Expression.Eval(Expr); + public long NumericValue => Expression.Eval(Expr); } // class TpmConstExpr @@ -987,7 +987,7 @@ public TpmNamedConstant(TpmEnum enclosingEnum, string specName, string value, st } /// Result of computing the constant's value expression - public int NumericValue => SpecValue.NumericValue; + public long NumericValue => SpecValue.NumericValue; /// Enum member name qualified with the its enum type name public string QualifiedName => EnclosingEnum.Name + TargetLang.ClassMember + Name; From 0561e499ae91081778d56bca78ae0b65688ca3d0 Mon Sep 17 00:00:00 2001 From: Matan Radomski Date: Wed, 12 Aug 2026 14:38:25 +0300 Subject: [PATCH 02/13] Added support for unowned TBS context --- TSS.Rust/src/device.rs | 59 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 54 insertions(+), 5 deletions(-) diff --git a/TSS.Rust/src/device.rs b/TSS.Rust/src/device.rs index 381213e8..70c24fcd 100644 --- a/TSS.Rust/src/device.rs +++ b/TSS.Rust/src/device.rs @@ -429,6 +429,7 @@ pub trait TpmDevice { #[cfg(target_os = "windows")] pub struct TpmTbsDevice { context: *mut c_void, + owns_context: bool, result_buffer: [u8; 4096], res_size: u32, tpm_info: u32, @@ -439,11 +440,35 @@ impl TpmTbsDevice { pub fn new() -> Self { TpmTbsDevice { context: ptr::null_mut(), + owns_context: false, result_buffer: [0; 4096], res_size: 0, tpm_info: 0, } } + + /// Creates a TPM device that submits commands through a caller-owned TBS context. + /// + /// The context is borrowed and will not be closed by [`TpmDevice::close`] or when the device + /// is dropped. + /// + /// # Safety + /// + /// `context` must be a valid TBS context and must remain valid until this device is closed or + /// dropped. The caller must synchronize any other use of the context. + pub unsafe fn from_borrowed_context(context: *mut c_void) -> Result { + if context.is_null() { + return Err(TpmError::InvalidParameter); + } + + Ok(Self { + context, + owns_context: false, + result_buffer: [0; 4096], + res_size: 0, + tpm_info: TpmConnInfo::TpmTbsConn as u32, + }) + } } #[cfg(target_os = "windows")] @@ -472,6 +497,7 @@ impl TpmDevice for TpmTbsDevice { res ))); } + self.owns_context = true; // Get device info to check if TPM 2.0 is available let mut info = TPM_DEVICE_INFO::default(); @@ -483,10 +509,10 @@ impl TpmDevice for TpmTbsDevice { }; if res != TBS_SUCCESS { + self.close(); return Err(TpmError::TbsError("Failed to get device info".to_string())); } else if info.tpmVersion != TPM_VERSION_20 { - unsafe { Tbsip_Context_Close(self.context) }; - self.context = ptr::null_mut(); + self.close(); return Err(TpmError::TbsError( "Platform does not contain a TPM 2.0".to_string(), )); @@ -499,11 +525,12 @@ impl TpmDevice for TpmTbsDevice { } fn close(&mut self) { - if !self.context.is_null() { + if self.owns_context && !self.context.is_null() { unsafe { Tbsip_Context_Close(self.context) }; - self.context = ptr::null_mut(); } - + self.context = ptr::null_mut(); + self.owns_context = false; + self.res_size = 0; self.tpm_info = 0; } @@ -570,6 +597,28 @@ impl TpmDevice for TpmTbsDevice { } } +#[cfg(all(test, target_os = "windows"))] +mod windows_tests { + use std::ptr::NonNull; + + use super::*; + + #[test] + fn borrowed_context_rejects_null() { + let result = unsafe { TpmTbsDevice::from_borrowed_context(ptr::null_mut()) }; + assert!(matches!(result, Err(TpmError::InvalidParameter))); + } + + #[test] + fn borrowed_context_is_not_owned() { + let context = NonNull::::dangling().as_ptr(); + let device = unsafe { TpmTbsDevice::from_borrowed_context(context) }.unwrap(); + + assert_eq!(device.context, context); + assert!(!device.owns_context); + } +} + // Linux TPM device implementation #[cfg(target_os = "linux")] pub struct TpmTbsDevice { From 93729bf6e2345b10dff02e61eb50a7c731057f93 Mon Sep 17 00:00:00 2001 From: Roee Kasher Date: Wed, 12 Aug 2026 15:31:31 +0300 Subject: [PATCH 03/13] Harden TSS.Rust unmarshaling and clean up clippy warnings Add bounds/underflow checking to TpmBuffer reads so truncated or malformed responses fail instead of silently returning zeros, fix ValidateSignature to use the signature's own hash algorithm, and move fromTpm/fromBytes to TpmStructure trait defaults (removing ~3.6k lines of generated code). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/copilot-instructions.md | 98 + TSS.Rust/clippy.toml | 17 - TSS.Rust/examples/tpm_samples.rs | 267 +- TSS.Rust/src/auth_session.rs | 3 + TSS.Rust/src/crypto.rs | 82 +- TSS.Rust/src/device.rs | 13 +- TSS.Rust/src/policy.rs | 26 +- TSS.Rust/src/tpm2.rs | 14 +- TSS.Rust/src/tpm2_helpers.rs | 2 +- TSS.Rust/src/tpm2_impl.rs | 33 +- TSS.Rust/src/tpm_buffer.rs | 181 +- TSS.Rust/src/tpm_structure.rs | 63 +- TSS.Rust/src/tpm_type_extensions.rs | 68 +- TSS.Rust/src/tpm_types.rs | 3661 +-------------------------- TssCodeGen/src/CGenRust.cs | 16 +- 15 files changed, 699 insertions(+), 3845 deletions(-) create mode 100644 .github/copilot-instructions.md delete mode 100644 TSS.Rust/clippy.toml diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 00000000..13fdce77 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,98 @@ +# Copilot Instructions for TSS.MSR + +## Project Overview + +TSS.MSR is a multi-language TPM 2.0 Software Stack providing complete TPM 2.0 API abstractions. It contains parallel implementations in C# (.NET), C++, Java, TypeScript/Node.js, Python, and Rust, plus the **TssCodeGen** tool that auto-generates TPM type/command definitions across all languages from the TPM 2.0 specification documents. + +## Architecture + +### Code Generation Pipeline (TssCodeGen) + +TssCodeGen is the central tool that keeps all language implementations in sync with the TPM 2.0 spec. It runs a 3-phase workflow: + +1. **Table Extraction** — Parses TPM 2.0 spec Word documents into `RawTables.xml` (slow, uses Office interop; cached) +2. **Type Extraction** — Builds an AST of all TPM 2.0 entities from the raw tables +3. **Code Generation** — Language-specific generators (`CGenDotNet`, `CGenCpp`, `CGenJava`, `CGenNode`, `CGenPy`, `CGenRust`) emit target code + +**Generated output files:** +- **TSS.NET:** `TSS.Net/X_TpmDefs.cs` +- **TSS.CPP:** `TpmTypes.h`, `Tpm2.h`, `TpmTypes.cpp` (between `<>` / `<>` markers) +- **TSS.Java:** One `.java` file per type in `src/tss/tpm/` plus `Tpm.java` +- **TSS.JS:** `src/TpmTypes.ts`, `src/Tpm.ts` +- **TSS.Py:** `src/TpmTypes.py`, `src/Tpm.py` + +**⚠️ Never manually edit auto-generated files.** They will be overwritten by TssCodeGen. Look for file headers stating "automatically generated" or `<>` markers. + +### Extension Mechanism (.snips files) + +Each language has `.snips` files (e.g., `TpmExtensions.js.snips`) that inject hand-written methods into auto-generated classes during code generation. Lines starting with `>> CLASSNAME` mark insertion points for the target class. + +### Shared Patterns Across All Languages + +- **TpmStructure base class** — All TPM types inherit from it; provides `toTpm()`/`initFromTpm()` (or language equivalent) for binary serialization +- **Union-as-interface** — TPM unions are represented as interfaces (e.g., `TPMU_SCHEME_KEYEDHASH`), with concrete structs implementing them. Each implementer provides `GetUnionSelector()` returning the discriminator value +- **Device abstraction** — Platform-specific TPM access (Linux `/dev/tpmrm0`, Windows TBS, TCP simulator) behind a common `TpmDevice` interface/abstract class + +### Naming Conventions + +| Aspect | TSS.NET | Other Languages | +|--------|---------|-----------------| +| Types | CamelCase, drops `TPM_`/`TPMS_` prefixes (`TpmAlgId`, `TpmRsa`) | Preserves spec names (`TPM_ALG_ID`, `TPMS_RSA_PARMS`) | +| Fields | PascalCase (`AuthPolicy`) | camelCase (JS/Py) or spec-style (Java/Rust) | +| Commands | `Tpm2.Hash()` | `tpm.Hash()` or similar | + +## Build Commands + +### C++ (`TSS.CPP/`) +```bash +make # Build library + samples (debug) +make CONFIG=release # Release build +make test # Build and run samples as tests +make clean +``` + +### Java (`TSS.Java/`) +```bash +mvn clean compile # Compile +mvn clean install # Build and install +``` + +### .NET (`TSS.NET/`) +```bash +dotnet build TSS.NET.sln +``` +Targets: .NET 4.7.2 and .NET 5. Release builds use strong-name signing. + +### Rust (`TSS.Rust/`) +```bash +cargo build +cargo test +cargo run --example tpm_samples +``` + +### TssCodeGen +```bash +TssCodeGen [-spec ] [-dest ] [-extract] [-dotNet] [-cpp] [-java] [-node] [-py] +``` +Use `-extract` to force re-parsing of spec documents. Without it, uses cached `RawTables.xml`. Language flags generate only selected targets. + +### Tpm2Tester +```bash +# Run specific test profiles against a TPM simulator +TestSuiteApp -device tcp -address localhost:2321 -randSeed startup nv + +# Run a single test +TestSuiteApp -device tcp -tests TestCaseName + +# Stress test +TestSuiteApp -device tcp -stress -threads 4 -mins 10 +``` + +## Key Dependencies + +| Language | Crypto Library | Native Access | +|----------|---------------|---------------| +| .NET | BouncyCastle.NetCore | - | +| Java | BouncyCastle (bcprov-jdk15on) | JNA | +| JS | - | ffi-napi, ref-napi | +| Rust | rsa, aes, sha1/sha2, hmac | windows crate (Win32) / libc (Unix) | diff --git a/TSS.Rust/clippy.toml b/TSS.Rust/clippy.toml deleted file mode 100644 index ec880d98..00000000 --- a/TSS.Rust/clippy.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "tss-rust" -version = "0.1.0" -edition = "2021" - -[build] -rustflags = ["-A", "clippy::non_camel_case_types", "-A", "clippy::unused_variables"] - -[lib] -crate-type = ["cdylib", "lib"] - -[dependencies] -num_enum = "0.7.3" - -[[example]] -name = "tpm_samples" -path = "examples/tpm_samples.rs" diff --git a/TSS.Rust/examples/tpm_samples.rs b/TSS.Rust/examples/tpm_samples.rs index bafa94fe..d8368b5a 100644 --- a/TSS.Rust/examples/tpm_samples.rs +++ b/TSS.Rust/examples/tpm_samples.rs @@ -1,4 +1,33 @@ -use std::io::{self, Write}; +//! TSS.Rust sample suite. +//! +//! # This suite mutates TPM state +//! +//! These samples are ports of the C++ TSS samples and were written against the TPM +//! *simulator*, where state is disposable. Several of them change persistent state: +//! `misc_admin_sample` and `bound_session_sample` rewrite the OWNER hierarchy auth +//! value, and `policy_counter_timer_sample` rewrites the OWNER primary policy. Each +//! restores what it changed, but a failure part-way through can leave it dirty. +//! +//! The recovery prologue (`reset_da_lockout`, `recover_endorsement_hierarchy`, +//! `recover_owner_hierarchy`) exists to clean that up between simulator runs. On real +//! hardware it is destructive: it submits known-wrong auth values to the OWNER and +//! LOCKOUT hierarchies, and every wrong guess feeds the TPM's dictionary attack +//! counter. Enough runs will push a real TPM into DA lockout, after which unrelated +//! software - anything going through the Platform Crypto Provider, for instance - +//! starts failing. Run elevated, it would also rewrite the ENDORSEMENT hierarchy auth +//! and primary policy outright. +//! +//! The prologue is therefore opt-in. Pass `--recover-hierarchies` to enable it, and +//! only against a simulator or a machine whose TPM you are willing to disturb. +//! +//! # This suite is not a regression oracle +//! +//! Because it mutates TPM state, consecutive runs against real hardware are not +//! comparable: run N alters the state run N+1 observes, so output length and error +//! counts drift on their own. To A/B two builds, run them adjacently in the same state +//! and compare output as a set. The crate's unit tests are the reliable signal. + +use std::io::{self, Write}; use tss_rust::{ auth_session::Session, crypto::Crypto, @@ -47,20 +76,16 @@ fn get_capabilities(tpm: &mut Tpm2) -> Result<(), Box> { let addition_to_start_val: u32; let caps = tpm.GetCapability(TPM_CAP::ALGS, start_val, 8)?; - if let Some(caps) = caps.capabilityData { - if let TPMU_CAPABILITIES::algorithms(props) = caps { - for p in props.algProperties.iter() { - println!("{}: {}", p.alg, p.algProperties); - } - - addition_to_start_val = (props.algProperties[props.algProperties.len() - 1] - .alg - .get_value() - + 1) - .into(); - } else { - break; + if let Some(TPMU_CAPABILITIES::algorithms(props)) = caps.capabilityData { + for p in props.algProperties.iter() { + println!("{}: {}", p.alg, p.algProperties); } + + addition_to_start_val = (props.algProperties[props.algProperties.len() - 1] + .alg + .get_value() + + 1) + .into(); } else { break; } @@ -79,22 +104,18 @@ fn get_capabilities(tpm: &mut Tpm2) -> Result<(), Box> { loop { let caps = tpm.GetCapability(TPM_CAP::COMMANDS, start_val, 32)?; - if let Some(caps) = caps.capabilityData { - if let TPMU_CAPABILITIES::command(props) = caps { - for p in props.commandAttributes.iter() { - let command_value = p.get_value() & 0xFFFF; - // Decode the packed structure - if let Ok(cc) = TPM_CC::try_from(command_value) { - supported_commands.push(format!("TPM_CC_{}", cc.to_string())); - } - // let masked_attr = TPMA_CC::try_from(p.get_value() & 0xFFff0000)?; + if let Some(TPMU_CAPABILITIES::command(props)) = caps.capabilityData { + for p in props.commandAttributes.iter() { + let command_value = p.get_value() & 0xFFFF; + // Decode the packed structure + if let Ok(cc) = TPM_CC::try_from(command_value) { + supported_commands.push(format!("TPM_CC_{}", cc)); + } + // let masked_attr = TPMA_CC::try_from(p.get_value() & 0xFFff0000)?; - // println!("Command {}", cc); + // println!("Command {}", cc); - start_val = command_value; - } - } else { - break; + start_val = command_value; } } else { break; @@ -114,7 +135,7 @@ fn get_capabilities(tpm: &mut Tpm2) -> Result<(), Box> { announce(&announcement); let column_width = 35; let columns = 3; - let rows = (supported_commands.len() + columns - 1) / columns; + let rows = supported_commands.len().div_ceil(columns); for row in 0..rows { for col in 0..columns { @@ -168,9 +189,9 @@ fn make_child_signing_key(tpm: &mut Tpm2, parent: &TPM_HANDLE, restricted: bool) let template = TPMT_PUBLIC::new(TPM_ALG_ID::SHA1, object_attributes, &Default::default(), &Some(parameters), &Some(unique)); - let new_signing_key = tpm.Create(&parent, &Default::default(), &template, &Default::default(), &Default::default())?; + let new_signing_key = tpm.Create(parent, &Default::default(), &template, &Default::default(), &Default::default())?; - tpm.Load(&parent, &new_signing_key.outPrivate, &new_signing_key.outPublic) + tpm.Load(parent, &new_signing_key.outPrivate, &new_signing_key.outPublic) } fn make_endorsement_key(tpm: &mut Tpm2) -> Result { @@ -465,7 +486,7 @@ fn pcr_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { println!("PCR 16 after event: {:?}", pcr_vals2.pcrValues); // Extend with a hash value - let extend_hash = TPMT_HA::new(TPM_ALG_ID::SHA256, &Crypto::hash(TPM_ALG_ID::SHA256, &vec![6, 7, 8])?); + let extend_hash = TPMT_HA::new(TPM_ALG_ID::SHA256, &Crypto::hash(TPM_ALG_ID::SHA256, &[6, 7, 8])?); tpm.PCR_Extend(&pcr_handle, &vec![extend_hash])?; println!("Extended hash into PCR 16"); @@ -514,7 +535,7 @@ fn primary_keys_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { println!("Created signing primary key with handle: {:?}", new_primary.handle); // Sign some data - let data_to_sign = Crypto::hash(TPM_ALG_ID::SHA256, &b"Data to sign".to_vec())?; + let data_to_sign = Crypto::hash(TPM_ALG_ID::SHA256, b"Data to sign".as_ref())?; let signature = tpm.Sign( &new_primary.handle, &data_to_sign, @@ -571,7 +592,7 @@ fn child_keys_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { println!("Created child signing key: {:?}", sign_key); // Sign some data - let data_to_sign = Crypto::hash(TPM_ALG_ID::SHA1, &b"Test data for signing".to_vec())?; + let data_to_sign = Crypto::hash(TPM_ALG_ID::SHA1, b"Test data for signing".as_ref())?; let signature = tpm.Sign( &sign_key, &data_to_sign, @@ -927,7 +948,7 @@ fn auth_sessions_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { println!("Loaded child key with HMAC session: {:?}", loaded_key); // Sign data with the loaded key using the session - let data_to_sign = Crypto::hash(TPM_ALG_ID::SHA1, &b"Auth session test data".to_vec())?; + let data_to_sign = Crypto::hash(TPM_ALG_ID::SHA1, b"Auth session test data".as_ref())?; let sig = tpm.with_session(sess.clone()).Sign( &loaded_key, &data_to_sign, &TPMU_SIG_SCHEME::create(TPM_ALG_ID::NULL)?, @@ -1277,7 +1298,7 @@ fn policy_with_passwords_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { tpm.FlushContext(&session_handle(&trial))?; println!("PolicyPassword digest: {:?}", policy_digest); - let use_auth = Crypto::hash(TPM_ALG_ID::SHA256, &b"password".to_vec())?; + let use_auth = Crypto::hash(TPM_ALG_ID::SHA256, b"password".as_ref())?; let mut hmac_handle = make_hmac_primary_with_policy(tpm, &policy_digest, &use_auth, TPM_ALG_ID::SHA256)?; hmac_handle.set_auth(&use_auth); @@ -1311,7 +1332,7 @@ fn policy_with_passwords_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { tpm.FlushContext(&session_handle(&trial2))?; println!("PolicyAuthValue digest: {:?}", policy_digest2); - let use_auth2 = Crypto::hash(TPM_ALG_ID::SHA256, &b"password2".to_vec())?; + let use_auth2 = Crypto::hash(TPM_ALG_ID::SHA256, b"password2".as_ref())?; let mut hmac_handle2 = make_hmac_primary_with_policy(tpm, &policy_digest2, &use_auth2, TPM_ALG_ID::SHA256)?; hmac_handle2.set_auth(&use_auth2); @@ -1393,7 +1414,7 @@ fn import_duplicate_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { // Load the imported key and sign with it let imported_key = tpm.Load(&primary, &imported, &new_key.outPublic)?; - let data_to_sign = Crypto::hash(TPM_ALG_ID::SHA256, &b"test import".to_vec())?; + let data_to_sign = Crypto::hash(TPM_ALG_ID::SHA256, b"test import".as_ref())?; let sig = tpm.Sign(&imported_key, &data_to_sign, &TPMU_SIG_SCHEME::create(TPM_ALG_ID::NULL)?, &TPMT_TK_HASHCHECK::default())?; @@ -1458,9 +1479,20 @@ fn policy_counter_timer_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { std::thread::sleep(std::time::Duration::from_millis(1500)); } - // Put things back the way they were - tpm.SetPrimaryPolicy(&TPM_HANDLE::new(TPM_RH::OWNER.get_value()), - &vec![], TPM_ALG_ID::NULL)?; + // Put things back the way they were. Deliberately not `?` - see misc_admin_sample. + tpm.allow_errors(); + let _ = tpm.SetPrimaryPolicy( + &TPM_HANDLE::new(TPM_RH::OWNER.get_value()), + &vec![], + TPM_ALG_ID::NULL, + ); + if tpm.last_response_code() != TPM_RC::SUCCESS { + print_error(&format!( + "FAILED to clear the OWNER primary policy (rc={}). This TPM's owner hierarchy \ + still carries the PolicyCounterTimer digest.", + tpm.last_response_code() + )); + } println!("PolicyCounterTimer sample completed successfully"); Ok(()) @@ -1617,7 +1649,7 @@ fn software_keys_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { println!("Created duplicatable signing key in TPM"); // Sign with the TPM key - let to_sign = Crypto::hash(TPM_ALG_ID::SHA256, &b"hello from software key".to_vec())?; + let to_sign = Crypto::hash(TPM_ALG_ID::SHA256, b"hello from software key".as_ref())?; let tpm_sig = tpm.Sign(&tpm_key, &to_sign, &TPMU_SIG_SCHEME::create(TPM_ALG_ID::NULL)?, &TPMT_TK_HASHCHECK::default())?; @@ -2109,22 +2141,24 @@ fn policy_signed_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { let hash_alg = TPM_ALG_ID::SHA256; // Create a SW signing key - let mut sw_key = TSS_KEY::default(); - sw_key.publicPart = TPMT_PUBLIC { - nameAlg: hash_alg, - objectAttributes: TPMA_OBJECT( - TPMA_OBJECT::sign.get_value() | TPMA_OBJECT::userWithAuth.get_value(), - ), - authPolicy: vec![], - parameters: Some(TPMU_PUBLIC_PARMS::rsaDetail(TPMS_RSA_PARMS { - symmetric: TPMT_SYM_DEF_OBJECT::default(), - scheme: Some(TPMU_ASYM_SCHEME::rsassa(TPMS_SIG_SCHEME_RSASSA { - hashAlg: hash_alg, + let mut sw_key = TSS_KEY { + publicPart: TPMT_PUBLIC { + nameAlg: hash_alg, + objectAttributes: TPMA_OBJECT( + TPMA_OBJECT::sign.get_value() | TPMA_OBJECT::userWithAuth.get_value(), + ), + authPolicy: vec![], + parameters: Some(TPMU_PUBLIC_PARMS::rsaDetail(TPMS_RSA_PARMS { + symmetric: TPMT_SYM_DEF_OBJECT::default(), + scheme: Some(TPMU_ASYM_SCHEME::rsassa(TPMS_SIG_SCHEME_RSASSA { + hashAlg: hash_alg, + })), + keyBits: 2048, + exponent: 0, })), - keyBits: 2048, - exponent: 0, - })), - unique: Some(TPMU_PUBLIC_ID::rsa(TPM2B_PUBLIC_KEY_RSA::default())), + unique: Some(TPMU_PUBLIC_ID::rsa(TPM2B_PUBLIC_KEY_RSA::default())), + }, + ..Default::default() }; sw_key.create_key()?; println!("Created software RSA-2048 signing key"); @@ -2216,22 +2250,24 @@ fn policy_authorize_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { let hash_alg = TPM_ALG_ID::SHA256; // Create a software signing key (the "authorizing" key) - let mut sw_key = TSS_KEY::default(); - sw_key.publicPart = TPMT_PUBLIC { - nameAlg: hash_alg, - objectAttributes: TPMA_OBJECT( - TPMA_OBJECT::sign.get_value() | TPMA_OBJECT::userWithAuth.get_value(), - ), - authPolicy: vec![], - parameters: Some(TPMU_PUBLIC_PARMS::rsaDetail(TPMS_RSA_PARMS { - symmetric: TPMT_SYM_DEF_OBJECT::default(), - scheme: Some(TPMU_ASYM_SCHEME::rsassa(TPMS_SIG_SCHEME_RSASSA { - hashAlg: hash_alg, + let mut sw_key = TSS_KEY { + publicPart: TPMT_PUBLIC { + nameAlg: hash_alg, + objectAttributes: TPMA_OBJECT( + TPMA_OBJECT::sign.get_value() | TPMA_OBJECT::userWithAuth.get_value(), + ), + authPolicy: vec![], + parameters: Some(TPMU_PUBLIC_PARMS::rsaDetail(TPMS_RSA_PARMS { + symmetric: TPMT_SYM_DEF_OBJECT::default(), + scheme: Some(TPMU_ASYM_SCHEME::rsassa(TPMS_SIG_SCHEME_RSASSA { + hashAlg: hash_alg, + })), + keyBits: 2048, + exponent: 0, })), - keyBits: 2048, - exponent: 0, - })), - unique: Some(TPMU_PUBLIC_ID::rsa(TPM2B_PUBLIC_KEY_RSA::default())), + unique: Some(TPMU_PUBLIC_ID::rsa(TPM2B_PUBLIC_KEY_RSA::default())), + }, + ..Default::default() }; sw_key.create_key()?; println!("Created authorizing SW key"); @@ -2337,12 +2373,21 @@ fn admin_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { // TSS.Rust tracks changes of auth-values and updates the relevant handle. // Because we have the new auth-value we can continue managing the TPM. - // Now set it back to empty. - tpm.HierarchyChangeAuth( - &TPM_HANDLE::new(TPM_RH::OWNER.get_value()), - &vec![], - )?; - println!("OWNER auth reset to empty"); + // Now set it back to empty. This must not use `?`: leaving the sample early here + // would strand the OWNER hierarchy on a non-empty auth value, and the recovery + // prologue that used to clean that up is opt-in (see the module docs). + tpm.allow_errors(); + let _ = tpm.HierarchyChangeAuth(&TPM_HANDLE::new(TPM_RH::OWNER.get_value()), &vec![]); + if tpm.last_response_code() == TPM_RC::SUCCESS { + println!("OWNER auth reset to empty"); + } else { + print_error(&format!( + "FAILED to reset OWNER auth (rc={}). This TPM's owner hierarchy is now set to \ + SHA1(\"passw0rd\"); re-run with {} to restore it.", + tpm.last_response_code(), + RECOVER_HIERARCHIES_FLAG + )); + } // --- Demonstrate that primary keys are deterministic --- println!("\n>> Primary key determinism"); @@ -2574,7 +2619,7 @@ fn bound_session_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { // Always reset owner auth, even if the test failed tpm.allow_errors(); let _ = tpm.HierarchyChangeAuth(&TPM_HANDLE::new(TPM_RH::OWNER.get_value()), &vec![]); - tpm.set_admin_auth(TPM_RH::OWNER, &vec![]); + tpm.set_admin_auth(TPM_RH::OWNER, &[]); result } @@ -2654,6 +2699,19 @@ fn bound_session_inner(tpm: &mut Tpm2, owner_auth: &[u8]) -> Result<(), TpmError Ok(()) } +/// Opt-in flag for the destructive hierarchy recovery prologue. See the module docs. +const RECOVER_HIERARCHIES_FLAG: &str = "--recover-hierarchies"; + +fn hierarchy_recovery_requested() -> bool { + std::env::args().any(|arg| arg == RECOVER_HIERARCHIES_FLAG) +} + +/// Clears the TPM's dictionary attack lockout. +/// +/// Destructive on real hardware: if `lockoutAuth` is not empty, this is a failed auth +/// attempt against it, which disables `lockoutAuth` until the lockout recovery interval +/// elapses (24 hours on a typical Windows machine). Gated behind +/// [`RECOVER_HIERARCHIES_FLAG`]. fn reset_da_lockout(tpm: &mut Tpm2) { tpm.allow_errors(); let _ = tpm.DictionaryAttackLockReset(&TPM_HANDLE::new(TPM_RH::LOCKOUT.get_value())); @@ -2677,6 +2735,11 @@ fn reset_da_lockout(tpm: &mut Tpm2) { } } +/// Resets the ENDORSEMENT hierarchy auth value and primary policy. +/// +/// Destructive on real hardware: this rewrites the endorsement hierarchy outright, +/// which can invalidate existing EK-based enrollments. Gated behind +/// [`RECOVER_HIERARCHIES_FLAG`]. fn recover_endorsement_hierarchy(tpm: &mut Tpm2) { let hash_alg = TPM_ALG_ID::SHA256; let endorsement_name = TPM_HANDLE::new(TPM_RH::ENDORSEMENT.get_value()).get_name().unwrap_or_default(); @@ -2699,6 +2762,12 @@ fn recover_endorsement_hierarchy(tpm: &mut Tpm2) { ); } +/// Restores an empty OWNER auth value after a sample left one of its known values behind. +/// +/// Destructive on real hardware: every entry in `known_auths` that does not match is a +/// failed auth attempt that increments the TPM's dictionary attack counter, so each run +/// costs up to two counts even when it does nothing useful. Gated behind +/// [`RECOVER_HIERARCHIES_FLAG`]. fn recover_owner_hierarchy(tpm: &mut Tpm2) { let known_auths: Vec> = vec![ Crypto::hash(TPM_ALG_ID::SHA1, b"passw0rd").unwrap_or_default(), @@ -2721,23 +2790,45 @@ fn main() -> Result<(), Box> { device.connect()?; let mut tpm = create_tpm_with_device(device); - reset_da_lockout(&mut tpm); - recover_endorsement_hierarchy(&mut tpm); - recover_owner_hierarchy(&mut tpm); + if hierarchy_recovery_requested() { + print_error(&format!( + "{} given: running hierarchy recovery. This submits known-wrong auth values \ + to the OWNER and LOCKOUT hierarchies and will increment this TPM's dictionary \ + attack counter.", + RECOVER_HIERARCHIES_FLAG + )); + reset_da_lockout(&mut tpm); + recover_endorsement_hierarchy(&mut tpm); + recover_owner_hierarchy(&mut tpm); + } else { + println!( + "Skipping hierarchy recovery. Pass {} to enable it - simulator only, it feeds \ + the TPM's dictionary attack counter on real hardware.", + RECOVER_HIERARCHIES_FLAG + ); + } - get_capabilities(&mut tpm)?; + if let Err(e) = get_capabilities(&mut tpm) { + print_error(&format!("get_capabilities failed: {}", e)); + } // ---- Samples ordered to match C++ RunAllSamples() ---- - rand_sample(&mut tpm)?; + if let Err(e) = rand_sample(&mut tpm) { + print_error(&format!("rand_sample failed: {}", e)); + } if let Err(e) = dictionary_attack_sample(&mut tpm) { print_error(&format!("dictionary_attack_sample failed (TPM may be in lockout): {}", e)); } - hash_sample(&mut tpm)?; + if let Err(e) = hash_sample(&mut tpm) { + print_error(&format!("hash_sample failed: {}", e)); + } if let Err(e) = hmac_sample(&mut tpm) { print_error(&format!("hmac_sample failed (may be DA lockout): {}", e)); } - pcr_sample(&mut tpm)?; + if let Err(e) = pcr_sample(&mut tpm) { + print_error(&format!("pcr_sample failed (PCR_Reset is admin-only on Windows): {}", e)); + } if let Err(e) = policy_locality_sample(&mut tpm) { print_error(&format!("policy_locality_sample failed: {}", e)); } @@ -2766,7 +2857,9 @@ fn main() -> Result<(), Box> { if let Err(e) = policy_or_sample(&mut tpm) { print_error(&format!("policy_or_sample failed: {}", e)); } - counter_timer_sample(&mut tpm)?; + if let Err(e) = counter_timer_sample(&mut tpm) { + print_error(&format!("counter_timer_sample failed: {}", e)); + } if let Err(e) = attestation(&mut tpm) { print_error(&format!("attestation failed: {}", e)); } diff --git a/TSS.Rust/src/auth_session.rs b/TSS.Rust/src/auth_session.rs index fb3819f1..69198a15 100644 --- a/TSS.Rust/src/auth_session.rs +++ b/TSS.Rust/src/auth_session.rs @@ -71,6 +71,9 @@ impl Session { } /// Create a fully initialized HMAC or policy session from a TPM StartAuthSession response. + // The parameter list mirrors the TPM2_StartAuthSession response fields; grouping them into a + // struct would just move the same values behind another type. + #[allow(clippy::too_many_arguments)] pub fn from_tpm_response( session_handle: TPM_HANDLE, session_type: TPM_SE, diff --git a/TSS.Rust/src/crypto.rs b/TSS.Rust/src/crypto.rs index 865a78b8..41feb4d4 100644 --- a/TSS.Rust/src/crypto.rs +++ b/TSS.Rust/src/crypto.rs @@ -115,12 +115,23 @@ impl Crypto { mac.update(to_hash); Ok(mac.finalize().into_bytes().to_vec()) } - _ => { - return Err(TpmError::NotSupported(format!( - "Unsupported hash algorithm: {:?}", - hash_alg - ))) - } + _ => Err(TpmError::NotSupported(format!( + "Unsupported hash algorithm: {:?}", + hash_alg + ))), + } + } + + pub(crate) fn pkcs1v15_sign_scheme(hash_alg: TPM_ALG_ID) -> Result { + match hash_alg { + TPM_ALG_ID::SHA1 => Ok(Pkcs1v15Sign::new::()), + TPM_ALG_ID::SHA256 => Ok(Pkcs1v15Sign::new::()), + TPM_ALG_ID::SHA384 => Ok(Pkcs1v15Sign::new::()), + TPM_ALG_ID::SHA512 => Ok(Pkcs1v15Sign::new::()), + _ => Err(TpmError::NotSupported(format!( + "Unsupported RSASSA hash algorithm: {:?}", + hash_alg + ))), } } @@ -154,12 +165,20 @@ impl Crypto { let rsa_public_key = RsaPublicKey::new(BigUint::from_bytes_be(rsa_pub_key), BigUint::from_bytes_be(&[1, 0, 1])) .map_err(|_| TpmError::InvalidArraySize("Invalid RSA public key".to_string()))?; + let scheme = Self::pkcs1v15_sign_scheme(signature.hash)?; + let expected_digest_size = Self::digestSize(signature.hash); + if signed_blob_hash.len() != expected_digest_size { + return Err(TpmError::InvalidArraySize(format!( + "ValidateSignature: digest length {} does not match {:?} length {}", + signed_blob_hash.len(), + signature.hash, + expected_digest_size + ))); + } + Ok(rsa_public_key - .verify( - Pkcs1v15Sign::new::(), - &signed_blob_hash, - &signature.sig - ).is_ok()) + .verify(scheme, &signed_blob_hash, &signature.sig) + .is_ok()) } // KDFa implementation as specified in TPM 2.0 Part 1 @@ -171,7 +190,7 @@ impl Crypto { context_v: &[u8], bits: usize, ) -> Result, TpmError> { - let bytes_needed = (bits + 7) / 8; + let bytes_needed = bits.div_ceil(8); let mut result = Vec::new(); let mut counter = 1u32; @@ -231,11 +250,11 @@ impl Crypto { let cipher = Aes128::new(GenericArray::from_slice(key)); let mut result = Vec::with_capacity(data.len()); - let mut feedback = GenericArray::from_slice(iv).clone(); + let mut feedback = *GenericArray::from_slice(iv); for chunk in data.chunks(16) { // Encrypt the feedback (IV or previous ciphertext) - let mut encrypted_feedback = feedback.clone(); + let mut encrypted_feedback = feedback; cipher.encrypt_block(&mut encrypted_feedback); if encrypt { @@ -270,3 +289,38 @@ impl Crypto { result } } + +#[cfg(test)] +mod tests { + use super::*; + use rand::rngs::OsRng; + use rsa::traits::PublicKeyParts; + use rsa::RsaPrivateKey; + + #[test] + fn validate_signature_uses_signature_hash_algorithm() -> Result<(), TpmError> { + let mut rng = OsRng; + let private_key = RsaPrivateKey::new(&mut rng, 2048) + .map_err(|e| TpmError::GenericError(format!("RSA key generation failed: {e}")))?; + let public_key = TPMT_PUBLIC { + parameters: Some(TPMU_PUBLIC_PARMS::rsaDetail(TPMS_RSA_PARMS::default())), + unique: Some(TPMU_PUBLIC_ID::rsa(TPM2B_PUBLIC_KEY_RSA { + buffer: private_key.n().to_bytes_be(), + })), + ..Default::default() + }; + + let message = b"digest dispatch regression"; + let digest = Sha256::digest(message).to_vec(); + let sig = private_key + .sign(Pkcs1v15Sign::new::(), &digest) + .map_err(|e| TpmError::GenericError(format!("RSA signing failed: {e}")))?; + let signature = Some(TPMU_SIGNATURE::rsassa(TPMS_SIGNATURE_RSASSA { + hash: TPM_ALG_ID::SHA256, + sig, + })); + + assert!(Crypto::validate_signature(&public_key, digest, &signature)?); + Ok(()) + } +} diff --git a/TSS.Rust/src/device.rs b/TSS.Rust/src/device.rs index 381213e8..b3149b56 100644 --- a/TSS.Rust/src/device.rs +++ b/TSS.Rust/src/device.rs @@ -434,6 +434,13 @@ pub struct TpmTbsDevice { tpm_info: u32, } +#[cfg(target_os = "windows")] +impl Default for TpmTbsDevice { + fn default() -> Self { + Self::new() + } +} + #[cfg(target_os = "windows")] impl TpmTbsDevice { pub fn new() -> Self { @@ -453,8 +460,10 @@ impl TpmDevice for TpmTbsDevice { return Ok(true); // Already connected } - let mut params = TBS_CONTEXT_PARAMS2::default(); - params.version = TBS_CONTEXT_VERSION_TWO; + let mut params = TBS_CONTEXT_PARAMS2 { + version: TBS_CONTEXT_VERSION_TWO, + ..Default::default() + }; params.Anonymous.Anonymous._bitfield = 4; params.Anonymous.asUINT32 = 4; diff --git a/TSS.Rust/src/policy.rs b/TSS.Rust/src/policy.rs index 8191e189..d9d268b1 100644 --- a/TSS.Rust/src/policy.rs +++ b/TSS.Rust/src/policy.rs @@ -75,6 +75,12 @@ pub struct PolicyTree { assertions: Vec>, } +impl Default for PolicyTree { + fn default() -> Self { + Self::new() + } +} + impl PolicyTree { /// Create an empty policy tree. pub fn new() -> Self { @@ -82,6 +88,8 @@ impl PolicyTree { } /// Add a policy assertion to the tree. Assertions execute in order (first added = first executed). + // This is a consuming builder method, not arithmetic - `std::ops::Add` is the wrong shape for it. + #[allow(clippy::should_implement_trait)] pub fn add(mut self, assertion: impl PolicyAssertion + 'static) -> Self { self.assertions.push(Box::new(assertion)); self @@ -161,7 +169,7 @@ impl PolicyAssertion for PolicyLocality { let mut buf = Vec::new(); buf.extend_from_slice(acc); buf.extend_from_slice(&TPM_CC::PolicyLocality.get_value().to_be_bytes()); - buf.push(self.locality.get_value() as u8); + buf.push(self.locality.get_value()); *acc = Crypto::hash(hash_alg, &buf)?; Ok(()) } @@ -215,6 +223,12 @@ impl PolicyAssertion for PolicyPcr { /// PolicyPassword - requires the object's authorization value be provided as a password. pub struct PolicyPassword; +impl Default for PolicyPassword { + fn default() -> Self { + Self::new() + } +} + impl PolicyPassword { pub fn new() -> Self { Self } } @@ -236,6 +250,12 @@ impl PolicyAssertion for PolicyPassword { /// PolicyAuthValue - requires auth-value HMAC during policy use. pub struct PolicyAuthValue; +impl Default for PolicyAuthValue { + fn default() -> Self { + Self::new() + } +} + impl PolicyAuthValue { pub fn new() -> Self { Self } } @@ -321,7 +341,7 @@ impl PolicyAssertion for PolicyCounterTimer { let mut inner = Vec::new(); inner.extend_from_slice(&self.operand_b); inner.extend_from_slice(&self.offset.to_be_bytes()); - inner.extend_from_slice(&(self.operation.get_value() as u16).to_be_bytes()); + inner.extend_from_slice(&self.operation.get_value().to_be_bytes()); let arg_hash = Crypto::hash(hash_alg, &inner)?; policy_update(hash_alg, acc, TPM_CC::PolicyCounterTimer, &arg_hash, &[]) } @@ -497,7 +517,7 @@ impl PolicyAssertion for PolicyNv { let mut inner = Vec::new(); inner.extend_from_slice(&self.operand_b); inner.extend_from_slice(&self.offset.to_be_bytes()); - inner.extend_from_slice(&(self.operation.get_value() as u16).to_be_bytes()); + inner.extend_from_slice(&self.operation.get_value().to_be_bytes()); let args_hash = Crypto::hash(hash_alg, &inner)?; policy_update(hash_alg, acc, TPM_CC::PolicyNV, &args_hash, &self.nv_index_name) } diff --git a/TSS.Rust/src/tpm2.rs b/TSS.Rust/src/tpm2.rs index 5c2b08d7..11294996 100644 --- a/TSS.Rust/src/tpm2.rs +++ b/TSS.Rust/src/tpm2.rs @@ -10,6 +10,10 @@ //! TPM2 command implementations #![allow(non_snake_case)] +// The autogenerated part of this file mirrors the TPM 2.0 command signatures verbatim, so +// commands with many parameters are unavoidable. Scoped to this file rather than the crate +// so handwritten code is still linted. +#![allow(clippy::too_many_arguments)] use crate::error::TpmError; use crate::tpm2_impl::*; @@ -19,7 +23,7 @@ use crate::tpm_structure::*; use crate::tpm_types::*; impl Tpm2 { - pub fn async_methods(&mut self) -> AsyncMethods { + pub fn async_methods(&mut self) -> AsyncMethods<'_> { AsyncMethods { tpm: self } } } @@ -46,14 +50,6 @@ impl TpmStructure for EmptyTpmResponse { fn deserialize(&mut self, _buffer: &mut TpmBuffer) -> Result<(), TpmError> { Ok(()) } - - fn fromTpm(&self, _buffer: &mut TpmBuffer) -> Result<(), TpmError> { - Ok(()) - } - - fn fromBytes(&mut self, _buffer: &mut Vec) -> Result<(), TpmError> { - Ok(()) - } } impl CmdStructure for EmptyTpmResponse {} diff --git a/TSS.Rust/src/tpm2_helpers.rs b/TSS.Rust/src/tpm2_helpers.rs index 34904e5d..a6313111 100644 --- a/TSS.Rust/src/tpm2_helpers.rs +++ b/TSS.Rust/src/tpm2_helpers.rs @@ -50,6 +50,6 @@ pub fn enum_to_str(enum_val: u64, enum_id: std::any::TypeId) -> String { pub fn int_to_tpm>(val: T) -> Vec { let mut buffer = TpmBuffer::new(None); - buffer.write_num(val.into(), std::mem::size_of::().into()); + buffer.write_num(val.into(), std::mem::size_of::()); buffer.trim().to_vec() } \ No newline at end of file diff --git a/TSS.Rust/src/tpm2_impl.rs b/TSS.Rust/src/tpm2_impl.rs index 74936a83..f80bd1df 100644 --- a/TSS.Rust/src/tpm2_impl.rs +++ b/TSS.Rust/src/tpm2_impl.rs @@ -168,10 +168,9 @@ impl Tpm2 { let raw_response_u32 = raw_response.get_value(); let is_fmt = (raw_response_u32 & TPM_RC::RC_FMT1.get_value()) != 0; - let mask: u32 = if is_fmt { 0xBF } else { 0x97F }; - TPM_RC { 0: (raw_response_u32 & mask) } + TPM_RC(raw_response_u32 & mask) } /// Send a TPM command to the underlying TPM device. @@ -239,7 +238,7 @@ impl Tpm2 { let mut cmd_buf = TpmBuffer::new(None); // Create command buffer header - cmd_buf.writeShort(self.current_session_tag.unwrap().get_value() as u16); + cmd_buf.writeShort(self.current_session_tag.unwrap().get_value()); cmd_buf.writeInt(0); // to be filled in later cmd_buf.writeInt(cmd_code.get_value()); @@ -293,7 +292,7 @@ impl Tpm2 { &mut cmd_buf, cmd_code, num_auth_handles, - ¶m_buf.buffer(), + param_buf.buffer(), )?; } else { // Create all password sessions with auth from the corresponding handles @@ -324,7 +323,7 @@ impl Tpm2 { } // Write marshaled command params to the command buffer - cmd_buf.writeByteBuf(¶m_buf.buffer()); + cmd_buf.writeByteBuf(param_buf.buffer()); // Fill in command buffer size in the command header cmd_buf.write_num_at_pos(cmd_buf.current_pos() as u64, 2, 4); @@ -333,7 +332,7 @@ impl Tpm2 { // Handle CpHash and Audit processing if self.cp_hash.is_some() || self.audit_command { if cp_hash_data.is_empty() { - cp_hash_data = self.get_cp_hash_data(cmd_code, ¶m_buf.buffer())?; + cp_hash_data = self.get_cp_hash_data(cmd_code, param_buf.buffer())?; } if let Some(ref mut cp_hash) = self.cp_hash { @@ -547,6 +546,7 @@ impl Tpm2 { // Reset position to start of parameters area and unmarshall resp_buf.set_current_pos(resp_params_pos); resp_struct.initFromTpm(&mut resp_buf)?; + resp_buf.check_status()?; // Validate that we read the exact number of bytes expected if resp_buf.current_pos() != resp_params_pos + resp_params_size { @@ -671,6 +671,8 @@ impl Tpm2 { } /// Start an auth session with full control (salt key, bind object, etc.). + // The parameter list mirrors the TPM2_StartAuthSession command parameters. + #[allow(clippy::too_many_arguments)] pub fn start_auth_session_ex( &mut self, tpm_key: &TPM_HANDLE, @@ -784,7 +786,7 @@ impl Tpm2 { buf.writeByteBuf(&name); } - buf.writeByteBuf(&cmd_params.to_vec()); + buf.writeByteBuf(cmd_params); Ok(buf.buffer().clone()) } @@ -835,11 +837,9 @@ impl Tpm2 { // For non-PWAP sessions, we need more complex processing let mut h_copy = None; - if i < num_auth_handles as usize { - if i < self.in_handles.len() { - // Set appropriate auth value on handle - h_copy = Some(self.in_handles[i].clone()); - } + if i < num_auth_handles as usize && i < self.in_handles.len() { + // Set appropriate auth value on handle + h_copy = Some(self.in_handles[i].clone()); } auth_cmd.nonce = session.sess_in.nonce.clone(); @@ -964,6 +964,7 @@ impl Tpm2 { // Read the size of the first parameter (TPM2B prefix) let arr_size = param_buf.read_num(sei.size_len as usize) as usize; + param_buf.check_status()?; let arr_pos = param_buf.current_pos(); if arr_size == 0 { @@ -972,7 +973,11 @@ impl Tpm2 { } // Read the data to encrypt/decrypt - let to_xcrypt = param_buf.readByteBuf(arr_size * sei.val_len as usize); + let xcrypt_size = arr_size + .checked_mul(sei.val_len as usize) + .ok_or(TpmError::BufferUnderflow)?; + let to_xcrypt = param_buf.readByteBuf(xcrypt_size); + param_buf.check_status()?; // Perform encryption/decryption let result = sess.param_xcrypt(&to_xcrypt, is_request)?; @@ -1023,6 +1028,7 @@ impl Tpm2 { ) -> Result { let mut rp_ready = false; resp_buf.set_current_pos(resp_params_pos + resp_params_size); + resp_buf.check_status()?; // Pre-compute values needed for HMAC verification to avoid borrow conflicts let nonce_tpm_dec = self.nonce_tpm_dec.clone(); @@ -1033,6 +1039,7 @@ impl Tpm2 { for (j, session) in sessions.iter_mut().enumerate() { let mut auth_response = TPMS_AUTH_RESPONSE::default(); auth_response.initFromTpm(resp_buf)?; + resp_buf.check_status()?; if session.is_pwap() { // PWAP sessions should have empty nonce and hmac diff --git a/TSS.Rust/src/tpm_buffer.rs b/TSS.Rust/src/tpm_buffer.rs index 31b1b7eb..0fe7b8eb 100644 --- a/TSS.Rust/src/tpm_buffer.rs +++ b/TSS.Rust/src/tpm_buffer.rs @@ -87,20 +87,68 @@ impl TpmBuffer { pub fn getCurStuctRemainingSize(&self) -> usize { if let Some(ssi) = self.sized_struct_sizes.last() { - return ssi.size - (self.pos - ssi.start_pos); + return ssi + .size + .saturating_sub(self.pos.saturating_sub(ssi.start_pos)); } 0 } fn check_len(&mut self, len: usize) -> bool { - if self.buf.len() < self.pos + len { - // Grow the buffer if needed on write operations - self.buf.resize(self.pos + len, 0); + self.ensure_write_len(len) + } + + fn ensure_write_len(&mut self, len: usize) -> bool { + let Some(end_pos) = self.pos.checked_add(len) else { + self.out_of_bounds = true; + return false; + }; + + if self.buf.len() < end_pos { + self.buf.resize(end_pos, 0); } true } + fn check_read_len(&mut self, len: usize) -> bool { + let Some(end_pos) = self.pos.checked_add(len) else { + self.out_of_bounds = true; + return false; + }; + + if let Some(ssi) = self.sized_struct_sizes.last() { + let consumed = self.pos.saturating_sub(ssi.start_pos); + let remaining = ssi.size.saturating_sub(consumed); + if consumed > ssi.size || len > remaining { + self.out_of_bounds = true; + return false; + } + } + + if self.buf.len() < end_pos { + self.out_of_bounds = true; + return false; + } + true + } + + fn remaining_len(&self) -> usize { + self.buf.len().saturating_sub(self.pos) + } + + pub fn check_status(&self) -> Result<(), TpmError> { + if self.isOk() { + Ok(()) + } else { + Err(TpmError::BufferUnderflow) + } + } + pub fn write_num(&mut self, val: u64, len: usize) { + if len == 0 { + return; + } + if !self.check_len(len) { return; } @@ -130,7 +178,11 @@ impl TpmBuffer { } pub fn read_num(&mut self, len: usize) -> u64 { - if !self.check_len(len) { + if len == 0 { + return 0; + } + + if !self.check_read_len(len) { return 0; } @@ -155,7 +207,7 @@ impl TpmBuffer { res += (self.buf[self.pos] as u64) << 8; self.pos += 1; } - res += (self.buf[self.pos] as u8) as u64; + res += self.buf[self.pos] as u64; self.pos += 1; res } @@ -192,7 +244,7 @@ impl TpmBuffer { /** Reads a byte from this buffer. */ pub fn readByte(&mut self) -> u8 { - if self.check_len(1) { + if self.check_read_len(1) { let val = self.buf[self.pos]; self.pos += 1; return val; @@ -216,22 +268,25 @@ impl TpmBuffer { } /** Marshalls the given byte buffer with no length prefix. */ - pub fn writeByteBuf(&mut self, data: &Vec) { + pub fn writeByteBuf(&mut self, data: &[u8]) { let data_size = data.len(); if data_size == 0 || !self.check_len(data_size) { return; } - for i in 0..data_size { - self.buf[self.pos + i] = data[i]; - } + self.buf[self.pos..self.pos + data_size].copy_from_slice(data); self.pos += data_size; } /** Unmarshalls a byte buffer of the given size (no marshaled length prefix). */ pub fn readByteBuf(&mut self, size: usize) -> Vec { - if !self.check_len(size) { - return Vec::new().into(); + if size == 0 { + return Vec::new(); + } + + if !self.check_read_len(size) { + return Vec::new(); } + let mut new_buf = Vec::with_capacity(size); for i in 0..size { new_buf.push(self.buf[self.pos + i]); @@ -241,7 +296,7 @@ impl TpmBuffer { } /** Marshalls the given byte buffer with a length prefix. */ - pub fn writeSizedByteBuf(&mut self, data: &Vec, size_len: usize) { + pub fn writeSizedByteBuf(&mut self, data: &[u8], size_len: usize) { self.write_num(data.len() as u64, size_len); self.writeByteBuf(data); } @@ -249,12 +304,16 @@ impl TpmBuffer { /** Unmarshals a byte buffer from its size-prefixed representation in the TPM wire format. */ pub fn readSizedByteBuf(&mut self, size_len: usize) -> Vec { let size = self.read_num(size_len) as usize; + if !self.isOk() { + return Vec::new(); + } self.readByteBuf(size) } pub fn createObj(&mut self) -> Result { let mut new_obj = T::default(); new_obj.initFromTpm(self)?; + self.check_status()?; Ok(new_obj) } @@ -285,18 +344,33 @@ impl TpmBuffer { obj: &mut T, ) -> Result<(), TpmError> { let size = self.readShort(); + if !self.isOk() { + return Err(TpmError::BufferUnderflow); + } if size == 0 { return Ok(()); } + if size as usize > self.remaining_len() { + self.out_of_bounds = true; + return Err(TpmError::BufferUnderflow); + } + + let end_pos = self.pos + size as usize; self.sized_struct_sizes.push(SizedStructInfo { start_pos: self.pos, size: size as usize, }); - obj.initFromTpm(self)?; + let result = obj.initFromTpm(self); self.sized_struct_sizes.pop(); + result?; + self.check_status()?; + if self.pos != end_pos { + self.out_of_bounds = true; + return Err(TpmError::BufferUnderflow); + } Ok(()) } @@ -317,11 +391,21 @@ impl TpmBuffer { arr: &mut Vec, ) -> Result<(), TpmError> { let len = self.readInt(); + if !self.isOk() { + return Err(TpmError::BufferUnderflow); + } if len == 0 { - return Ok(arr.clear()); + arr.clear(); + return Ok(()); + } + + let len = len as usize; + if len > self.remaining_len() { + self.out_of_bounds = true; + return Err(TpmError::BufferUnderflow); } - arr.resize_with(len as usize, T::default); + arr.resize_with(len, T::default); for elt in arr { if !self.isOk() { break; @@ -329,7 +413,7 @@ impl TpmBuffer { elt.initFromTpm(self)?; } - Ok(()) + self.check_status() } pub fn writeValArr(&mut self, arr: &[T], val_size: usize) @@ -354,11 +438,25 @@ impl TpmBuffer { { // Length of the array size is always 4 bytes let len = self.readInt(); + if !self.isOk() { + return Err(TpmError::BufferUnderflow); + } if len == 0 { - return Ok(arr.clear()); + arr.clear(); + return Ok(()); + } + + let len = len as usize; + let Some(byte_len) = len.checked_mul(val_size) else { + self.out_of_bounds = true; + return Err(TpmError::BufferUnderflow); + }; + if val_size == 0 || byte_len > self.remaining_len() { + self.out_of_bounds = true; + return Err(TpmError::BufferUnderflow); } - arr.resize_with(len as usize, Default::default); + arr.resize_with(len, Default::default); for elt in arr { if !self.isOk() { @@ -368,6 +466,47 @@ impl TpmBuffer { *elt = T::new_from_trait((self.read_num(val_size) as u32).into())?; } - Ok(()) + self.check_status() + } +} +#[cfg(test)] +mod tests { + use super::*; + use crate::tpm_structure::TpmStructure; + use crate::tpm_types::{TPM2B_DIGEST, TPM_HANDLE}; + + #[test] + fn create_obj_rejects_zero_length_input() { + let mut buffer = TpmBuffer::from(&[]); + + assert!(matches!( + buffer.createObj::(), + Err(TpmError::BufferUnderflow) + )); + assert_eq!(buffer.size(), 0); + assert_eq!(buffer.current_pos(), 0); + } + + #[test] + fn from_bytes_rejects_truncated_input() { + let mut bytes = vec![0x12, 0x34]; + let mut handle = TPM_HANDLE::default(); + + assert!(matches!( + handle.fromBytes(&mut bytes), + Err(TpmError::BufferUnderflow) + )); + } + + #[test] + fn sized_byte_buffer_rejects_length_larger_than_remaining_input() { + let mut buffer = TpmBuffer::from(&[0x00, 0x04, 0xAA]); + + assert!(matches!( + buffer.createObj::(), + Err(TpmError::BufferUnderflow) + )); + assert_eq!(buffer.size(), 3); + assert_eq!(buffer.current_pos(), 2); } } diff --git a/TSS.Rust/src/tpm_structure.rs b/TSS.Rust/src/tpm_structure.rs index 1d23d8f6..39c6f5f0 100644 --- a/TSS.Rust/src/tpm_structure.rs +++ b/TSS.Rust/src/tpm_structure.rs @@ -15,10 +15,26 @@ use crate::tpm_types::*; pub trait TpmStructure: TpmMarshaller { fn serialize(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError>; fn deserialize(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError>; + + /// Unmarshals this object in place from the TPM wire representation contained in the + /// given buffer, and fails if the buffer did not hold a complete representation. + /// + /// Note that this populates `self`; use [`TpmBuffer::createObj`] to build a new object + /// instead. #[allow(non_snake_case)] - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError>; + fn fromTpm(&mut self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + self.initFromTpm(buffer)?; + buffer.check_status() + } + + /// Unmarshals this object in place from its TPM wire representation contained in the + /// given byte vector, and fails if the vector did not hold a complete representation. #[allow(non_snake_case)] - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError>; + fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { + let mut tpm_buffer = TpmBuffer::from(buffer); + self.initFromTpm(&mut tpm_buffer)?; + tpm_buffer.check_status() + } } /// Common trait for all TPM enumeration types @@ -107,3 +123,46 @@ pub trait RespStructure: CmdStructure { "RespStructure".to_string() } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn from_tpm_populates_existing_receiver() -> Result<(), TpmError> { + let expected_attributes = TPMA_OBJECT( + TPMA_OBJECT::fixedTPM.0 | TPMA_OBJECT::userWithAuth.0 | TPMA_OBJECT::sign.0, + ); + let public = TPMT_PUBLIC { + nameAlg: TPM_ALG_ID::SHA256, + objectAttributes: expected_attributes, + authPolicy: vec![1, 2, 3], + parameters: Some(TPMU_PUBLIC_PARMS::rsaDetail(TPMS_RSA_PARMS { + symmetric: TPMT_SYM_DEF_OBJECT::default(), + scheme: Some(TPMU_ASYM_SCHEME::null(TPMS_NULL_ASYM_SCHEME::default())), + keyBits: 2048, + exponent: 0, + })), + unique: Some(TPMU_PUBLIC_ID::rsa(TPM2B_PUBLIC_KEY_RSA { + buffer: vec![0xA5; 256], + })), + }; + + let mut out = TpmBuffer::new(None); + public.toTpm(&mut out)?; + let serialized = out.trim().clone(); + let mut input = TpmBuffer::from(serialized.as_slice()); + let mut parsed = TPMT_PUBLIC::default(); + + parsed.fromTpm(&mut input)?; + + assert_eq!(parsed.nameAlg, public.nameAlg); + assert_eq!(parsed.objectAttributes.0, expected_attributes.0); + assert_eq!(parsed.authPolicy, public.authPolicy); + match parsed.unique { + Some(TPMU_PUBLIC_ID::rsa(unique)) => assert_eq!(unique.buffer, vec![0xA5; 256]), + _ => panic!("expected RSA public unique field"), + } + Ok(()) + } +} diff --git a/TSS.Rust/src/tpm_type_extensions.rs b/TSS.Rust/src/tpm_type_extensions.rs index ed444e5e..6e0752ea 100644 --- a/TSS.Rust/src/tpm_type_extensions.rs +++ b/TSS.Rust/src/tpm_type_extensions.rs @@ -5,11 +5,32 @@ use crate::tpm_buffer::*; use crate::tpm_structure::TpmEnum; use crate::tpm_types::CertifyResponse; use crate::tpm_types::*; -use rsa::{BigUint, RsaPublicKey, RsaPrivateKey, Oaep, Pkcs1v15Sign}; +use rsa::{BigUint, RsaPublicKey, RsaPrivateKey, Oaep}; use rsa::traits::{PublicKeyParts, PrivateKeyParts}; use rand::rngs::OsRng; use zeroize::Zeroize; +/// RSA-OAEP encrypt using the hash algorithm matching the key's nameAlg. +fn rsa_oaep_encrypt( + rsa_key: &RsaPublicKey, + name_alg: TPM_ALG_ID, + label: &str, + data: &[u8], +) -> Result, TpmError> { + match name_alg { + TPM_ALG_ID::SHA1 => rsa_key + .encrypt(&mut OsRng, Oaep::new_with_label::(label), data) + .map_err(|e| TpmError::GenericError(format!("RSA-OAEP encryption failed: {e}"))), + TPM_ALG_ID::SHA256 => rsa_key + .encrypt(&mut OsRng, Oaep::new_with_label::(label), data) + .map_err(|e| TpmError::GenericError(format!("RSA-OAEP encryption failed: {e}"))), + _ => Err(TpmError::NotSupported(format!( + "Unsupported nameAlg for OAEP: {:?}", + name_alg + ))), + } +} + /// Activation data returned from create_activation #[derive(Debug)] pub struct ActivationData { @@ -56,7 +77,16 @@ impl TPMT_PUBLIC { nonce: &[u8], certify_response: &CertifyResponse, ) -> Result { - let hash_alg = self.get_signing_hash_alg()?; + let key_hash_alg = self.get_signing_hash_alg()?; + let signature_hash_alg = if let Some(TPMU_SIGNATURE::rsassa(signature)) = &certify_response.signature { + signature.hash + } else { + return Crypto::validate_signature(self, Vec::new(), &certify_response.signature); + }; + if key_hash_alg != signature_hash_alg { + return Ok(false); + } + let attest = &certify_response.certifyInfo; if (attest.extraData != nonce) { @@ -82,7 +112,7 @@ impl TPMT_PUBLIC { buffer.trim().to_vec() }; - let signed_blob_hash = Crypto::hash(hash_alg, &signed_blob)?; + let signed_blob_hash = Crypto::hash(signature_hash_alg, &signed_blob)?; Crypto::validate_signature(self, signed_blob_hash, &certify_response.signature) } @@ -127,11 +157,8 @@ impl TPMT_PUBLIC { BigUint::from_bytes_be(&[1, 0, 1]) // e = 65537 ).map_err(|_| TpmError::GenericError("Invalid RSA parameters".to_string()))?; - // Encrypt seed with label "IDENTITY" using OAEP-SHA1 - let padding = Oaep::new_with_label::("IDENTITY\0"); - let secret = rsa_public_key - .encrypt(&mut OsRng, padding, &seed) - .map_err(|_| TpmError::GenericError("Failed to encrypt seed".to_string()))?; + // Encrypt seed with label "IDENTITY" using OAEP with the key's nameAlg + let secret = rsa_oaep_encrypt(&rsa_public_key, self.nameAlg, "IDENTITY\0", &seed)?; // Make the credential blob: @@ -154,7 +181,7 @@ impl TPMT_PUBLIC { let enc_credential = Crypto::cfb_xcrypt( true, &sym_key, - &vec![0u8; 16], // Zero IV + &[0u8; 16], // Zero IV &credential_with_size )?; @@ -223,11 +250,8 @@ impl TPMT_PUBLIC { BigUint::from_bytes_be(&[1, 0, 1]) // e = 65537 ).map_err(|_| TpmError::InvalidArraySize("Invalid RSA parameters".to_string()))?; - // Encrypt the data using OAEP padding with SHA-1 hash function - let padding = Oaep::new_with_label::("IDENTITY\0"); - let encrypted_data = rsa_public_key - .encrypt(&mut OsRng, padding, data) - .map_err(|_| TpmError::GenericError("Failed to encrypt data".to_string()))?; + // Encrypt the data using OAEP padding with the key's nameAlg + let encrypted_data = rsa_oaep_encrypt(&rsa_public_key, self.nameAlg, "IDENTITY\0", data)?; Ok(encrypted_data) } @@ -328,7 +352,6 @@ impl TPM_HANDLE { if (handle_type == TPM_HT::NV_INDEX || handle_type == TPM_HT::TRANSIENT - || handle_type == TPM_HT::PERSISTENT || handle_type == TPM_HT::PERSISTENT) { self.name = name.to_vec(); @@ -375,10 +398,12 @@ impl TPM_HANDLE { handle_type ))) } +} +impl std::fmt::Display for TPM_HANDLE { /// Get a string representation of this handle - pub fn to_string(&self) -> String { - format!("{}:0x{:x}", self.get_type(), self.handle) + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}:0x{:x}", self.get_type(), self.handle) } } @@ -430,14 +455,7 @@ impl TSS_KEY { let priv_key = RsaPrivateKey::from_p_q(p, q, e) .map_err(|e| TpmError::GenericError(format!("Failed to reconstruct RSA key: {}", e)))?; - // Sign with PKCS#1 v1.5 - let scheme = match hash_alg { - TPM_ALG_ID::SHA1 => Pkcs1v15Sign::new::(), - TPM_ALG_ID::SHA256 => Pkcs1v15Sign::new::(), - _ => return Err(TpmError::GenericError(format!("Unsupported hash algorithm for signing: {:?}", hash_alg))), - }; - - let sig_bytes = priv_key.sign(scheme, digest) + let sig_bytes = priv_key.sign(Crypto::pkcs1v15_sign_scheme(hash_alg)?, digest) .map_err(|e| TpmError::GenericError(format!("RSA signing failed: {}", e)))?; Ok(TPMT_SIGNATURE { diff --git a/TSS.Rust/src/tpm_types.rs b/TSS.Rust/src/tpm_types.rs index 814df6f7..2798edf1 100644 --- a/TSS.Rust/src/tpm_types.rs +++ b/TSS.Rust/src/tpm_types.rs @@ -19,6 +19,21 @@ non_upper_case_globals, dead_code )] +// Everything below the <> marker is emitted by TssCodeGen from the TPM 2.0 +// specification tables, so these lints cannot be fixed here - a hand edit would be lost on the +// next regeneration. Two of them are also not fixable in the generator without breaking the +// public API: `ptr_arg` would change every `&Vec` parameter, and `too_many_arguments` is +// dictated by the TPM command signatures themselves. The rest are cosmetic artifacts of +// uniform code emission. Listed individually rather than blanket-allowing `clippy::all`, so a +// new class of lint in generated code still surfaces. +#![allow( + clippy::clone_on_copy, + clippy::needless_update, + clippy::ptr_arg, + clippy::too_many_arguments, + clippy::unnecessary_cast, + clippy::useless_conversion +)] //! TPM type definitions @@ -6325,38 +6340,6 @@ impl TpmStructure for TPMU_CAPABILITIES { } } - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - match self { - Self::algorithms(inner) => inner.fromTpm(buffer), - Self::handles(inner) => inner.fromTpm(buffer), - Self::command(inner) => inner.fromTpm(buffer), - Self::ppCommands(inner) => inner.fromTpm(buffer), - Self::auditCommands(inner) => inner.fromTpm(buffer), - Self::assignedPCR(inner) => inner.fromTpm(buffer), - Self::tpmProperties(inner) => inner.fromTpm(buffer), - Self::pcrProperties(inner) => inner.fromTpm(buffer), - Self::eccCurves(inner) => inner.fromTpm(buffer), - Self::authPolicies(inner) => inner.fromTpm(buffer), - Self::actData(inner) => inner.fromTpm(buffer), - } - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - match self { - Self::algorithms(inner) => inner.fromBytes(buffer), - Self::handles(inner) => inner.fromBytes(buffer), - Self::command(inner) => inner.fromBytes(buffer), - Self::ppCommands(inner) => inner.fromBytes(buffer), - Self::auditCommands(inner) => inner.fromBytes(buffer), - Self::assignedPCR(inner) => inner.fromBytes(buffer), - Self::tpmProperties(inner) => inner.fromBytes(buffer), - Self::pcrProperties(inner) => inner.fromBytes(buffer), - Self::eccCurves(inner) => inner.fromBytes(buffer), - Self::authPolicies(inner) => inner.fromBytes(buffer), - Self::actData(inner) => inner.fromBytes(buffer), - } - } - } impl TpmMarshaller for TPMU_CAPABILITIES { @@ -6481,32 +6464,6 @@ impl TpmStructure for TPMU_ATTEST { } } - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - match self { - Self::certify(inner) => inner.fromTpm(buffer), - Self::creation(inner) => inner.fromTpm(buffer), - Self::quote(inner) => inner.fromTpm(buffer), - Self::commandAudit(inner) => inner.fromTpm(buffer), - Self::sessionAudit(inner) => inner.fromTpm(buffer), - Self::time(inner) => inner.fromTpm(buffer), - Self::nv(inner) => inner.fromTpm(buffer), - Self::nvDigest(inner) => inner.fromTpm(buffer), - } - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - match self { - Self::certify(inner) => inner.fromBytes(buffer), - Self::creation(inner) => inner.fromBytes(buffer), - Self::quote(inner) => inner.fromBytes(buffer), - Self::commandAudit(inner) => inner.fromBytes(buffer), - Self::sessionAudit(inner) => inner.fromBytes(buffer), - Self::time(inner) => inner.fromBytes(buffer), - Self::nv(inner) => inner.fromBytes(buffer), - Self::nvDigest(inner) => inner.fromBytes(buffer), - } - } - } impl TpmMarshaller for TPMU_ATTEST { @@ -6619,30 +6576,6 @@ impl TpmStructure for TPMU_SYM_DETAILS { } } - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - match self { - Self::tdes(inner) => inner.fromTpm(buffer), - Self::aes(inner) => inner.fromTpm(buffer), - Self::sm4(inner) => inner.fromTpm(buffer), - Self::camellia(inner) => inner.fromTpm(buffer), - Self::sym(inner) => inner.fromTpm(buffer), - Self::xor(inner) => inner.fromTpm(buffer), - Self::null(inner) => inner.fromTpm(buffer), - } - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - match self { - Self::tdes(inner) => inner.fromBytes(buffer), - Self::aes(inner) => inner.fromBytes(buffer), - Self::sm4(inner) => inner.fromBytes(buffer), - Self::camellia(inner) => inner.fromBytes(buffer), - Self::sym(inner) => inner.fromBytes(buffer), - Self::xor(inner) => inner.fromBytes(buffer), - Self::null(inner) => inner.fromBytes(buffer), - } - } - } impl TpmMarshaller for TPMU_SYM_DETAILS { @@ -6723,20 +6656,6 @@ impl TpmStructure for TPMU_SENSITIVE_CREATE { } } - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - match self { - Self::create => Ok(()), - Self::derive(inner) => inner.fromTpm(buffer), - } - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - match self { - Self::create => Ok(()), - Self::derive(inner) => inner.fromBytes(buffer), - } - } - } impl TpmMarshaller for TPMU_SENSITIVE_CREATE { @@ -6811,22 +6730,6 @@ impl TpmStructure for TPMU_SCHEME_KEYEDHASH { } } - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - match self { - Self::hmac(inner) => inner.fromTpm(buffer), - Self::xor(inner) => inner.fromTpm(buffer), - Self::null(inner) => inner.fromTpm(buffer), - } - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - match self { - Self::hmac(inner) => inner.fromBytes(buffer), - Self::xor(inner) => inner.fromBytes(buffer), - Self::null(inner) => inner.fromBytes(buffer), - } - } - } impl TpmMarshaller for TPMU_SCHEME_KEYEDHASH { @@ -6941,34 +6844,6 @@ impl TpmStructure for TPMU_SIG_SCHEME { } } - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - match self { - Self::rsassa(inner) => inner.fromTpm(buffer), - Self::rsapss(inner) => inner.fromTpm(buffer), - Self::ecdsa(inner) => inner.fromTpm(buffer), - Self::ecdaa(inner) => inner.fromTpm(buffer), - Self::sm2(inner) => inner.fromTpm(buffer), - Self::ecschnorr(inner) => inner.fromTpm(buffer), - Self::hmac(inner) => inner.fromTpm(buffer), - Self::any(inner) => inner.fromTpm(buffer), - Self::null(inner) => inner.fromTpm(buffer), - } - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - match self { - Self::rsassa(inner) => inner.fromBytes(buffer), - Self::rsapss(inner) => inner.fromBytes(buffer), - Self::ecdsa(inner) => inner.fromBytes(buffer), - Self::ecdaa(inner) => inner.fromBytes(buffer), - Self::sm2(inner) => inner.fromBytes(buffer), - Self::ecschnorr(inner) => inner.fromBytes(buffer), - Self::hmac(inner) => inner.fromBytes(buffer), - Self::any(inner) => inner.fromBytes(buffer), - Self::null(inner) => inner.fromBytes(buffer), - } - } - } impl TpmMarshaller for TPMU_SIG_SCHEME { @@ -7076,28 +6951,6 @@ impl TpmStructure for TPMU_KDF_SCHEME { } } - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - match self { - Self::mgf1(inner) => inner.fromTpm(buffer), - Self::kdf1_sp800_56a(inner) => inner.fromTpm(buffer), - Self::kdf2(inner) => inner.fromTpm(buffer), - Self::kdf1_sp800_108(inner) => inner.fromTpm(buffer), - Self::anyKdf(inner) => inner.fromTpm(buffer), - Self::null(inner) => inner.fromTpm(buffer), - } - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - match self { - Self::mgf1(inner) => inner.fromBytes(buffer), - Self::kdf1_sp800_56a(inner) => inner.fromBytes(buffer), - Self::kdf2(inner) => inner.fromBytes(buffer), - Self::kdf1_sp800_108(inner) => inner.fromBytes(buffer), - Self::anyKdf(inner) => inner.fromBytes(buffer), - Self::null(inner) => inner.fromBytes(buffer), - } - } - } impl TpmMarshaller for TPMU_KDF_SCHEME { @@ -7239,40 +7092,6 @@ impl TpmStructure for TPMU_ASYM_SCHEME { } } - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - match self { - Self::ecdh(inner) => inner.fromTpm(buffer), - Self::ecmqv(inner) => inner.fromTpm(buffer), - Self::rsassa(inner) => inner.fromTpm(buffer), - Self::rsapss(inner) => inner.fromTpm(buffer), - Self::ecdsa(inner) => inner.fromTpm(buffer), - Self::ecdaa(inner) => inner.fromTpm(buffer), - Self::sm2(inner) => inner.fromTpm(buffer), - Self::ecschnorr(inner) => inner.fromTpm(buffer), - Self::rsaes(inner) => inner.fromTpm(buffer), - Self::oaep(inner) => inner.fromTpm(buffer), - Self::anySig(inner) => inner.fromTpm(buffer), - Self::null(inner) => inner.fromTpm(buffer), - } - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - match self { - Self::ecdh(inner) => inner.fromBytes(buffer), - Self::ecmqv(inner) => inner.fromBytes(buffer), - Self::rsassa(inner) => inner.fromBytes(buffer), - Self::rsapss(inner) => inner.fromBytes(buffer), - Self::ecdsa(inner) => inner.fromBytes(buffer), - Self::ecdaa(inner) => inner.fromBytes(buffer), - Self::sm2(inner) => inner.fromBytes(buffer), - Self::ecschnorr(inner) => inner.fromBytes(buffer), - Self::rsaes(inner) => inner.fromBytes(buffer), - Self::oaep(inner) => inner.fromBytes(buffer), - Self::anySig(inner) => inner.fromBytes(buffer), - Self::null(inner) => inner.fromBytes(buffer), - } - } - } impl TpmMarshaller for TPMU_ASYM_SCHEME { @@ -7407,34 +7226,6 @@ impl TpmStructure for TPMU_SIGNATURE { } } - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - match self { - Self::rsassa(inner) => inner.fromTpm(buffer), - Self::rsapss(inner) => inner.fromTpm(buffer), - Self::ecdsa(inner) => inner.fromTpm(buffer), - Self::ecdaa(inner) => inner.fromTpm(buffer), - Self::sm2(inner) => inner.fromTpm(buffer), - Self::ecschnorr(inner) => inner.fromTpm(buffer), - Self::hmac(inner) => inner.fromTpm(buffer), - Self::any(inner) => inner.fromTpm(buffer), - Self::null(inner) => inner.fromTpm(buffer), - } - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - match self { - Self::rsassa(inner) => inner.fromBytes(buffer), - Self::rsapss(inner) => inner.fromBytes(buffer), - Self::ecdsa(inner) => inner.fromBytes(buffer), - Self::ecdaa(inner) => inner.fromBytes(buffer), - Self::sm2(inner) => inner.fromBytes(buffer), - Self::ecschnorr(inner) => inner.fromBytes(buffer), - Self::hmac(inner) => inner.fromBytes(buffer), - Self::any(inner) => inner.fromBytes(buffer), - Self::null(inner) => inner.fromBytes(buffer), - } - } - } impl TpmMarshaller for TPMU_SIGNATURE { @@ -7536,26 +7327,6 @@ impl TpmStructure for TPMU_PUBLIC_ID { } } - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - match self { - Self::keyedHash(inner) => inner.fromTpm(buffer), - Self::sym(inner) => inner.fromTpm(buffer), - Self::rsa(inner) => inner.fromTpm(buffer), - Self::ecc(inner) => inner.fromTpm(buffer), - Self::derive(inner) => inner.fromTpm(buffer), - } - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - match self { - Self::keyedHash(inner) => inner.fromBytes(buffer), - Self::sym(inner) => inner.fromBytes(buffer), - Self::rsa(inner) => inner.fromBytes(buffer), - Self::ecc(inner) => inner.fromBytes(buffer), - Self::derive(inner) => inner.fromBytes(buffer), - } - } - } impl TpmMarshaller for TPMU_PUBLIC_ID { @@ -7651,26 +7422,6 @@ impl TpmStructure for TPMU_PUBLIC_PARMS { } } - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - match self { - Self::keyedHashDetail(inner) => inner.fromTpm(buffer), - Self::symDetail(inner) => inner.fromTpm(buffer), - Self::rsaDetail(inner) => inner.fromTpm(buffer), - Self::eccDetail(inner) => inner.fromTpm(buffer), - Self::asymDetail(inner) => inner.fromTpm(buffer), - } - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - match self { - Self::keyedHashDetail(inner) => inner.fromBytes(buffer), - Self::symDetail(inner) => inner.fromBytes(buffer), - Self::rsaDetail(inner) => inner.fromBytes(buffer), - Self::eccDetail(inner) => inner.fromBytes(buffer), - Self::asymDetail(inner) => inner.fromBytes(buffer), - } - } - } impl TpmMarshaller for TPMU_PUBLIC_PARMS { @@ -7764,26 +7515,6 @@ impl TpmStructure for TPMU_SENSITIVE_COMPOSITE { } } - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - match self { - Self::rsa(inner) => inner.fromTpm(buffer), - Self::ecc(inner) => inner.fromTpm(buffer), - Self::bits(inner) => inner.fromTpm(buffer), - Self::sym(inner) => inner.fromTpm(buffer), - Self::any(inner) => inner.fromTpm(buffer), - } - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - match self { - Self::rsa(inner) => inner.fromBytes(buffer), - Self::ecc(inner) => inner.fromBytes(buffer), - Self::bits(inner) => inner.fromBytes(buffer), - Self::sym(inner) => inner.fromBytes(buffer), - Self::any(inner) => inner.fromBytes(buffer), - } - } - } impl TpmMarshaller for TPMU_SENSITIVE_COMPOSITE { @@ -7838,16 +7569,6 @@ impl TPM_HANDLE { } impl TpmStructure for TPM_HANDLE { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -7892,16 +7613,6 @@ impl TPMS_NULL_UNION { } impl TpmStructure for TPMS_NULL_UNION { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -7943,16 +7654,6 @@ impl TPMS_EMPTY { } impl TpmStructure for TPMS_EMPTY { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -8007,16 +7708,6 @@ impl TPMS_ALGORITHM_DESCRIPTION { } impl TpmStructure for TPMS_ALGORITHM_DESCRIPTION { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -8083,16 +7774,6 @@ impl TPMT_HA { } impl TpmStructure for TPMT_HA { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -8149,16 +7830,6 @@ impl TPM2B_DIGEST { } impl TpmStructure for TPM2B_DIGEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -8209,16 +7880,6 @@ impl TPM2B_DATA { } impl TpmStructure for TPM2B_DATA { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -8285,16 +7946,6 @@ impl TPM2B_EVENT { } impl TpmStructure for TPM2B_EVENT { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -8346,16 +7997,6 @@ impl TPM2B_MAX_BUFFER { } impl TpmStructure for TPM2B_MAX_BUFFER { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -8408,16 +8049,6 @@ impl TPM2B_MAX_NV_BUFFER { } impl TpmStructure for TPM2B_MAX_NV_BUFFER { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -8469,16 +8100,6 @@ impl TPM2B_TIMEOUT { } impl TpmStructure for TPM2B_TIMEOUT { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -8531,16 +8152,6 @@ impl TPM2B_IV { } impl TpmStructure for TPM2B_IV { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -8591,16 +8202,6 @@ impl TPM2B_NAME { } impl TpmStructure for TPM2B_NAME { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -8651,16 +8252,6 @@ impl TPMS_PCR_SELECT { } impl TpmStructure for TPMS_PCR_SELECT { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -8717,16 +8308,6 @@ impl TPMS_PCR_SELECTION { } impl TpmStructure for TPMS_PCR_SELECTION { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -8786,16 +8367,6 @@ impl TPMT_TK_CREATION { } impl TpmStructure for TPMT_TK_CREATION { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -8858,16 +8429,6 @@ impl TPMT_TK_VERIFIED { } impl TpmStructure for TPMT_TK_VERIFIED { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -8935,16 +8496,6 @@ impl TPMT_TK_AUTH { } impl TpmStructure for TPMT_TK_AUTH { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -9006,16 +8557,6 @@ impl TPMT_TK_HASHCHECK { } impl TpmStructure for TPMT_TK_HASHCHECK { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -9077,16 +8618,6 @@ impl TPMS_ALG_PROPERTY { } impl TpmStructure for TPMS_ALG_PROPERTY { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -9145,16 +8676,6 @@ impl TPMS_TAGGED_PROPERTY { } impl TpmStructure for TPMS_TAGGED_PROPERTY { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -9212,16 +8733,6 @@ impl TPMS_TAGGED_PCR_SELECT { } impl TpmStructure for TPMS_TAGGED_PCR_SELECT { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -9281,16 +8792,6 @@ impl TPMS_TAGGED_POLICY { } impl TpmStructure for TPMS_TAGGED_POLICY { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -9354,16 +8855,6 @@ impl TPMS_ACT_DATA { } impl TpmStructure for TPMS_ACT_DATA { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -9424,16 +8915,6 @@ impl TPML_CC { } impl TpmStructure for TPML_CC { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -9487,16 +8968,6 @@ impl TPML_CCA { } impl TpmStructure for TPML_CCA { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -9549,16 +9020,6 @@ impl TPML_ALG { } impl TpmStructure for TPML_ALG { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -9613,16 +9074,6 @@ impl TPML_HANDLE { } impl TpmStructure for TPML_HANDLE { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -9677,16 +9128,6 @@ impl TPML_DIGEST { } impl TpmStructure for TPML_DIGEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -9738,16 +9179,6 @@ impl TPML_DIGEST_VALUES { } impl TpmStructure for TPML_DIGEST_VALUES { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -9802,16 +9233,6 @@ impl TPML_PCR_SELECTION { } impl TpmStructure for TPML_PCR_SELECTION { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -9866,20 +9287,10 @@ impl TPML_ALG_PROPERTY { } impl TpmStructure for TPML_ALG_PROPERTY { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - - // Implement serialization/deserialization - fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { - // Serialize fields - buf.writeObjArr(self.algProperties.as_ref())?; + // Implement serialization/deserialization + fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { + // Serialize fields + buf.writeObjArr(self.algProperties.as_ref())?; Ok(()) } @@ -9930,16 +9341,6 @@ impl TPML_TAGGED_TPM_PROPERTY { } impl TpmStructure for TPML_TAGGED_TPM_PROPERTY { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -9994,16 +9395,6 @@ impl TPML_TAGGED_PCR_PROPERTY { } impl TpmStructure for TPML_TAGGED_PCR_PROPERTY { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -10058,16 +9449,6 @@ impl TPML_ECC_CURVE { } impl TpmStructure for TPML_ECC_CURVE { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -10123,16 +9504,6 @@ impl TPML_TAGGED_POLICY { } impl TpmStructure for TPML_TAGGED_POLICY { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -10187,16 +9558,6 @@ impl TPML_ACT_DATA { } impl TpmStructure for TPML_ACT_DATA { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -10252,16 +9613,6 @@ impl TPMS_CAPABILITY_DATA { } impl TpmStructure for TPMS_CAPABILITY_DATA { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -10338,16 +9689,6 @@ impl TPMS_CLOCK_INFO { } impl TpmStructure for TPMS_CLOCK_INFO { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -10410,16 +9751,6 @@ impl TPMS_TIME_INFO { } impl TpmStructure for TPMS_TIME_INFO { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -10480,16 +9811,6 @@ impl TPMS_TIME_ATTEST_INFO { } impl TpmStructure for TPMS_TIME_ATTEST_INFO { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -10550,16 +9871,6 @@ impl TPMS_CERTIFY_INFO { } impl TpmStructure for TPMS_CERTIFY_INFO { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -10620,16 +9931,6 @@ impl TPMS_QUOTE_INFO { } impl TpmStructure for TPMS_QUOTE_INFO { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -10701,16 +10002,6 @@ impl TPMS_COMMAND_AUDIT_INFO { } impl TpmStructure for TPMS_COMMAND_AUDIT_INFO { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -10777,16 +10068,6 @@ impl TPMS_SESSION_AUDIT_INFO { } impl TpmStructure for TPMS_SESSION_AUDIT_INFO { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -10847,16 +10128,6 @@ impl TPMS_CREATION_INFO { } impl TpmStructure for TPMS_CREATION_INFO { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -10923,16 +10194,6 @@ impl TPMS_NV_CERTIFY_INFO { } impl TpmStructure for TPMS_NV_CERTIFY_INFO { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -10996,16 +10257,6 @@ impl TPMS_NV_DIGEST_CERTIFY_INFO { } impl TpmStructure for TPMS_NV_DIGEST_CERTIFY_INFO { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -11092,16 +10343,6 @@ impl TPMS_ATTEST { } impl TpmStructure for TPMS_ATTEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -11166,16 +10407,6 @@ impl TPM2B_ATTEST { } impl TpmStructure for TPM2B_ATTEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -11242,16 +10473,6 @@ impl TPMS_AUTH_COMMAND { } impl TpmStructure for TPMS_AUTH_COMMAND { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -11320,16 +10541,6 @@ impl TPMS_AUTH_RESPONSE { } impl TpmStructure for TPMS_AUTH_RESPONSE { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -11376,16 +10587,6 @@ impl TPMS_TDES_SYM_DETAILS { } impl TpmStructure for TPMS_TDES_SYM_DETAILS { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -11426,16 +10627,6 @@ impl TPMS_AES_SYM_DETAILS { } impl TpmStructure for TPMS_AES_SYM_DETAILS { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -11476,16 +10667,6 @@ impl TPMS_SM4_SYM_DETAILS { } impl TpmStructure for TPMS_SM4_SYM_DETAILS { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -11526,16 +10707,6 @@ impl TPMS_CAMELLIA_SYM_DETAILS { } impl TpmStructure for TPMS_CAMELLIA_SYM_DETAILS { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -11576,16 +10747,6 @@ impl TPMS_ANY_SYM_DETAILS { } impl TpmStructure for TPMS_ANY_SYM_DETAILS { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -11626,16 +10787,6 @@ impl TPMS_XOR_SYM_DETAILS { } impl TpmStructure for TPMS_XOR_SYM_DETAILS { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -11676,16 +10827,6 @@ impl TPMS_NULL_SYM_DETAILS { } impl TpmStructure for TPMS_NULL_SYM_DETAILS { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -11747,16 +10888,6 @@ impl TPMT_SYM_DEF { } impl TpmStructure for TPMT_SYM_DEF { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -11830,16 +10961,6 @@ impl TPMT_SYM_DEF_OBJECT { } impl TpmStructure for TPMT_SYM_DEF_OBJECT { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -11899,16 +11020,6 @@ impl TPM2B_SYM_KEY { } impl TpmStructure for TPM2B_SYM_KEY { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -11962,16 +11073,6 @@ impl TPMS_SYMCIPHER_PARMS { } impl TpmStructure for TPMS_SYMCIPHER_PARMS { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -12024,16 +11125,6 @@ impl TPM2B_LABEL { } impl TpmStructure for TPM2B_LABEL { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -12091,16 +11182,6 @@ impl TPMS_DERIVE { } impl TpmStructure for TPMS_DERIVE { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -12153,16 +11234,6 @@ impl TPM2B_DERIVE { } impl TpmStructure for TPM2B_DERIVE { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -12216,16 +11287,6 @@ impl TPM2B_SENSITIVE_DATA { } impl TpmStructure for TPM2B_SENSITIVE_DATA { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -12282,16 +11343,6 @@ impl TPMS_SENSITIVE_CREATE { } impl TpmStructure for TPMS_SENSITIVE_CREATE { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -12346,16 +11397,6 @@ impl TPM2B_SENSITIVE_CREATE { } impl TpmStructure for TPM2B_SENSITIVE_CREATE { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -12411,16 +11452,6 @@ impl TPMS_SCHEME_HASH { } impl TpmStructure for TPMS_SCHEME_HASH { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -12480,16 +11511,6 @@ impl TPMS_SCHEME_ECDAA { } impl TpmStructure for TPMS_SCHEME_ECDAA { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -12536,16 +11557,6 @@ impl TPMS_SCHEME_HMAC { } impl TpmStructure for TPMS_SCHEME_HMAC { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -12606,16 +11617,6 @@ impl TPMS_SCHEME_XOR { } impl TpmStructure for TPMS_SCHEME_XOR { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -12660,16 +11661,6 @@ impl TPMS_NULL_SCHEME_KEYEDHASH { } impl TpmStructure for TPMS_NULL_SCHEME_KEYEDHASH { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -12721,16 +11712,6 @@ impl TPMT_KEYEDHASH_SCHEME { } impl TpmStructure for TPMT_KEYEDHASH_SCHEME { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -12779,16 +11760,6 @@ impl TPMS_SIG_SCHEME_RSASSA { } impl TpmStructure for TPMS_SIG_SCHEME_RSASSA { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -12833,16 +11804,6 @@ impl TPMS_SIG_SCHEME_RSAPSS { } impl TpmStructure for TPMS_SIG_SCHEME_RSAPSS { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -12889,16 +11850,6 @@ impl TPMS_SIG_SCHEME_ECDSA { } impl TpmStructure for TPMS_SIG_SCHEME_ECDSA { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -12945,16 +11896,6 @@ impl TPMS_SIG_SCHEME_SM2 { } impl TpmStructure for TPMS_SIG_SCHEME_SM2 { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -13001,16 +11942,6 @@ impl TPMS_SIG_SCHEME_ECSCHNORR { } impl TpmStructure for TPMS_SIG_SCHEME_ECSCHNORR { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -13060,16 +11991,6 @@ impl TPMS_SIG_SCHEME_ECDAA { } impl TpmStructure for TPMS_SIG_SCHEME_ECDAA { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -13114,16 +12035,6 @@ impl TPMS_NULL_SIG_SCHEME { } impl TpmStructure for TPMS_NULL_SIG_SCHEME { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -13177,16 +12088,6 @@ impl TPMT_SIG_SCHEME { } impl TpmStructure for TPMT_SIG_SCHEME { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -13235,16 +12136,6 @@ impl TPMS_ENC_SCHEME_OAEP { } impl TpmStructure for TPMS_ENC_SCHEME_OAEP { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -13286,16 +12177,6 @@ impl TPMS_ENC_SCHEME_RSAES { } impl TpmStructure for TPMS_ENC_SCHEME_RSAES { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -13338,16 +12219,6 @@ impl TPMS_KEY_SCHEME_ECDH { } impl TpmStructure for TPMS_KEY_SCHEME_ECDH { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -13392,16 +12263,6 @@ impl TPMS_KEY_SCHEME_ECMQV { } impl TpmStructure for TPMS_KEY_SCHEME_ECMQV { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -13448,16 +12309,6 @@ impl TPMS_KDF_SCHEME_MGF1 { } impl TpmStructure for TPMS_KDF_SCHEME_MGF1 { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -13504,16 +12355,6 @@ impl TPMS_KDF_SCHEME_KDF1_SP800_56A { } impl TpmStructure for TPMS_KDF_SCHEME_KDF1_SP800_56A { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -13560,16 +12401,6 @@ impl TPMS_KDF_SCHEME_KDF2 { } impl TpmStructure for TPMS_KDF_SCHEME_KDF2 { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -13616,16 +12447,6 @@ impl TPMS_KDF_SCHEME_KDF1_SP800_108 { } impl TpmStructure for TPMS_KDF_SCHEME_KDF1_SP800_108 { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -13668,16 +12489,6 @@ impl TPMS_NULL_KDF_SCHEME { } impl TpmStructure for TPMS_NULL_KDF_SCHEME { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -13730,16 +12541,6 @@ impl TPMT_KDF_SCHEME { } impl TpmStructure for TPMT_KDF_SCHEME { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -13786,16 +12587,6 @@ impl TPMS_NULL_ASYM_SCHEME { } impl TpmStructure for TPMS_NULL_ASYM_SCHEME { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -13852,16 +12643,6 @@ impl TPMT_ASYM_SCHEME { } impl TpmStructure for TPMT_ASYM_SCHEME { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -13922,16 +12703,6 @@ impl TPMT_RSA_SCHEME { } impl TpmStructure for TPMT_RSA_SCHEME { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -13992,16 +12763,6 @@ impl TPMT_RSA_DECRYPT { } impl TpmStructure for TPMT_RSA_DECRYPT { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -14059,16 +12820,6 @@ impl TPM2B_PUBLIC_KEY_RSA { } impl TpmStructure for TPM2B_PUBLIC_KEY_RSA { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -14121,16 +12872,6 @@ impl TPM2B_PRIVATE_KEY_RSA { } impl TpmStructure for TPM2B_PRIVATE_KEY_RSA { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -14184,16 +12925,6 @@ impl TPM2B_ECC_PARAMETER { } impl TpmStructure for TPM2B_ECC_PARAMETER { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -14252,16 +12983,6 @@ impl TPMS_ECC_POINT { } impl TpmStructure for TPMS_ECC_POINT { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -14315,16 +13036,6 @@ impl TPM2B_ECC_POINT { } impl TpmStructure for TPM2B_ECC_POINT { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -14381,16 +13092,6 @@ impl TPMT_ECC_SCHEME { } impl TpmStructure for TPMT_ECC_SCHEME { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -14507,16 +13208,6 @@ impl TPMS_ALGORITHM_DETAIL_ECC { } impl TpmStructure for TPMS_ALGORITHM_DETAIL_ECC { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -14603,16 +13294,6 @@ impl TPMS_SIGNATURE_RSA { } impl TpmStructure for TPMS_SIGNATURE_RSA { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -14663,16 +13344,6 @@ impl TPMS_SIGNATURE_RSASSA { } impl TpmStructure for TPMS_SIGNATURE_RSASSA { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -14723,16 +13394,6 @@ impl TPMS_SIGNATURE_RSAPSS { } impl TpmStructure for TPMS_SIGNATURE_RSAPSS { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -14796,16 +13457,6 @@ impl TPMS_SIGNATURE_ECC { } impl TpmStructure for TPMS_SIGNATURE_ECC { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -14857,16 +13508,6 @@ impl TPMS_SIGNATURE_ECDSA { } impl TpmStructure for TPMS_SIGNATURE_ECDSA { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -14918,16 +13559,6 @@ impl TPMS_SIGNATURE_ECDAA { } impl TpmStructure for TPMS_SIGNATURE_ECDAA { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -14979,16 +13610,6 @@ impl TPMS_SIGNATURE_SM2 { } impl TpmStructure for TPMS_SIGNATURE_SM2 { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -15040,16 +13661,6 @@ impl TPMS_SIGNATURE_ECSCHNORR { } impl TpmStructure for TPMS_SIGNATURE_ECSCHNORR { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -15096,16 +13707,6 @@ impl TPMS_NULL_SIGNATURE { } impl TpmStructure for TPMS_NULL_SIGNATURE { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -15163,16 +13764,6 @@ impl TPMT_SIGNATURE { } impl TpmStructure for TPMT_SIGNATURE { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -15227,16 +13818,6 @@ impl TPM2B_ENCRYPTED_SECRET { } impl TpmStructure for TPM2B_ENCRYPTED_SECRET { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -15296,16 +13877,6 @@ impl TPMS_KEYEDHASH_PARMS { } impl TpmStructure for TPMS_KEYEDHASH_PARMS { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -15381,16 +13952,6 @@ impl TPMS_ASYM_PARMS { } impl TpmStructure for TPMS_ASYM_PARMS { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -15484,16 +14045,6 @@ impl TPMS_RSA_PARMS { } impl TpmStructure for TPMS_RSA_PARMS { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -15592,16 +14143,6 @@ impl TPMS_ECC_PARMS { } impl TpmStructure for TPMS_ECC_PARMS { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -15669,16 +14210,6 @@ impl TPMT_PUBLIC_PARMS { } impl TpmStructure for TPMT_PUBLIC_PARMS { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -15766,16 +14297,6 @@ impl TPMT_PUBLIC { } impl TpmStructure for TPMT_PUBLIC { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -15842,16 +14363,6 @@ impl TPM2B_PUBLIC { } impl TpmStructure for TPM2B_PUBLIC { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -15902,16 +14413,6 @@ impl TPM2B_TEMPLATE { } impl TpmStructure for TPM2B_TEMPLATE { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -15969,16 +14470,6 @@ impl TPM2B_PRIVATE_VENDOR_SPECIFIC { } impl TpmStructure for TPM2B_PRIVATE_VENDOR_SPECIFIC { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -16046,16 +14537,6 @@ impl TPMT_SENSITIVE { } impl TpmStructure for TPMT_SENSITIVE { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -16115,16 +14596,6 @@ impl TPM2B_SENSITIVE { } impl TpmStructure for TPM2B_SENSITIVE { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -16185,16 +14656,6 @@ impl _PRIVATE { } impl TpmStructure for _PRIVATE { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::<_PRIVATE>()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -16250,16 +14711,6 @@ impl TPM2B_PRIVATE { } impl TpmStructure for TPM2B_PRIVATE { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -16319,16 +14770,6 @@ impl TPMS_ID_OBJECT { } impl TpmStructure for TPMS_ID_OBJECT { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -16382,16 +14823,6 @@ impl TPM2B_ID_OBJECT { } impl TpmStructure for TPM2B_ID_OBJECT { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -16452,16 +14883,6 @@ impl TPMS_NV_PIN_COUNTER_PARAMETERS { } impl TpmStructure for TPMS_NV_PIN_COUNTER_PARAMETERS { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -16540,16 +14961,6 @@ impl TPMS_NV_PUBLIC { } impl TpmStructure for TPMS_NV_PUBLIC { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -16608,16 +15019,6 @@ impl TPM2B_NV_PUBLIC { } impl TpmStructure for TPM2B_NV_PUBLIC { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -16669,16 +15070,6 @@ impl TPM2B_CONTEXT_SENSITIVE { } impl TpmStructure for TPM2B_CONTEXT_SENSITIVE { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -16734,16 +15125,6 @@ impl TPMS_CONTEXT_DATA { } impl TpmStructure for TPMS_CONTEXT_DATA { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -16795,16 +15176,6 @@ impl TPM2B_CONTEXT_DATA { } impl TpmStructure for TPM2B_CONTEXT_DATA { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -16876,16 +15247,6 @@ impl TPMS_CONTEXT { } impl TpmStructure for TPMS_CONTEXT { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -16983,16 +15344,6 @@ impl TPMS_CREATION_DATA { } impl TpmStructure for TPMS_CREATION_DATA { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -17055,16 +15406,6 @@ impl TPM2B_CREATION_DATA { } impl TpmStructure for TPM2B_CREATION_DATA { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -17121,16 +15462,6 @@ impl TPMS_AC_OUTPUT { } impl TpmStructure for TPMS_AC_OUTPUT { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -17183,16 +15514,6 @@ impl TPML_AC_CAPABILITIES { } impl TpmStructure for TPML_AC_CAPABILITIES { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -17248,16 +15569,6 @@ impl TPM2_Startup_REQUEST { } impl TpmStructure for TPM2_Startup_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -17320,16 +15631,6 @@ impl TPM2_Shutdown_REQUEST { } impl TpmStructure for TPM2_Shutdown_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -17394,16 +15695,6 @@ impl TPM2_SelfTest_REQUEST { } impl TpmStructure for TPM2_SelfTest_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -17465,16 +15756,6 @@ impl TPM2_IncrementalSelfTest_REQUEST { } impl TpmStructure for TPM2_IncrementalSelfTest_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -17527,16 +15808,6 @@ impl IncrementalSelfTestResponse { } impl TpmStructure for IncrementalSelfTestResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -17588,16 +15859,6 @@ impl TPM2_GetTestResult_REQUEST { } impl TpmStructure for TPM2_GetTestResult_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -17650,16 +15911,6 @@ impl GetTestResultResponse { } impl TpmStructure for GetTestResultResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -17767,16 +16018,6 @@ impl TPM2_StartAuthSession_REQUEST { } impl TpmStructure for TPM2_StartAuthSession_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -17843,16 +16084,6 @@ impl StartAuthSessionResponse { } impl TpmStructure for StartAuthSessionResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -17921,16 +16152,6 @@ impl TPM2_PolicyRestart_REQUEST { } impl TpmStructure for TPM2_PolicyRestart_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -18020,16 +16241,6 @@ impl TPM2_Create_REQUEST { } impl TpmStructure for TPM2_Create_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -18107,16 +16318,6 @@ impl CreateResponse { } impl TpmStructure for CreateResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -18201,16 +16402,6 @@ impl TPM2_Load_REQUEST { } impl TpmStructure for TPM2_Load_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -18270,16 +16461,6 @@ impl LoadResponse { } impl TpmStructure for LoadResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -18356,16 +16537,6 @@ impl TPM2_LoadExternal_REQUEST { } impl TpmStructure for TPM2_LoadExternal_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -18427,16 +16598,6 @@ impl LoadExternalResponse { } impl TpmStructure for LoadExternalResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -18503,16 +16664,6 @@ impl TPM2_ReadPublic_REQUEST { } impl TpmStructure for TPM2_ReadPublic_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -18568,16 +16719,6 @@ impl ReadPublicResponse { } impl TpmStructure for ReadPublicResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -18668,16 +16809,6 @@ impl TPM2_ActivateCredential_REQUEST { } impl TpmStructure for TPM2_ActivateCredential_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -18735,16 +16866,6 @@ impl ActivateCredentialResponse { } impl TpmStructure for ActivateCredentialResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -18820,16 +16941,6 @@ impl TPM2_MakeCredential_REQUEST { } impl TpmStructure for TPM2_MakeCredential_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -18888,16 +16999,6 @@ impl MakeCredentialResponse { } impl TpmStructure for MakeCredentialResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -18965,16 +17066,6 @@ impl TPM2_Unseal_REQUEST { } impl TpmStructure for TPM2_Unseal_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -19025,16 +17116,6 @@ impl UnsealResponse { } impl TpmStructure for UnsealResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -19112,16 +17193,6 @@ impl TPM2_ObjectChangeAuth_REQUEST { } impl TpmStructure for TPM2_ObjectChangeAuth_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -19174,16 +17245,6 @@ impl ObjectChangeAuthResponse { } impl TpmStructure for ObjectChangeAuthResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -19263,16 +17324,6 @@ impl TPM2_CreateLoaded_REQUEST { } impl TpmStructure for TPM2_CreateLoaded_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -19341,16 +17392,6 @@ impl CreateLoadedResponse { } impl TpmStructure for CreateLoadedResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -19443,16 +17484,6 @@ impl TPM2_Duplicate_REQUEST { } impl TpmStructure for TPM2_Duplicate_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -19517,16 +17548,6 @@ impl DuplicateResponse { } impl TpmStructure for DuplicateResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -19624,16 +17645,6 @@ impl TPM2_Rewrap_REQUEST { } impl TpmStructure for TPM2_Rewrap_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -19697,16 +17708,6 @@ impl RewrapResponse { } impl TpmStructure for RewrapResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -19809,16 +17810,6 @@ impl TPM2_Import_REQUEST { } impl TpmStructure for TPM2_Import_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -19882,16 +17873,6 @@ impl ImportResponse { } impl TpmStructure for ImportResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -19984,16 +17965,6 @@ impl TPM2_RSA_Encrypt_REQUEST { } impl TpmStructure for TPM2_RSA_Encrypt_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -20056,16 +18027,6 @@ impl RSA_EncryptResponse { } impl TpmStructure for RSA_EncryptResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -20154,16 +18115,6 @@ impl TPM2_RSA_Decrypt_REQUEST { } impl TpmStructure for TPM2_RSA_Decrypt_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -20224,16 +18175,6 @@ impl RSA_DecryptResponse { } impl TpmStructure for RSA_DecryptResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -20300,16 +18241,6 @@ impl TPM2_ECDH_KeyGen_REQUEST { } impl TpmStructure for TPM2_ECDH_KeyGen_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -20364,16 +18295,6 @@ impl ECDH_KeyGenResponse { } impl TpmStructure for ECDH_KeyGenResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -20448,17 +18369,7 @@ impl TPM2_ECDH_ZGen_REQUEST { } -impl TpmStructure for TPM2_ECDH_ZGen_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - +impl TpmStructure for TPM2_ECDH_ZGen_REQUEST { // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -20514,16 +18425,6 @@ impl ECDH_ZGenResponse { } impl TpmStructure for ECDH_ZGenResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -20586,16 +18487,6 @@ impl TPM2_ECC_Parameters_REQUEST { } impl TpmStructure for TPM2_ECC_Parameters_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -20647,16 +18538,6 @@ impl ECC_ParametersResponse { } impl TpmStructure for ECC_ParametersResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -20746,16 +18627,6 @@ impl TPM2_ZGen_2Phase_REQUEST { } impl TpmStructure for TPM2_ZGen_2Phase_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -20820,16 +18691,6 @@ impl ZGen_2PhaseResponse { } impl TpmStructure for ZGen_2PhaseResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -20910,16 +18771,6 @@ impl TPM2_ECC_Encrypt_REQUEST { } impl TpmStructure for TPM2_ECC_Encrypt_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -20983,16 +18834,6 @@ impl ECC_EncryptResponse { } impl TpmStructure for ECC_EncryptResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -21086,16 +18927,6 @@ impl TPM2_ECC_Decrypt_REQUEST { } impl TpmStructure for TPM2_ECC_Decrypt_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -21157,16 +18988,6 @@ impl ECC_DecryptResponse { } impl TpmStructure for ECC_DecryptResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -21255,16 +19076,6 @@ impl TPM2_EncryptDecrypt_REQUEST { } impl TpmStructure for TPM2_EncryptDecrypt_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -21326,16 +19137,6 @@ impl EncryptDecryptResponse { } impl TpmStructure for EncryptDecryptResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -21426,16 +19227,6 @@ impl TPM2_EncryptDecrypt2_REQUEST { } impl TpmStructure for TPM2_EncryptDecrypt2_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -21498,16 +19289,6 @@ impl EncryptDecrypt2Response { } impl TpmStructure for EncryptDecrypt2Response { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -21584,16 +19365,6 @@ impl TPM2_Hash_REQUEST { } impl TpmStructure for TPM2_Hash_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -21655,16 +19426,6 @@ impl HashResponse { } impl TpmStructure for HashResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -21743,16 +19504,6 @@ impl TPM2_HMAC_REQUEST { } impl TpmStructure for TPM2_HMAC_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -21807,16 +19558,6 @@ impl HMACResponse { } impl TpmStructure for HMACResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -21894,16 +19635,6 @@ impl TPM2_MAC_REQUEST { } impl TpmStructure for TPM2_MAC_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -21959,16 +19690,6 @@ impl MACResponse { } impl TpmStructure for MACResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -22031,16 +19752,6 @@ impl TPM2_GetRandom_REQUEST { } impl TpmStructure for TPM2_GetRandom_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -22092,16 +19803,6 @@ impl GetRandomResponse { } impl TpmStructure for GetRandomResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -22164,16 +19865,6 @@ impl TPM2_StirRandom_REQUEST { } impl TpmStructure for TPM2_StirRandom_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -22252,16 +19943,6 @@ impl TPM2_HMAC_Start_REQUEST { } impl TpmStructure for TPM2_HMAC_Start_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -22319,16 +20000,6 @@ impl HMAC_StartResponse { } impl TpmStructure for HMAC_StartResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -22404,16 +20075,6 @@ impl TPM2_MAC_Start_REQUEST { } impl TpmStructure for TPM2_MAC_Start_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -22471,16 +20132,6 @@ impl MAC_StartResponse { } impl TpmStructure for MAC_StartResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -22550,16 +20201,6 @@ impl TPM2_HashSequenceStart_REQUEST { } impl TpmStructure for TPM2_HashSequenceStart_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -22618,16 +20259,6 @@ impl HashSequenceStartResponse { } impl TpmStructure for HashSequenceStartResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -22696,16 +20327,6 @@ impl TPM2_SequenceUpdate_REQUEST { } impl TpmStructure for TPM2_SequenceUpdate_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -22783,16 +20404,6 @@ impl TPM2_SequenceComplete_REQUEST { } impl TpmStructure for TPM2_SequenceComplete_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -22853,16 +20464,6 @@ impl SequenceCompleteResponse { } impl TpmStructure for SequenceCompleteResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -22947,16 +20548,6 @@ impl TPM2_EventSequenceComplete_REQUEST { } impl TpmStructure for TPM2_EventSequenceComplete_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -23013,16 +20604,6 @@ impl EventSequenceCompleteResponse { } impl TpmStructure for EventSequenceCompleteResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -23115,16 +20696,6 @@ impl TPM2_Certify_REQUEST { } impl TpmStructure for TPM2_Certify_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -23194,16 +20765,6 @@ impl CertifyResponse { } impl TpmStructure for CertifyResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -23309,16 +20870,6 @@ impl TPM2_CertifyCreation_REQUEST { } impl TpmStructure for TPM2_CertifyCreation_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -23391,16 +20942,6 @@ impl CertifyCreationResponse { } impl TpmStructure for CertifyCreationResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -23491,16 +21032,6 @@ impl TPM2_Quote_REQUEST { } impl TpmStructure for TPM2_Quote_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -23568,16 +21099,6 @@ impl QuoteResponse { } impl TpmStructure for QuoteResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -23678,16 +21199,6 @@ impl TPM2_GetSessionAuditDigest_REQUEST { } impl TpmStructure for TPM2_GetSessionAuditDigest_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -23753,16 +21264,6 @@ impl GetSessionAuditDigestResponse { } impl TpmStructure for GetSessionAuditDigestResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -23858,16 +21359,6 @@ impl TPM2_GetCommandAuditDigest_REQUEST { } impl TpmStructure for TPM2_GetCommandAuditDigest_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -23935,16 +21426,6 @@ impl GetCommandAuditDigestResponse { } impl TpmStructure for GetCommandAuditDigestResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -24038,16 +21519,6 @@ impl TPM2_GetTime_REQUEST { } impl TpmStructure for TPM2_GetTime_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -24113,16 +21584,6 @@ impl GetTimeResponse { } impl TpmStructure for GetTimeResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -24226,16 +21687,6 @@ impl TPM2_CertifyX509_REQUEST { } impl TpmStructure for TPM2_CertifyX509_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -24312,16 +21763,6 @@ impl CertifyX509Response { } impl TpmStructure for CertifyX509Response { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -24412,16 +21853,6 @@ impl TPM2_Commit_REQUEST { } impl TpmStructure for TPM2_Commit_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -24490,16 +21921,6 @@ impl CommitResponse { } impl TpmStructure for CommitResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -24568,16 +21989,6 @@ impl TPM2_EC_Ephemeral_REQUEST { } impl TpmStructure for TPM2_EC_Ephemeral_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -24632,16 +22043,6 @@ impl EC_EphemeralResponse { } impl TpmStructure for EC_EphemeralResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -24724,16 +22125,6 @@ impl TPM2_VerifySignature_REQUEST { } impl TpmStructure for TPM2_VerifySignature_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -24791,16 +22182,6 @@ impl VerifySignatureResponse { } impl TpmStructure for VerifySignatureResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -24888,16 +22269,6 @@ impl TPM2_Sign_REQUEST { } impl TpmStructure for TPM2_Sign_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -24963,16 +22334,6 @@ impl SignResponse { } impl TpmStructure for SignResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -25059,16 +22420,6 @@ impl TPM2_SetCommandCodeAuditStatus_REQUEST { } impl TpmStructure for TPM2_SetCommandCodeAuditStatus_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -25145,16 +22496,6 @@ impl TPM2_PCR_Extend_REQUEST { } impl TpmStructure for TPM2_PCR_Extend_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -25225,16 +22566,6 @@ impl TPM2_PCR_Event_REQUEST { } impl TpmStructure for TPM2_PCR_Event_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -25286,16 +22617,6 @@ impl PCR_EventResponse { } impl TpmStructure for PCR_EventResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -25358,16 +22679,6 @@ impl TPM2_PCR_Read_REQUEST { } impl TpmStructure for TPM2_PCR_Read_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -25426,16 +22737,6 @@ impl PCR_ReadResponse { } impl TpmStructure for PCR_ReadResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -25510,16 +22811,6 @@ impl TPM2_PCR_Allocate_REQUEST { } impl TpmStructure for TPM2_PCR_Allocate_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -25582,16 +22873,6 @@ impl PCR_AllocateResponse { } impl TpmStructure for PCR_AllocateResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -25680,16 +22961,6 @@ impl TPM2_PCR_SetAuthPolicy_REQUEST { } impl TpmStructure for TPM2_PCR_SetAuthPolicy_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -25764,16 +23035,6 @@ impl TPM2_PCR_SetAuthValue_REQUEST { } impl TpmStructure for TPM2_PCR_SetAuthValue_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -25841,16 +23102,6 @@ impl TPM2_PCR_Reset_REQUEST { } impl TpmStructure for TPM2_PCR_Reset_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -25956,16 +23207,6 @@ impl TPM2_PolicySigned_REQUEST { } impl TpmStructure for TPM2_PolicySigned_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -26035,16 +23276,6 @@ impl PolicySignedResponse { } impl TpmStructure for PolicySignedResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -26148,16 +23379,6 @@ impl TPM2_PolicySecret_REQUEST { } impl TpmStructure for TPM2_PolicySecret_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -26223,16 +23444,6 @@ impl PolicySecretResponse { } impl TpmStructure for PolicySecretResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -26329,16 +23540,6 @@ impl TPM2_PolicyTicket_REQUEST { } impl TpmStructure for TPM2_PolicyTicket_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -26419,16 +23620,6 @@ impl TPM2_PolicyOR_REQUEST { } impl TpmStructure for TPM2_PolicyOR_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -26507,16 +23698,6 @@ impl TPM2_PolicyPCR_REQUEST { } impl TpmStructure for TPM2_PolicyPCR_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -26588,16 +23769,6 @@ impl TPM2_PolicyLocality_REQUEST { } impl TpmStructure for TPM2_PolicyLocality_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -26693,16 +23864,6 @@ impl TPM2_PolicyNV_REQUEST { } impl TpmStructure for TPM2_PolicyNV_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -26787,16 +23948,6 @@ impl TPM2_PolicyCounterTimer_REQUEST { } impl TpmStructure for TPM2_PolicyCounterTimer_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -26870,16 +24021,6 @@ impl TPM2_PolicyCommandCode_REQUEST { } impl TpmStructure for TPM2_PolicyCommandCode_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -26944,16 +24085,6 @@ impl TPM2_PolicyPhysicalPresence_REQUEST { } impl TpmStructure for TPM2_PolicyPhysicalPresence_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -27020,16 +24151,6 @@ impl TPM2_PolicyCpHash_REQUEST { } impl TpmStructure for TPM2_PolicyCpHash_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -27101,16 +24222,6 @@ impl TPM2_PolicyNameHash_REQUEST { } impl TpmStructure for TPM2_PolicyNameHash_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -27191,16 +24302,6 @@ impl TPM2_PolicyDuplicationSelect_REQUEST { } impl TpmStructure for TPM2_PolicyDuplicationSelect_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -27291,16 +24392,6 @@ impl TPM2_PolicyAuthorize_REQUEST { } impl TpmStructure for TPM2_PolicyAuthorize_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -27371,16 +24462,6 @@ impl TPM2_PolicyAuthValue_REQUEST { } impl TpmStructure for TPM2_PolicyAuthValue_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -27442,16 +24523,6 @@ impl TPM2_PolicyPassword_REQUEST { } impl TpmStructure for TPM2_PolicyPassword_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -27514,16 +24585,6 @@ impl TPM2_PolicyGetDigest_REQUEST { } impl TpmStructure for TPM2_PolicyGetDigest_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -27574,16 +24635,6 @@ impl PolicyGetDigestResponse { } impl TpmStructure for PolicyGetDigestResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -27656,16 +24707,6 @@ impl TPM2_PolicyNvWritten_REQUEST { } impl TpmStructure for TPM2_PolicyNvWritten_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -27736,16 +24777,6 @@ impl TPM2_PolicyTemplate_REQUEST { } impl TpmStructure for TPM2_PolicyTemplate_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -27828,16 +24859,6 @@ impl TPM2_PolicyAuthorizeNV_REQUEST { } impl TpmStructure for TPM2_PolicyAuthorizeNV_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -27925,16 +24946,6 @@ impl TPM2_CreatePrimary_REQUEST { } impl TpmStructure for TPM2_CreatePrimary_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -28014,16 +25025,6 @@ impl CreatePrimaryResponse { } impl TpmStructure for CreatePrimaryResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -28113,16 +25114,6 @@ impl TPM2_HierarchyControl_REQUEST { } impl TpmStructure for TPM2_HierarchyControl_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -28206,16 +25197,6 @@ impl TPM2_SetPrimaryPolicy_REQUEST { } impl TpmStructure for TPM2_SetPrimaryPolicy_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -28284,16 +25265,6 @@ impl TPM2_ChangePPS_REQUEST { } impl TpmStructure for TPM2_ChangePPS_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -28361,16 +25332,6 @@ impl TPM2_ChangeEPS_REQUEST { } impl TpmStructure for TPM2_ChangeEPS_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -28433,16 +25394,6 @@ impl TPM2_Clear_REQUEST { } impl TpmStructure for TPM2_Clear_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -28510,16 +25461,6 @@ impl TPM2_ClearControl_REQUEST { } impl TpmStructure for TPM2_ClearControl_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -28590,16 +25531,6 @@ impl TPM2_HierarchyChangeAuth_REQUEST { } impl TpmStructure for TPM2_HierarchyChangeAuth_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -28667,16 +25598,6 @@ impl TPM2_DictionaryAttackLockReset_REQUEST { } impl TpmStructure for TPM2_DictionaryAttackLockReset_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -28756,16 +25677,6 @@ impl TPM2_DictionaryAttackParameters_REQUEST { } impl TpmStructure for TPM2_DictionaryAttackParameters_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -28845,16 +25756,6 @@ impl TPM2_PP_Commands_REQUEST { } impl TpmStructure for TPM2_PP_Commands_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -28927,17 +25828,7 @@ impl TPM2_SetAlgorithmSet_REQUEST { } -impl TpmStructure for TPM2_SetAlgorithmSet_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - +impl TpmStructure for TPM2_SetAlgorithmSet_REQUEST { // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -29026,16 +25917,6 @@ impl TPM2_FieldUpgradeStart_REQUEST { } impl TpmStructure for TPM2_FieldUpgradeStart_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -29106,16 +25987,6 @@ impl TPM2_FieldUpgradeData_REQUEST { } impl TpmStructure for TPM2_FieldUpgradeData_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -29175,16 +26046,6 @@ impl FieldUpgradeDataResponse { } impl TpmStructure for FieldUpgradeDataResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -29249,16 +26110,6 @@ impl TPM2_FirmwareRead_REQUEST { } impl TpmStructure for TPM2_FirmwareRead_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -29310,16 +26161,6 @@ impl FirmwareReadResponse { } impl TpmStructure for FirmwareReadResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -29385,16 +26226,6 @@ impl TPM2_ContextSave_REQUEST { } impl TpmStructure for TPM2_ContextSave_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -29444,16 +26275,6 @@ impl ContextSaveResponse { } impl TpmStructure for ContextSaveResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -29515,16 +26336,6 @@ impl TPM2_ContextLoad_REQUEST { } impl TpmStructure for TPM2_ContextLoad_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -29577,16 +26388,6 @@ impl ContextLoadResponse { } impl TpmStructure for ContextLoadResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -29649,16 +26450,6 @@ impl TPM2_FlushContext_REQUEST { } impl TpmStructure for TPM2_FlushContext_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -29740,16 +26531,6 @@ impl TPM2_EvictControl_REQUEST { } impl TpmStructure for TPM2_EvictControl_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -29800,16 +26581,6 @@ impl TPM2_ReadClock_REQUEST { } impl TpmStructure for TPM2_ReadClock_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -29859,16 +26630,6 @@ impl ReadClockResponse { } impl TpmStructure for ReadClockResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -29941,16 +26702,6 @@ impl TPM2_ClockSet_REQUEST { } impl TpmStructure for TPM2_ClockSet_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -30021,16 +26772,6 @@ impl TPM2_ClockRateAdjust_REQUEST { } impl TpmStructure for TPM2_ClockRateAdjust_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -30102,16 +26843,6 @@ impl TPM2_GetCapability_REQUEST { } impl TpmStructure for TPM2_GetCapability_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -30175,16 +26906,6 @@ impl GetCapabilityResponse { } impl TpmStructure for GetCapabilityResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -30256,16 +26977,6 @@ impl TPM2_TestParms_REQUEST { } impl TpmStructure for TPM2_TestParms_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -30346,16 +27057,6 @@ impl TPM2_NV_DefineSpace_REQUEST { } impl TpmStructure for TPM2_NV_DefineSpace_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -30430,16 +27131,6 @@ impl TPM2_NV_UndefineSpace_REQUEST { } impl TpmStructure for TPM2_NV_UndefineSpace_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -30511,16 +27202,6 @@ impl TPM2_NV_UndefineSpaceSpecial_REQUEST { } impl TpmStructure for TPM2_NV_UndefineSpaceSpecial_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -30583,16 +27264,6 @@ impl TPM2_NV_ReadPublic_REQUEST { } impl TpmStructure for TPM2_NV_ReadPublic_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -30646,16 +27317,6 @@ impl NV_ReadPublicResponse { } impl TpmStructure for NV_ReadPublicResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -30741,16 +27402,6 @@ impl TPM2_NV_Write_REQUEST { } impl TpmStructure for TPM2_NV_Write_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -30826,16 +27477,6 @@ impl TPM2_NV_Increment_REQUEST { } impl TpmStructure for TPM2_NV_Increment_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -30911,16 +27552,6 @@ impl TPM2_NV_Extend_REQUEST { } impl TpmStructure for TPM2_NV_Extend_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -31000,16 +27631,6 @@ impl TPM2_NV_SetBits_REQUEST { } impl TpmStructure for TPM2_NV_SetBits_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -31082,16 +27703,6 @@ impl TPM2_NV_WriteLock_REQUEST { } impl TpmStructure for TPM2_NV_WriteLock_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -31155,16 +27766,6 @@ impl TPM2_NV_GlobalWriteLock_REQUEST { } impl TpmStructure for TPM2_NV_GlobalWriteLock_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -31245,16 +27846,6 @@ impl TPM2_NV_Read_REQUEST { } impl TpmStructure for TPM2_NV_Read_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -31308,16 +27899,6 @@ impl NV_ReadResponse { } impl TpmStructure for NV_ReadResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -31391,16 +27972,6 @@ impl TPM2_NV_ReadLock_REQUEST { } impl TpmStructure for TPM2_NV_ReadLock_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -31468,16 +28039,6 @@ impl TPM2_NV_ChangeAuth_REQUEST { } impl TpmStructure for TPM2_NV_ChangeAuth_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -31585,16 +28146,6 @@ impl TPM2_NV_Certify_REQUEST { } impl TpmStructure for TPM2_NV_Certify_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -31665,16 +28216,6 @@ impl NV_CertifyResponse { } impl TpmStructure for NV_CertifyResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -31755,16 +28296,6 @@ impl TPM2_AC_GetCapability_REQUEST { } impl TpmStructure for TPM2_AC_GetCapability_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -31822,16 +28353,6 @@ impl AC_GetCapabilityResponse { } impl TpmStructure for AC_GetCapabilityResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -31919,16 +28440,6 @@ impl TPM2_AC_Send_REQUEST { } impl TpmStructure for TPM2_AC_Send_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -31982,16 +28493,6 @@ impl AC_SendResponse { } impl TpmStructure for AC_SendResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -32078,16 +28579,6 @@ impl TPM2_Policy_AC_SendSelect_REQUEST { } impl TpmStructure for TPM2_Policy_AC_SendSelect_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -32165,16 +28656,6 @@ impl TPM2_ACT_SetTimeout_REQUEST { } impl TpmStructure for TPM2_ACT_SetTimeout_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -32236,16 +28717,6 @@ impl TPM2_Vendor_TCG_Test_REQUEST { } impl TpmStructure for TPM2_Vendor_TCG_Test_REQUEST { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -32298,16 +28769,6 @@ impl Vendor_TCG_TestResponse { } impl TpmStructure for Vendor_TCG_TestResponse { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -32434,16 +28895,6 @@ impl TssObject { } impl TpmStructure for TssObject { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -32503,16 +28954,6 @@ impl PcrValue { } impl TpmStructure for PcrValue { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -32581,16 +29022,6 @@ impl SessionIn { } impl TpmStructure for SessionIn { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -32657,16 +29088,6 @@ impl SessionOut { } impl TpmStructure for SessionOut { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -32731,16 +29152,6 @@ impl CommandHeader { } impl TpmStructure for CommandHeader { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -32800,16 +29211,6 @@ impl TSS_KEY { } impl TpmStructure for TSS_KEY { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -32855,16 +29256,6 @@ impl TPM2B_DIGEST_SYMCIPHER { } impl TpmStructure for TPM2B_DIGEST_SYMCIPHER { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields @@ -32908,16 +29299,6 @@ impl TPM2B_DIGEST_KEYEDHASH { } impl TpmStructure for TPM2B_DIGEST_KEYEDHASH { - fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { - buffer.createObj::()?; - Ok(()) - } - - fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> { - let mut tpm_buffer = TpmBuffer::from(buffer); - self.initFromTpm(&mut tpm_buffer) - } - // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields diff --git a/TssCodeGen/src/CGenRust.cs b/TssCodeGen/src/CGenRust.cs index 7c681bdf..ec9e777a 100644 --- a/TssCodeGen/src/CGenRust.cs +++ b/TssCodeGen/src/CGenRust.cs @@ -14,11 +14,13 @@ namespace CodeGen /// Rust TSS code generator internal class CGenRust : CodeGenBase { + // Note that TpmStructure::fromTpm() and fromBytes() are deliberately not generated. + // Their bodies are type independent (they only forward to TpmMarshaller::initFromTpm(), + // which is dispatched dynamically), so they are implemented once as default methods of + // the TpmStructure trait in the handwritten src/tpm_structure.rs. static readonly (string, string)[] TpmStructureFunctions = new (string, string)[] { ("serialize", "(&self, buffer: &mut TpmBuffer)"), ("deserialize", "(&mut self, buffer: &mut TpmBuffer)"), - ("fromTpm", "(&self, buffer: &mut TpmBuffer)"), - ("fromBytes", "(&mut self, buffer: &mut Vec)"), }; // Maps enum type to a map of enumerator names to values @@ -566,15 +568,7 @@ void GenTpmStructureImplementation(TpmStruct s) // Marshaling methods TabIn($"impl TpmStructure for {s.Name} {{"); - TabIn("fn fromTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> {"); - Write($"buffer.createObj::<{s.Name}>()?;"); - Write("Ok(())"); - TabOut("}"); - - TabIn("fn fromBytes(&mut self, buffer: &mut Vec) -> Result<(), TpmError> {"); - Write("let mut tpm_buffer = TpmBuffer::from(buffer);"); - Write($"self.initFromTpm(&mut tpm_buffer)"); - TabOut("}"); + // fromTpm() and fromBytes() come from the TpmStructure trait default methods. GenStructMarshalingImpl(s); From 03b3bc7d4604c3b232a59b070b33cf1d367ec832 Mon Sep 17 00:00:00 2001 From: Matan Radomski Date: Wed, 12 Aug 2026 15:39:41 +0300 Subject: [PATCH 04/13] Add checked TPM serialization and deserialization --- TSS.Rust/src/error.rs | 4 +++ TSS.Rust/src/tpm_buffer.rs | 17 +++++++-- TSS.Rust/src/tpm_structure.rs | 66 ++++++++++++++++++++++++++++++++++- 3 files changed, 83 insertions(+), 4 deletions(-) diff --git a/TSS.Rust/src/error.rs b/TSS.Rust/src/error.rs index f9739623..e6937144 100644 --- a/TSS.Rust/src/error.rs +++ b/TSS.Rust/src/error.rs @@ -12,6 +12,9 @@ pub enum TpmError { /// Buffer overflow occurred during serialization BufferOverflow, + /// Bytes remained after deserializing a complete TPM value + TrailingData, + /// Invalid array size InvalidArraySize(String), @@ -70,6 +73,7 @@ impl fmt::Display for TpmError { match self { Self::BufferUnderflow => write!(f, "Buffer underflow during deserialization"), Self::BufferOverflow => write!(f, "Buffer overflow during serialization"), + Self::TrailingData => write!(f, "Trailing data after TPM value"), Self::InvalidArraySize(msg) => write!(f, "Invalid array size: {}", msg), Self::InvalidEnumValue => write!(f, "Invalid enum value"), Self::InvalidUnion => write!(f, "Invalid union type"), diff --git a/TSS.Rust/src/tpm_buffer.rs b/TSS.Rust/src/tpm_buffer.rs index 0fe7b8eb..28aaa6f2 100644 --- a/TSS.Rust/src/tpm_buffer.rs +++ b/TSS.Rust/src/tpm_buffer.rs @@ -16,6 +16,14 @@ pub trait TpmMarshaller { /** Populate this object from the TPM representation in the given marshaling buffer */ fn initFromTpm(&mut self, buf: &mut TpmBuffer) -> Result<(), TpmError>; + + /** Convert this object to its complete TPM wire representation. */ + #[allow(non_snake_case)] + fn toBytes(&self) -> Result, TpmError> { + let mut buffer = TpmBuffer::new(None); + self.toTpm(&mut buffer)?; + Ok(buffer.trim().to_vec()) + } } pub struct TpmBuffer { @@ -221,7 +229,7 @@ impl TpmBuffer { /** Writes the given 8-bit integer to this buffer */ pub fn writeByte(&mut self, val: u8) { - if self.check_len(1) { + if self.ensure_write_len(1) { self.buf[self.pos] = val; self.pos += 1; } @@ -270,7 +278,7 @@ impl TpmBuffer { /** Marshalls the given byte buffer with no length prefix. */ pub fn writeByteBuf(&mut self, data: &[u8]) { let data_size = data.len(); - if data_size == 0 || !self.check_len(data_size) { + if data_size == 0 || !self.ensure_write_len(data_size) { return; } self.buf[self.pos..self.pos + data_size].copy_from_slice(data); @@ -319,7 +327,7 @@ impl TpmBuffer { pub fn writeSizedObj(&mut self, obj: &T) -> Result<(), TpmError> { const LEN_SIZE: usize = 2; // Length of the object size is always 2 bytes - if !self.check_len(LEN_SIZE) { + if !self.ensure_write_len(LEN_SIZE) { return Ok(()); } @@ -350,6 +358,9 @@ impl TpmBuffer { if size == 0 { return Ok(()); } + if !self.check_read_len(size as usize) { + return Err(TpmError::BufferUnderflow); + } if size as usize > self.remaining_len() { self.out_of_bounds = true; diff --git a/TSS.Rust/src/tpm_structure.rs b/TSS.Rust/src/tpm_structure.rs index 39c6f5f0..5321dab3 100644 --- a/TSS.Rust/src/tpm_structure.rs +++ b/TSS.Rust/src/tpm_structure.rs @@ -35,6 +35,68 @@ pub trait TpmStructure: TpmMarshaller { self.initFromTpm(&mut tpm_buffer)?; tpm_buffer.check_status() } + + /// Decode one complete TPM value, rejecting truncated or trailing input. + #[allow(non_snake_case)] + fn fromBytesExact(bytes: &[u8]) -> Result + where + Self: Default + Sized, + { + let mut buffer = TpmBuffer::from(bytes); + let value = buffer.createObj::()?; + if buffer.current_pos() != buffer.size() { + return Err(TpmError::TrailingData); + } + Ok(value) + } +} + +#[cfg(test)] +mod exact_decode_tests { + use std::panic::catch_unwind; + + use super::*; + + #[test] + fn exact_decode_round_trips() { + let value = TPM2B_PRIVATE::new(&vec![0xaa, 0xbb]); + let bytes = value.toBytes().unwrap(); + + let decoded = TPM2B_PRIVATE::fromBytesExact(&bytes).unwrap(); + + assert_eq!(decoded.buffer, value.buffer); + } + + #[test] + fn exact_decode_rejects_truncated_input() { + assert!(matches!( + TPM2B_PRIVATE::fromBytesExact(&[0, 2, 0xaa]), + Err(TpmError::BufferUnderflow) + )); + } + + #[test] + fn exact_decode_rejects_trailing_input() { + assert!(matches!( + TPM2B_PRIVATE::fromBytesExact(&[0, 1, 0xaa, 0xff]), + Err(TpmError::TrailingData) + )); + } + + #[test] + fn malformed_tpm2b_values_do_not_panic() { + for length in 0..=64 { + let bytes: Vec = (0..length) + .map(|index| (index as u8).wrapping_mul(37).wrapping_add(11)) + .collect(); + assert!(catch_unwind(|| TPM2B_PUBLIC::fromBytesExact(&bytes)).is_ok()); + assert!(catch_unwind(|| TPM2B_PRIVATE::fromBytesExact(&bytes)).is_ok()); + assert!(catch_unwind(|| TPM2B_ENCRYPTED_SECRET::fromBytesExact(&bytes)).is_ok()); + } + + let oversized_array = [0xff; 8]; + assert!(catch_unwind(|| TPML_ALG::fromBytesExact(&oversized_array)).is_ok()); + } } /// Common trait for all TPM enumeration types @@ -116,7 +178,9 @@ pub trait RespStructure: CmdStructure { fn set_handle(&mut self, _handle: &TPM_HANDLE) {} /// Returns the name field from the response, if present - fn get_resp_name(&self) -> Vec { Vec::new() } + fn get_resp_name(&self) -> Vec { + Vec::new() + } /// Serializable method fn type_name(&self) -> String { From 9274a16e86af9625ba87ac89d75706d7a9750060 Mon Sep 17 00:00:00 2001 From: Matan Radomski Date: Wed, 12 Aug 2026 15:58:37 +0300 Subject: [PATCH 05/13] Added size prefix check for martialling --- TSS.Rust/src/tpm_buffer.rs | 83 +++++++++++++++++++++++++++++++++++++- 1 file changed, 82 insertions(+), 1 deletion(-) diff --git a/TSS.Rust/src/tpm_buffer.rs b/TSS.Rust/src/tpm_buffer.rs index 28aaa6f2..7e96b47c 100644 --- a/TSS.Rust/src/tpm_buffer.rs +++ b/TSS.Rust/src/tpm_buffer.rs @@ -22,6 +22,9 @@ pub trait TpmMarshaller { fn toBytes(&self) -> Result, TpmError> { let mut buffer = TpmBuffer::new(None); self.toTpm(&mut buffer)?; + if !buffer.isOk() { + return Err(TpmError::BufferOverflow); + } Ok(buffer.trim().to_vec()) } } @@ -144,6 +147,24 @@ impl TpmBuffer { self.buf.len().saturating_sub(self.pos) } + /// Returns whether `size` can be represented without truncation by a `prefix_len`-byte + /// unsigned length field. + fn size_fits_prefix(size: usize, prefix_len: usize) -> bool { + let Some(bit_count) = prefix_len.checked_mul(8) else { + return false; + }; + if bit_count == 0 || bit_count > u64::BITS as usize { + return false; + } + + let max_size = if bit_count == u64::BITS as usize { + u64::MAX + } else { + (1_u64 << bit_count) - 1 + }; + u64::try_from(size).is_ok_and(|size| size <= max_size) + } + pub fn check_status(&self) -> Result<(), TpmError> { if self.isOk() { Ok(()) @@ -305,6 +326,11 @@ impl TpmBuffer { /** Marshalls the given byte buffer with a length prefix. */ pub fn writeSizedByteBuf(&mut self, data: &[u8], size_len: usize) { + // Reject the payload before narrowing its length into the wire-format prefix. + if !Self::size_fits_prefix(data.len(), size_len) { + self.out_of_bounds = true; + return; + } self.write_num(data.len() as u64, size_len); self.writeByteBuf(data); } @@ -339,6 +365,11 @@ impl TpmBuffer { obj.toTpm(self)?; // Calc marshaled object len let obj_size = self.pos - (size_pos + LEN_SIZE); + // Sized TPM objects always use a two-byte prefix; a larger body cannot be encoded. + if !Self::size_fits_prefix(obj_size, LEN_SIZE) { + self.out_of_bounds = true; + return Err(TpmError::BufferOverflow); + } // Marshal it in the appropriate position self.pos = size_pos; self.writeShort(obj_size as u16); @@ -386,6 +417,11 @@ impl TpmBuffer { } pub fn writeObjArr(&mut self, arr: &[T]) -> Result<(), TpmError> { + // Array counts are encoded as u32 and must not be truncated on 64-bit platforms. + if !Self::size_fits_prefix(arr.len(), std::mem::size_of::()) { + self.out_of_bounds = true; + return Err(TpmError::BufferOverflow); + } self.writeInt(arr.len() as u32); for elt in arr { if !self.isOk() { @@ -433,6 +469,11 @@ impl TpmBuffer { U: Into, { // Length of the array size is always 4 bytes + // Array counts are encoded as u32 and must not be truncated on 64-bit platforms. + if !Self::size_fits_prefix(arr.len(), std::mem::size_of::()) { + self.out_of_bounds = true; + return; + } self.writeInt(arr.len() as u32); for val in arr { if !self.isOk() { @@ -484,7 +525,32 @@ impl TpmBuffer { mod tests { use super::*; use crate::tpm_structure::TpmStructure; - use crate::tpm_types::{TPM2B_DIGEST, TPM_HANDLE}; + use crate::tpm_types::{TPM2B_DIGEST, TPM2B_PRIVATE, TPM_HANDLE}; + + struct OversizedSizedObject; + + impl TpmMarshaller for OversizedSizedObject { + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.writeByteBuf(&vec![0; u16::MAX as usize + 1]); + Ok(()) + } + + fn initFromTpm(&mut self, _buffer: &mut TpmBuffer) -> Result<(), TpmError> { + Ok(()) + } + } + + struct SizedObjectWrapper; + + impl TpmMarshaller for SizedObjectWrapper { + fn toTpm(&self, buffer: &mut TpmBuffer) -> Result<(), TpmError> { + buffer.writeSizedObj(&OversizedSizedObject) + } + + fn initFromTpm(&mut self, _buffer: &mut TpmBuffer) -> Result<(), TpmError> { + Ok(()) + } + } #[test] fn create_obj_rejects_zero_length_input() { @@ -520,4 +586,19 @@ mod tests { assert_eq!(buffer.size(), 3); assert_eq!(buffer.current_pos(), 2); } + + #[test] + fn to_bytes_rejects_sized_byte_buffer_larger_than_prefix() { + let value = TPM2B_PRIVATE::new(&vec![0; u16::MAX as usize + 1]); + + assert!(matches!(value.toBytes(), Err(TpmError::BufferOverflow))); + } + + #[test] + fn to_bytes_rejects_sized_object_larger_than_prefix() { + assert!(matches!( + SizedObjectWrapper.toBytes(), + Err(TpmError::BufferOverflow) + )); + } } From 4bf0765a37b0e24e6b33f842b6c941277eccbf21 Mon Sep 17 00:00:00 2001 From: Roee Kasher Date: Thu, 13 Aug 2026 14:45:36 +0300 Subject: [PATCH 06/13] Consolidate RSA primitives into the Crypto facade (#4) * Consolidate RSA primitives into the Crypto facade tpm_type_extensions.rs reached directly for the `rsa` and `rand` crates, making it the only file bypassing `Crypto` and leaving two separate RSA-OAEP implementations in the tree. Move all of it behind `Crypto` so there is a single place where a crypto backend is selected. - Add `Crypto::rsa_oaep_encrypt`, `rsa_pkcs1v15_verify`, `rsa_generate_keypair` and `rsa_pkcs1v15_sign`, plus the `RsaKeyParts` carrier and the shared `RSA_DEFAULT_EXPONENT` constant. - Collapse the duplicate OAEP paths in `create_activation`, `encrypt` and `encrypt_session_salt` onto one implementation. Labels are now passed as bytes, which is how the TPM specification defines them. - Route `validate_signature` and `TSS_KEY::{create_key, sign}` through the facade. `tpm_type_extensions.rs` no longer imports `rsa` or `rand`. Two panics become errors on the way: `create_key` no longer indexes into an empty prime list, and `sign` no longer divides by a zero prime. Error text converges at four sites that previously had their own wording for the same failure. Behavior is otherwise unchanged. * Size the activation seed from the key's name algorithm `create_activation` generated a fixed 16 byte seed. TPM 2.0 Part 1 "Credential Protection" sizes the seed from the key's nameAlg, and Part 4 `CryptSecretDecrypt` rejects any other size with TPM_RC_VALUE, so `TPM2_ActivateCredential` could never recover a credential built this way. A SHA-256 key needs 32 bytes and a SHA-1 key 20. `tpm_samples::activate_credentials` has been tolerating the resulting mismatch with a "known create_activation issue" message. TSS.NET already gets this right in `TpmKey.CreateActivationCredentials`, which carries a comment stating the rule. TSS.CPP has the same defect in `TPMT_PUBLIC::CreateActivation` and is the likely origin of this one. Add a test that plays the part of TPM2_ActivateCredential in software: it recovers the seed, enforces the same seed size check the TPM makes, rederives both keys, verifies the integrity HMAC and decrypts the credential. Modelling the TPM's size check is what gives the test its value, because the seed travels inside the blob and would otherwise round trip at any length. --- TSS.Rust/examples/tpm_samples.rs | 6 +- TSS.Rust/src/crypto.rs | 192 +++++++++++++++++++- TSS.Rust/src/tpm_type_extensions.rs | 268 ++++++++++++++++++++-------- 3 files changed, 378 insertions(+), 88 deletions(-) diff --git a/TSS.Rust/examples/tpm_samples.rs b/TSS.Rust/examples/tpm_samples.rs index d8368b5a..c30e6e74 100644 --- a/TSS.Rust/examples/tpm_samples.rs +++ b/TSS.Rust/examples/tpm_samples.rs @@ -336,11 +336,7 @@ fn activate_credentials(tpm: &mut Tpm2) -> Result<(), TpmError> { println!("Secret: {:?}", secret); println!("Secret recovered from Activate: {:?}", recovered_secret); - if secret != recovered_secret { - print_error("Secret mismatch when using TSS.Rust to create an activation credential (known create_activation issue)"); - } else { - println!("TSS.Rust-created activation blob verified"); - } + assert!(secret == recovered_secret, "Secret mismatch when using TSS.Rust to create an activation credential"); // You can also use the TPM to make the activation credential let tpm_activator = tpm.MakeCredential(&ek_handle, &secret, &name_of_key_to_activate)?; diff --git a/TSS.Rust/src/crypto.rs b/TSS.Rust/src/crypto.rs index 41feb4d4..2d209ee2 100644 --- a/TSS.Rust/src/crypto.rs +++ b/TSS.Rust/src/crypto.rs @@ -1,6 +1,7 @@ use crate::{error::TpmError, tpm_types::*}; use hmac::{Hmac, Mac}; -use rsa::{BigUint, Pkcs1v15Sign, RsaPublicKey}; +use rsa::traits::{PrivateKeyParts, PublicKeyParts}; +use rsa::{BigUint, Oaep, Pkcs1v15Sign, RsaPrivateKey, RsaPublicKey}; use sha1::Sha1; use sha2::{Digest as Sha2Digest, Sha256, Sha384, Sha512}; use sm3::Sm3; @@ -9,6 +10,21 @@ use aes::Aes128; use cipher::{BlockEncrypt, KeyInit}; use cipher::generic_array::GenericArray; +/// The RSA public exponent used by every key this library creates or consumes (65537, "F4"). +/// +/// A TPM encodes this value as zero in `TPMS_RSA_PARMS::exponent`, so it never travels on the +/// wire and has to be supplied by the caller. +pub const RSA_DEFAULT_EXPONENT: [u8; 3] = [0x01, 0x00, 0x01]; + +/// RSA private key material in the form `TSS_KEY` persists it: the modulus and the first prime. +/// +/// The second prime is recovered by dividing the modulus by the first, so it is not stored. +#[derive(Clone, Debug)] +pub struct RsaKeyParts { + pub modulus: Vec, + pub prime: Vec, +} + pub struct Crypto; impl Crypto { @@ -122,7 +138,7 @@ impl Crypto { } } - pub(crate) fn pkcs1v15_sign_scheme(hash_alg: TPM_ALG_ID) -> Result { + fn pkcs1v15_sign_scheme(hash_alg: TPM_ALG_ID) -> Result { match hash_alg { TPM_ALG_ID::SHA1 => Ok(Pkcs1v15Sign::new::()), TPM_ALG_ID::SHA256 => Ok(Pkcs1v15Sign::new::()), @@ -135,6 +151,107 @@ impl Crypto { } } + /// Build an RSA public key from its big-endian components. + fn rsa_public_key(modulus: &[u8], exponent: &[u8]) -> Result { + RsaPublicKey::new( + BigUint::from_bytes_be(modulus), + BigUint::from_bytes_be(exponent), + ) + .map_err(|_| TpmError::InvalidArraySize("Invalid RSA public key".to_string())) + } + + /// RSA-OAEP encrypt `data` under the public key given by its big-endian components. + /// + /// `label` is used verbatim, so callers must include the trailing NUL that the TPM + /// specification puts in labels such as `b"IDENTITY\0"`. + pub fn rsa_oaep_encrypt( + modulus: &[u8], + exponent: &[u8], + hash_alg: TPM_ALG_ID, + label: &[u8], + data: &[u8], + ) -> Result, TpmError> { + let rsa_key = Self::rsa_public_key(modulus, exponent)?; + + // The `rsa` crate models an OAEP label as a string rather than as bytes, so the label + // has to be converted here. Callers work in bytes because that is what the TPM + // specification and other crypto backends use. + let label = std::str::from_utf8(label) + .map_err(|_| TpmError::NotSupported("OAEP label must be valid UTF-8".to_string()))?; + + let padding = match hash_alg { + TPM_ALG_ID::SHA1 => Oaep::new_with_label::(label), + TPM_ALG_ID::SHA256 => Oaep::new_with_label::(label), + _ => { + return Err(TpmError::NotSupported(format!( + "Unsupported nameAlg for OAEP: {:?}", + hash_alg + ))) + } + }; + + rsa_key + .encrypt(&mut OsRng, padding, data) + .map_err(|e| TpmError::GenericError(format!("RSA-OAEP encryption failed: {e}"))) + } + + /// Verify an RSASSA-PKCS1-v1_5 signature over an already computed digest. + pub fn rsa_pkcs1v15_verify( + modulus: &[u8], + exponent: &[u8], + hash_alg: TPM_ALG_ID, + digest: &[u8], + signature: &[u8], + ) -> Result { + let rsa_key = Self::rsa_public_key(modulus, exponent)?; + let scheme = Self::pkcs1v15_sign_scheme(hash_alg)?; + Ok(rsa_key.verify(scheme, digest, signature).is_ok()) + } + + /// Generate an RSA key pair in software, returning the modulus and the first prime. + pub fn rsa_generate_keypair(key_bits: usize) -> Result { + let priv_key = RsaPrivateKey::new(&mut OsRng, key_bits) + .map_err(|e| TpmError::GenericError(format!("RSA key generation failed: {}", e)))?; + + let prime = priv_key.primes().first().ok_or_else(|| { + TpmError::GenericError("Generated RSA key exposes no primes".to_string()) + })?; + + Ok(RsaKeyParts { + modulus: priv_key.n().to_bytes_be(), + prime: prime.to_bytes_be(), + }) + } + + /// Sign an already computed digest with RSASSA-PKCS1-v1_5. + /// + /// The second prime is recovered as `modulus / prime`. + pub fn rsa_pkcs1v15_sign( + key: &RsaKeyParts, + hash_alg: TPM_ALG_ID, + digest: &[u8], + ) -> Result, TpmError> { + // Recovering the second prime divides by the first, so reject a zero prime up front + // instead of letting the big-integer division panic. + if key.prime.iter().all(|&byte| byte == 0) { + return Err(TpmError::InvalidArraySize( + "RSA private key prime is zero".to_string(), + )); + } + + let modulus = BigUint::from_bytes_be(&key.modulus); + let first_prime = BigUint::from_bytes_be(&key.prime); + let second_prime = &modulus / &first_prime; + let exponent = BigUint::from_bytes_be(&RSA_DEFAULT_EXPONENT); + + let priv_key = RsaPrivateKey::from_p_q(first_prime, second_prime, exponent) + .map_err(|e| TpmError::GenericError(format!("Failed to reconstruct RSA key: {}", e)))?; + + priv_key + .sign(Self::pkcs1v15_sign_scheme(hash_alg)?, digest) + .map_err(|e| TpmError::GenericError(format!("RSA signing failed: {}", e))) + } + pub fn validate_signature( public_key: &TPMT_PUBLIC, signed_blob_hash: Vec, @@ -162,10 +279,6 @@ impl Crypto { )); }; - let rsa_public_key = RsaPublicKey::new(BigUint::from_bytes_be(rsa_pub_key), BigUint::from_bytes_be(&[1, 0, 1])) - .map_err(|_| TpmError::InvalidArraySize("Invalid RSA public key".to_string()))?; - - let scheme = Self::pkcs1v15_sign_scheme(signature.hash)?; let expected_digest_size = Self::digestSize(signature.hash); if signed_blob_hash.len() != expected_digest_size { return Err(TpmError::InvalidArraySize(format!( @@ -176,9 +289,13 @@ impl Crypto { ))); } - Ok(rsa_public_key - .verify(scheme, &signed_blob_hash, &signature.sig) - .is_ok()) + Self::rsa_pkcs1v15_verify( + rsa_pub_key, + &RSA_DEFAULT_EXPONENT, + signature.hash, + &signed_blob_hash, + &signature.sig, + ) } // KDFa implementation as specified in TPM 2.0 Part 1 @@ -323,4 +440,61 @@ mod tests { assert!(Crypto::validate_signature(&public_key, digest, &signature)?); Ok(()) } + + #[test] + fn rsa_oaep_encrypt_round_trips_and_binds_the_label() -> Result<(), TpmError> { + let mut rng = OsRng; + let private_key = RsaPrivateKey::new(&mut rng, 2048) + .map_err(|e| TpmError::GenericError(format!("RSA key generation failed: {e}")))?; + let modulus = private_key.n().to_bytes_be(); + + let plaintext = b"seed material"; + let ciphertext = Crypto::rsa_oaep_encrypt( + &modulus, + &RSA_DEFAULT_EXPONENT, + TPM_ALG_ID::SHA256, + b"IDENTITY\0", + plaintext, + )?; + + let decrypted = private_key + .decrypt(Oaep::new_with_label::("IDENTITY\0"), &ciphertext) + .map_err(|e| TpmError::GenericError(format!("OAEP decryption failed: {e}")))?; + assert_eq!(decrypted, plaintext); + + // A different label must not recover the plaintext. This is what keeps the "IDENTITY\0" + // and "SECRET\0" call sites distinct now that they share one implementation. + assert!(private_key + .decrypt(Oaep::new_with_label::("SECRET\0"), &ciphertext) + .is_err()); + + Ok(()) + } + + #[test] + fn rsa_sign_round_trips_through_verify() -> Result<(), TpmError> { + let key = Crypto::rsa_generate_keypair(2048)?; + let digest = Sha256::digest(b"software key signing regression").to_vec(); + + let signature = Crypto::rsa_pkcs1v15_sign(&key, TPM_ALG_ID::SHA256, &digest)?; + + assert!(Crypto::rsa_pkcs1v15_verify( + &key.modulus, + &RSA_DEFAULT_EXPONENT, + TPM_ALG_ID::SHA256, + &digest, + &signature, + )?); + Ok(()) + } + + #[test] + fn rsa_sign_rejects_a_zero_prime_instead_of_dividing_by_it() { + let key = RsaKeyParts { + modulus: vec![0xff; 256], + prime: vec![0u8; 128], + }; + + assert!(Crypto::rsa_pkcs1v15_sign(&key, TPM_ALG_ID::SHA256, &[0u8; 32]).is_err()); + } } diff --git a/TSS.Rust/src/tpm_type_extensions.rs b/TSS.Rust/src/tpm_type_extensions.rs index 6e0752ea..b65bbc6a 100644 --- a/TSS.Rust/src/tpm_type_extensions.rs +++ b/TSS.Rust/src/tpm_type_extensions.rs @@ -1,36 +1,12 @@ -use crate::crypto::Crypto; +use crate::crypto::{Crypto, RsaKeyParts, RSA_DEFAULT_EXPONENT}; use crate::error::TpmError; use crate::tpm2_helpers::int_to_tpm; use crate::tpm_buffer::*; use crate::tpm_structure::TpmEnum; use crate::tpm_types::CertifyResponse; use crate::tpm_types::*; -use rsa::{BigUint, RsaPublicKey, RsaPrivateKey, Oaep}; -use rsa::traits::{PublicKeyParts, PrivateKeyParts}; -use rand::rngs::OsRng; use zeroize::Zeroize; -/// RSA-OAEP encrypt using the hash algorithm matching the key's nameAlg. -fn rsa_oaep_encrypt( - rsa_key: &RsaPublicKey, - name_alg: TPM_ALG_ID, - label: &str, - data: &[u8], -) -> Result, TpmError> { - match name_alg { - TPM_ALG_ID::SHA1 => rsa_key - .encrypt(&mut OsRng, Oaep::new_with_label::(label), data) - .map_err(|e| TpmError::GenericError(format!("RSA-OAEP encryption failed: {e}"))), - TPM_ALG_ID::SHA256 => rsa_key - .encrypt(&mut OsRng, Oaep::new_with_label::(label), data) - .map_err(|e| TpmError::GenericError(format!("RSA-OAEP encryption failed: {e}"))), - _ => Err(TpmError::NotSupported(format!( - "Unsupported nameAlg for OAEP: {:?}", - name_alg - ))), - } -} - /// Activation data returned from create_activation #[derive(Debug)] pub struct ActivationData { @@ -142,8 +118,9 @@ impl TPMT_PUBLIC { return Err(TpmError::NotSupported("Unsupported wrapping scheme".to_string())); } - // Generate random 16-byte seed - let mut seed = Crypto::get_random(16); + // The seed is the same size as the nameAlg digest, per TPM 2.0 Part 1 "Credential + // Protection". TSS.NET does the same in TpmKey.CreateActivationCredentials. + let mut seed = Crypto::get_random(Crypto::digestSize(self.nameAlg)); // Get RSA public key components for encrypting the seed let rsa_pub_n = if let Some(TPMU_PUBLIC_ID::rsa(unique)) = &self.unique { @@ -152,13 +129,14 @@ impl TPMT_PUBLIC { return Err(TpmError::NotSupported("Invalid RSA public key".to_string())); }; - let rsa_public_key = RsaPublicKey::new( - BigUint::from_bytes_be(rsa_pub_n), - BigUint::from_bytes_be(&[1, 0, 1]) // e = 65537 - ).map_err(|_| TpmError::GenericError("Invalid RSA parameters".to_string()))?; - // Encrypt seed with label "IDENTITY" using OAEP with the key's nameAlg - let secret = rsa_oaep_encrypt(&rsa_public_key, self.nameAlg, "IDENTITY\0", &seed)?; + let secret = Crypto::rsa_oaep_encrypt( + rsa_pub_n, + &RSA_DEFAULT_EXPONENT, + self.nameAlg, + b"IDENTITY\0", + &seed, + )?; // Make the credential blob: @@ -244,16 +222,14 @@ impl TPMT_PUBLIC { return Err(TpmError::NotSupported("Invalid RSA public key".to_string())); }; - // Create RSA public key (usually e = 65537) - let rsa_public_key = RsaPublicKey::new( - BigUint::from_bytes_be(rsa_pub_n), - BigUint::from_bytes_be(&[1, 0, 1]) // e = 65537 - ).map_err(|_| TpmError::InvalidArraySize("Invalid RSA parameters".to_string()))?; - // Encrypt the data using OAEP padding with the key's nameAlg - let encrypted_data = rsa_oaep_encrypt(&rsa_public_key, self.nameAlg, "IDENTITY\0", data)?; - - Ok(encrypted_data) + Crypto::rsa_oaep_encrypt( + rsa_pub_n, + &RSA_DEFAULT_EXPONENT, + self.nameAlg, + b"IDENTITY\0", + data, + ) } /// Encrypt a session salt for use with salted auth sessions. @@ -265,20 +241,13 @@ impl TPMT_PUBLIC { return Err(TpmError::NotSupported("Only RSA keys can encrypt session salt".to_string())); }; - let rsa_public_key = RsaPublicKey::new( - BigUint::from_bytes_be(rsa_pub_n), - BigUint::from_bytes_be(&[1, 0, 1]), - ).map_err(|_| TpmError::InvalidArraySize("Invalid RSA parameters".to_string()))?; - - let padding = match self.nameAlg { - TPM_ALG_ID::SHA1 => Oaep::new_with_label::("SECRET\0"), - TPM_ALG_ID::SHA256 => Oaep::new_with_label::("SECRET\0"), - _ => return Err(TpmError::NotSupported(format!("Unsupported nameAlg for session salt: {:?}", self.nameAlg))), - }; - - rsa_public_key - .encrypt(&mut OsRng, padding, salt) - .map_err(|e| TpmError::GenericError(format!("Failed to encrypt session salt: {}", e))) + Crypto::rsa_oaep_encrypt( + rsa_pub_n, + &RSA_DEFAULT_EXPONENT, + self.nameAlg, + b"SECRET\0", + salt, + ) } } @@ -411,23 +380,19 @@ impl TSS_KEY { /// Generate an RSA key pair in software. /// Populates publicPart.unique with the modulus and privatePart with the first prime (p). pub fn create_key(&mut self) -> Result<(), TpmError> { - let rsa_params = if let Some(TPMU_PUBLIC_PARMS::rsaDetail(ref params)) = self.publicPart.parameters { - params.clone() + let key_bits = if let Some(TPMU_PUBLIC_PARMS::rsaDetail(ref params)) = self.publicPart.parameters { + params.keyBits as usize } else { return Err(TpmError::GenericError("Only RSA key creation is supported".to_string())); }; - let key_bits = rsa_params.keyBits as usize; - let priv_key = RsaPrivateKey::new(&mut OsRng, key_bits) - .map_err(|e| TpmError::GenericError(format!("RSA key generation failed: {}", e)))?; + let key = Crypto::rsa_generate_keypair(key_bits)?; // Store modulus (n) in publicPart.unique - let n_bytes = priv_key.n().to_bytes_be(); - self.publicPart.unique = Some(TPMU_PUBLIC_ID::rsa(TPM2B_PUBLIC_KEY_RSA { buffer: n_bytes })); + self.publicPart.unique = Some(TPMU_PUBLIC_ID::rsa(TPM2B_PUBLIC_KEY_RSA { buffer: key.modulus })); // Store first prime (p) as privatePart - let primes = priv_key.primes(); - self.privatePart = primes[0].to_bytes_be(); + self.privatePart = key.prime; Ok(()) } @@ -447,16 +412,12 @@ impl TSS_KEY { }; // Reconstruct RSA private key from modulus + prime p - let n = BigUint::from_bytes_be(&n_bytes); - let p = BigUint::from_bytes_be(&self.privatePart); - let q = &n / &p; - let e = BigUint::from(65537u32); - - let priv_key = RsaPrivateKey::from_p_q(p, q, e) - .map_err(|e| TpmError::GenericError(format!("Failed to reconstruct RSA key: {}", e)))?; + let key = RsaKeyParts { + modulus: n_bytes, + prime: self.privatePart.clone(), + }; - let sig_bytes = priv_key.sign(Crypto::pkcs1v15_sign_scheme(hash_alg)?, digest) - .map_err(|e| TpmError::GenericError(format!("RSA signing failed: {}", e)))?; + let sig_bytes = Crypto::rsa_pkcs1v15_sign(&key, hash_alg, digest)?; Ok(TPMT_SIGNATURE { signature: Some(TPMU_SIGNATURE::rsassa(TPMS_SIGNATURE_RSASSA { @@ -466,3 +427,162 @@ impl TSS_KEY { }) } } + +#[cfg(test)] +mod tests { + use super::*; + use rand::rngs::OsRng; + use rsa::traits::PublicKeyParts; + use rsa::{Oaep, RsaPrivateKey}; + use sha1::Sha1; + use sha2::Sha256; + + /// Build a software stand-in for an endorsement key, along with its public area. + fn endorsement_key(name_alg: TPM_ALG_ID) -> Result<(RsaPrivateKey, TPMT_PUBLIC), TpmError> { + let private_key = RsaPrivateKey::new(&mut OsRng, 2048) + .map_err(|e| TpmError::GenericError(format!("RSA key generation failed: {e}")))?; + + let parameters = TPMS_RSA_PARMS::new( + &TPMT_SYM_DEF_OBJECT::new(TPM_ALG_ID::AES, 128, TPM_ALG_ID::CFB), + &Some(TPMU_ASYM_SCHEME::null(TPMS_NULL_ASYM_SCHEME::default())), + 2048, + 65537, + ); + + let public_area = TPMT_PUBLIC { + nameAlg: name_alg, + parameters: Some(TPMU_PUBLIC_PARMS::rsaDetail(parameters)), + unique: Some(TPMU_PUBLIC_ID::rsa(TPM2B_PUBLIC_KEY_RSA { + buffer: private_key.n().to_bytes_be(), + })), + ..Default::default() + }; + + Ok((private_key, public_area)) + } + + /// A Name is a two byte algorithm identifier followed by a digest. `create_activation` + /// treats it as opaque input to KDFa and the integrity HMAC, so the contents do not matter + /// as long as both sides agree on them. + fn activated_name(name_alg: TPM_ALG_ID) -> Vec { + vec![0xab; 2 + Crypto::digestSize(name_alg)] + } + + /// Play the part of `TPM2_ActivateCredential` so `create_activation` can be exercised end + /// to end without a TPM. + fn activate_credential( + endorsement_private: &RsaPrivateKey, + name_alg: TPM_ALG_ID, + activated_name: &[u8], + activation: &ActivationData, + ) -> Result, TpmError> { + let padding = match name_alg { + TPM_ALG_ID::SHA1 => Oaep::new_with_label::("IDENTITY\0"), + TPM_ALG_ID::SHA256 => Oaep::new_with_label::("IDENTITY\0"), + _ => { + return Err(TpmError::NotSupported(format!( + "Unsupported nameAlg for OAEP: {:?}", + name_alg + ))) + } + }; + + let seed = endorsement_private + .decrypt(padding, &activation.secret) + .map_err(|e| TpmError::GenericError(format!("Seed decryption failed: {e}")))?; + + // A TPM rejects a seed whose size is not the nameAlg digest size: TPM 2.0 Part 4, + // CryptSecretDecrypt, returns TPM_RC_VALUE. Modelling that check here is what makes + // this test able to catch a wrongly sized seed, because the seed itself travels inside + // the blob and would otherwise round trip at any length. + let expected_seed_size = Crypto::digestSize(name_alg); + if seed.len() != expected_seed_size { + return Err(TpmError::InvalidArraySize(format!( + "Seed is {} bytes, but {:?} requires {}", + seed.len(), + name_alg, + expected_seed_size + ))); + } + + let sym_key = Crypto::kdfa(name_alg, &seed, "STORAGE", activated_name, &[], 128)?; + let hmac_key = Crypto::kdfa( + name_alg, + &seed, + "INTEGRITY", + &[], + &[], + expected_seed_size * 8, + )?; + + let mut to_hmac = activation.credential_blob.encIdentity.clone(); + to_hmac.extend_from_slice(activated_name); + if Crypto::hmac(name_alg, &hmac_key, &to_hmac)? != activation.credential_blob.integrityHMAC + { + return Err(TpmError::GenericError( + "Integrity HMAC mismatch".to_string(), + )); + } + + let plaintext = Crypto::cfb_xcrypt( + false, + &sym_key, + &[0u8; 16], + &activation.credential_blob.encIdentity, + )?; + + let Some(size_bytes) = plaintext.get(..2) else { + return Err(TpmError::InvalidArraySize( + "Credential is missing its size prefix".to_string(), + )); + }; + let size = u16::from_be_bytes([size_bytes[0], size_bytes[1]]) as usize; + + plaintext + .get(2..2 + size) + .map(<[u8]>::to_vec) + .ok_or_else(|| { + TpmError::InvalidArraySize("Credential size overruns the blob".to_string()) + }) + } + + #[test] + fn create_activation_round_trips_through_a_software_activate() -> Result<(), TpmError> { + for name_alg in [TPM_ALG_ID::SHA1, TPM_ALG_ID::SHA256] { + let (endorsement_private, endorsement_public) = endorsement_key(name_alg)?; + let activated_name = activated_name(name_alg); + let credential = b"credential to activate".to_vec(); + + let activation = endorsement_public.create_activation(&credential, &activated_name)?; + let recovered = activate_credential( + &endorsement_private, + name_alg, + &activated_name, + &activation, + )?; + + assert_eq!(recovered, credential, "nameAlg {:?}", name_alg); + } + + Ok(()) + } + + #[test] + fn create_activation_rejects_a_non_storage_wrapping_scheme() -> Result<(), TpmError> { + let (_, mut endorsement_public) = endorsement_key(TPM_ALG_ID::SHA256)?; + + let parameters = TPMS_RSA_PARMS::new( + &TPMT_SYM_DEF_OBJECT::new(TPM_ALG_ID::AES, 256, TPM_ALG_ID::CFB), + &Some(TPMU_ASYM_SCHEME::null(TPMS_NULL_ASYM_SCHEME::default())), + 2048, + 65537, + ); + endorsement_public.parameters = Some(TPMU_PUBLIC_PARMS::rsaDetail(parameters)); + + assert!(endorsement_public + .create_activation(b"credential", &activated_name(TPM_ALG_ID::SHA256)) + .is_err()); + + Ok(()) + } +} From fc40076e9b6d5802b0055a01233f9df163c4f3ea Mon Sep 17 00:00:00 2001 From: Roee Kasher Date: Thu, 13 Aug 2026 15:57:28 +0300 Subject: [PATCH 07/13] Split the crypto layer behind a CryptoProvider (#5) * Consolidate RSA primitives into the Crypto facade tpm_type_extensions.rs reached directly for the `rsa` and `rand` crates, making it the only file bypassing `Crypto` and leaving two separate RSA-OAEP implementations in the tree. Move all of it behind `Crypto` so there is a single place where a crypto backend is selected. - Add `Crypto::rsa_oaep_encrypt`, `rsa_pkcs1v15_verify`, `rsa_generate_keypair` and `rsa_pkcs1v15_sign`, plus the `RsaKeyParts` carrier and the shared `RSA_DEFAULT_EXPONENT` constant. - Collapse the duplicate OAEP paths in `create_activation`, `encrypt` and `encrypt_session_salt` onto one implementation. Labels are now passed as bytes, which is how the TPM specification defines them. - Route `validate_signature` and `TSS_KEY::{create_key, sign}` through the facade. `tpm_type_extensions.rs` no longer imports `rsa` or `rand`. Two panics become errors on the way: `create_key` no longer indexes into an empty prime list, and `sign` no longer divides by a zero prime. Error text converges at four sites that previously had their own wording for the same failure. Behavior is otherwise unchanged. * Size the activation seed from the key's name algorithm `create_activation` generated a fixed 16 byte seed. TPM 2.0 Part 1 "Credential Protection" sizes the seed from the key's nameAlg, and Part 4 `CryptSecretDecrypt` rejects any other size with TPM_RC_VALUE, so `TPM2_ActivateCredential` could never recover a credential built this way. A SHA-256 key needs 32 bytes and a SHA-1 key 20. `tpm_samples::activate_credentials` has been tolerating the resulting mismatch with a "known create_activation issue" message. TSS.NET already gets this right in `TpmKey.CreateActivationCredentials`, which carries a comment stating the rule. TSS.CPP has the same defect in `TPMT_PUBLIC::CreateActivation` and is the likely origin of this one. Add a test that plays the part of TPM2_ActivateCredential in software: it recovers the seed, enforces the same seed size check the TPM makes, rederives both keys, verifies the integrity HMAC and decrypts the credential. Modelling the TPM's size check is what gives the test its value, because the seed travels inside the blob and would otherwise round trip at any length. * Split the crypto layer behind a CryptoProvider Move crypto.rs into a crypto/ directory module. crypto::provider defines the primitives TSS.Rust needs from a backend as a struct of function pointers; crypto::software_provider supplies one built on the RustCrypto crates. Crypto keeps the logic the TPM specification defines on top of those primitives -- digest sizes, KDFa, signature validation -- and delegates the rest. Crypto's public signatures are unchanged except get_random, which now returns Result so an RNG failure is reported rather than swallowed. Tpm2::roll_nonces becomes fallible as a consequence. The provider is still selected internally by a temporary Crypto::provider(). Callers will pass one explicitly in a later change. * Make the software crypto backend optional Put the RustCrypto-backed provider behind a software-crypto feature, on by default, and mark the eight crates it needs optional. Building with --no-default-features drops them entirely, so a host that would rather not link a second implementation of primitives its operating system already provides can supply its own provider instead. With no backend compiled in, Crypto routes to a provider whose every primitive reports NotSupported. The tests that verify against the rsa crate are gated on the feature; the remaining 12 still run. Every sample opens an HMAC session and so derives a session key on the host, so tpm_samples now requires the feature rather than building into a binary that cannot work. * Thread the crypto provider through every call path The provider added in the previous commit was not reachable: every public Crypto operation went through a private selector that always picked either the software backend or an unimplemented one. Building without the software-crypto feature therefore produced a library where all crypto-dependent operations failed at runtime. Take the provider explicitly on each Crypto primitive and on the library call paths that use them, and drop the hidden selector along with the unimplemented placeholder provider. The generated command methods dispatch through `&mut self` and have no parameter to carry a provider, so Tpm2 holds one. Tpm2::new now takes it, Tpm2::with_software_crypto supplies the built-in backend, and Tpm2::crypto exposes it so callers computing a policy digest or a key name alongside a live TPM agree on one backend. Split create_tpm into create_tpm_with_crypto, which keeps the platform selection logic, and a feature-gated create_tpm on top of it, so a build without the software backend keeps that logic instead of reimplementing it. Breaking: PolicyAssertion::update_policy_digest, the TPMT_PUBLIC and TSS_KEY helpers, Tpm2::new and all Crypto primitives take a provider; create_tpm and create_tpm_with_device now require the software-crypto feature. --- TSS.Rust/Cargo.toml | 37 +- TSS.Rust/examples/tpm_samples.rs | 72 ++-- TSS.Rust/src/auth_session.rs | 26 +- TSS.Rust/src/crypto.rs | 500 ----------------------- TSS.Rust/src/crypto/mod.rs | 343 ++++++++++++++++ TSS.Rust/src/crypto/provider.rs | 156 +++++++ TSS.Rust/src/crypto/software_provider.rs | 296 ++++++++++++++ TSS.Rust/src/policy.rs | 185 ++++++--- TSS.Rust/src/tpm2_impl.rs | 84 +++- TSS.Rust/src/tpm_type_extensions.rs | 74 +++- 10 files changed, 1134 insertions(+), 639 deletions(-) delete mode 100644 TSS.Rust/src/crypto.rs create mode 100644 TSS.Rust/src/crypto/mod.rs create mode 100644 TSS.Rust/src/crypto/provider.rs create mode 100644 TSS.Rust/src/crypto/software_provider.rs diff --git a/TSS.Rust/Cargo.toml b/TSS.Rust/Cargo.toml index fabcb17c..2755490c 100644 --- a/TSS.Rust/Cargo.toml +++ b/TSS.Rust/Cargo.toml @@ -10,20 +10,38 @@ unused-parens = "allow" [lib] crate-type = ["cdylib", "lib"] +[features] +default = ["software-crypto"] + +# Build the RustCrypto-backed CryptoProvider. Disabling this drops every pure-Rust crypto +# dependency, leaving the caller to supply a provider of their own. +software-crypto = [ + "dep:aes", + "dep:cipher", + "dep:hmac", + "dep:rand", + "dep:rsa", + "dep:sha1", + "dep:sha2", + "dep:sm3", +] + [dependencies] derivative = "2.2.0" -hmac = "0.12.1" lazy_static = "1.5.0" -rsa = { version = "0.9.8" } -sm3 = "0.4.2" windows = "0.61.1" -sha1 = { version = "0.10.6", features = ["oid"] } -sha2 = { version = "0.10.8", features = ["oid"] } -rand = "0.8" -aes = "0.8" -cipher = { version = "0.4", features = ["block-padding"] } zeroize = "1.8" +# Used only by the software-crypto provider. +aes = { version = "0.8", optional = true } +cipher = { version = "0.4", features = ["block-padding"], optional = true } +hmac = { version = "0.12.1", optional = true } +rand = { version = "0.8", optional = true } +rsa = { version = "0.9.8", optional = true } +sha1 = { version = "0.10.6", features = ["oid"], optional = true } +sha2 = { version = "0.10.8", features = ["oid"], optional = true } +sm3 = { version = "0.4.2", optional = true } + [target.'cfg(windows)'.dependencies] windows = { version = "0.61.1", features = ["Win32_Foundation", "Win32_Security", "Win32_System_TpmBaseServices", "Win32_Networking", "Win32_Networking_WinSock"] } @@ -33,3 +51,6 @@ libc = "0.2" [[example]] name = "tpm_samples" path = "examples/tpm_samples.rs" +# Every sample opens an HMAC session, which derives its session key on the host, so the samples +# cannot run without a crypto backend compiled in. +required-features = ["software-crypto"] diff --git a/TSS.Rust/examples/tpm_samples.rs b/TSS.Rust/examples/tpm_samples.rs index c30e6e74..7def48dc 100644 --- a/TSS.Rust/examples/tpm_samples.rs +++ b/TSS.Rust/examples/tpm_samples.rs @@ -30,7 +30,7 @@ use std::io::{self, Write}; use tss_rust::{ auth_session::Session, - crypto::Crypto, + crypto::{software_provider::SOFTWARE_PROVIDER, Crypto}, device::{TpmDevice, TpmTbsDevice}, error::TpmError, policy::{self, PolicyTree, PolicyCommandCode, PolicyLocality, PolicyOr, PolicyPassword}, tpm2_impl::*, tpm_structure::{TpmEnum}, tpm_types::* @@ -297,7 +297,7 @@ fn attestation(tpm: &mut Tpm2) -> Result<(), TpmError> { let pub_key = tpm.ReadPublic(&sig_key)?; - if (pub_key.outPublic.validate_certify(&pub_key.outPublic, &key_nonce, &key_quote)?) { + if (pub_key.outPublic.validate_certify(&SOFTWARE_PROVIDER, &pub_key.outPublic, &key_nonce, &key_quote)?) { println!("Key certification signature verification SUCCESSFUL! "); } else { println!("Key certification signature verification FAILED! "); @@ -325,11 +325,11 @@ fn activate_credentials(tpm: &mut Tpm2) -> Result<(), TpmError> { tpm.FlushContext(&srk)?; // Make a secret using the TSS.Rust RNG - let secret = Crypto::get_random(20); + let secret = Crypto::get_random(&SOFTWARE_PROVIDER, 20)?; let name_of_key_to_activate = key_to_activate.get_name()?; // Use TSS.Rust to get an activation blob - let cred = ek_pub.create_activation(&secret, &name_of_key_to_activate)?; + let cred = ek_pub.create_activation(&SOFTWARE_PROVIDER, &secret, &name_of_key_to_activate)?; let recovered_secret = tpm.ActivateCredential(&key_to_activate, &ek_handle, &cred.credential_blob, &cred.secret)?; @@ -482,7 +482,7 @@ fn pcr_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { println!("PCR 16 after event: {:?}", pcr_vals2.pcrValues); // Extend with a hash value - let extend_hash = TPMT_HA::new(TPM_ALG_ID::SHA256, &Crypto::hash(TPM_ALG_ID::SHA256, &[6, 7, 8])?); + let extend_hash = TPMT_HA::new(TPM_ALG_ID::SHA256, &Crypto::hash(&SOFTWARE_PROVIDER, TPM_ALG_ID::SHA256, &[6, 7, 8])?); tpm.PCR_Extend(&pcr_handle, &vec![extend_hash])?; println!("Extended hash into PCR 16"); @@ -531,7 +531,7 @@ fn primary_keys_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { println!("Created signing primary key with handle: {:?}", new_primary.handle); // Sign some data - let data_to_sign = Crypto::hash(TPM_ALG_ID::SHA256, b"Data to sign".as_ref())?; + let data_to_sign = Crypto::hash(&SOFTWARE_PROVIDER, TPM_ALG_ID::SHA256, b"Data to sign".as_ref())?; let signature = tpm.Sign( &new_primary.handle, &data_to_sign, @@ -588,7 +588,7 @@ fn child_keys_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { println!("Created child signing key: {:?}", sign_key); // Sign some data - let data_to_sign = Crypto::hash(TPM_ALG_ID::SHA1, b"Test data for signing".as_ref())?; + let data_to_sign = Crypto::hash(&SOFTWARE_PROVIDER, TPM_ALG_ID::SHA1, b"Test data for signing".as_ref())?; let signature = tpm.Sign( &sign_key, &data_to_sign, @@ -944,7 +944,7 @@ fn auth_sessions_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { println!("Loaded child key with HMAC session: {:?}", loaded_key); // Sign data with the loaded key using the session - let data_to_sign = Crypto::hash(TPM_ALG_ID::SHA1, b"Auth session test data".as_ref())?; + let data_to_sign = Crypto::hash(&SOFTWARE_PROVIDER, TPM_ALG_ID::SHA1, b"Auth session test data".as_ref())?; let sig = tpm.with_session(sess.clone()).Sign( &loaded_key, &data_to_sign, &TPMU_SIG_SCHEME::create(TPM_ALG_ID::NULL)?, @@ -1114,7 +1114,7 @@ fn unseal_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { for v in &pcr_vals.pcrValues { pcr_digest_data.extend_from_slice(&v.buffer); } - let pcr_digest = Crypto::hash(bank, &pcr_digest_data)?; + let pcr_digest = Crypto::hash(&SOFTWARE_PROVIDER, bank, &pcr_digest_data)?; tpm.PolicyPCR(&session_handle(&trial), &pcr_digest, &pcr_selection)?; tpm.PolicyPassword(&session_handle(&trial))?; @@ -1209,7 +1209,7 @@ fn policy_or_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { for v in &pcr_vals.pcrValues { pcr_digest_data.extend_from_slice(&v.buffer); } - let pcr_digest = Crypto::hash(bank, &pcr_digest_data)?; + let pcr_digest = Crypto::hash(&SOFTWARE_PROVIDER, bank, &pcr_digest_data)?; // Branch 1: PolicyPCR (current PCR value) let trial1 = tpm.start_auth_session(TPM_SE::TRIAL, TPM_ALG_ID::SHA256)?; @@ -1294,7 +1294,7 @@ fn policy_with_passwords_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { tpm.FlushContext(&session_handle(&trial))?; println!("PolicyPassword digest: {:?}", policy_digest); - let use_auth = Crypto::hash(TPM_ALG_ID::SHA256, b"password".as_ref())?; + let use_auth = Crypto::hash(&SOFTWARE_PROVIDER, TPM_ALG_ID::SHA256, b"password".as_ref())?; let mut hmac_handle = make_hmac_primary_with_policy(tpm, &policy_digest, &use_auth, TPM_ALG_ID::SHA256)?; hmac_handle.set_auth(&use_auth); @@ -1328,7 +1328,7 @@ fn policy_with_passwords_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { tpm.FlushContext(&session_handle(&trial2))?; println!("PolicyAuthValue digest: {:?}", policy_digest2); - let use_auth2 = Crypto::hash(TPM_ALG_ID::SHA256, b"password2".as_ref())?; + let use_auth2 = Crypto::hash(&SOFTWARE_PROVIDER, TPM_ALG_ID::SHA256, b"password2".as_ref())?; let mut hmac_handle2 = make_hmac_primary_with_policy(tpm, &policy_digest2, &use_auth2, TPM_ALG_ID::SHA256)?; hmac_handle2.set_auth(&use_auth2); @@ -1410,7 +1410,7 @@ fn import_duplicate_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { // Load the imported key and sign with it let imported_key = tpm.Load(&primary, &imported, &new_key.outPublic)?; - let data_to_sign = Crypto::hash(TPM_ALG_ID::SHA256, b"test import".as_ref())?; + let data_to_sign = Crypto::hash(&SOFTWARE_PROVIDER, TPM_ALG_ID::SHA256, b"test import".as_ref())?; let sig = tpm.Sign(&imported_key, &data_to_sign, &TPMU_SIG_SCHEME::create(TPM_ALG_ID::NULL)?, &TPMT_TK_HASHCHECK::default())?; @@ -1645,7 +1645,7 @@ fn software_keys_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { println!("Created duplicatable signing key in TPM"); // Sign with the TPM key - let to_sign = Crypto::hash(TPM_ALG_ID::SHA256, b"hello from software key".as_ref())?; + let to_sign = Crypto::hash(&SOFTWARE_PROVIDER, TPM_ALG_ID::SHA256, b"hello from software key".as_ref())?; let tpm_sig = tpm.Sign(&tpm_key, &to_sign, &TPMU_SIG_SCHEME::create(TPM_ALG_ID::NULL)?, &TPMT_TK_HASHCHECK::default())?; @@ -1707,7 +1707,7 @@ fn policy_pcr_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { for v in &pcr_vals.pcrValues { pcr_digest_data.extend_from_slice(&v.buffer); } - let pcr_digest = Crypto::hash(bank, &pcr_digest_data)?; + let pcr_digest = Crypto::hash(&SOFTWARE_PROVIDER, bank, &pcr_digest_data)?; // Compute policy digest using trial session let trial = tpm.start_auth_session(TPM_SE::TRIAL, TPM_ALG_ID::SHA256)?; @@ -1757,7 +1757,7 @@ fn policy_cphash_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { // Compute trial PolicyCpHash to demonstrate how it works // cpHash = H(cc || handle_names || parameters) // We'll use a dummy hash value for the trial - let dummy_cphash = Crypto::hash(hash_alg, b"example cpHash input")?; + let dummy_cphash = Crypto::hash(&SOFTWARE_PROVIDER, hash_alg, b"example cpHash input")?; let trial = tpm.start_auth_session(TPM_SE::TRIAL, hash_alg)?; tpm.PolicyCpHash(&session_handle(&trial), &dummy_cphash)?; @@ -1793,7 +1793,7 @@ fn policy_name_hash_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { // Compute nameHash for the OWNER handle let owner_name = TPM_HANDLE::new(TPM_RH::OWNER.get_value()).get_name()?; - let name_hash = Crypto::hash(hash_alg, &owner_name)?; + let name_hash = Crypto::hash(&SOFTWARE_PROVIDER, hash_alg, &owner_name)?; println!("nameHash(OWNER): {:?}", &name_hash[..8]); // Build policy digest using trial session @@ -2156,7 +2156,7 @@ fn policy_signed_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { }, ..Default::default() }; - sw_key.create_key()?; + sw_key.create_key(&SOFTWARE_PROVIDER)?; println!("Created software RSA-2048 signing key"); // Load the public part into the TPM (OWNER hierarchy for valid tickets) @@ -2173,8 +2173,8 @@ fn policy_signed_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { let trial = tpm.start_auth_session(TPM_SE::TRIAL, hash_alg)?; let policy_ref: Vec = vec![]; - let dummy_hash = Crypto::hash(hash_alg, &[])?; - let dummy_sig = sw_key.sign(&dummy_hash, hash_alg)?; + let dummy_hash = Crypto::hash(&SOFTWARE_PROVIDER, hash_alg, &[])?; + let dummy_sig = sw_key.sign(&SOFTWARE_PROVIDER, &dummy_hash, hash_alg)?; tpm.PolicySigned( &auth_key_handle, &session_handle(&trial), @@ -2197,10 +2197,10 @@ fn policy_signed_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { to_hash.extend_from_slice(&nonce_tpm); to_hash.extend_from_slice(&0i32.to_be_bytes()); // expiration = 0 // cpHashA is empty, policyRef is empty - let a_hash = Crypto::hash(hash_alg, &to_hash)?; + let a_hash = Crypto::hash(&SOFTWARE_PROVIDER, hash_alg, &to_hash)?; // Step 4: Sign the aHash with our SW key - let signature = sw_key.sign(&a_hash, hash_alg)?; + let signature = sw_key.sign(&SOFTWARE_PROVIDER, &a_hash, hash_alg)?; println!("Signed aHash ({} bytes) with SW key", a_hash.len()); // Step 5: Execute PolicySigned with the real signature @@ -2265,7 +2265,7 @@ fn policy_authorize_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { }, ..Default::default() }; - sw_key.create_key()?; + sw_key.create_key(&SOFTWARE_PROVIDER)?; println!("Created authorizing SW key"); // Load the public part into the TPM (OWNER hierarchy for valid tickets) @@ -2276,7 +2276,7 @@ fn policy_authorize_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { )?; // Get the authorizing key name - let key_name = sw_key.publicPart.get_name()?; + let key_name = sw_key.publicPart.get_name(&SOFTWARE_PROVIDER)?; // Step 1: Get the pre-policy digest we want to authorize (PolicyLocality(LOC_ONE)) let trial_pre = tpm.start_auth_session(TPM_SE::TRIAL, hash_alg)?; @@ -2291,9 +2291,9 @@ fn policy_authorize_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { let mut a_hash_data = Vec::new(); a_hash_data.extend_from_slice(&pre_digest); a_hash_data.extend_from_slice(&policy_ref); - let a_hash = Crypto::hash(hash_alg, &a_hash_data)?; + let a_hash = Crypto::hash(&SOFTWARE_PROVIDER, hash_alg, &a_hash_data)?; - let signature = sw_key.sign(&a_hash, hash_alg)?; + let signature = sw_key.sign(&SOFTWARE_PROVIDER, &a_hash, hash_alg)?; println!("Signed approvedPolicy with authorizing key"); // Step 3: Use VerifySignature to get a validation ticket @@ -2324,12 +2324,12 @@ fn policy_authorize_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { // Compute expected: PolicyUpdate for PolicyAuthorize // policyDigest_new = H(0...0 || TPM_CC_PolicyAuthorize || keyName || policyRef) - let hash_len = Crypto::hash(hash_alg, &[])?.len(); + let hash_len = Crypto::hash(&SOFTWARE_PROVIDER, hash_alg, &[])?.len(); let mut expected_data = vec![0u8; hash_len]; expected_data.extend_from_slice(&TPM_CC::PolicyAuthorize.get_value().to_be_bytes()); expected_data.extend_from_slice(&key_name); // policyRef is empty, no need to extend - let expected_digest = Crypto::hash(hash_alg, &expected_data)?; + let expected_digest = Crypto::hash(&SOFTWARE_PROVIDER, hash_alg, &expected_data)?; if actual_digest == expected_digest { println!("PolicyAuthorize digest is correct"); @@ -2358,7 +2358,7 @@ fn admin_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { // We can change the authValue for the owner hierarchy. println!(">> HierarchyChangeAuth"); - let new_owner_auth = Crypto::hash(TPM_ALG_ID::SHA1, b"passw0rd")?; + let new_owner_auth = Crypto::hash(&SOFTWARE_PROVIDER, TPM_ALG_ID::SHA1, b"passw0rd")?; println!("Setting OWNER auth to hash of 'passw0rd': {} bytes", new_owner_auth.len()); tpm.HierarchyChangeAuth( @@ -2428,7 +2428,7 @@ fn policy_tree_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { .add(PolicyCommandCode::new(TPM_CC::HMAC_Start)); // Compute digest in software (no TPM trial session needed) - let sw_digest = tree.get_policy_digest(hash_alg)?; + let sw_digest = tree.get_policy_digest(&SOFTWARE_PROVIDER, hash_alg)?; // Verify against a trial session on the TPM let trial = tpm.start_auth_session(TPM_SE::TRIAL, hash_alg)?; @@ -2446,7 +2446,7 @@ fn policy_tree_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { .add(PolicyLocality::new(TPMA_LOCALITY::LOC_ZERO)) .add(PolicyCommandCode::new(TPM_CC::Sign)); - let sw_digest2 = tree2.get_policy_digest(hash_alg)?; + let sw_digest2 = tree2.get_policy_digest(&SOFTWARE_PROVIDER, hash_alg)?; let trial2 = tpm.start_auth_session(TPM_SE::TRIAL, hash_alg)?; tpm.PolicyLocality(&session_handle(&trial2), TPMA_LOCALITY::LOC_ZERO)?; @@ -2472,7 +2472,7 @@ fn policy_tree_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { let or_tree = PolicyTree::new() .add(PolicyOr::new(vec![branch1, branch2])); - let sw_or_digest = or_tree.get_policy_digest(hash_alg)?; + let sw_or_digest = or_tree.get_policy_digest(&SOFTWARE_PROVIDER, hash_alg)?; // Verify OR digest with TPM trial session let trial_b1 = tpm.start_auth_session(TPM_SE::TRIAL, hash_alg)?; @@ -2520,7 +2520,7 @@ fn policy_tree_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { let pw_tree = PolicyTree::new() .add(PolicyPassword::new()); - let pw_digest = pw_tree.get_policy_digest(hash_alg)?; + let pw_digest = pw_tree.get_policy_digest(&SOFTWARE_PROVIDER, hash_alg)?; let trial_pw = tpm.start_auth_session(TPM_SE::TRIAL, hash_alg)?; tpm.PolicyPassword(&session_handle(&trial_pw))?; @@ -2544,7 +2544,7 @@ fn seeded_session_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { let salt_key = make_storage_primary(tpm)?; // Generate a random salt - let salt = Crypto::get_random(20); + let salt = Crypto::get_random(&SOFTWARE_PROVIDER, 20)?; println!("Salt ({} bytes): {:?}", salt.len(), &salt[..8]); // Start a salted HMAC session. @@ -2739,7 +2739,7 @@ fn reset_da_lockout(tpm: &mut Tpm2) { fn recover_endorsement_hierarchy(tpm: &mut Tpm2) { let hash_alg = TPM_ALG_ID::SHA256; let endorsement_name = TPM_HANDLE::new(TPM_RH::ENDORSEMENT.get_value()).get_name().unwrap_or_default(); - let name_hash = Crypto::hash(hash_alg, &endorsement_name).unwrap_or_default(); + let name_hash = Crypto::hash(&SOFTWARE_PROVIDER, hash_alg, &endorsement_name).unwrap_or_default(); tpm.allow_errors(); if let Ok(sess) = tpm.start_auth_session(TPM_SE::POLICY, hash_alg) { @@ -2766,7 +2766,7 @@ fn recover_endorsement_hierarchy(tpm: &mut Tpm2) { /// [`RECOVER_HIERARCHIES_FLAG`]. fn recover_owner_hierarchy(tpm: &mut Tpm2) { let known_auths: Vec> = vec![ - Crypto::hash(TPM_ALG_ID::SHA1, b"passw0rd").unwrap_or_default(), + Crypto::hash(&SOFTWARE_PROVIDER, TPM_ALG_ID::SHA1, b"passw0rd").unwrap_or_default(), vec![0, 2, 1, 3, 5, 6], // bound_session_sample ]; for known_auth in &known_auths { diff --git a/TSS.Rust/src/auth_session.rs b/TSS.Rust/src/auth_session.rs index 69198a15..cfae20aa 100644 --- a/TSS.Rust/src/auth_session.rs +++ b/TSS.Rust/src/auth_session.rs @@ -1,4 +1,4 @@ -use crate::crypto::Crypto; +use crate::crypto::{provider::CryptoProvider, Crypto}; use crate::error::TpmError; use crate::{tpm_structure::TpmEnum, tpm_types::*}; @@ -75,6 +75,7 @@ impl Session { // struct would just move the same values behind another type. #[allow(clippy::too_many_arguments)] pub fn from_tpm_response( + crypto: &CryptoProvider, session_handle: TPM_HANDLE, session_type: TPM_SE, hash_alg: TPM_ALG_ID, @@ -106,13 +107,18 @@ impl Session { bind_handle: bind_object.handle, }; - sess.calc_session_key(salt, bind_object)?; + sess.calc_session_key(crypto, salt, bind_object)?; Ok(sess) } /// Derive the session key using KDFa with label "ATH". /// SessionKey = KDFa(hashAlg, bindAuth || salt, "ATH", nonceTPM, nonceCaller, hashBits) - fn calc_session_key(&mut self, salt: &[u8], bind_object: &TPM_HANDLE) -> Result<(), TpmError> { + fn calc_session_key( + &mut self, + crypto: &CryptoProvider, + salt: &[u8], + bind_object: &TPM_HANDLE, + ) -> Result<(), TpmError> { let null_handle = TPM_HANDLE::new(TPM_RH::NULL.get_value()); let has_salt = !salt.is_empty(); let is_bound = bind_object.handle != null_handle.handle; @@ -132,6 +138,7 @@ impl Session { let hash_bits = Crypto::digestSize(self.hash_alg) * 8; self.session_key = Crypto::kdfa( + crypto, self.hash_alg, &hmac_key, "ATH", @@ -165,6 +172,7 @@ impl Session { /// hmac = HMAC(hashAlg, hmacKey, parmHash || nonceNewer || nonceOlder || nonceDec || nonceEnc || sessionAttrs) pub fn get_auth_hmac( &self, + crypto: &CryptoProvider, cp_hash: Vec, is_command: bool, nonce_tpm_dec: &[u8], @@ -225,13 +233,18 @@ impl Session { buf_to_hmac.extend_from_slice(nonce_tpm_enc); buf_to_hmac.extend_from_slice(&session_attrs); - Crypto::hmac(self.hash_alg, &hmac_key, &buf_to_hmac) + Crypto::hmac(crypto, self.hash_alg, &hmac_key, &buf_to_hmac) } /// Process parameter encryption/decryption using AES-CFB. /// Key derivation: KDFa(hashAlg, sessionKey, "CFB", nonceNewer, nonceOlder, 256) /// First keyBits/8 bytes = AES key, next 16 bytes = IV - pub fn param_xcrypt(&self, data: &[u8], is_command: bool) -> Result, TpmError> { + pub fn param_xcrypt( + &self, + crypto: &CryptoProvider, + data: &[u8], + is_command: bool, + ) -> Result, TpmError> { if data.is_empty() { return Ok(Vec::new()); } @@ -264,6 +277,7 @@ impl Session { // Produces key_size + 16 bytes (key + IV) let num_bits = (key_size + 16) * 8; let key_info = Crypto::kdfa( + crypto, self.hash_alg, &self.session_key, "CFB", @@ -277,7 +291,7 @@ impl Session { // For requests: encrypt (TPM will decrypt) // For responses: decrypt (TPM encrypted it) - Crypto::cfb_xcrypt(is_command, aes_key, iv, data) + Crypto::cfb_xcrypt(crypto, is_command, aes_key, iv, data) } } diff --git a/TSS.Rust/src/crypto.rs b/TSS.Rust/src/crypto.rs deleted file mode 100644 index 2d209ee2..00000000 --- a/TSS.Rust/src/crypto.rs +++ /dev/null @@ -1,500 +0,0 @@ -use crate::{error::TpmError, tpm_types::*}; -use hmac::{Hmac, Mac}; -use rsa::traits::{PrivateKeyParts, PublicKeyParts}; -use rsa::{BigUint, Oaep, Pkcs1v15Sign, RsaPrivateKey, RsaPublicKey}; -use sha1::Sha1; -use sha2::{Digest as Sha2Digest, Sha256, Sha384, Sha512}; -use sm3::Sm3; -use rand::{rngs::OsRng, RngCore}; -use aes::Aes128; -use cipher::{BlockEncrypt, KeyInit}; -use cipher::generic_array::GenericArray; - -/// The RSA public exponent used by every key this library creates or consumes (65537, "F4"). -/// -/// A TPM encodes this value as zero in `TPMS_RSA_PARMS::exponent`, so it never travels on the -/// wire and has to be supplied by the caller. -pub const RSA_DEFAULT_EXPONENT: [u8; 3] = [0x01, 0x00, 0x01]; - -/// RSA private key material in the form `TSS_KEY` persists it: the modulus and the first prime. -/// -/// The second prime is recovered by dividing the modulus by the first, so it is not stored. -#[derive(Clone, Debug)] -pub struct RsaKeyParts { - pub modulus: Vec, - pub prime: Vec, -} - -pub struct Crypto; - -impl Crypto { - // The function is called from an auto-generated file that expects this specific (non snake_cased) name - #[allow(non_snake_case)] - pub fn digestSize(alg: TPM_ALG_ID) -> usize { - match alg { - TPM_ALG_ID::SHA1 => 20, - TPM_ALG_ID::SHA256 => 32, - TPM_ALG_ID::SHA384 => 48, - TPM_ALG_ID::SHA512 => 64, - TPM_ALG_ID::SM3_256 => 32, - _ => 0, - } - } - - // Hash a byte buffer using the specified algorithm - pub fn hash(alg: TPM_ALG_ID, data: &[u8]) -> Result, TpmError> { - // If the data is empty, return an empty digest of correct size - if data.is_empty() { - return Ok(vec![0; Self::digestSize(alg)]); - } - - let digest = match alg { - TPM_ALG_ID::SHA1 => { - let mut hasher = Sha1::new(); - hasher.update(data); - hasher.finalize().to_vec() - } - TPM_ALG_ID::SHA256 => { - let mut hasher = Sha256::new(); - hasher.update(data); - hasher.finalize().to_vec() - } - TPM_ALG_ID::SHA384 => { - let mut hasher = Sha384::new(); - hasher.update(data); - hasher.finalize().to_vec() - } - TPM_ALG_ID::SHA512 => { - let mut hasher = Sha512::new(); - hasher.update(data); - hasher.finalize().to_vec() - } - TPM_ALG_ID::SM3_256 => { - let mut hasher = Sm3::new(); - hasher.update(data); - hasher.finalize().to_vec() - } - _ => { - return Err(TpmError::NotSupported(format!( - "Unsupported hash algorithm: {:?}", - alg - ))) - } - }; - - let expected_size = Self::digestSize(alg); - if (digest.len() != expected_size) { - return Err(TpmError::InvalidArraySize(format!( - "Hash output length mismatch: expected {}, got {}", - expected_size, - digest.len() - ))); - } - - Ok(digest) - } - - pub fn hmac(hash_alg: TPM_ALG_ID, key: &[u8], to_hash: &[u8]) -> Result, TpmError> { - // Choose the appropriate HMAC algorithm based on the hash algorithm - match hash_alg { - TPM_ALG_ID::SHA1 => { - let mut mac = as Mac>::new_from_slice(key).map_err(|_| { - TpmError::InvalidArraySize("HMAC can take key of any size".to_string()) - })?; - mac.update(to_hash); - Ok(mac.finalize().into_bytes().to_vec()) - } - TPM_ALG_ID::SHA256 => { - let mut mac = as Mac>::new_from_slice(key).map_err(|_| { - TpmError::InvalidArraySize("HMAC can take key of any size".to_string()) - })?; - mac.update(to_hash); - Ok(mac.finalize().into_bytes().to_vec()) - } - TPM_ALG_ID::SHA384 => { - let mut mac = as Mac>::new_from_slice(key).map_err(|_| { - TpmError::InvalidArraySize("HMAC can take key of any size".to_string()) - })?; - mac.update(to_hash); - Ok(mac.finalize().into_bytes().to_vec()) - } - TPM_ALG_ID::SHA512 => { - let mut mac = as Mac>::new_from_slice(key).map_err(|_| { - TpmError::InvalidArraySize("HMAC can take key of any size".to_string()) - })?; - mac.update(to_hash); - Ok(mac.finalize().into_bytes().to_vec()) - } - TPM_ALG_ID::SM3_256 => { - let mut mac = - as Mac>::new_from_slice(key).expect("HMAC can take key of any size"); - mac.update(to_hash); - Ok(mac.finalize().into_bytes().to_vec()) - } - _ => Err(TpmError::NotSupported(format!( - "Unsupported hash algorithm: {:?}", - hash_alg - ))), - } - } - - fn pkcs1v15_sign_scheme(hash_alg: TPM_ALG_ID) -> Result { - match hash_alg { - TPM_ALG_ID::SHA1 => Ok(Pkcs1v15Sign::new::()), - TPM_ALG_ID::SHA256 => Ok(Pkcs1v15Sign::new::()), - TPM_ALG_ID::SHA384 => Ok(Pkcs1v15Sign::new::()), - TPM_ALG_ID::SHA512 => Ok(Pkcs1v15Sign::new::()), - _ => Err(TpmError::NotSupported(format!( - "Unsupported RSASSA hash algorithm: {:?}", - hash_alg - ))), - } - } - - /// Build an RSA public key from its big-endian components. - fn rsa_public_key(modulus: &[u8], exponent: &[u8]) -> Result { - RsaPublicKey::new( - BigUint::from_bytes_be(modulus), - BigUint::from_bytes_be(exponent), - ) - .map_err(|_| TpmError::InvalidArraySize("Invalid RSA public key".to_string())) - } - - /// RSA-OAEP encrypt `data` under the public key given by its big-endian components. - /// - /// `label` is used verbatim, so callers must include the trailing NUL that the TPM - /// specification puts in labels such as `b"IDENTITY\0"`. - pub fn rsa_oaep_encrypt( - modulus: &[u8], - exponent: &[u8], - hash_alg: TPM_ALG_ID, - label: &[u8], - data: &[u8], - ) -> Result, TpmError> { - let rsa_key = Self::rsa_public_key(modulus, exponent)?; - - // The `rsa` crate models an OAEP label as a string rather than as bytes, so the label - // has to be converted here. Callers work in bytes because that is what the TPM - // specification and other crypto backends use. - let label = std::str::from_utf8(label) - .map_err(|_| TpmError::NotSupported("OAEP label must be valid UTF-8".to_string()))?; - - let padding = match hash_alg { - TPM_ALG_ID::SHA1 => Oaep::new_with_label::(label), - TPM_ALG_ID::SHA256 => Oaep::new_with_label::(label), - _ => { - return Err(TpmError::NotSupported(format!( - "Unsupported nameAlg for OAEP: {:?}", - hash_alg - ))) - } - }; - - rsa_key - .encrypt(&mut OsRng, padding, data) - .map_err(|e| TpmError::GenericError(format!("RSA-OAEP encryption failed: {e}"))) - } - - /// Verify an RSASSA-PKCS1-v1_5 signature over an already computed digest. - pub fn rsa_pkcs1v15_verify( - modulus: &[u8], - exponent: &[u8], - hash_alg: TPM_ALG_ID, - digest: &[u8], - signature: &[u8], - ) -> Result { - let rsa_key = Self::rsa_public_key(modulus, exponent)?; - let scheme = Self::pkcs1v15_sign_scheme(hash_alg)?; - Ok(rsa_key.verify(scheme, digest, signature).is_ok()) - } - - /// Generate an RSA key pair in software, returning the modulus and the first prime. - pub fn rsa_generate_keypair(key_bits: usize) -> Result { - let priv_key = RsaPrivateKey::new(&mut OsRng, key_bits) - .map_err(|e| TpmError::GenericError(format!("RSA key generation failed: {}", e)))?; - - let prime = priv_key.primes().first().ok_or_else(|| { - TpmError::GenericError("Generated RSA key exposes no primes".to_string()) - })?; - - Ok(RsaKeyParts { - modulus: priv_key.n().to_bytes_be(), - prime: prime.to_bytes_be(), - }) - } - - /// Sign an already computed digest with RSASSA-PKCS1-v1_5. - /// - /// The second prime is recovered as `modulus / prime`. - pub fn rsa_pkcs1v15_sign( - key: &RsaKeyParts, - hash_alg: TPM_ALG_ID, - digest: &[u8], - ) -> Result, TpmError> { - // Recovering the second prime divides by the first, so reject a zero prime up front - // instead of letting the big-integer division panic. - if key.prime.iter().all(|&byte| byte == 0) { - return Err(TpmError::InvalidArraySize( - "RSA private key prime is zero".to_string(), - )); - } - - let modulus = BigUint::from_bytes_be(&key.modulus); - let first_prime = BigUint::from_bytes_be(&key.prime); - let second_prime = &modulus / &first_prime; - let exponent = BigUint::from_bytes_be(&RSA_DEFAULT_EXPONENT); - - let priv_key = RsaPrivateKey::from_p_q(first_prime, second_prime, exponent) - .map_err(|e| TpmError::GenericError(format!("Failed to reconstruct RSA key: {}", e)))?; - - priv_key - .sign(Self::pkcs1v15_sign_scheme(hash_alg)?, digest) - .map_err(|e| TpmError::GenericError(format!("RSA signing failed: {}", e))) - } - - pub fn validate_signature( - public_key: &TPMT_PUBLIC, - signed_blob_hash: Vec, - signature: &Option, - ) -> Result { - if !matches!(&public_key.parameters, Some(TPMU_PUBLIC_PARMS::rsaDetail(_))) { - return Err(TpmError::NotSupported( - "ValidateSignature: Only RSA is supported".to_string(), - )); - }; - - let signature = if let Some(TPMU_SIGNATURE::rsassa(signature)) = &signature { - signature - } else { - return Err(TpmError::NotSupported( - "ValidateSignature: Only RSASSA scheme is supported".to_string(), - )); - }; - - let rsa_pub_key = if let Some(TPMU_PUBLIC_ID::rsa(unique)) = &public_key.unique { - &unique.buffer - } else { - return Err(TpmError::NotSupported( - "ValidateSignature: Only RSA public key is supported".to_string(), - )); - }; - - let expected_digest_size = Self::digestSize(signature.hash); - if signed_blob_hash.len() != expected_digest_size { - return Err(TpmError::InvalidArraySize(format!( - "ValidateSignature: digest length {} does not match {:?} length {}", - signed_blob_hash.len(), - signature.hash, - expected_digest_size - ))); - } - - Self::rsa_pkcs1v15_verify( - rsa_pub_key, - &RSA_DEFAULT_EXPONENT, - signature.hash, - &signed_blob_hash, - &signature.sig, - ) - } - - // KDFa implementation as specified in TPM 2.0 Part 1 - pub fn kdfa( - hash_alg: TPM_ALG_ID, - key: &[u8], - label: &str, - context_u: &[u8], - context_v: &[u8], - bits: usize, - ) -> Result, TpmError> { - let bytes_needed = bits.div_ceil(8); - let mut result = Vec::new(); - let mut counter = 1u32; - - while result.len() < bytes_needed { - let mut to_hash = Vec::new(); - - // Counter in big-endian - to_hash.extend_from_slice(&counter.to_be_bytes()); - - // Label - to_hash.extend_from_slice(label.as_bytes()); - - // 00 byte separator - to_hash.push(0u8); - - // contextU - to_hash.extend_from_slice(context_u); - - // contextV - to_hash.extend_from_slice(context_v); - - // Number of bits in big-endian - to_hash.extend_from_slice(&(bits as u32).to_be_bytes()); - - // Perform HMAC - let hmac_result = Self::hmac(hash_alg, key, &to_hash)?; - result.extend_from_slice(&hmac_result); - - counter = counter.checked_add(1).ok_or_else(|| { - TpmError::InvalidArraySize("Counter overflow in KDFa".to_string()) - })?; - } - - // Truncate to exact size needed - result.truncate(bytes_needed); - Ok(result) - } - - // AES CFB encryption/decryption - pub fn cfb_xcrypt( - encrypt: bool, - key: &[u8], - iv: &[u8], - data: &[u8] - ) -> Result, TpmError> { - if data.is_empty() { - return Ok(Vec::new()); - } - - if key.len() != 16 && key.len() != 24 && key.len() != 32 { - return Err(TpmError::InvalidArraySize("Invalid AES key length".to_string())); - } - - if iv.len() != 16 { - return Err(TpmError::InvalidArraySize("IV must be 16 bytes".to_string())); - } - - let cipher = Aes128::new(GenericArray::from_slice(key)); - let mut result = Vec::with_capacity(data.len()); - let mut feedback = *GenericArray::from_slice(iv); - - for chunk in data.chunks(16) { - // Encrypt the feedback (IV or previous ciphertext) - let mut encrypted_feedback = feedback; - cipher.encrypt_block(&mut encrypted_feedback); - - if encrypt { - // CFB encrypt: ciphertext = plaintext XOR encrypt(feedback) - // Next feedback = ciphertext - let mut ct_block = [0u8; 16]; - for (i, &b) in chunk.iter().enumerate() { - ct_block[i] = b ^ encrypted_feedback[i]; - result.push(ct_block[i]); - } - feedback.copy_from_slice(&ct_block); - } else { - // CFB decrypt: plaintext = ciphertext XOR encrypt(feedback) - // Next feedback = ciphertext (input) - let mut ct_block = [0u8; 16]; - ct_block[..chunk.len()].copy_from_slice(chunk); - for (i, &b) in chunk.iter().enumerate() { - result.push(b ^ encrypted_feedback[i]); - } - feedback.copy_from_slice(&ct_block); - } - } - - result.truncate(data.len()); - Ok(result) - } - - // Get random bytes - pub fn get_random(num_bytes: usize) -> Vec { - let mut result = vec![0u8; num_bytes]; - OsRng.fill_bytes(&mut result); - result - } -} - -#[cfg(test)] -mod tests { - use super::*; - use rand::rngs::OsRng; - use rsa::traits::PublicKeyParts; - use rsa::RsaPrivateKey; - - #[test] - fn validate_signature_uses_signature_hash_algorithm() -> Result<(), TpmError> { - let mut rng = OsRng; - let private_key = RsaPrivateKey::new(&mut rng, 2048) - .map_err(|e| TpmError::GenericError(format!("RSA key generation failed: {e}")))?; - let public_key = TPMT_PUBLIC { - parameters: Some(TPMU_PUBLIC_PARMS::rsaDetail(TPMS_RSA_PARMS::default())), - unique: Some(TPMU_PUBLIC_ID::rsa(TPM2B_PUBLIC_KEY_RSA { - buffer: private_key.n().to_bytes_be(), - })), - ..Default::default() - }; - - let message = b"digest dispatch regression"; - let digest = Sha256::digest(message).to_vec(); - let sig = private_key - .sign(Pkcs1v15Sign::new::(), &digest) - .map_err(|e| TpmError::GenericError(format!("RSA signing failed: {e}")))?; - let signature = Some(TPMU_SIGNATURE::rsassa(TPMS_SIGNATURE_RSASSA { - hash: TPM_ALG_ID::SHA256, - sig, - })); - - assert!(Crypto::validate_signature(&public_key, digest, &signature)?); - Ok(()) - } - - #[test] - fn rsa_oaep_encrypt_round_trips_and_binds_the_label() -> Result<(), TpmError> { - let mut rng = OsRng; - let private_key = RsaPrivateKey::new(&mut rng, 2048) - .map_err(|e| TpmError::GenericError(format!("RSA key generation failed: {e}")))?; - let modulus = private_key.n().to_bytes_be(); - - let plaintext = b"seed material"; - let ciphertext = Crypto::rsa_oaep_encrypt( - &modulus, - &RSA_DEFAULT_EXPONENT, - TPM_ALG_ID::SHA256, - b"IDENTITY\0", - plaintext, - )?; - - let decrypted = private_key - .decrypt(Oaep::new_with_label::("IDENTITY\0"), &ciphertext) - .map_err(|e| TpmError::GenericError(format!("OAEP decryption failed: {e}")))?; - assert_eq!(decrypted, plaintext); - - // A different label must not recover the plaintext. This is what keeps the "IDENTITY\0" - // and "SECRET\0" call sites distinct now that they share one implementation. - assert!(private_key - .decrypt(Oaep::new_with_label::("SECRET\0"), &ciphertext) - .is_err()); - - Ok(()) - } - - #[test] - fn rsa_sign_round_trips_through_verify() -> Result<(), TpmError> { - let key = Crypto::rsa_generate_keypair(2048)?; - let digest = Sha256::digest(b"software key signing regression").to_vec(); - - let signature = Crypto::rsa_pkcs1v15_sign(&key, TPM_ALG_ID::SHA256, &digest)?; - - assert!(Crypto::rsa_pkcs1v15_verify( - &key.modulus, - &RSA_DEFAULT_EXPONENT, - TPM_ALG_ID::SHA256, - &digest, - &signature, - )?); - Ok(()) - } - - #[test] - fn rsa_sign_rejects_a_zero_prime_instead_of_dividing_by_it() { - let key = RsaKeyParts { - modulus: vec![0xff; 256], - prime: vec![0u8; 128], - }; - - assert!(Crypto::rsa_pkcs1v15_sign(&key, TPM_ALG_ID::SHA256, &[0u8; 32]).is_err()); - } -} diff --git a/TSS.Rust/src/crypto/mod.rs b/TSS.Rust/src/crypto/mod.rs new file mode 100644 index 00000000..a9ce8778 --- /dev/null +++ b/TSS.Rust/src/crypto/mod.rs @@ -0,0 +1,343 @@ +//! Cryptography used to build and check TPM structures on the host. +//! +//! This module is split into two layers. [`provider`] defines the primitives TSS.Rust needs from +//! a crypto backend, and [`software_provider`] supplies one built on the pure-Rust RustCrypto +//! crates. +//! [`Crypto`] sits on top and adds the logic that the TPM 2.0 specification defines in terms of +//! those primitives — digest sizes, KDFa, signature validation — which is the same regardless of +//! which backend is in use. +//! +//! There is no ambient default backend. Every operation that needs one takes a +//! [`CryptoProvider`](provider::CryptoProvider) from its caller, so which backend runs is always +//! visible at the call site. [`Tpm2`](crate::tpm2_impl::Tpm2) holds the provider it was built with +//! and supplies it to the command dispatch path on the caller's behalf. + +pub mod provider; +#[cfg(feature = "software-crypto")] +pub mod software_provider; + +use crate::{error::TpmError, tpm_types::*}; +use provider::CryptoProvider; + +/// The RSA public exponent used by every key this library creates or consumes (65537, "F4"). +/// +/// A TPM encodes this value as zero in `TPMS_RSA_PARMS::exponent`, so it never travels on the +/// wire and has to be supplied by the caller. +pub const RSA_DEFAULT_EXPONENT: [u8; 3] = [0x01, 0x00, 0x01]; + +/// RSA private key material in the form `TSS_KEY` persists it: the modulus and the first prime. +/// +/// The second prime is recovered by dividing the modulus by the first, so it is not stored. +#[derive(Clone, Debug)] +pub struct RsaKeyParts { + pub modulus: Vec, + pub prime: Vec, +} + +pub struct Crypto; + +impl Crypto { + /// The length in bytes of a digest produced by `alg`, or zero if `alg` is not a hash. + /// + /// This is fixed by the TPM 2.0 specification, so it does not depend on the backend. + // The function is called from an auto-generated file that expects this specific (non snake_cased) name + #[allow(non_snake_case)] + pub fn digestSize(alg: TPM_ALG_ID) -> usize { + match alg { + TPM_ALG_ID::SHA1 => 20, + TPM_ALG_ID::SHA256 => 32, + TPM_ALG_ID::SHA384 => 48, + TPM_ALG_ID::SHA512 => 64, + TPM_ALG_ID::SM3_256 => 32, + _ => 0, + } + } + + // Hash a byte buffer using the specified algorithm + pub fn hash( + provider: &CryptoProvider, + alg: TPM_ALG_ID, + data: &[u8], + ) -> Result, TpmError> { + (provider.hash)(alg, data) + } + + pub fn hmac( + provider: &CryptoProvider, + hash_alg: TPM_ALG_ID, + key: &[u8], + to_hash: &[u8], + ) -> Result, TpmError> { + (provider.hmac)(hash_alg, key, to_hash) + } + + /// RSA-OAEP encrypt `data` under the public key given by its big-endian components. + /// + /// `label` is used verbatim, so callers must include the trailing NUL that the TPM + /// specification puts in labels such as `b"IDENTITY\0"`. + pub fn rsa_oaep_encrypt( + provider: &CryptoProvider, + modulus: &[u8], + exponent: &[u8], + hash_alg: TPM_ALG_ID, + label: &[u8], + data: &[u8], + ) -> Result, TpmError> { + (provider.rsa.oaep_encrypt)(modulus, exponent, hash_alg, label, data) + } + + /// Verify an RSASSA-PKCS1-v1_5 signature over an already computed digest. + pub fn rsa_pkcs1v15_verify( + provider: &CryptoProvider, + modulus: &[u8], + exponent: &[u8], + hash_alg: TPM_ALG_ID, + digest: &[u8], + signature: &[u8], + ) -> Result { + (provider.rsa.pkcs1v15_verify)(modulus, exponent, hash_alg, digest, signature) + } + + /// Generate an RSA key pair, returning the modulus and the first prime. + pub fn rsa_generate_keypair( + provider: &CryptoProvider, + key_bits: usize, + ) -> Result { + (provider.rsa.generate_keypair)(key_bits) + } + + /// Sign an already computed digest with RSASSA-PKCS1-v1_5. + pub fn rsa_pkcs1v15_sign( + provider: &CryptoProvider, + key: &RsaKeyParts, + hash_alg: TPM_ALG_ID, + digest: &[u8], + ) -> Result, TpmError> { + (provider.rsa.pkcs1v15_sign)(key, hash_alg, digest) + } + + pub fn validate_signature( + provider: &CryptoProvider, + public_key: &TPMT_PUBLIC, + signed_blob_hash: Vec, + signature: &Option, + ) -> Result { + if !matches!(&public_key.parameters, Some(TPMU_PUBLIC_PARMS::rsaDetail(_))) { + return Err(TpmError::NotSupported( + "ValidateSignature: Only RSA is supported".to_string(), + )); + }; + + let signature = if let Some(TPMU_SIGNATURE::rsassa(signature)) = &signature { + signature + } else { + return Err(TpmError::NotSupported( + "ValidateSignature: Only RSASSA scheme is supported".to_string(), + )); + }; + + let rsa_pub_key = if let Some(TPMU_PUBLIC_ID::rsa(unique)) = &public_key.unique { + &unique.buffer + } else { + return Err(TpmError::NotSupported( + "ValidateSignature: Only RSA public key is supported".to_string(), + )); + }; + + let expected_digest_size = Self::digestSize(signature.hash); + if signed_blob_hash.len() != expected_digest_size { + return Err(TpmError::InvalidArraySize(format!( + "ValidateSignature: digest length {} does not match {:?} length {}", + signed_blob_hash.len(), + signature.hash, + expected_digest_size + ))); + } + + Self::rsa_pkcs1v15_verify( + provider, + rsa_pub_key, + &RSA_DEFAULT_EXPONENT, + signature.hash, + &signed_blob_hash, + &signature.sig, + ) + } + + // KDFa implementation as specified in TPM 2.0 Part 1 + pub fn kdfa( + provider: &CryptoProvider, + hash_alg: TPM_ALG_ID, + key: &[u8], + label: &str, + context_u: &[u8], + context_v: &[u8], + bits: usize, + ) -> Result, TpmError> { + let bytes_needed = bits.div_ceil(8); + let mut result = Vec::new(); + let mut counter = 1u32; + + while result.len() < bytes_needed { + let mut to_hash = Vec::new(); + + // Counter in big-endian + to_hash.extend_from_slice(&counter.to_be_bytes()); + + // Label + to_hash.extend_from_slice(label.as_bytes()); + + // 00 byte separator + to_hash.push(0u8); + + // contextU + to_hash.extend_from_slice(context_u); + + // contextV + to_hash.extend_from_slice(context_v); + + // Number of bits in big-endian + to_hash.extend_from_slice(&(bits as u32).to_be_bytes()); + + // Perform HMAC + let hmac_result = Self::hmac(provider, hash_alg, key, &to_hash)?; + result.extend_from_slice(&hmac_result); + + counter = counter.checked_add(1).ok_or_else(|| { + TpmError::InvalidArraySize("Counter overflow in KDFa".to_string()) + })?; + } + + // Truncate to exact size needed + result.truncate(bytes_needed); + Ok(result) + } + + // AES CFB encryption/decryption + pub fn cfb_xcrypt( + provider: &CryptoProvider, + encrypt: bool, + key: &[u8], + iv: &[u8], + data: &[u8], + ) -> Result, TpmError> { + (provider.aes_cfb)(encrypt, key, iv, data) + } + + /// Return `num_bytes` of cryptographically secure random data. + pub fn get_random(provider: &CryptoProvider, num_bytes: usize) -> Result, TpmError> { + let mut result = vec![0u8; num_bytes]; + (provider.random)(&mut result)?; + Ok(result) + } +} + +// These tests exercise the software provider directly -- they verify against the `rsa` crate -- +// so they only apply when that backend is compiled in. +#[cfg(all(test, feature = "software-crypto"))] +mod tests { + use super::*; + use rand::rngs::OsRng; + use rsa::traits::PublicKeyParts; + use rsa::{Oaep, Pkcs1v15Sign, RsaPrivateKey}; + use sha2::{Digest as Sha2Digest, Sha256}; + use software_provider::SOFTWARE_PROVIDER; + + #[test] + fn validate_signature_uses_signature_hash_algorithm() -> Result<(), TpmError> { + let mut rng = OsRng; + let private_key = RsaPrivateKey::new(&mut rng, 2048) + .map_err(|e| TpmError::GenericError(format!("RSA key generation failed: {e}")))?; + let public_key = TPMT_PUBLIC { + parameters: Some(TPMU_PUBLIC_PARMS::rsaDetail(TPMS_RSA_PARMS::default())), + unique: Some(TPMU_PUBLIC_ID::rsa(TPM2B_PUBLIC_KEY_RSA { + buffer: private_key.n().to_bytes_be(), + })), + ..Default::default() + }; + + let message = b"digest dispatch regression"; + let digest = Sha256::digest(message).to_vec(); + let sig = private_key + .sign(Pkcs1v15Sign::new::(), &digest) + .map_err(|e| TpmError::GenericError(format!("RSA signing failed: {e}")))?; + let signature = Some(TPMU_SIGNATURE::rsassa(TPMS_SIGNATURE_RSASSA { + hash: TPM_ALG_ID::SHA256, + sig, + })); + + assert!(Crypto::validate_signature( + &SOFTWARE_PROVIDER, + &public_key, + digest, + &signature + )?); + Ok(()) + } + + #[test] + fn rsa_oaep_encrypt_round_trips_and_binds_the_label() -> Result<(), TpmError> { + let mut rng = OsRng; + let private_key = RsaPrivateKey::new(&mut rng, 2048) + .map_err(|e| TpmError::GenericError(format!("RSA key generation failed: {e}")))?; + let modulus = private_key.n().to_bytes_be(); + + let plaintext = b"seed material"; + let ciphertext = Crypto::rsa_oaep_encrypt( + &SOFTWARE_PROVIDER, + &modulus, + &RSA_DEFAULT_EXPONENT, + TPM_ALG_ID::SHA256, + b"IDENTITY\0", + plaintext, + )?; + + let decrypted = private_key + .decrypt(Oaep::new_with_label::("IDENTITY\0"), &ciphertext) + .map_err(|e| TpmError::GenericError(format!("OAEP decryption failed: {e}")))?; + assert_eq!(decrypted, plaintext); + + // A different label must not recover the plaintext. This is what keeps the "IDENTITY\0" + // and "SECRET\0" call sites distinct now that they share one implementation. + assert!(private_key + .decrypt(Oaep::new_with_label::("SECRET\0"), &ciphertext) + .is_err()); + + Ok(()) + } + + #[test] + fn rsa_sign_round_trips_through_verify() -> Result<(), TpmError> { + let key = Crypto::rsa_generate_keypair(&SOFTWARE_PROVIDER, 2048)?; + let digest = Sha256::digest(b"software key signing regression").to_vec(); + + let signature = + Crypto::rsa_pkcs1v15_sign(&SOFTWARE_PROVIDER, &key, TPM_ALG_ID::SHA256, &digest)?; + + assert!(Crypto::rsa_pkcs1v15_verify( + &SOFTWARE_PROVIDER, + &key.modulus, + &RSA_DEFAULT_EXPONENT, + TPM_ALG_ID::SHA256, + &digest, + &signature, + )?); + Ok(()) + } + + #[test] + fn rsa_sign_rejects_a_zero_prime_instead_of_dividing_by_it() { + let key = RsaKeyParts { + modulus: vec![0xff; 256], + prime: vec![0u8; 128], + }; + + assert!(Crypto::rsa_pkcs1v15_sign( + &SOFTWARE_PROVIDER, + &key, + TPM_ALG_ID::SHA256, + &[0u8; 32] + ) + .is_err()); + } +} diff --git a/TSS.Rust/src/crypto/provider.rs b/TSS.Rust/src/crypto/provider.rs new file mode 100644 index 00000000..cb16a125 --- /dev/null +++ b/TSS.Rust/src/crypto/provider.rs @@ -0,0 +1,156 @@ +//! The pluggable crypto backend interface. +//! +//! TSS.Rust needs a handful of cryptographic primitives to build TPM structures on the host: to +//! hash a public area into a name, to derive session keys with KDFa, to wrap an activation +//! credential, and so on. Which library performs those primitives is a deployment decision, not a +//! protocol decision, so it is expressed here as a value the caller supplies. +//! +//! A provider is a plain struct of function pointers rather than a trait object. That keeps +//! [`CryptoProvider`] `Copy`, lets it be built in a `const` context, and means threading one +//! through a call chain costs no more than passing a pointer. This mirrors how `jsonwebtoken` +//! models its own pluggable backend. +//! +//! Deliberately, there is no process-wide default provider. TSS.Rust is built as a `cdylib` as +//! well as an `rlib`, and hosts that load and unload it repeatedly would have to reason about the +//! lifetime of any global. Requiring the provider at the call site also lets a single process use +//! two backends at once, which is what makes cross-provider equivalence testing possible. +//! +//! Only primitives belong here. Logic defined by the TPM 2.0 specification — digest sizes, KDFa, +//! signature validation — is built on top of these primitives by [`Crypto`](super::Crypto) and is +//! identical no matter which backend is in use. + +use super::RsaKeyParts; +use crate::{error::TpmError, tpm_types::TPM_ALG_ID}; + +/// Signature of [`CryptoProvider::hash`]. +pub type HashFn = fn(alg: TPM_ALG_ID, data: &[u8]) -> Result, TpmError>; + +/// Signature of [`CryptoProvider::hmac`]. +pub type HmacFn = fn(alg: TPM_ALG_ID, key: &[u8], data: &[u8]) -> Result, TpmError>; + +/// Signature of [`CryptoProvider::aes_cfb`]. +pub type AesCfbFn = + fn(encrypt: bool, key: &[u8], iv: &[u8], data: &[u8]) -> Result, TpmError>; + +/// Signature of [`CryptoProvider::random`]. +pub type RandomFn = fn(out: &mut [u8]) -> Result<(), TpmError>; + +/// Signature of [`RsaOps::oaep_encrypt`]. +pub type RsaOaepEncryptFn = fn( + modulus: &[u8], + exponent: &[u8], + hash_alg: TPM_ALG_ID, + label: &[u8], + data: &[u8], +) -> Result, TpmError>; + +/// Signature of [`RsaOps::pkcs1v15_verify`]. +pub type RsaPkcs1v15VerifyFn = fn( + modulus: &[u8], + exponent: &[u8], + hash_alg: TPM_ALG_ID, + digest: &[u8], + signature: &[u8], +) -> Result; + +/// Signature of [`RsaOps::generate_keypair`]. +pub type RsaGenerateKeypairFn = fn(key_bits: usize) -> Result; + +/// Signature of [`RsaOps::pkcs1v15_sign`]. +pub type RsaPkcs1v15SignFn = + fn(key: &RsaKeyParts, hash_alg: TPM_ALG_ID, digest: &[u8]) -> Result, TpmError>; + +/// Returns the error reported by every primitive a provider leaves unimplemented. +fn unimplemented(operation: &str) -> TpmError { + TpmError::NotSupported(format!( + "The configured crypto provider does not implement {operation}" + )) +} + +/// The RSA primitives a provider supplies. +/// +/// These are split out from [`CryptoProvider`] so that a backend able to offer only some of them +/// can start from [`RsaOps::new_unimplemented`] and fill in what it supports. That is not a +/// hypothetical: a provider built on Windows CNG cannot implement [`RsaOps::pkcs1v15_sign`], +/// because signing here has to recover the second prime by dividing the modulus by the first and +/// CNG exposes no big-integer division. +#[derive(Clone, Copy, Debug)] +pub struct RsaOps { + /// RSA-OAEP encrypt `data` under the public key given by its big-endian components. + /// + /// `label` is passed through verbatim, so it must already include the trailing NUL that the + /// TPM specification puts in labels such as `b"IDENTITY\0"`. + pub oaep_encrypt: RsaOaepEncryptFn, + + /// Verify an RSASSA-PKCS1-v1_5 signature over an already computed digest. + /// + /// A `false` result means the signature did not verify. An `Err` means the verification could + /// not be performed at all, for instance because the key or the hash algorithm was rejected. + pub pkcs1v15_verify: RsaPkcs1v15VerifyFn, + + /// Generate an RSA key pair, returning the modulus and the first prime. + pub generate_keypair: RsaGenerateKeypairFn, + + /// Sign an already computed digest with RSASSA-PKCS1-v1_5. + pub pkcs1v15_sign: RsaPkcs1v15SignFn, +} + +impl RsaOps { + /// A set of RSA operations that all report [`TpmError::NotSupported`]. + /// + /// Intended as a base for functional record update, so a backend states only what it provides: + /// + /// ```ignore + /// RsaOps { + /// oaep_encrypt: my_oaep_encrypt, + /// ..RsaOps::new_unimplemented() + /// } + /// ``` + pub const fn new_unimplemented() -> Self { + Self { + oaep_encrypt: |_, _, _, _, _| Err(unimplemented("RSA-OAEP encryption")), + pkcs1v15_verify: |_, _, _, _, _| Err(unimplemented("RSA PKCS#1 v1.5 verification")), + generate_keypair: |_| Err(unimplemented("RSA key generation")), + pkcs1v15_sign: |_, _, _| Err(unimplemented("RSA PKCS#1 v1.5 signing")), + } + } +} + +/// The cryptographic primitives TSS.Rust needs from its host. +#[derive(Clone, Copy, Debug)] +pub struct CryptoProvider { + /// Hash `data` with `alg`, returning a digest of exactly `Crypto::digestSize(alg)` bytes. + pub hash: HashFn, + + /// HMAC `data` under `key` using `alg`. The key may be of any length. + pub hmac: HmacFn, + + /// AES in CFB mode with a full 128-bit segment, as the TPM specification requires. + /// + /// `data` is not required to be a multiple of the block size; the final partial block is + /// processed against a truncated key stream. Backends layered on an API whose CFB mode + /// defaults to an 8-bit segment must not use that mode here. + pub aes_cfb: AesCfbFn, + + /// Fill `out` with cryptographically secure random bytes. + pub random: RandomFn, + + /// The RSA primitives. + pub rsa: RsaOps, +} + +impl CryptoProvider { + /// A provider whose every primitive reports [`TpmError::NotSupported`]. + /// + /// Intended as a base for functional record update, in the same way as + /// [`RsaOps::new_unimplemented`]. + pub const fn new_unimplemented() -> Self { + Self { + hash: |_, _| Err(unimplemented("hashing")), + hmac: |_, _, _| Err(unimplemented("HMAC")), + aes_cfb: |_, _, _, _| Err(unimplemented("AES-CFB")), + random: |_| Err(unimplemented("random number generation")), + rsa: RsaOps::new_unimplemented(), + } + } +} diff --git a/TSS.Rust/src/crypto/software_provider.rs b/TSS.Rust/src/crypto/software_provider.rs new file mode 100644 index 00000000..bb62eedb --- /dev/null +++ b/TSS.Rust/src/crypto/software_provider.rs @@ -0,0 +1,296 @@ +//! A [`CryptoProvider`] built on the pure-Rust RustCrypto crates. +//! +//! This is the default backend and needs no platform support, so it works the same on every +//! target. Hosts that would rather not link a second implementation of primitives their operating +//! system already provides can disable the `software-crypto` feature and supply their own +//! provider instead. + +use super::provider::{CryptoProvider, RsaOps}; +use super::{Crypto, RsaKeyParts, RSA_DEFAULT_EXPONENT}; +use crate::{error::TpmError, tpm_types::TPM_ALG_ID}; + +use aes::Aes128; +use cipher::generic_array::GenericArray; +use cipher::{BlockEncrypt, KeyInit}; +use hmac::{Hmac, Mac}; +use rand::{rngs::OsRng, RngCore}; +use rsa::traits::{PrivateKeyParts, PublicKeyParts}; +use rsa::{BigUint, Oaep, Pkcs1v15Sign, RsaPrivateKey, RsaPublicKey}; +use sha1::Sha1; +use sha2::{Digest as Sha2Digest, Sha256, Sha384, Sha512}; +use sm3::Sm3; + +/// The RustCrypto-backed provider. +pub static SOFTWARE_PROVIDER: CryptoProvider = CryptoProvider { + hash, + hmac, + aes_cfb, + random, + rsa: RsaOps { + oaep_encrypt: rsa_oaep_encrypt, + pkcs1v15_verify: rsa_pkcs1v15_verify, + generate_keypair: rsa_generate_keypair, + pkcs1v15_sign: rsa_pkcs1v15_sign, + }, +}; + +fn hash(alg: TPM_ALG_ID, data: &[u8]) -> Result, TpmError> { + // If the data is empty, return an empty digest of correct size + if data.is_empty() { + return Ok(vec![0; Crypto::digestSize(alg)]); + } + + let digest = match alg { + TPM_ALG_ID::SHA1 => { + let mut hasher = Sha1::new(); + hasher.update(data); + hasher.finalize().to_vec() + } + TPM_ALG_ID::SHA256 => { + let mut hasher = Sha256::new(); + hasher.update(data); + hasher.finalize().to_vec() + } + TPM_ALG_ID::SHA384 => { + let mut hasher = Sha384::new(); + hasher.update(data); + hasher.finalize().to_vec() + } + TPM_ALG_ID::SHA512 => { + let mut hasher = Sha512::new(); + hasher.update(data); + hasher.finalize().to_vec() + } + TPM_ALG_ID::SM3_256 => { + let mut hasher = Sm3::new(); + hasher.update(data); + hasher.finalize().to_vec() + } + _ => { + return Err(TpmError::NotSupported(format!( + "Unsupported hash algorithm: {:?}", + alg + ))) + } + }; + + let expected_size = Crypto::digestSize(alg); + if digest.len() != expected_size { + return Err(TpmError::InvalidArraySize(format!( + "Hash output length mismatch: expected {}, got {}", + expected_size, + digest.len() + ))); + } + + Ok(digest) +} + +fn hmac(hash_alg: TPM_ALG_ID, key: &[u8], to_hash: &[u8]) -> Result, TpmError> { + // Choose the appropriate HMAC algorithm based on the hash algorithm + match hash_alg { + TPM_ALG_ID::SHA1 => { + let mut mac = as Mac>::new_from_slice(key).map_err(|_| { + TpmError::InvalidArraySize("HMAC can take key of any size".to_string()) + })?; + mac.update(to_hash); + Ok(mac.finalize().into_bytes().to_vec()) + } + TPM_ALG_ID::SHA256 => { + let mut mac = as Mac>::new_from_slice(key).map_err(|_| { + TpmError::InvalidArraySize("HMAC can take key of any size".to_string()) + })?; + mac.update(to_hash); + Ok(mac.finalize().into_bytes().to_vec()) + } + TPM_ALG_ID::SHA384 => { + let mut mac = as Mac>::new_from_slice(key).map_err(|_| { + TpmError::InvalidArraySize("HMAC can take key of any size".to_string()) + })?; + mac.update(to_hash); + Ok(mac.finalize().into_bytes().to_vec()) + } + TPM_ALG_ID::SHA512 => { + let mut mac = as Mac>::new_from_slice(key).map_err(|_| { + TpmError::InvalidArraySize("HMAC can take key of any size".to_string()) + })?; + mac.update(to_hash); + Ok(mac.finalize().into_bytes().to_vec()) + } + TPM_ALG_ID::SM3_256 => { + let mut mac = as Mac>::new_from_slice(key).map_err(|_| { + TpmError::InvalidArraySize("HMAC can take key of any size".to_string()) + })?; + mac.update(to_hash); + Ok(mac.finalize().into_bytes().to_vec()) + } + _ => Err(TpmError::NotSupported(format!( + "Unsupported hash algorithm: {:?}", + hash_alg + ))), + } +} + +fn pkcs1v15_sign_scheme(hash_alg: TPM_ALG_ID) -> Result { + match hash_alg { + TPM_ALG_ID::SHA1 => Ok(Pkcs1v15Sign::new::()), + TPM_ALG_ID::SHA256 => Ok(Pkcs1v15Sign::new::()), + TPM_ALG_ID::SHA384 => Ok(Pkcs1v15Sign::new::()), + TPM_ALG_ID::SHA512 => Ok(Pkcs1v15Sign::new::()), + _ => Err(TpmError::NotSupported(format!( + "Unsupported RSASSA hash algorithm: {:?}", + hash_alg + ))), + } +} + +/// Build an RSA public key from its big-endian components. +fn rsa_public_key(modulus: &[u8], exponent: &[u8]) -> Result { + RsaPublicKey::new( + BigUint::from_bytes_be(modulus), + BigUint::from_bytes_be(exponent), + ) + .map_err(|_| TpmError::InvalidArraySize("Invalid RSA public key".to_string())) +} + +fn rsa_oaep_encrypt( + modulus: &[u8], + exponent: &[u8], + hash_alg: TPM_ALG_ID, + label: &[u8], + data: &[u8], +) -> Result, TpmError> { + let rsa_key = rsa_public_key(modulus, exponent)?; + + // The `rsa` crate models an OAEP label as a string rather than as bytes, so the label + // has to be converted here. Callers work in bytes because that is what the TPM + // specification and other crypto backends use. + let label = std::str::from_utf8(label) + .map_err(|_| TpmError::NotSupported("OAEP label must be valid UTF-8".to_string()))?; + + let padding = match hash_alg { + TPM_ALG_ID::SHA1 => Oaep::new_with_label::(label), + TPM_ALG_ID::SHA256 => Oaep::new_with_label::(label), + _ => { + return Err(TpmError::NotSupported(format!( + "Unsupported nameAlg for OAEP: {:?}", + hash_alg + ))) + } + }; + + rsa_key + .encrypt(&mut OsRng, padding, data) + .map_err(|e| TpmError::GenericError(format!("RSA-OAEP encryption failed: {e}"))) +} + +fn rsa_pkcs1v15_verify( + modulus: &[u8], + exponent: &[u8], + hash_alg: TPM_ALG_ID, + digest: &[u8], + signature: &[u8], +) -> Result { + let rsa_key = rsa_public_key(modulus, exponent)?; + let scheme = pkcs1v15_sign_scheme(hash_alg)?; + Ok(rsa_key.verify(scheme, digest, signature).is_ok()) +} + +fn rsa_generate_keypair(key_bits: usize) -> Result { + let priv_key = RsaPrivateKey::new(&mut OsRng, key_bits) + .map_err(|e| TpmError::GenericError(format!("RSA key generation failed: {}", e)))?; + + let prime = priv_key + .primes() + .first() + .ok_or_else(|| TpmError::GenericError("Generated RSA key exposes no primes".to_string()))?; + + Ok(RsaKeyParts { + modulus: priv_key.n().to_bytes_be(), + prime: prime.to_bytes_be(), + }) +} + +/// Sign an already computed digest with RSASSA-PKCS1-v1_5. +/// +/// The second prime is recovered as `modulus / prime`. +fn rsa_pkcs1v15_sign( + key: &RsaKeyParts, + hash_alg: TPM_ALG_ID, + digest: &[u8], +) -> Result, TpmError> { + // Recovering the second prime divides by the first, so reject a zero prime up front + // instead of letting the big-integer division panic. + if key.prime.iter().all(|&byte| byte == 0) { + return Err(TpmError::InvalidArraySize( + "RSA private key prime is zero".to_string(), + )); + } + + let modulus = BigUint::from_bytes_be(&key.modulus); + let first_prime = BigUint::from_bytes_be(&key.prime); + let second_prime = &modulus / &first_prime; + let exponent = BigUint::from_bytes_be(&RSA_DEFAULT_EXPONENT); + + let priv_key = RsaPrivateKey::from_p_q(first_prime, second_prime, exponent) + .map_err(|e| TpmError::GenericError(format!("Failed to reconstruct RSA key: {}", e)))?; + + priv_key + .sign(pkcs1v15_sign_scheme(hash_alg)?, digest) + .map_err(|e| TpmError::GenericError(format!("RSA signing failed: {}", e))) +} + +fn aes_cfb(encrypt: bool, key: &[u8], iv: &[u8], data: &[u8]) -> Result, TpmError> { + if data.is_empty() { + return Ok(Vec::new()); + } + + if key.len() != 16 && key.len() != 24 && key.len() != 32 { + return Err(TpmError::InvalidArraySize( + "Invalid AES key length".to_string(), + )); + } + + if iv.len() != 16 { + return Err(TpmError::InvalidArraySize("IV must be 16 bytes".to_string())); + } + + let cipher = Aes128::new(GenericArray::from_slice(key)); + let mut result = Vec::with_capacity(data.len()); + let mut feedback = *GenericArray::from_slice(iv); + + for chunk in data.chunks(16) { + // Encrypt the feedback (IV or previous ciphertext) + let mut encrypted_feedback = feedback; + cipher.encrypt_block(&mut encrypted_feedback); + + if encrypt { + // CFB encrypt: ciphertext = plaintext XOR encrypt(feedback) + // Next feedback = ciphertext + let mut ct_block = [0u8; 16]; + for (i, &b) in chunk.iter().enumerate() { + ct_block[i] = b ^ encrypted_feedback[i]; + result.push(ct_block[i]); + } + feedback.copy_from_slice(&ct_block); + } else { + // CFB decrypt: plaintext = ciphertext XOR encrypt(feedback) + // Next feedback = ciphertext (input) + let mut ct_block = [0u8; 16]; + ct_block[..chunk.len()].copy_from_slice(chunk); + for (i, &b) in chunk.iter().enumerate() { + result.push(b ^ encrypted_feedback[i]); + } + feedback.copy_from_slice(&ct_block); + } + } + + result.truncate(data.len()); + Ok(result) +} + +fn random(out: &mut [u8]) -> Result<(), TpmError> { + OsRng + .try_fill_bytes(out) + .map_err(|e| TpmError::GenericError(format!("Failed to obtain random bytes: {e}"))) +} diff --git a/TSS.Rust/src/policy.rs b/TSS.Rust/src/policy.rs index d9d268b1..0c82b9a1 100644 --- a/TSS.Rust/src/policy.rs +++ b/TSS.Rust/src/policy.rs @@ -11,7 +11,7 @@ //! against a real policy session on the TPM. use crate::auth_session::Session; -use crate::crypto::Crypto; +use crate::crypto::{provider::CryptoProvider, Crypto}; use crate::error::TpmError; use crate::tpm2_impl::Tpm2; use crate::tpm_buffer::{TpmBuffer, TpmMarshaller}; @@ -25,7 +25,12 @@ use crate::tpm_types::*; /// Trait implemented by all policy assertion types. pub trait PolicyAssertion { /// Update a policy digest accumulator (used for trial/software digest computation). - fn update_policy_digest(&self, hash_alg: TPM_ALG_ID, accumulator: &mut Vec) -> Result<(), TpmError>; + fn update_policy_digest( + &self, + crypto: &CryptoProvider, + hash_alg: TPM_ALG_ID, + accumulator: &mut Vec, + ) -> Result<(), TpmError>; /// Execute this policy assertion against a live TPM policy session. fn execute(&self, tpm: &mut Tpm2, session: &Session) -> Result; @@ -38,6 +43,7 @@ pub trait PolicyAssertion { /// `policyDigest = H(policyDigest || commandCode || arg2)` /// Then: `policyDigest = H(policyDigest || arg3)` fn policy_update( + crypto: &CryptoProvider, hash_alg: TPM_ALG_ID, accumulator: &mut Vec, command_code: TPM_CC, @@ -49,14 +55,14 @@ fn policy_update( buf.extend_from_slice(accumulator); buf.extend_from_slice(&command_code.get_value().to_be_bytes()); buf.extend_from_slice(arg2); - *accumulator = Crypto::hash(hash_alg, &buf)?; + *accumulator = Crypto::hash(crypto, hash_alg, &buf)?; // Second extend (if arg3 is non-empty): H(accumulator || arg3) if !arg3.is_empty() { let mut buf2 = Vec::new(); buf2.extend_from_slice(accumulator); buf2.extend_from_slice(arg3); - *accumulator = Crypto::hash(hash_alg, &buf2)?; + *accumulator = Crypto::hash(crypto, hash_alg, &buf2)?; } Ok(()) } @@ -96,8 +102,12 @@ impl PolicyTree { } /// Compute the policy digest in software (equivalent to a trial session). - pub fn get_policy_digest(&self, hash_alg: TPM_ALG_ID) -> Result, TpmError> { - compute_digest(&self.assertions, hash_alg) + pub fn get_policy_digest( + &self, + crypto: &CryptoProvider, + hash_alg: TPM_ALG_ID, + ) -> Result, TpmError> { + compute_digest(crypto, &self.assertions, hash_alg) } /// Execute all assertions in order against a live policy session. @@ -113,13 +123,14 @@ impl PolicyTree { /// Compute the digest for a slice of assertions (used by PolicyTree and PolicyOr). pub(crate) fn compute_digest( + crypto: &CryptoProvider, assertions: &[Box], hash_alg: TPM_ALG_ID, ) -> Result, TpmError> { - let hash_len = Crypto::hash(hash_alg, &[])?.len(); + let hash_len = Crypto::hash(crypto, hash_alg, &[])?.len(); let mut accumulator = vec![0u8; hash_len]; for assertion in assertions { - assertion.update_policy_digest(hash_alg, &mut accumulator)?; + assertion.update_policy_digest(crypto, hash_alg, &mut accumulator)?; } Ok(accumulator) } @@ -140,10 +151,15 @@ impl PolicyCommandCode { } impl PolicyAssertion for PolicyCommandCode { - fn update_policy_digest(&self, hash_alg: TPM_ALG_ID, acc: &mut Vec) -> Result<(), TpmError> { + fn update_policy_digest( + &self, + crypto: &CryptoProvider, + hash_alg: TPM_ALG_ID, + acc: &mut Vec, + ) -> Result<(), TpmError> { let mut buf = Vec::new(); buf.extend_from_slice(&self.command_code.get_value().to_be_bytes()); - policy_update(hash_alg, acc, TPM_CC::PolicyCommandCode, &buf, &[]) + policy_update(crypto, hash_alg, acc, TPM_CC::PolicyCommandCode, &buf, &[]) } fn execute(&self, tpm: &mut Tpm2, session: &Session) -> Result { @@ -164,13 +180,18 @@ impl PolicyLocality { } impl PolicyAssertion for PolicyLocality { - fn update_policy_digest(&self, hash_alg: TPM_ALG_ID, acc: &mut Vec) -> Result<(), TpmError> { + fn update_policy_digest( + &self, + crypto: &CryptoProvider, + hash_alg: TPM_ALG_ID, + acc: &mut Vec, + ) -> Result<(), TpmError> { // PolicyLocality: H(acc || TPM_CC_PolicyLocality || locality_byte) let mut buf = Vec::new(); buf.extend_from_slice(acc); buf.extend_from_slice(&TPM_CC::PolicyLocality.get_value().to_be_bytes()); buf.push(self.locality.get_value()); - *acc = Crypto::hash(hash_alg, &buf)?; + *acc = Crypto::hash(crypto, hash_alg, &buf)?; Ok(()) } @@ -193,13 +214,18 @@ impl PolicyPcr { } impl PolicyAssertion for PolicyPcr { - fn update_policy_digest(&self, hash_alg: TPM_ALG_ID, acc: &mut Vec) -> Result<(), TpmError> { + fn update_policy_digest( + &self, + crypto: &CryptoProvider, + hash_alg: TPM_ALG_ID, + acc: &mut Vec, + ) -> Result<(), TpmError> { // Concatenate all PCR values and hash them let mut pcr_data = Vec::new(); for v in &self.pcr_values { pcr_data.extend_from_slice(&v.buffer); } - let pcr_digest = Crypto::hash(hash_alg, &pcr_data)?; + let pcr_digest = Crypto::hash(crypto, hash_alg, &pcr_data)?; // Marshal PCR selections let mut sel_buf = TpmBuffer::new(None); @@ -211,7 +237,7 @@ impl PolicyAssertion for PolicyPcr { let mut arg2 = Vec::new(); arg2.extend_from_slice(sel_buf.trim()); arg2.extend_from_slice(&pcr_digest); - policy_update(hash_alg, acc, TPM_CC::PolicyPCR, &arg2, &[]) + policy_update(crypto, hash_alg, acc, TPM_CC::PolicyPCR, &arg2, &[]) } fn execute(&self, tpm: &mut Tpm2, session: &Session) -> Result { @@ -234,9 +260,14 @@ impl PolicyPassword { } impl PolicyAssertion for PolicyPassword { - fn update_policy_digest(&self, hash_alg: TPM_ALG_ID, acc: &mut Vec) -> Result<(), TpmError> { + fn update_policy_digest( + &self, + crypto: &CryptoProvider, + hash_alg: TPM_ALG_ID, + acc: &mut Vec, + ) -> Result<(), TpmError> { // PolicyPassword uses the same digest as PolicyAuthValue per spec - policy_update(hash_alg, acc, TPM_CC::PolicyAuthValue, &[], &[]) + policy_update(crypto, hash_alg, acc, TPM_CC::PolicyAuthValue, &[], &[]) } fn execute(&self, tpm: &mut Tpm2, session: &Session) -> Result { @@ -261,8 +292,13 @@ impl PolicyAuthValue { } impl PolicyAssertion for PolicyAuthValue { - fn update_policy_digest(&self, hash_alg: TPM_ALG_ID, acc: &mut Vec) -> Result<(), TpmError> { - policy_update(hash_alg, acc, TPM_CC::PolicyAuthValue, &[], &[]) + fn update_policy_digest( + &self, + crypto: &CryptoProvider, + hash_alg: TPM_ALG_ID, + acc: &mut Vec, + ) -> Result<(), TpmError> { + policy_update(crypto, hash_alg, acc, TPM_CC::PolicyAuthValue, &[], &[]) } fn execute(&self, tpm: &mut Tpm2, session: &Session) -> Result { @@ -285,8 +321,13 @@ impl PolicyCpHash { } impl PolicyAssertion for PolicyCpHash { - fn update_policy_digest(&self, hash_alg: TPM_ALG_ID, acc: &mut Vec) -> Result<(), TpmError> { - policy_update(hash_alg, acc, TPM_CC::PolicyCpHash, &self.cp_hash, &[]) + fn update_policy_digest( + &self, + crypto: &CryptoProvider, + hash_alg: TPM_ALG_ID, + acc: &mut Vec, + ) -> Result<(), TpmError> { + policy_update(crypto, hash_alg, acc, TPM_CC::PolicyCpHash, &self.cp_hash, &[]) } fn execute(&self, tpm: &mut Tpm2, session: &Session) -> Result { @@ -307,8 +348,13 @@ impl PolicyNameHash { } impl PolicyAssertion for PolicyNameHash { - fn update_policy_digest(&self, hash_alg: TPM_ALG_ID, acc: &mut Vec) -> Result<(), TpmError> { - policy_update(hash_alg, acc, TPM_CC::PolicyNameHash, &self.name_hash, &[]) + fn update_policy_digest( + &self, + crypto: &CryptoProvider, + hash_alg: TPM_ALG_ID, + acc: &mut Vec, + ) -> Result<(), TpmError> { + policy_update(crypto, hash_alg, acc, TPM_CC::PolicyNameHash, &self.name_hash, &[]) } fn execute(&self, tpm: &mut Tpm2, session: &Session) -> Result { @@ -336,14 +382,19 @@ impl PolicyCounterTimer { } impl PolicyAssertion for PolicyCounterTimer { - fn update_policy_digest(&self, hash_alg: TPM_ALG_ID, acc: &mut Vec) -> Result<(), TpmError> { + fn update_policy_digest( + &self, + crypto: &CryptoProvider, + hash_alg: TPM_ALG_ID, + acc: &mut Vec, + ) -> Result<(), TpmError> { // arg2 = H(operandB || offset || operation) let mut inner = Vec::new(); inner.extend_from_slice(&self.operand_b); inner.extend_from_slice(&self.offset.to_be_bytes()); inner.extend_from_slice(&self.operation.get_value().to_be_bytes()); - let arg_hash = Crypto::hash(hash_alg, &inner)?; - policy_update(hash_alg, acc, TPM_CC::PolicyCounterTimer, &arg_hash, &[]) + let arg_hash = Crypto::hash(crypto, hash_alg, &inner)?; + policy_update(crypto, hash_alg, acc, TPM_CC::PolicyCounterTimer, &arg_hash, &[]) } fn execute(&self, tpm: &mut Tpm2, session: &Session) -> Result { @@ -379,8 +430,13 @@ impl PolicySecret { } impl PolicyAssertion for PolicySecret { - fn update_policy_digest(&self, hash_alg: TPM_ALG_ID, acc: &mut Vec) -> Result<(), TpmError> { - policy_update(hash_alg, acc, TPM_CC::PolicySecret, &self.auth_object_name, &self.policy_ref) + fn update_policy_digest( + &self, + crypto: &CryptoProvider, + hash_alg: TPM_ALG_ID, + acc: &mut Vec, + ) -> Result<(), TpmError> { + policy_update(crypto, hash_alg, acc, TPM_CC::PolicySecret, &self.auth_object_name, &self.policy_ref) } fn execute(&self, tpm: &mut Tpm2, session: &Session) -> Result { @@ -433,12 +489,19 @@ impl PolicySigned { } impl PolicyAssertion for PolicySigned { - fn update_policy_digest(&self, hash_alg: TPM_ALG_ID, acc: &mut Vec) -> Result<(), TpmError> { - let key_name = self.public_key.get_name()?; - policy_update(hash_alg, acc, TPM_CC::PolicySigned, &key_name, &self.policy_ref) + fn update_policy_digest( + &self, + crypto: &CryptoProvider, + hash_alg: TPM_ALG_ID, + acc: &mut Vec, + ) -> Result<(), TpmError> { + let key_name = self.public_key.get_name(crypto)?; + policy_update(crypto, hash_alg, acc, TPM_CC::PolicySigned, &key_name, &self.policy_ref) } fn execute(&self, tpm: &mut Tpm2, session: &Session) -> Result { + // Copied out because `tpm` is borrowed mutably by the command calls below. + let crypto = *tpm.crypto(); let nonce_tpm = if self.include_tpm_nonce { session.sess_out.nonce.clone() } else { @@ -462,12 +525,12 @@ impl PolicyAssertion for PolicySigned { to_hash.extend_from_slice(&self.expiration.to_be_bytes()); to_hash.extend_from_slice(&self.cp_hash_a); to_hash.extend_from_slice(&self.policy_ref); - let a_hash = Crypto::hash(hash_alg, &to_hash)?; + let a_hash = Crypto::hash(&crypto, hash_alg, &to_hash)?; let sw_key = self.sw_key.as_ref().ok_or_else(|| { TpmError::GenericError("PolicySigned: no SW key set (callbacks not yet supported)".into()) })?; - let signature = sw_key.sign(&a_hash, hash_alg)?; + let signature = sw_key.sign(&crypto, &a_hash, hash_alg)?; // Load the public key into the TPM (OWNER hierarchy for valid tickets) let pub_key_handle = tpm.LoadExternal( @@ -512,14 +575,19 @@ impl PolicyNv { } impl PolicyAssertion for PolicyNv { - fn update_policy_digest(&self, hash_alg: TPM_ALG_ID, acc: &mut Vec) -> Result<(), TpmError> { + fn update_policy_digest( + &self, + crypto: &CryptoProvider, + hash_alg: TPM_ALG_ID, + acc: &mut Vec, + ) -> Result<(), TpmError> { // arg2 = H(operandB || offset || operation) let mut inner = Vec::new(); inner.extend_from_slice(&self.operand_b); inner.extend_from_slice(&self.offset.to_be_bytes()); inner.extend_from_slice(&self.operation.get_value().to_be_bytes()); - let args_hash = Crypto::hash(hash_alg, &inner)?; - policy_update(hash_alg, acc, TPM_CC::PolicyNV, &args_hash, &self.nv_index_name) + let args_hash = Crypto::hash(crypto, hash_alg, &inner)?; + policy_update(crypto, hash_alg, acc, TPM_CC::PolicyNV, &args_hash, &self.nv_index_name) } fn execute(&self, tpm: &mut Tpm2, session: &Session) -> Result { @@ -552,25 +620,32 @@ impl PolicyOr { } impl PolicyAssertion for PolicyOr { - fn update_policy_digest(&self, hash_alg: TPM_ALG_ID, acc: &mut Vec) -> Result<(), TpmError> { + fn update_policy_digest( + &self, + crypto: &CryptoProvider, + hash_alg: TPM_ALG_ID, + acc: &mut Vec, + ) -> Result<(), TpmError> { // PolicyOR: accumulator = H(0...0 || TPM_CC_PolicyOR || digest1 || digest2 || ...) - let hash_len = Crypto::hash(hash_alg, &[])?.len(); + let hash_len = Crypto::hash(crypto, hash_alg, &[])?.len(); let mut buf = Vec::new(); buf.extend_from_slice(&vec![0u8; hash_len]); // reset to zero buf.extend_from_slice(&TPM_CC::PolicyOR.get_value().to_be_bytes()); for branch in &self.branches { - let branch_digest = compute_digest(branch, hash_alg)?; + let branch_digest = compute_digest(crypto, branch, hash_alg)?; buf.extend_from_slice(&branch_digest); } - *acc = Crypto::hash(hash_alg, &buf)?; + *acc = Crypto::hash(crypto, hash_alg, &buf)?; Ok(()) } fn execute(&self, tpm: &mut Tpm2, session: &Session) -> Result { + // Copied out because `tpm` is borrowed mutably by the command calls below. + let crypto = *tpm.crypto(); let hash_alg = session.get_hash_alg(); let mut hash_list: Vec = Vec::new(); for branch in &self.branches { - let digest = compute_digest(branch, hash_alg)?; + let digest = compute_digest(&crypto, branch, hash_alg)?; hash_list.push(TPM2B_DIGEST { buffer: digest }); } tpm.PolicyOR(&sess_handle(session), &hash_list)?; @@ -598,16 +673,23 @@ impl PolicyAuthorize { } impl PolicyAssertion for PolicyAuthorize { - fn update_policy_digest(&self, hash_alg: TPM_ALG_ID, acc: &mut Vec) -> Result<(), TpmError> { - let key_name = self.authorizing_key.get_name()?; + fn update_policy_digest( + &self, + crypto: &CryptoProvider, + hash_alg: TPM_ALG_ID, + acc: &mut Vec, + ) -> Result<(), TpmError> { + let key_name = self.authorizing_key.get_name(crypto)?; // PolicyAuthorize resets the digest, then does PolicyUpdate - let hash_len = Crypto::hash(hash_alg, &[])?.len(); + let hash_len = Crypto::hash(crypto, hash_alg, &[])?.len(); *acc = vec![0u8; hash_len]; - policy_update(hash_alg, acc, TPM_CC::PolicyAuthorize, &key_name, &self.policy_ref) + policy_update(crypto, hash_alg, acc, TPM_CC::PolicyAuthorize, &key_name, &self.policy_ref) } fn execute(&self, tpm: &mut Tpm2, session: &Session) -> Result { - let key_name = self.authorizing_key.get_name()?; + // Copied out because `tpm` is borrowed mutably by the command calls below. + let crypto = *tpm.crypto(); + let key_name = self.authorizing_key.get_name(&crypto)?; // Load the authorizing key (OWNER hierarchy for valid tickets) let key_handle = tpm.LoadExternal( @@ -620,7 +702,7 @@ impl PolicyAssertion for PolicyAuthorize { let mut a_hash_data = Vec::new(); a_hash_data.extend_from_slice(&self.approved_policy); a_hash_data.extend_from_slice(&self.policy_ref); - let a_hash = Crypto::hash(self.authorizing_key.nameAlg, &a_hash_data)?; + let a_hash = Crypto::hash(&crypto, self.authorizing_key.nameAlg, &a_hash_data)?; let check_ticket = tpm.VerifySignature( &key_handle, &a_hash, &self.signature.signature, @@ -654,14 +736,19 @@ impl PolicyDuplicationSelect { } impl PolicyAssertion for PolicyDuplicationSelect { - fn update_policy_digest(&self, hash_alg: TPM_ALG_ID, acc: &mut Vec) -> Result<(), TpmError> { + fn update_policy_digest( + &self, + crypto: &CryptoProvider, + hash_alg: TPM_ALG_ID, + acc: &mut Vec, + ) -> Result<(), TpmError> { let mut arg2 = Vec::new(); if self.include_object { arg2.extend_from_slice(&self.object_name); } arg2.extend_from_slice(&self.new_parent_name); arg2.push(if self.include_object { 1 } else { 0 }); - policy_update(hash_alg, acc, TPM_CC::PolicyDuplicationSelect, &arg2, &[]) + policy_update(crypto, hash_alg, acc, TPM_CC::PolicyDuplicationSelect, &arg2, &[]) } fn execute(&self, tpm: &mut Tpm2, session: &Session) -> Result { diff --git a/TSS.Rust/src/tpm2_impl.rs b/TSS.Rust/src/tpm2_impl.rs index f80bd1df..3482721c 100644 --- a/TSS.Rust/src/tpm2_impl.rs +++ b/TSS.Rust/src/tpm2_impl.rs @@ -4,7 +4,7 @@ */ use crate::auth_session::Session; -use crate::crypto::Crypto; +use crate::crypto::{provider::CryptoProvider, Crypto}; use crate::device::TpmDevice; use crate::error::TpmError; use crate::tpm_buffer::{TpmBuffer, TpmMarshaller}; @@ -48,6 +48,13 @@ pub struct Tpm2 { /// The TPM device used for communication device: Box, + /// The crypto backend used for the host-side work a TPM session requires: deriving session + /// keys, computing command parameter hashes, and encrypting command parameters. + /// + /// This is held rather than passed per call because the generated command methods dispatch + /// through `&mut self` and have no parameter to carry it. + crypto: CryptoProvider, + /// Response code returned by the last executed command last_response_code: TPM_RC, @@ -120,10 +127,11 @@ pub struct Tpm2 { } impl Tpm2 { - /// Creates a new Tpm2 with the specified device - pub fn new(device: Box) -> Self { + /// Creates a new Tpm2 that performs its host-side crypto with `crypto`. + pub fn new(device: Box, crypto: CryptoProvider) -> Self { Tpm2 { device, + crypto, last_response_code: TPM_RC::SUCCESS, last_error: None, sessions: None, @@ -153,6 +161,20 @@ impl Tpm2 { } } + /// Creates a new Tpm2 that performs its host-side crypto with the built-in software backend. + #[cfg(feature = "software-crypto")] + pub fn with_software_crypto(device: Box) -> Self { + Self::new(device, crate::crypto::software_provider::SOFTWARE_PROVIDER) + } + + /// The crypto backend this instance was built with. + /// + /// Callers that need to compute a policy digest or a key name alongside a live TPM can pass + /// this to the corresponding `Crypto` entry point, so both agree on one backend. + pub fn crypto(&self) -> &CryptoProvider { + &self.crypto + } + /// Checks whether the response code is generated by the TSS.Rust implementation fn is_comm_medium_error(code: TPM_RC) -> bool { // Check if error is in the TSS communication layer rather than TPM itself @@ -279,7 +301,7 @@ impl Tpm2 { } // Roll nonces - self.roll_nonces(); + self.roll_nonces()?; // Prepare parameter encryption sessions self.prepare_param_encryption_sessions(); @@ -336,7 +358,7 @@ impl Tpm2 { } if let Some(ref mut cp_hash) = self.cp_hash { - cp_hash.digest = Crypto::hash(cp_hash.hashAlg, &cp_hash_data)?; + cp_hash.digest = Crypto::hash(&self.crypto, cp_hash.hashAlg, &cp_hash_data)?; self.clear_invocation_state(); self.sessions = None; self.cp_hash = None; @@ -345,7 +367,7 @@ impl Tpm2 { if self.audit_command { self.audit_cp_hash.digest = - Crypto::hash(self.command_audit_hash.hashAlg, &cp_hash_data)?; + Crypto::hash(&self.crypto, self.command_audit_hash.hashAlg, &cp_hash_data)?; } } @@ -527,7 +549,7 @@ impl Tpm2 { extend_data.extend_from_slice(&self.command_audit_hash.digest); extend_data.extend_from_slice(&self.audit_cp_hash.digest); extend_data.extend_from_slice(&rp_hash); - if let Ok(new_digest) = Crypto::hash(hash_alg, &extend_data) { + if let Ok(new_digest) = Crypto::hash(&self.crypto, hash_alg, &extend_data) { self.command_audit_hash.digest = new_digest; } } @@ -684,12 +706,14 @@ impl Tpm2 { salt: &[u8], ) -> Result { let nonce_size = Crypto::digestSize(auth_hash); - let nonce_caller = Crypto::get_random(nonce_size); + let nonce_caller = Crypto::get_random(&self.crypto, nonce_size)?; // For salted sessions, encrypt the salt to the tpmKey's public area let encrypted_salt = if !salt.is_empty() { let pub_info = self.ReadPublic(tpm_key)?; - pub_info.outPublic.encrypt_session_salt(salt)? + pub_info + .outPublic + .encrypt_session_salt(&self.crypto, salt)? } else { Vec::new() }; @@ -705,6 +729,7 @@ impl Tpm2 { )?; Session::from_tpm_response( + &self.crypto, resp.handle, session_type, auth_hash, @@ -727,15 +752,16 @@ impl Tpm2 { // Additional helper methods to support the dispatch_command and process_response implementations /// Roll nonces for all non-PWAP sessions - fn roll_nonces(&mut self) { + fn roll_nonces(&mut self) -> Result<(), TpmError> { if let Some(ref mut sessions) = self.sessions { for session in sessions.iter_mut() { if !session.is_pwap() { let nonce_size = session.sess_out.nonce.len(); - session.sess_in.nonce = Crypto::get_random(nonce_size.max(16)); + session.sess_in.nonce = Crypto::get_random(&self.crypto, nonce_size.max(16))?; } } } + Ok(()) } /// Clear the current invocation state @@ -848,8 +874,9 @@ impl Tpm2 { if session.session_type == TPM_SE::HMAC || session.needs_hmac { // Calculate HMAC based on CpHash - let cp_hash = Crypto::hash(session.get_hash_alg(), &cp_hash_data)?; + let cp_hash = Crypto::hash(&self.crypto, session.get_hash_alg(), &cp_hash_data)?; auth_cmd.hmac = session.get_auth_hmac( + &self.crypto, cp_hash, true, &self.nonce_tpm_dec, @@ -980,7 +1007,7 @@ impl Tpm2 { param_buf.check_status()?; // Perform encryption/decryption - let result = sess.param_xcrypt(&to_xcrypt, is_request)?; + let result = sess.param_xcrypt(&self.crypto, &to_xcrypt, is_request)?; // Write the result back into the buffer param_buf.set_current_pos(arr_pos); @@ -1015,7 +1042,7 @@ impl Tpm2 { let data_to_hash = &resp_buf.buffer() [rp_hash_data_pos..(rp_hash_data_pos + rp_header_size + resp_params_size)]; - Crypto::hash(hash_alg, data_to_hash) + Crypto::hash(&self.crypto, hash_alg, data_to_hash) } /// Process response sessions @@ -1082,11 +1109,12 @@ impl Tpm2 { let data_to_hash = &resp_buf.buffer() [rp_hash_data_pos..(rp_hash_data_pos + rp_header_size + resp_params_size)]; - Crypto::hash(session.get_hash_alg(), data_to_hash)? + Crypto::hash(&self.crypto, session.get_hash_alg(), data_to_hash)? }; rp_ready = true; let expected_hmac = session.get_auth_hmac( + &self.crypto, rp_hash, false, &nonce_tpm_dec, @@ -1286,12 +1314,13 @@ impl Tpm2 { } } -/// Factory function to create a new TPM implementation based on the available platform -pub fn create_tpm() -> Tpm2 { +/// Factory function to create a new TPM implementation based on the available platform, +/// performing its host-side crypto with `crypto`. +pub fn create_tpm_with_crypto(crypto: CryptoProvider) -> Tpm2 { #[cfg(target_os = "windows")] { use crate::device::TpmTbsDevice; - Tpm2::new(Box::new(TpmTbsDevice::new())) + Tpm2::new(Box::new(TpmTbsDevice::new()), crypto) } #[cfg(not(target_os = "windows"))] { @@ -1300,17 +1329,28 @@ pub fn create_tpm() -> Tpm2 { // Try to create a TBS device first (for Linux/Unix), falling back to TCP simulator let mut tbs_device = TpmTbsDevice::new(); match tbs_device.connect() { - Ok(_) => Tpm2::new(tbs_device), + Ok(_) => Tpm2::new(tbs_device, crypto), Err(_) => { // Fall back to TCP simulator let tcp_device = TpmTcpDevice::new("127.0.0.1".to_string(), 2321); - Tpm2::new(Box::new(tcp_device)) + Tpm2::new(Box::new(tcp_device), crypto) } } } } -/// Factory function to create a TPM implementation with a custom device +/// Factory function to create a new TPM implementation based on the available platform, using +/// the built-in software crypto backend. +#[cfg(feature = "software-crypto")] +pub fn create_tpm() -> Tpm2 { + create_tpm_with_crypto(crate::crypto::software_provider::SOFTWARE_PROVIDER) +} + +/// Factory function to create a TPM implementation with a custom device, using the built-in +/// software crypto backend. +/// +/// To supply a different backend, call [`Tpm2::new`] directly. +#[cfg(feature = "software-crypto")] pub fn create_tpm_with_device(device: Box) -> Tpm2 { - Tpm2::new(device) + Tpm2::with_software_crypto(device) } diff --git a/TSS.Rust/src/tpm_type_extensions.rs b/TSS.Rust/src/tpm_type_extensions.rs index b65bbc6a..0d9269d3 100644 --- a/TSS.Rust/src/tpm_type_extensions.rs +++ b/TSS.Rust/src/tpm_type_extensions.rs @@ -1,4 +1,4 @@ -use crate::crypto::{Crypto, RsaKeyParts, RSA_DEFAULT_EXPONENT}; +use crate::crypto::{provider::CryptoProvider, Crypto, RsaKeyParts, RSA_DEFAULT_EXPONENT}; use crate::error::TpmError; use crate::tpm2_helpers::int_to_tpm; use crate::tpm_buffer::*; @@ -15,11 +15,11 @@ pub struct ActivationData { } impl TPMT_PUBLIC { - pub fn get_name(&self) -> Result, TpmError> { + pub fn get_name(&self, crypto: &CryptoProvider) -> Result, TpmError> { let mut buffer = TpmBuffer::new(None); self.toTpm(&mut buffer)?; - let mut pub_hash = Crypto::hash(self.nameAlg, buffer.trim())?; + let mut pub_hash = Crypto::hash(crypto, self.nameAlg, buffer.trim())?; let hash_alg = int_to_tpm(self.nameAlg.get_value()); pub_hash.splice(0..0, hash_alg.iter().cloned()); @@ -49,6 +49,7 @@ impl TPMT_PUBLIC { pub fn validate_certify( &self, + crypto: &CryptoProvider, certified_key: &TPMT_PUBLIC, nonce: &[u8], certify_response: &CertifyResponse, @@ -57,7 +58,12 @@ impl TPMT_PUBLIC { let signature_hash_alg = if let Some(TPMU_SIGNATURE::rsassa(signature)) = &certify_response.signature { signature.hash } else { - return Crypto::validate_signature(self, Vec::new(), &certify_response.signature); + return Crypto::validate_signature( + crypto, + self, + Vec::new(), + &certify_response.signature, + ); }; if key_hash_alg != signature_hash_alg { return Ok(false); @@ -74,7 +80,7 @@ impl TPMT_PUBLIC { } if let Some(TPMU_ATTEST::certify(quote_info)) = &attest.attested { - if (quote_info.name != certified_key.get_name()?) { + if (quote_info.name != certified_key.get_name(crypto)?) { return Ok(false); } } else { @@ -88,9 +94,9 @@ impl TPMT_PUBLIC { buffer.trim().to_vec() }; - let signed_blob_hash = Crypto::hash(signature_hash_alg, &signed_blob)?; + let signed_blob_hash = Crypto::hash(crypto, signature_hash_alg, &signed_blob)?; - Crypto::validate_signature(self, signed_blob_hash, &certify_response.signature) + Crypto::validate_signature(crypto, self, signed_blob_hash, &certify_response.signature) } /// Implements the TPM2_MakeCredential command functionality: @@ -100,6 +106,7 @@ impl TPMT_PUBLIC { /// 4. Encrypt credential + create integrity HMAC pub fn create_activation( &self, + crypto: &CryptoProvider, credential: &[u8], activated_name: &[u8], ) -> Result { @@ -120,7 +127,7 @@ impl TPMT_PUBLIC { // The seed is the same size as the nameAlg digest, per TPM 2.0 Part 1 "Credential // Protection". TSS.NET does the same in TpmKey.CreateActivationCredentials. - let mut seed = Crypto::get_random(Crypto::digestSize(self.nameAlg)); + let mut seed = Crypto::get_random(crypto, Crypto::digestSize(self.nameAlg))?; // Get RSA public key components for encrypting the seed let rsa_pub_n = if let Some(TPMU_PUBLIC_ID::rsa(unique)) = &self.unique { @@ -131,6 +138,7 @@ impl TPMT_PUBLIC { // Encrypt seed with label "IDENTITY" using OAEP with the key's nameAlg let secret = Crypto::rsa_oaep_encrypt( + crypto, rsa_pub_n, &RSA_DEFAULT_EXPONENT, self.nameAlg, @@ -142,6 +150,7 @@ impl TPMT_PUBLIC { // 1. Create the symmetric key via KDFa let mut sym_key = Crypto::kdfa( + crypto, self.nameAlg, &seed, "STORAGE", @@ -157,6 +166,7 @@ impl TPMT_PUBLIC { // 3. Encrypt the credential let enc_credential = Crypto::cfb_xcrypt( + crypto, true, &sym_key, &[0u8; 16], // Zero IV @@ -165,6 +175,7 @@ impl TPMT_PUBLIC { // 4. Generate the integrity HMAC key let mut hmac_key = Crypto::kdfa( + crypto, self.nameAlg, &seed, "INTEGRITY", @@ -179,6 +190,7 @@ impl TPMT_PUBLIC { to_hmac.extend_from_slice(activated_name); let integrity_hmac = Crypto::hmac( + crypto, self.nameAlg, &hmac_key, &to_hmac @@ -198,6 +210,7 @@ impl TPMT_PUBLIC { // Performs RSA encryption of the given data using the public key pub fn encrypt( &self, + crypto: &CryptoProvider, data: &[u8], ) -> Result, TpmError> { // Verify we have an RSA key with correct parameters @@ -224,6 +237,7 @@ impl TPMT_PUBLIC { // Encrypt the data using OAEP padding with the key's nameAlg Crypto::rsa_oaep_encrypt( + crypto, rsa_pub_n, &RSA_DEFAULT_EXPONENT, self.nameAlg, @@ -234,7 +248,11 @@ impl TPMT_PUBLIC { /// Encrypt a session salt for use with salted auth sessions. /// Uses RSA-OAEP with the nameAlg hash and label "SECRET\0". - pub fn encrypt_session_salt(&self, salt: &[u8]) -> Result, TpmError> { + pub fn encrypt_session_salt( + &self, + crypto: &CryptoProvider, + salt: &[u8], + ) -> Result, TpmError> { let rsa_pub_n = if let Some(TPMU_PUBLIC_ID::rsa(unique)) = &self.unique { &unique.buffer } else { @@ -242,6 +260,7 @@ impl TPMT_PUBLIC { }; Crypto::rsa_oaep_encrypt( + crypto, rsa_pub_n, &RSA_DEFAULT_EXPONENT, self.nameAlg, @@ -379,14 +398,14 @@ impl std::fmt::Display for TPM_HANDLE { impl TSS_KEY { /// Generate an RSA key pair in software. /// Populates publicPart.unique with the modulus and privatePart with the first prime (p). - pub fn create_key(&mut self) -> Result<(), TpmError> { + pub fn create_key(&mut self, crypto: &CryptoProvider) -> Result<(), TpmError> { let key_bits = if let Some(TPMU_PUBLIC_PARMS::rsaDetail(ref params)) = self.publicPart.parameters { params.keyBits as usize } else { return Err(TpmError::GenericError("Only RSA key creation is supported".to_string())); }; - let key = Crypto::rsa_generate_keypair(key_bits)?; + let key = Crypto::rsa_generate_keypair(crypto, key_bits)?; // Store modulus (n) in publicPart.unique self.publicPart.unique = Some(TPMU_PUBLIC_ID::rsa(TPM2B_PUBLIC_KEY_RSA { buffer: key.modulus })); @@ -400,7 +419,12 @@ impl TSS_KEY { /// Sign a digest using the software key (RSASSA-PKCS1-v1_5). /// `digest` should be the hash of the data to sign. /// Returns a TPMT_SIGNATURE with RSASSA scheme. - pub fn sign(&self, digest: &[u8], hash_alg: TPM_ALG_ID) -> Result { + pub fn sign( + &self, + crypto: &CryptoProvider, + digest: &[u8], + hash_alg: TPM_ALG_ID, + ) -> Result { if !matches!(&self.publicPart.parameters, Some(TPMU_PUBLIC_PARMS::rsaDetail(_))) { return Err(TpmError::GenericError("Only RSA signing is supported".to_string())); } @@ -417,7 +441,7 @@ impl TSS_KEY { prime: self.privatePart.clone(), }; - let sig_bytes = Crypto::rsa_pkcs1v15_sign(&key, hash_alg, digest)?; + let sig_bytes = Crypto::rsa_pkcs1v15_sign(crypto, &key, hash_alg, digest)?; Ok(TPMT_SIGNATURE { signature: Some(TPMU_SIGNATURE::rsassa(TPMS_SIGNATURE_RSASSA { @@ -428,9 +452,12 @@ impl TSS_KEY { } } -#[cfg(test)] +// The activation round trip is checked against a software endorsement key built with the `rsa` +// crate, so these tests only apply when the software provider is compiled in. +#[cfg(all(test, feature = "software-crypto"))] mod tests { use super::*; + use crate::crypto::software_provider::SOFTWARE_PROVIDER; use rand::rngs::OsRng; use rsa::traits::PublicKeyParts; use rsa::{Oaep, RsaPrivateKey}; @@ -505,8 +532,9 @@ mod tests { ))); } - let sym_key = Crypto::kdfa(name_alg, &seed, "STORAGE", activated_name, &[], 128)?; + let sym_key = Crypto::kdfa(&SOFTWARE_PROVIDER, name_alg, &seed, "STORAGE", activated_name, &[], 128)?; let hmac_key = Crypto::kdfa( + &SOFTWARE_PROVIDER, name_alg, &seed, "INTEGRITY", @@ -517,7 +545,8 @@ mod tests { let mut to_hmac = activation.credential_blob.encIdentity.clone(); to_hmac.extend_from_slice(activated_name); - if Crypto::hmac(name_alg, &hmac_key, &to_hmac)? != activation.credential_blob.integrityHMAC + if Crypto::hmac(&SOFTWARE_PROVIDER, name_alg, &hmac_key, &to_hmac)? + != activation.credential_blob.integrityHMAC { return Err(TpmError::GenericError( "Integrity HMAC mismatch".to_string(), @@ -525,6 +554,7 @@ mod tests { } let plaintext = Crypto::cfb_xcrypt( + &SOFTWARE_PROVIDER, false, &sym_key, &[0u8; 16], @@ -553,7 +583,11 @@ mod tests { let activated_name = activated_name(name_alg); let credential = b"credential to activate".to_vec(); - let activation = endorsement_public.create_activation(&credential, &activated_name)?; + let activation = endorsement_public.create_activation( + &SOFTWARE_PROVIDER, + &credential, + &activated_name, + )?; let recovered = activate_credential( &endorsement_private, name_alg, @@ -580,7 +614,11 @@ mod tests { endorsement_public.parameters = Some(TPMU_PUBLIC_PARMS::rsaDetail(parameters)); assert!(endorsement_public - .create_activation(b"credential", &activated_name(TPM_ALG_ID::SHA256)) + .create_activation( + &SOFTWARE_PROVIDER, + b"credential", + &activated_name(TPM_ALG_ID::SHA256) + ) .is_err()); Ok(()) From d5a68383ce3546be4abf5e9b01c696d23d1172aa Mon Sep 17 00:00:00 2001 From: Roee Kasher Date: Thu, 13 Aug 2026 17:02:41 +0300 Subject: [PATCH 08/13] Fix five crypto defects surfaced while reviewing the provider split (#6) None of these are regressions from the CryptoProvider work; the split simply made them visible by gathering the primitives into one place. AES-192 and AES-256 panicked. The CFB routine handed every key to Aes128::new regardless of length, and that constructor asserts on a key it cannot take, so a 24 or 32 byte key aborted the process. Dispatch on key length instead, and build the cipher with KeyInit::new_from_slice, which reports a bad length rather than panicking. All three variants share a 128 bit block, so the CFB loop itself is generic over the cipher and unchanged. Hashing an empty input returned zeros. `hash` short circuited on empty data and handed back a buffer of digestSize zero bytes, so hash(SHA256, &[]) gave zeros instead of e3b0c442..., and an unsupported algorithm returned Ok. The special case exists because three callers in policy.rs only wanted the digest length, which they obtained by hashing nothing and measuring the result. Give them Crypto::digest_size_checked and delete the special case. PolicyPcr with an empty pcrValues was reaching the wrong path for real, not just in theory. The RSA public exponent was ignored. Every operation assumed 65537, so a key declaring any other exponent was encrypted to, and verified against, the wrong key. Add TPMS_RSA_PARMS::exponent_bytes, which resolves the specification's zero encoding to 65537 at the point of use, and thread it through the five sites that needed it. Generation had the same defect from the other side: create_key ignored params.exponent, so requesting e=3 produced a 65537 key whose stored public area still claimed 3. RsaGenerateKeypairFn therefore takes the exponent and returns the one actually used. The resolution deliberately happens at each call site rather than by normalising the stored field. A key's Name is a digest over its public area, so rewriting exponent 0 to 65537 would change the Name of every default key and silently break every policy digest, ActivateCredential and Name comparison. exponent_bytes carries that reasoning in its doc comment. Signing did not check that the supplied prime divides the modulus. q was computed as n / p by truncating division, which yields a plausible looking but wrong q for any p that is not a factor, and the resulting signature fails to verify with no indication why. Reject a non-zero remainder. KDFa returned an empty key when asked for zero bits. The loop is driven by the output length, so bits = 0 exits immediately with Ok(vec![]), and callers used that empty vector as key material. Callers reached that state by sizing their request as digestSize(alg) * 8, which is zero for anything that is not a hash. Reject the request in KDFa, and size those requests with digest_size_checked so the failure names the actual problem. Crypto::digestSize keeps returning zero, because TPMT_HA unmarshalling depends on TPM_ALG_NULL having a zero length digest. Eleven tests cover the fixes. Nothing in the existing suite would have caught any of them. --- TSS.Rust/src/auth_session.rs | 2 +- TSS.Rust/src/crypto/mod.rs | 216 +++++++++++++++++++++-- TSS.Rust/src/crypto/provider.rs | 5 +- TSS.Rust/src/crypto/software_provider.rs | 82 ++++++--- TSS.Rust/src/policy.rs | 6 +- TSS.Rust/src/tpm2_impl.rs | 2 +- TSS.Rust/src/tpm_type_extensions.rs | 104 +++++++++-- 7 files changed, 354 insertions(+), 63 deletions(-) diff --git a/TSS.Rust/src/auth_session.rs b/TSS.Rust/src/auth_session.rs index cfae20aa..f5866cfd 100644 --- a/TSS.Rust/src/auth_session.rs +++ b/TSS.Rust/src/auth_session.rs @@ -136,7 +136,7 @@ impl Session { } hmac_key.extend_from_slice(salt); - let hash_bits = Crypto::digestSize(self.hash_alg) * 8; + let hash_bits = Crypto::digest_size_checked(self.hash_alg)? * 8; self.session_key = Crypto::kdfa( crypto, self.hash_alg, diff --git a/TSS.Rust/src/crypto/mod.rs b/TSS.Rust/src/crypto/mod.rs index a9ce8778..b19ce4fd 100644 --- a/TSS.Rust/src/crypto/mod.rs +++ b/TSS.Rust/src/crypto/mod.rs @@ -19,19 +19,25 @@ pub mod software_provider; use crate::{error::TpmError, tpm_types::*}; use provider::CryptoProvider; -/// The RSA public exponent used by every key this library creates or consumes (65537, "F4"). +/// The RSA public exponent the TPM 2.0 specification defines as the default (65537, "F4"). /// -/// A TPM encodes this value as zero in `TPMS_RSA_PARMS::exponent`, so it never travels on the -/// wire and has to be supplied by the caller. +/// `TPMS_RSA_PARMS::exponent` encodes this value as zero, so it never travels on the wire. +/// Resolve a stored zero with `TPMS_RSA_PARMS::exponent_bytes` rather than reaching for this +/// constant directly, so that a key declaring a different exponent is honoured. pub const RSA_DEFAULT_EXPONENT: [u8; 3] = [0x01, 0x00, 0x01]; -/// RSA private key material in the form `TSS_KEY` persists it: the modulus and the first prime. +/// RSA private key material in the form `TSS_KEY` persists it: the modulus and the first prime, +/// plus the public exponent needed to reconstruct the key. /// /// The second prime is recovered by dividing the modulus by the first, so it is not stored. #[derive(Clone, Debug)] pub struct RsaKeyParts { pub modulus: Vec, pub prime: Vec, + /// The public exponent, big-endian and without leading zeros. Callers holding a + /// `TPMS_RSA_PARMS` should populate this with `TPMS_RSA_PARMS::exponent_bytes`, which + /// resolves the specification's zero-means-65537 encoding. + pub exponent: Vec, } pub struct Crypto; @@ -40,6 +46,14 @@ impl Crypto { /// The length in bytes of a digest produced by `alg`, or zero if `alg` is not a hash. /// /// This is fixed by the TPM 2.0 specification, so it does not depend on the backend. + /// + /// Returning zero rather than an error is deliberate, and there are two reasons not to + /// "fix" it. `TPMT_HA` unmarshalling calls this to decide how many digest bytes to read, + /// and a `TPMT_HA` selected by `TPM_ALG_NULL` carries no digest at all, so zero is the + /// correct answer there rather than a failure. That call site also lives in a generated + /// file, which cannot be hand edited, and it has no error path to return one through. + /// + /// Every other caller wants `digest_size_checked`, which turns the zero into an error. // The function is called from an auto-generated file that expects this specific (non snake_cased) name #[allow(non_snake_case)] pub fn digestSize(alg: TPM_ALG_ID) -> usize { @@ -53,6 +67,21 @@ impl Crypto { } } + /// The length in bytes of a digest produced by `alg`, or an error if `alg` is not a hash. + /// + /// This is the variant to reach for by default. `digestSize` answers zero for a non-hash + /// algorithm, which silently produces an empty seed, key or nonce wherever the result sizes + /// a buffer. Use `digestSize` only where a zero length is a legitimate answer, which in + /// practice means `TPMT_HA` unmarshalling. + pub fn digest_size_checked(alg: TPM_ALG_ID) -> Result { + match Self::digestSize(alg) { + 0 => Err(TpmError::NotSupported(format!( + "Not a hash algorithm: {alg:?}" + ))), + size => Ok(size), + } + } + // Hash a byte buffer using the specified algorithm pub fn hash( provider: &CryptoProvider, @@ -98,12 +127,18 @@ impl Crypto { (provider.rsa.pkcs1v15_verify)(modulus, exponent, hash_alg, digest, signature) } - /// Generate an RSA key pair, returning the modulus and the first prime. + /// Generate an RSA key pair with the given public exponent, returning the modulus and the + /// first prime. + /// + /// `exponent` is big-endian. Callers holding a `TPMS_RSA_PARMS` should pass + /// `TPMS_RSA_PARMS::exponent_bytes`, which resolves the zero-means-65537 encoding. A backend + /// that cannot honour an arbitrary exponent must reject it rather than substitute its own. pub fn rsa_generate_keypair( provider: &CryptoProvider, key_bits: usize, + exponent: &[u8], ) -> Result { - (provider.rsa.generate_keypair)(key_bits) + (provider.rsa.generate_keypair)(key_bits, exponent) } /// Sign an already computed digest with RSASSA-PKCS1-v1_5. @@ -122,11 +157,14 @@ impl Crypto { signed_blob_hash: Vec, signature: &Option, ) -> Result { - if !matches!(&public_key.parameters, Some(TPMU_PUBLIC_PARMS::rsaDetail(_))) { - return Err(TpmError::NotSupported( - "ValidateSignature: Only RSA is supported".to_string(), - )); - }; + let rsa_params = + if let Some(TPMU_PUBLIC_PARMS::rsaDetail(params)) = &public_key.parameters { + params + } else { + return Err(TpmError::NotSupported( + "ValidateSignature: Only RSA is supported".to_string(), + )); + }; let signature = if let Some(TPMU_SIGNATURE::rsassa(signature)) = &signature { signature @@ -144,7 +182,7 @@ impl Crypto { )); }; - let expected_digest_size = Self::digestSize(signature.hash); + let expected_digest_size = Self::digest_size_checked(signature.hash)?; if signed_blob_hash.len() != expected_digest_size { return Err(TpmError::InvalidArraySize(format!( "ValidateSignature: digest length {} does not match {:?} length {}", @@ -157,7 +195,7 @@ impl Crypto { Self::rsa_pkcs1v15_verify( provider, rsa_pub_key, - &RSA_DEFAULT_EXPONENT, + &rsa_params.exponent_bytes(), signature.hash, &signed_blob_hash, &signature.sig, @@ -174,6 +212,14 @@ impl Crypto { context_v: &[u8], bits: usize, ) -> Result, TpmError> { + // Zero bits would make the loop below exit immediately and hand back an empty key, which + // every caller would then use as if it were real key material. + if bits == 0 { + return Err(TpmError::InvalidArraySize( + "KDFa was asked to produce zero bits of key material".to_string(), + )); + } + let bytes_needed = bits.div_ceil(8); let mut result = Vec::new(); let mut counter = 1u32; @@ -308,7 +354,7 @@ mod tests { #[test] fn rsa_sign_round_trips_through_verify() -> Result<(), TpmError> { - let key = Crypto::rsa_generate_keypair(&SOFTWARE_PROVIDER, 2048)?; + let key = Crypto::rsa_generate_keypair(&SOFTWARE_PROVIDER, 2048, &RSA_DEFAULT_EXPONENT)?; let digest = Sha256::digest(b"software key signing regression").to_vec(); let signature = @@ -330,6 +376,27 @@ mod tests { let key = RsaKeyParts { modulus: vec![0xff; 256], prime: vec![0u8; 128], + exponent: RSA_DEFAULT_EXPONENT.to_vec(), + }; + + assert!(Crypto::rsa_pkcs1v15_sign( + &SOFTWARE_PROVIDER, + &key, + TPM_ALG_ID::SHA256, + &[0u8; 32] + ) + .is_err()); + } + + #[test] + fn rsa_sign_rejects_a_prime_that_does_not_divide_the_modulus() { + // `from_p_q` recomputes the modulus as `p * q` rather than checking it against the one + // supplied, so a prime that does not divide the modulus exactly would otherwise yield a + // key with a silently different modulus whose signatures could never verify. + let key = RsaKeyParts { + modulus: vec![0xff; 256], + prime: vec![0xfe; 128], + exponent: RSA_DEFAULT_EXPONENT.to_vec(), }; assert!(Crypto::rsa_pkcs1v15_sign( @@ -340,4 +407,125 @@ mod tests { ) .is_err()); } + + #[test] + fn rsa_round_trips_with_a_non_default_exponent() -> Result<(), TpmError> { + // Generating with an exponent other than the default proves that generation, signing and + // verification all read the caller's exponent instead of assuming 65537. + let exponent: [u8; 3] = [0x00, 0x00, 0x03]; + let key = Crypto::rsa_generate_keypair(&SOFTWARE_PROVIDER, 2048, &exponent)?; + assert_eq!(key.exponent, vec![0x03]); + + let digest = Sha256::digest(b"non default exponent").to_vec(); + let signature = + Crypto::rsa_pkcs1v15_sign(&SOFTWARE_PROVIDER, &key, TPM_ALG_ID::SHA256, &digest)?; + + assert!(Crypto::rsa_pkcs1v15_verify( + &SOFTWARE_PROVIDER, + &key.modulus, + &key.exponent, + TPM_ALG_ID::SHA256, + &digest, + &signature, + )?); + + // The default exponent must not verify a signature made with this key. + assert!(!Crypto::rsa_pkcs1v15_verify( + &SOFTWARE_PROVIDER, + &key.modulus, + &RSA_DEFAULT_EXPONENT, + TPM_ALG_ID::SHA256, + &digest, + &signature, + )?); + Ok(()) + } + + #[test] + fn hash_of_empty_input_is_the_real_digest() -> Result<(), TpmError> { + // The empty string has a well known SHA-256 digest. Returning zeros of the right length + // instead looks plausible but never matches what a TPM computes. + let expected: [u8; 32] = [ + 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, + 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, + 0x78, 0x52, 0xb8, 0x55, + ]; + assert_eq!( + Crypto::hash(&SOFTWARE_PROVIDER, TPM_ALG_ID::SHA256, &[])?, + expected + ); + Ok(()) + } + + #[test] + fn hash_of_empty_input_still_rejects_an_unsupported_algorithm() { + assert!(Crypto::hash(&SOFTWARE_PROVIDER, TPM_ALG_ID::NULL, &[]).is_err()); + } + + #[test] + fn digest_size_checked_rejects_a_non_hash_algorithm() { + assert_eq!( + Crypto::digest_size_checked(TPM_ALG_ID::SHA256).ok(), + Some(32) + ); + assert!(Crypto::digest_size_checked(TPM_ALG_ID::NULL).is_err()); + assert!(Crypto::digest_size_checked(TPM_ALG_ID::RSA).is_err()); + } + + #[test] + fn kdfa_rejects_a_request_for_zero_bits() { + // Sizing a KDFa request from `digestSize` of a non-hash algorithm used to ask for zero + // bits, and KDFa answered with an empty key instead of failing. + assert!(Crypto::kdfa( + &SOFTWARE_PROVIDER, + TPM_ALG_ID::SHA256, + b"key", + "ATH", + &[], + &[], + 0 + ) + .is_err()); + } + + #[test] + fn kdfa_produces_the_requested_length() -> Result<(), TpmError> { + let derived = Crypto::kdfa( + &SOFTWARE_PROVIDER, + TPM_ALG_ID::SHA256, + b"key", + "ATH", + &[], + &[], + 256, + )?; + assert_eq!(derived.len(), 32); + Ok(()) + } + + #[test] + fn aes_cfb_round_trips_at_every_key_size() -> Result<(), TpmError> { + // AES-192 and AES-256 keys used to be handed to an AES-128 cipher, which panicked. + let iv = [0x5au8; 16]; + // Deliberately not a multiple of the block size, to cover the trailing partial block. + let plaintext = b"CFB spans partial blocks too"; + + for key_size in [16usize, 24, 32] { + let key = vec![0xa5u8; key_size]; + let ciphertext = Crypto::cfb_xcrypt(&SOFTWARE_PROVIDER, true, &key, &iv, plaintext)?; + assert_eq!(ciphertext.len(), plaintext.len()); + assert_ne!(ciphertext.as_slice(), plaintext.as_slice()); + + let recovered = Crypto::cfb_xcrypt(&SOFTWARE_PROVIDER, false, &key, &iv, &ciphertext)?; + assert_eq!(recovered.as_slice(), plaintext.as_slice()); + } + Ok(()) + } + + #[test] + fn aes_cfb_rejects_an_unsupported_key_size() { + assert!( + Crypto::cfb_xcrypt(&SOFTWARE_PROVIDER, true, &[0u8; 20], &[0u8; 16], b"data").is_err() + ); + } } diff --git a/TSS.Rust/src/crypto/provider.rs b/TSS.Rust/src/crypto/provider.rs index cb16a125..8e2c539a 100644 --- a/TSS.Rust/src/crypto/provider.rs +++ b/TSS.Rust/src/crypto/provider.rs @@ -54,7 +54,8 @@ pub type RsaPkcs1v15VerifyFn = fn( ) -> Result; /// Signature of [`RsaOps::generate_keypair`]. -pub type RsaGenerateKeypairFn = fn(key_bits: usize) -> Result; +pub type RsaGenerateKeypairFn = + fn(key_bits: usize, exponent: &[u8]) -> Result; /// Signature of [`RsaOps::pkcs1v15_sign`]. pub type RsaPkcs1v15SignFn = @@ -110,7 +111,7 @@ impl RsaOps { Self { oaep_encrypt: |_, _, _, _, _| Err(unimplemented("RSA-OAEP encryption")), pkcs1v15_verify: |_, _, _, _, _| Err(unimplemented("RSA PKCS#1 v1.5 verification")), - generate_keypair: |_| Err(unimplemented("RSA key generation")), + generate_keypair: |_, _| Err(unimplemented("RSA key generation")), pkcs1v15_sign: |_, _, _| Err(unimplemented("RSA PKCS#1 v1.5 signing")), } } diff --git a/TSS.Rust/src/crypto/software_provider.rs b/TSS.Rust/src/crypto/software_provider.rs index bb62eedb..52aa0803 100644 --- a/TSS.Rust/src/crypto/software_provider.rs +++ b/TSS.Rust/src/crypto/software_provider.rs @@ -6,12 +6,12 @@ //! provider instead. use super::provider::{CryptoProvider, RsaOps}; -use super::{Crypto, RsaKeyParts, RSA_DEFAULT_EXPONENT}; +use super::{Crypto, RsaKeyParts}; use crate::{error::TpmError, tpm_types::TPM_ALG_ID}; -use aes::Aes128; +use aes::{Aes128, Aes192, Aes256}; use cipher::generic_array::GenericArray; -use cipher::{BlockEncrypt, KeyInit}; +use cipher::{BlockEncrypt, BlockSizeUser, KeyInit}; use hmac::{Hmac, Mac}; use rand::{rngs::OsRng, RngCore}; use rsa::traits::{PrivateKeyParts, PublicKeyParts}; @@ -35,11 +35,6 @@ pub static SOFTWARE_PROVIDER: CryptoProvider = CryptoProvider { }; fn hash(alg: TPM_ALG_ID, data: &[u8]) -> Result, TpmError> { - // If the data is empty, return an empty digest of correct size - if data.is_empty() { - return Ok(vec![0; Crypto::digestSize(alg)]); - } - let digest = match alg { TPM_ALG_ID::SHA1 => { let mut hasher = Sha1::new(); @@ -196,8 +191,9 @@ fn rsa_pkcs1v15_verify( Ok(rsa_key.verify(scheme, digest, signature).is_ok()) } -fn rsa_generate_keypair(key_bits: usize) -> Result { - let priv_key = RsaPrivateKey::new(&mut OsRng, key_bits) +fn rsa_generate_keypair(key_bits: usize, exponent: &[u8]) -> Result { + let exponent_value = BigUint::from_bytes_be(exponent); + let priv_key = RsaPrivateKey::new_with_exp(&mut OsRng, key_bits, &exponent_value) .map_err(|e| TpmError::GenericError(format!("RSA key generation failed: {}", e)))?; let prime = priv_key @@ -208,6 +204,7 @@ fn rsa_generate_keypair(key_bits: usize) -> Result { Ok(RsaKeyParts { modulus: priv_key.n().to_bytes_be(), prime: prime.to_bytes_be(), + exponent: priv_key.e().to_bytes_be(), }) } @@ -229,8 +226,19 @@ fn rsa_pkcs1v15_sign( let modulus = BigUint::from_bytes_be(&key.modulus); let first_prime = BigUint::from_bytes_be(&key.prime); + + // Integer division truncates, and `from_p_q` recomputes the modulus as `p * q` rather than + // checking it against the one supplied. Without this guard a prime that does not divide the + // modulus exactly would silently produce a key with a different modulus, whose signatures + // could never verify against the stored public key. + if (&modulus % &first_prime) != BigUint::from(0u32) { + return Err(TpmError::InvalidArraySize( + "RSA private key prime does not divide the modulus".to_string(), + )); + } + let second_prime = &modulus / &first_prime; - let exponent = BigUint::from_bytes_be(&RSA_DEFAULT_EXPONENT); + let exponent = BigUint::from_bytes_be(&key.exponent); let priv_key = RsaPrivateKey::from_p_q(first_prime, second_prime, exponent) .map_err(|e| TpmError::GenericError(format!("Failed to reconstruct RSA key: {}", e)))?; @@ -245,44 +253,60 @@ fn aes_cfb(encrypt: bool, key: &[u8], iv: &[u8], data: &[u8]) -> Result, return Ok(Vec::new()); } - if key.len() != 16 && key.len() != 24 && key.len() != 32 { - return Err(TpmError::InvalidArraySize( - "Invalid AES key length".to_string(), - )); + // The key length selects the AES variant. All three share a 128 bit block, so the mode + // itself is identical; only the cipher differs. + match key.len() { + 16 => aes_cfb_with::(encrypt, key, iv, data), + 24 => aes_cfb_with::(encrypt, key, iv, data), + 32 => aes_cfb_with::(encrypt, key, iv, data), + other => Err(TpmError::InvalidArraySize(format!( + "Invalid AES key length: {other} bytes" + ))), } +} - if iv.len() != 16 { - return Err(TpmError::InvalidArraySize("IV must be 16 bytes".to_string())); +/// CFB mode over a full block width, built on `C`'s raw block encryption. +/// +/// CFB encrypts the feedback value in both directions, so only the block encryption of `C` is +/// needed even when decrypting. +fn aes_cfb_with(encrypt: bool, key: &[u8], iv: &[u8], data: &[u8]) -> Result, TpmError> +where + C: BlockEncrypt + BlockSizeUser + KeyInit, +{ + let cipher = C::new_from_slice(key) + .map_err(|_| TpmError::InvalidArraySize("Invalid AES key length".to_string()))?; + + let mut feedback = GenericArray::::default(); + let block_size = feedback.len(); + if iv.len() != block_size { + return Err(TpmError::InvalidArraySize(format!( + "IV must be {block_size} bytes" + ))); } + feedback.copy_from_slice(iv); - let cipher = Aes128::new(GenericArray::from_slice(key)); let mut result = Vec::with_capacity(data.len()); - let mut feedback = *GenericArray::from_slice(iv); - for chunk in data.chunks(16) { + for chunk in data.chunks(block_size) { // Encrypt the feedback (IV or previous ciphertext) - let mut encrypted_feedback = feedback; + let mut encrypted_feedback = feedback.clone(); cipher.encrypt_block(&mut encrypted_feedback); + // The next feedback value is the ciphertext either way: on encryption that is the + // output, on decryption it is the input. + let mut ct_block = GenericArray::::default(); if encrypt { - // CFB encrypt: ciphertext = plaintext XOR encrypt(feedback) - // Next feedback = ciphertext - let mut ct_block = [0u8; 16]; for (i, &b) in chunk.iter().enumerate() { ct_block[i] = b ^ encrypted_feedback[i]; result.push(ct_block[i]); } - feedback.copy_from_slice(&ct_block); } else { - // CFB decrypt: plaintext = ciphertext XOR encrypt(feedback) - // Next feedback = ciphertext (input) - let mut ct_block = [0u8; 16]; ct_block[..chunk.len()].copy_from_slice(chunk); for (i, &b) in chunk.iter().enumerate() { result.push(b ^ encrypted_feedback[i]); } - feedback.copy_from_slice(&ct_block); } + feedback = ct_block; } result.truncate(data.len()); diff --git a/TSS.Rust/src/policy.rs b/TSS.Rust/src/policy.rs index 0c82b9a1..5becfd2b 100644 --- a/TSS.Rust/src/policy.rs +++ b/TSS.Rust/src/policy.rs @@ -127,7 +127,7 @@ pub(crate) fn compute_digest( assertions: &[Box], hash_alg: TPM_ALG_ID, ) -> Result, TpmError> { - let hash_len = Crypto::hash(crypto, hash_alg, &[])?.len(); + let hash_len = Crypto::digest_size_checked(hash_alg)?; let mut accumulator = vec![0u8; hash_len]; for assertion in assertions { assertion.update_policy_digest(crypto, hash_alg, &mut accumulator)?; @@ -627,7 +627,7 @@ impl PolicyAssertion for PolicyOr { acc: &mut Vec, ) -> Result<(), TpmError> { // PolicyOR: accumulator = H(0...0 || TPM_CC_PolicyOR || digest1 || digest2 || ...) - let hash_len = Crypto::hash(crypto, hash_alg, &[])?.len(); + let hash_len = Crypto::digest_size_checked(hash_alg)?; let mut buf = Vec::new(); buf.extend_from_slice(&vec![0u8; hash_len]); // reset to zero buf.extend_from_slice(&TPM_CC::PolicyOR.get_value().to_be_bytes()); @@ -681,7 +681,7 @@ impl PolicyAssertion for PolicyAuthorize { ) -> Result<(), TpmError> { let key_name = self.authorizing_key.get_name(crypto)?; // PolicyAuthorize resets the digest, then does PolicyUpdate - let hash_len = Crypto::hash(crypto, hash_alg, &[])?.len(); + let hash_len = Crypto::digest_size_checked(hash_alg)?; *acc = vec![0u8; hash_len]; policy_update(crypto, hash_alg, acc, TPM_CC::PolicyAuthorize, &key_name, &self.policy_ref) } diff --git a/TSS.Rust/src/tpm2_impl.rs b/TSS.Rust/src/tpm2_impl.rs index 3482721c..208776b8 100644 --- a/TSS.Rust/src/tpm2_impl.rs +++ b/TSS.Rust/src/tpm2_impl.rs @@ -705,7 +705,7 @@ impl Tpm2 { symmetric: TPMT_SYM_DEF, salt: &[u8], ) -> Result { - let nonce_size = Crypto::digestSize(auth_hash); + let nonce_size = Crypto::digest_size_checked(auth_hash)?; let nonce_caller = Crypto::get_random(&self.crypto, nonce_size)?; // For salted sessions, encrypt the salt to the tpmKey's public area diff --git a/TSS.Rust/src/tpm_type_extensions.rs b/TSS.Rust/src/tpm_type_extensions.rs index 0d9269d3..d0b1fd8b 100644 --- a/TSS.Rust/src/tpm_type_extensions.rs +++ b/TSS.Rust/src/tpm_type_extensions.rs @@ -14,6 +14,30 @@ pub struct ActivationData { pub secret: Vec, // Encrypted seed (ENCRYPTED_SECRET) } +impl TPMS_RSA_PARMS { + /// The public exponent as big-endian bytes with no leading zeros. + /// + /// The TPM encodes the default exponent of 2^16 + 1 as zero, so a stored zero is resolved + /// here rather than by rewriting the field. That distinction matters: a key's Name is a + /// digest over its whole public area, so normalising a stored zero to 65537 would change + /// the Name of every key that uses the default and silently break every policy digest, + /// `TPM2_ActivateCredential` and handle-to-Name comparison that depends on it. Resolve at + /// the point of use, never in the structure. + pub fn exponent_bytes(&self) -> Vec { + if self.exponent == 0 { + return RSA_DEFAULT_EXPONENT.to_vec(); + } + + // The exponent is non-zero, so at least one byte survives. + self.exponent + .to_be_bytes() + .iter() + .skip_while(|&&byte| byte == 0) + .copied() + .collect() + } +} + impl TPMT_PUBLIC { pub fn get_name(&self, crypto: &CryptoProvider) -> Result, TpmError> { let mut buffer = TpmBuffer::new(None); @@ -127,7 +151,8 @@ impl TPMT_PUBLIC { // The seed is the same size as the nameAlg digest, per TPM 2.0 Part 1 "Credential // Protection". TSS.NET does the same in TpmKey.CreateActivationCredentials. - let mut seed = Crypto::get_random(crypto, Crypto::digestSize(self.nameAlg))?; + let name_alg_size = Crypto::digest_size_checked(self.nameAlg)?; + let mut seed = Crypto::get_random(crypto, name_alg_size)?; // Get RSA public key components for encrypting the seed let rsa_pub_n = if let Some(TPMU_PUBLIC_ID::rsa(unique)) = &self.unique { @@ -140,7 +165,7 @@ impl TPMT_PUBLIC { let secret = Crypto::rsa_oaep_encrypt( crypto, rsa_pub_n, - &RSA_DEFAULT_EXPONENT, + &rsa_params.exponent_bytes(), self.nameAlg, b"IDENTITY\0", &seed, @@ -181,7 +206,7 @@ impl TPMT_PUBLIC { "INTEGRITY", &[], &[], - Crypto::digestSize(self.nameAlg) * 8, + name_alg_size * 8, )?; // 5. Calculate outer HMAC @@ -239,7 +264,7 @@ impl TPMT_PUBLIC { Crypto::rsa_oaep_encrypt( crypto, rsa_pub_n, - &RSA_DEFAULT_EXPONENT, + &rsa_params.exponent_bytes(), self.nameAlg, b"IDENTITY\0", data, @@ -253,6 +278,12 @@ impl TPMT_PUBLIC { crypto: &CryptoProvider, salt: &[u8], ) -> Result, TpmError> { + let rsa_params = if let Some(TPMU_PUBLIC_PARMS::rsaDetail(params)) = &self.parameters { + params + } else { + return Err(TpmError::NotSupported("Only RSA keys can encrypt session salt".to_string())); + }; + let rsa_pub_n = if let Some(TPMU_PUBLIC_ID::rsa(unique)) = &self.unique { &unique.buffer } else { @@ -262,7 +293,7 @@ impl TPMT_PUBLIC { Crypto::rsa_oaep_encrypt( crypto, rsa_pub_n, - &RSA_DEFAULT_EXPONENT, + &rsa_params.exponent_bytes(), self.nameAlg, b"SECRET\0", salt, @@ -399,13 +430,14 @@ impl TSS_KEY { /// Generate an RSA key pair in software. /// Populates publicPart.unique with the modulus and privatePart with the first prime (p). pub fn create_key(&mut self, crypto: &CryptoProvider) -> Result<(), TpmError> { - let key_bits = if let Some(TPMU_PUBLIC_PARMS::rsaDetail(ref params)) = self.publicPart.parameters { - params.keyBits as usize - } else { - return Err(TpmError::GenericError("Only RSA key creation is supported".to_string())); - }; + let (key_bits, exponent) = + if let Some(TPMU_PUBLIC_PARMS::rsaDetail(ref params)) = self.publicPart.parameters { + (params.keyBits as usize, params.exponent_bytes()) + } else { + return Err(TpmError::GenericError("Only RSA key creation is supported".to_string())); + }; - let key = Crypto::rsa_generate_keypair(crypto, key_bits)?; + let key = Crypto::rsa_generate_keypair(crypto, key_bits, &exponent)?; // Store modulus (n) in publicPart.unique self.publicPart.unique = Some(TPMU_PUBLIC_ID::rsa(TPM2B_PUBLIC_KEY_RSA { buffer: key.modulus })); @@ -425,9 +457,11 @@ impl TSS_KEY { digest: &[u8], hash_alg: TPM_ALG_ID, ) -> Result { - if !matches!(&self.publicPart.parameters, Some(TPMU_PUBLIC_PARMS::rsaDetail(_))) { + let rsa_params = if let Some(TPMU_PUBLIC_PARMS::rsaDetail(ref params)) = self.publicPart.parameters { + params + } else { return Err(TpmError::GenericError("Only RSA signing is supported".to_string())); - } + }; let n_bytes = if let Some(TPMU_PUBLIC_ID::rsa(ref pub_key)) = self.publicPart.unique { pub_key.buffer.clone() @@ -439,6 +473,7 @@ impl TSS_KEY { let key = RsaKeyParts { modulus: n_bytes, prime: self.privatePart.clone(), + exponent: rsa_params.exponent_bytes(), }; let sig_bytes = Crypto::rsa_pkcs1v15_sign(crypto, &key, hash_alg, digest)?; @@ -601,6 +636,29 @@ mod tests { Ok(()) } + #[test] + fn exponent_bytes_resolves_the_specification_default() { + // The TPM encodes 2^16 + 1 as zero on the wire. + let mut parms = TPMS_RSA_PARMS::new( + &TPMT_SYM_DEF_OBJECT::new(TPM_ALG_ID::AES, 128, TPM_ALG_ID::CFB), + &Some(TPMU_ASYM_SCHEME::null(TPMS_NULL_ASYM_SCHEME::default())), + 2048, + 0, + ); + assert_eq!(parms.exponent_bytes(), vec![0x01, 0x00, 0x01]); + + // An explicit 65537 encodes to the same bytes as the default. + parms.exponent = 65537; + assert_eq!(parms.exponent_bytes(), vec![0x01, 0x00, 0x01]); + + // A non default exponent is returned big-endian with leading zeros stripped. + parms.exponent = 3; + assert_eq!(parms.exponent_bytes(), vec![0x03]); + + parms.exponent = u32::MAX; + assert_eq!(parms.exponent_bytes(), vec![0xff, 0xff, 0xff, 0xff]); + } + #[test] fn create_activation_rejects_a_non_storage_wrapping_scheme() -> Result<(), TpmError> { let (_, mut endorsement_public) = endorsement_key(TPM_ALG_ID::SHA256)?; @@ -623,4 +681,24 @@ mod tests { Ok(()) } + + #[test] + fn create_activation_rejects_a_name_alg_that_is_not_a_hash() -> Result<(), TpmError> { + // A behaviour lock, not a regression test: OAEP already rejects a non-hash nameAlg a few + // lines further on, so this held before the seed sizing was made checked. It pins the + // property itself so that reordering or relaxing either check cannot let a zero length + // seed through unnoticed. + let (_, mut endorsement_public) = endorsement_key(TPM_ALG_ID::SHA256)?; + endorsement_public.nameAlg = TPM_ALG_ID::NULL; + + assert!(endorsement_public + .create_activation( + &SOFTWARE_PROVIDER, + b"credential", + &activated_name(TPM_ALG_ID::SHA256) + ) + .is_err()); + + Ok(()) + } } From e0563552bf4e5f00d76165eac6c1c8fb9bd0b7cb Mon Sep 17 00:00:00 2001 From: Roee Kasher Date: Thu, 13 Aug 2026 23:12:00 +0300 Subject: [PATCH 09/13] Support ECC storage keys in create_activation (#7) * Support ECC storage keys in create_activation TPMT_PUBLIC::create_activation rejected anything that was not an RSA key, so a TPM whose endorsement key is ECC could not be issued a credential at all. This adds the ECC path. The two algorithms differ only in how the seed reaches the TPM, which is now isolated in produce_seed. With RSA the seed is random and the secret is that seed under OAEP. With ECC nothing is transported: both sides derive the seed from an ECDH agreement, and the secret is the ephemeral public point the TPM needs to repeat it. Everything after the seed is defined on the seed alone and is shared unchanged. The crypto layer gains KDFe, the SP800-56A concatenation KDF that TPM 2.0 Part 1 section 11.4.10.3 defines for this derivation. It is easy to confuse with KDFa: it hashes rather than HMACs, and it does not hash the requested length. Getting either wrong yields output of the right shape and the wrong value. Only the ephemeral agreement is delegated to the provider, and it returns the raw agreed value. Deriving from it is specification behaviour rather than backend behaviour, so it stays in Crypto. Some platform APIs offer to perform the concatenation themselves, but at least one silently ignores the requested hash algorithm and always uses SHA-256, which no interoperability failure would attribute to the KDF. Coordinate width is answered by Crypto rather than by a provider, because a TPM may drop leading zero bytes from a coordinate it marshals into a TPM2B while KDFe hashes coordinates at full width. A curve outside the TCG registry is an error rather than a guess, since guessing produces a plausible key that simply does not match the peer's. The software provider implements the agreement over P-256, P-384 and P-521. Barreto-Naehrig and SM2 curves are rejected rather than approximated with a NIST curve. Tested by a round trip against a stand-in that repeats the agreement, on three curves across three nameAlgs. Mutation testing confirms the round trip fails if partyU and partyV are swapped, or if the KDFe label is changed, on one side only. It cannot catch a mistake made identically on both sides, since both ends call the same KDFe, so KDFe is additionally pinned to an independently computed vector. * Address review of the ECC create_activation change Four defects found in review of the previous commit, two of them behavioural and two in what the code claims about itself. KDFa and KDFe are specified in bits but truncated to whole octets, so a request that is not a multiple of eight returned too many significant bits instead of the leftmost bits right aligned. TSS.NET and TSS.CPP shift the stream to correct this. Both KDFs now share one helper rather than being fixed apart, since the two disagreeing about what a bit count means is worse than the original bug. KDFa was affected identically and is fixed here even though the previous commit did not touch it. This is unreachable through TPM 2.0 itself, where every KDF request is a digest or symmetric key size and therefore already octet aligned. It is fixed so that a caller using the library directly agrees with the other stacks. The shift is applied to the retained octets rather than to the whole stream, which is equivalent because the octets a full shift would produce beyond the requested length are discarded in either order. Where the request is octet aligned the operation is byte for byte the previous truncation, confirmed by forcing the shift to zero and observing that only the new test fails. The agreed ECDH value was held in an ordinary Vec and printed by a derived Debug, while the seed derived from it was being zeroized. Wrapping it in Zeroizing alone would have left the printing, since Zeroizing implements Debug whenever its contents do, so Debug is now written by hand and shows the public coordinates in full while withholding the secret. That keeps the value useful for diagnosing an encoding mismatch, which is what it is for. EccEphemeralAgreement documented all three of its fields as KDFe inputs. Only z and the ephemeral X reach the KDF; the ephemeral Y travels to the peer inside the marshalled point. The correction says why Y is still padded, since a reader told only that it is unhashed could conclude it needs no padding, and a TPM parsing the point is entitled to a full width coordinate. The same claim appeared in a comment in produce_seed and is corrected there too. Coordinate restoration had no coverage. Points built from a SEC1 encoding carry full width coordinates, so the padding was exercised only as a no op and removing it entirely passed the whole suite. A round trip is added against a key whose public X carries a leading zero, stripped from the fixture the way a TPM marshalling a TPM2B may strip it, along with a rejection case for a coordinate wider than its curve: trimming an oversized coordinate to fit would agree with a point the peer never held and fail only at the TPM. That fixture uses a fixed scalar. One key in 256 has a leading zero octet, and generating that many in an unoptimised test build cost more than the rest of the suite together. The test asserts the coordinate is short before relying on it, so a fixture that stopped being short would fail rather than quietly revert to a no op. The KDF test pins both functions at 250 bits against independently computed vectors. The two are unrelated to each other because KDFa hashes the requested length into every iteration and KDFe does not, so KDFa at 250 bits is a different stream rather than a shortened one. * Address the second review pass on the ECC activation change Wipe the KDF intermediates. Both KDFs accumulated the derived key in a plain Vec, and KDFe additionally copied the agreed value into a plain per-iteration buffer, so several copies of key material were freed unwiped. All are now Zeroizing, and both are reserved to their final size up front because a Vec that grows frees its old allocation without wiping it, which would have left copies behind despite the wrapper. KDFa's hashed input is deliberately left plain: everything in it is public and the key travels separately as the HMAC key. Give TEST_P192 its coordinate width. It was the only registry curve other than NONE falling through to the unknown arm. This function is a registry lookup, so it answers for any curve the registry names; whether a backend will agree over that curve is answered separately. The new sweep test enumerates the registry through the generated try_from rather than a hand-written list, so a curve added upstream fails the test instead of silently falling through. Stop pulling default features from the curve crates. They brought in the ECDSA and RFC6979 crates for a provider that only ever agrees. The graph goes from 70 crates to 68; the PKCS#8 and PEM crates stay, since the rsa crate needs them independently. * Qualify size_of_val to match the rest of the crate Every other use of this family is written out in full: std::mem::size_of in device.rs, tpm2_helpers.rs and twice in tpm_buffer.rs. This one line was the only unqualified use, so it now matches the other four. This is a consistency change rather than a fix. size_of_val has been in the prelude since Rust 1.80, the crate declares no MSRV below that, and the unqualified form built and passed the suite; a review comment claiming otherwise was mistaken. The _val form is kept rather than size_of::() so that the reservation follows the counter's type if it ever changes, which is what makes the reservation correct. --- TSS.Rust/Cargo.lock | 125 ++++++ TSS.Rust/Cargo.toml | 12 + TSS.Rust/src/crypto/mod.rs | 441 +++++++++++++++++++- TSS.Rust/src/crypto/provider.rs | 94 ++++- TSS.Rust/src/crypto/software_provider.rs | 84 +++- TSS.Rust/src/tpm_type_extensions.rs | 494 ++++++++++++++++++++--- 6 files changed, 1183 insertions(+), 67 deletions(-) diff --git a/TSS.Rust/Cargo.lock b/TSS.Rust/Cargo.lock index 0077bd87..4ef55927 100644 --- a/TSS.Rust/Cargo.lock +++ b/TSS.Rust/Cargo.lock @@ -19,6 +19,12 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + [[package]] name = "base64ct" version = "1.7.3" @@ -80,6 +86,18 @@ dependencies = [ "libc", ] +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -124,6 +142,35 @@ dependencies = [ "subtle", ] +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array", + "group", + "hkdf", + "rand_core", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "ff" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" +dependencies = [ + "rand_core", + "subtle", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -132,6 +179,7 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", + "zeroize", ] [[package]] @@ -145,6 +193,26 @@ dependencies = [ "wasi", ] +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + [[package]] name = "hmac" version = "0.12.1" @@ -232,6 +300,37 @@ dependencies = [ "libm", ] +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "elliptic-curve", + "primeorder", +] + +[[package]] +name = "p384" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe42f1670a52a47d448f14b6a5c61dd78fce51856e68edaa38f7ae3a46b8d6b6" +dependencies = [ + "elliptic-curve", + "primeorder", +] + +[[package]] +name = "p521" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc9e2161f1f215afdfce23677034ae137bbd45016a880c2eb3ba8eb95f085b2" +dependencies = [ + "base16ct", + "elliptic-curve", + "primeorder", +] + [[package]] name = "pem-rfc7468" version = "0.7.0" @@ -271,6 +370,15 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + [[package]] name = "proc-macro2" version = "1.0.94" @@ -339,6 +447,19 @@ dependencies = [ "zeroize", ] +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "subtle", + "zeroize", +] + [[package]] name = "sha1" version = "0.10.6" @@ -437,9 +558,13 @@ dependencies = [ "aes", "cipher", "derivative", + "elliptic-curve", "hmac", "lazy_static", "libc", + "p256", + "p384", + "p521", "rand", "rsa", "sha1", diff --git a/TSS.Rust/Cargo.toml b/TSS.Rust/Cargo.toml index 2755490c..873b21ba 100644 --- a/TSS.Rust/Cargo.toml +++ b/TSS.Rust/Cargo.toml @@ -19,6 +19,10 @@ software-crypto = [ "dep:aes", "dep:cipher", "dep:hmac", + "dep:p256", + "dep:p384", + "dep:p521", + "dep:elliptic-curve", "dep:rand", "dep:rsa", "dep:sha1", @@ -42,6 +46,14 @@ sha1 = { version = "0.10.6", features = ["oid"], optional = true } sha2 = { version = "0.10.8", features = ["oid"], optional = true } sm3 = { version = "0.4.2", optional = true } +# The NIST prime curves a TPM may nominate for an ECC storage key, and the generic traits that +# let one agreement routine serve all three. Default features are off because they would pull in +# the ECDSA, PKCS#8 and PEM stacks, none of which this provider uses: it only ever agrees. +elliptic-curve = { version = "0.13", default-features = false, features = ["ecdh", "sec1"], optional = true } +p256 = { version = "0.13", default-features = false, features = ["ecdh"], optional = true } +p384 = { version = "0.13", default-features = false, features = ["ecdh"], optional = true } +p521 = { version = "0.13", default-features = false, features = ["ecdh"], optional = true } + [target.'cfg(windows)'.dependencies] windows = { version = "0.61.1", features = ["Win32_Foundation", "Win32_Security", "Win32_System_TpmBaseServices", "Win32_Networking", "Win32_Networking_WinSock"] } diff --git a/TSS.Rust/src/crypto/mod.rs b/TSS.Rust/src/crypto/mod.rs index b19ce4fd..2514ebeb 100644 --- a/TSS.Rust/src/crypto/mod.rs +++ b/TSS.Rust/src/crypto/mod.rs @@ -17,7 +17,8 @@ pub mod provider; pub mod software_provider; use crate::{error::TpmError, tpm_types::*}; -use provider::CryptoProvider; +use provider::{CryptoProvider, EccEphemeralAgreement}; +use zeroize::Zeroizing; /// The RSA public exponent the TPM 2.0 specification defines as the default (65537, "F4"). /// @@ -151,6 +152,70 @@ impl Crypto { (provider.rsa.pkcs1v15_sign)(key, hash_alg, digest) } + /// The width in bytes of one coordinate on `curve`. + /// + /// This is a property of the curve as the TCG registry defines it, not of the backend, so it + /// is answered here and every provider agrees on it. It matters because a TPM may drop leading + /// zero bytes from a coordinate it marshals into a `TPM2B`, while the key derivation hashes + /// coordinates at their full width. Padding a short coordinate back out before it reaches + /// [`Crypto::kdfe`] is what keeps both sides deriving the same value. + /// + /// A curve outside the registry is an error rather than a guess, because guessing a width + /// produces a plausible-looking key that simply does not match the peer's. + pub fn ecc_coordinate_size(curve: TPM_ECC_CURVE) -> Result { + match curve { + TPM_ECC_CURVE::NIST_P192 => Ok(24), + TPM_ECC_CURVE::NIST_P224 => Ok(28), + TPM_ECC_CURVE::NIST_P256 => Ok(32), + TPM_ECC_CURVE::NIST_P384 => Ok(48), + // P-521's order is 521 bits, which occupies 66 bytes with the top 7 bits unused. + TPM_ECC_CURVE::NIST_P521 => Ok(66), + TPM_ECC_CURVE::BN_P256 => Ok(32), + TPM_ECC_CURVE::BN_P638 => Ok(80), + TPM_ECC_CURVE::SM2_P256 => Ok(32), + // The registry's test curve, which is a 192 bit curve distinct from NIST P-192. Its + // width is answered like any other because this is a registry lookup; whether a + // backend will agree over it is a separate question that the backend answers. + TPM_ECC_CURVE::TEST_P192 => Ok(24), + other => Err(TpmError::NotSupported(format!( + "Unknown ECC curve {other}, so its coordinate width is unknown" + ))), + } + } + + /// Left pads an ECC coordinate to a fixed width. + /// + /// A TPM is free to drop leading zero bytes when it marshals a coordinate into a `TPM2B`, so a + /// coordinate arriving short is normal and is restored here. One arriving long belongs to a + /// different curve than the caller believes, which is an error rather than something to + /// truncate. + pub fn pad_ecc_coordinate(value: &[u8], width: usize) -> Result, TpmError> { + if value.len() > width { + return Err(TpmError::InvalidArraySize(format!( + "A {} byte coordinate does not fit a {} byte curve", + value.len(), + width + ))); + } + + let mut padded = vec![0u8; width - value.len()]; + padded.extend_from_slice(value); + Ok(padded) + } + + /// Generate an ephemeral key on `curve` and agree with the public point `(peer_x, peer_y)`. + /// + /// The agreed value is returned raw. Callers wanting key material run [`Crypto::kdfe`] over + /// it, which is where the TPM's derivation is defined. + pub fn ecc_ephemeral_agree( + provider: &CryptoProvider, + curve: TPM_ECC_CURVE, + peer_x: &[u8], + peer_y: &[u8], + ) -> Result { + (provider.ecc.ephemeral_agree)(curve, peer_x, peer_y) + } + pub fn validate_signature( provider: &CryptoProvider, public_key: &TPMT_PUBLIC, @@ -202,6 +267,57 @@ impl Crypto { ) } + /// Reduce a generated KDF stream to `bits` bits, as TPM 2.0 Part 1 section 11.4.10 requires. + /// + /// Both KDFs generate whole digests, so the stream is normally longer than the request. The + /// bits kept are the leftmost ones, and they come back right aligned in the fewest octets that + /// hold them: a request that is not a whole number of octets leaves the unused bits of the + /// leading octet zero rather than handing back extra significant bits. Simply truncating to + /// whole octets would return a different value, which is why TSS.NET and TSS.CPP both shift + /// their stream instead (`CryptoLib.KDFa` and `Crypto::KDFa` respectively). + /// + /// Every KDF call the TPM 2.0 protocol makes of itself asks for a digest or symmetric key + /// size, all of which are whole octets, and for those this is exactly a truncation. The shift + /// matters only to a caller using these KDFs for something the TPM does not. + /// + /// `stream` must hold at least `bits` bits, which both callers guarantee by generating whole + /// digests until it does. + fn truncate_kdf_stream(stream: &[u8], bits: usize) -> Vec { + debug_assert!( + stream.len() * 8 >= bits, + "KDF stream is shorter than the request" + ); + + let octets_needed = bits.div_ceil(8); + let bit_shift = (stream.len() * 8 - bits) % 8; + let mut result = stream[..octets_needed].to_vec(); + + if bit_shift != 0 { + // A big endian right shift: every octet takes the bits falling out of the one above it. + let mut carry = 0u8; + for octet in result.iter_mut() { + let fell_out = *octet << (8 - bit_shift); + *octet = (*octet >> bit_shift) | carry; + carry = fell_out; + } + } + + result + } + + /// A buffer for a KDF stream, sized so that filling it never reallocates. + /// + /// Both KDFs append whole digests until the stream covers the request, so one digest beyond + /// `bytes_needed` is the most that can ever be generated. Reserving that up front is not an + /// optimisation: the buffer accumulates the derived key, and growing a `Vec` frees the old + /// allocation without wiping it, which would leave a copy of that key behind and defeat the + /// `Zeroizing` wrapper. + fn kdf_stream_buffer(hash_alg: TPM_ALG_ID, bytes_needed: usize) -> Zeroizing> { + Zeroizing::new(Vec::with_capacity( + bytes_needed + Self::digestSize(hash_alg), + )) + } + // KDFa implementation as specified in TPM 2.0 Part 1 pub fn kdfa( provider: &CryptoProvider, @@ -221,7 +337,7 @@ impl Crypto { } let bytes_needed = bits.div_ceil(8); - let mut result = Vec::new(); + let mut result = Self::kdf_stream_buffer(hash_alg, bytes_needed); let mut counter = 1u32; while result.len() < bytes_needed { @@ -245,8 +361,9 @@ impl Crypto { // Number of bits in big-endian to_hash.extend_from_slice(&(bits as u32).to_be_bytes()); - // Perform HMAC - let hmac_result = Self::hmac(provider, hash_alg, key, &to_hash)?; + // Perform HMAC. The digest is key material, so it is wiped once appended; `to_hash` + // is not, because everything in it is public and the key travels separately. + let hmac_result = Zeroizing::new(Self::hmac(provider, hash_alg, key, &to_hash)?); result.extend_from_slice(&hmac_result); counter = counter.checked_add(1).ok_or_else(|| { @@ -255,8 +372,91 @@ impl Crypto { } // Truncate to exact size needed - result.truncate(bytes_needed); - Ok(result) + Ok(Self::truncate_kdf_stream(&result, bits)) + } + + /// KDFe, the derivation TPM 2.0 Part 1 section 11.4.10.3 defines for ECDH secret sharing. + /// + /// This is the SP800-56A concatenation KDF. Each iteration hashes a big endian counter, the + /// agreed value, the label and both parties' contributions; the iterations are concatenated + /// and truncated to the requested length. + /// + /// It differs from [`Crypto::kdfa`] in two ways that are easy to conflate. It hashes rather + /// than HMACs, so the agreed value is part of the hashed input instead of being a key. And the + /// requested length is not itself hashed, where KDFa appends it to every iteration. Using one + /// where the other is meant yields output of the right shape and the wrong value. + /// + /// `party_u_info` is the initiator's X coordinate and `party_v_info` the responder's. Both + /// ends have to make the same assignment regardless of which role they are playing, so a + /// party reproducing an agreement keeps the originator's point as U even though it is the one + /// receiving. Swapping them derives a different value in silence. + /// + /// Coordinates must arrive at the curve's full width; see [`Crypto::ecc_coordinate_size`]. + pub fn kdfe( + provider: &CryptoProvider, + hash_alg: TPM_ALG_ID, + z: &[u8], + label: &str, + party_u_info: &[u8], + party_v_info: &[u8], + bits: usize, + ) -> Result, TpmError> { + // As in KDFa, zero bits would exit the loop immediately and hand back an empty key that + // every caller would then treat as real key material. + if bits == 0 { + return Err(TpmError::InvalidArraySize( + "KDFe was asked to produce zero bits of key material".to_string(), + )); + } + + // An agreement that produced nothing cannot key anything, and hashing an empty Z would + // still yield plausible-looking output. + if z.is_empty() { + return Err(TpmError::InvalidArraySize( + "KDFe was given an empty agreed value".to_string(), + )); + } + + let bytes_needed = bits.div_ceil(8); + let mut result = Self::kdf_stream_buffer(hash_alg, bytes_needed); + let mut counter = 1u32; + + // Unlike KDFa, the hashed input contains the agreed value itself, so the buffer holding it + // is as sensitive as `z` and is wiped on the same terms. Its length is the same on every + // iteration, so reserving it exactly means the one allocation is the only copy made. + let hashed_len = std::mem::size_of_val(&counter) + + z.len() + + label.len() + + 1 + + party_u_info.len() + + party_v_info.len(); + + while result.len() < bytes_needed { + let mut to_hash = Zeroizing::new(Vec::with_capacity(hashed_len)); + + // Counter in big-endian + to_hash.extend_from_slice(&counter.to_be_bytes()); + + // The agreed value + to_hash.extend_from_slice(z); + + // Label, with the terminating NUL the specification includes in the hash + to_hash.extend_from_slice(label.as_bytes()); + to_hash.push(0u8); + + // Each party's contribution + to_hash.extend_from_slice(party_u_info); + to_hash.extend_from_slice(party_v_info); + + let digest = Zeroizing::new(Self::hash(provider, hash_alg, &to_hash)?); + result.extend_from_slice(&digest); + + counter = counter.checked_add(1).ok_or_else(|| { + TpmError::InvalidArraySize("Counter overflow in KDFe".to_string()) + })?; + } + + Ok(Self::truncate_kdf_stream(&result, bits)) } // AES CFB encryption/decryption @@ -472,6 +672,60 @@ mod tests { assert!(Crypto::digest_size_checked(TPM_ALG_ID::RSA).is_err()); } + #[test] + fn every_registry_curve_reports_a_coordinate_size() { + // The generated `try_from` accepts exactly the curves the TCG registry names, so sweeping + // it enumerates them without this test carrying a second list that could drift from the + // first. A curve that is in the registry has a defined width, and answering "unsupported" + // for one of them is the bug this guards against: it is a registry lookup, so it must not + // depend on which curves a backend happens to implement. `NONE` is the absence of a curve + // rather than a curve, so it has no width and is expected to fail. + let mut curves_seen = 0; + + for raw in 0..=u16::MAX { + let Ok(curve) = TPM_ECC_CURVE::try_from(raw) else { + continue; + }; + curves_seen += 1; + + if raw == 0 { + assert!( + Crypto::ecc_coordinate_size(curve).is_err(), + "TPM_ECC_CURVE::NONE is not a curve and must not report a width" + ); + continue; + } + + let size = Crypto::ecc_coordinate_size(curve).unwrap_or_else(|e| { + panic!("registry curve {raw:#06x} has no coordinate size: {e:?}") + }); + assert!(size > 0, "curve {raw:#06x} reported a zero width"); + } + + // Guards the sweep itself: if `try_from` ever stopped accepting anything, every assertion + // above would be skipped and the test would pass while checking nothing. + assert!( + curves_seen > 1, + "the curve sweep found nothing to check, so it proved nothing" + ); + } + + #[test] + fn ecc_coordinate_sizes_match_the_curve_widths() { + // Spot checks against the registry, so that a wrong-but-non-zero width cannot pass the + // sweep above. P-521 is the one worth stating outright: 521 bits occupies 66 octets, with + // the top seven bits of the leading octet unused. + for (curve, expected) in [ + (TPM_ECC_CURVE::NIST_P192, 24), + (TPM_ECC_CURVE::NIST_P224, 28), + (TPM_ECC_CURVE::NIST_P256, 32), + (TPM_ECC_CURVE::NIST_P384, 48), + (TPM_ECC_CURVE::NIST_P521, 66), + ] { + assert_eq!(Crypto::ecc_coordinate_size(curve).ok(), Some(expected)); + } + } + #[test] fn kdfa_rejects_a_request_for_zero_bits() { // Sizing a KDFa request from `digestSize` of a non-hash algorithm used to ask for zero @@ -503,6 +757,181 @@ mod tests { Ok(()) } + /// KDFe against a value computed outside this crate. + /// + /// The round trip in `tpm_type_extensions` runs both ends of an activation through this same + /// function, so it would agree with itself even if the construction were wrong. This pins the + /// construction to an independently derived answer instead. + #[test] + fn kdfe_matches_an_independently_computed_vector() -> Result<(), TpmError> { + let z = [ + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, + 0xee, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, + 0xcc, 0xdd, 0xee, 0xff, + ]; + let party_u = [0xaau8; 32]; + let party_v = [0xbbu8; 32]; + + // SHA256(BE32(1) || Z || "IDENTITY" || 0x00 || partyU || partyV). + let one_block = + hex_to_bytes("32721732041999b0cde95bc6f0702059883b6ddf7ba7635ffc3e3c09f4914cd4"); + + let derived = Crypto::kdfe( + &SOFTWARE_PROVIDER, + TPM_ALG_ID::SHA256, + &z, + "IDENTITY", + &party_u, + &party_v, + 256, + )?; + assert_eq!( + derived, one_block, + "KDFe should hash the counter, Z, the NUL terminated label and both parties, and \ + nothing else. In particular the requested length is not hashed, which is where it \ + differs from KDFa." + ); + + // A second block continues with counter 2 rather than restarting. + let two_blocks = hex_to_bytes( + "32721732041999b0cde95bc6f0702059883b6ddf7ba7635ffc3e3c09f4914cd4\ + b2f1a09b1730caf33fea691a5aac61ac2a064c64c0688fd3588776ed5cd6e5ec", + ); + assert_eq!( + Crypto::kdfe( + &SOFTWARE_PROVIDER, + TPM_ALG_ID::SHA256, + &z, + "IDENTITY", + &party_u, + &party_v, + 512 + )?, + two_blocks + ); + + // A length that is not a whole number of digests is truncated, not rounded up. + assert_eq!( + Crypto::kdfe( + &SOFTWARE_PROVIDER, + TPM_ALG_ID::SHA256, + &z, + "IDENTITY", + &party_u, + &party_v, + 200 + )?, + one_block[..25] + ); + + Ok(()) + } + + /// A request that is not a whole number of octets, which the TPM never makes but a caller can. + /// + /// The bits kept are the leftmost ones and they come back right aligned, so the answer is the + /// stream shifted right, not the stream with its tail chopped off. TSS.NET and TSS.CPP both + /// shift, and disagreeing with them would put this library on the wrong side of an interop + /// boundary the moment anyone drove a KDF from one of the other stacks. + #[test] + fn kdf_right_aligns_a_request_that_is_not_a_whole_number_of_octets() -> Result<(), TpmError> { + let z = [ + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, + 0xee, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, + 0xcc, 0xdd, 0xee, 0xff, + ]; + let party_u = [0xaau8; 32]; + let party_v = [0xbbu8; 32]; + + // The same inputs as the vector above, so the stream being reduced is already pinned to an + // independently computed digest. 250 bits still occupy 32 octets, holding that digest + // shifted right by the 6 bits that were not asked for. + let shifted = + hex_to_bytes("00c9c85cc8106666c337a56f1bc1c0816620edb77dee9d8d7ff0f8f027d24533"); + let derived = Crypto::kdfe( + &SOFTWARE_PROVIDER, + TPM_ALG_ID::SHA256, + &z, + "IDENTITY", + &party_u, + &party_v, + 250, + )?; + + assert_eq!(derived, shifted); + assert_eq!( + derived[0] >> 2, + 0, + "the 6 octet bits that were not requested should be zero" + ); + + // KDFa reduces its stream the same way. Its own answer has to be pinned separately rather + // than compared against a 256 bit call, because KDFa hashes the requested length into + // every iteration, so asking for 250 bits changes the stream instead of just shortening it. + let kdfa_shifted = + hex_to_bytes("020f0ff8ba4b653c0586d60a3a3e7c772a74a26b11f8d9304124f2b5dee29068"); + let kdfa_derived = Crypto::kdfa( + &SOFTWARE_PROVIDER, + TPM_ALG_ID::SHA256, + b"key", + "ATH", + &[], + &[], + 250, + )?; + assert_eq!( + kdfa_derived, kdfa_shifted, + "KDFa should shift its stream rather than truncate it" + ); + + Ok(()) + } + + #[test] + fn kdfe_rejects_inputs_that_would_yield_unusable_key_material() { + let z = [0x01u8; 32]; + + // Zero bits would leave the loop immediately and return an empty key that callers would + // treat as real, which is the same trap KDFa had. + assert!(Crypto::kdfe( + &SOFTWARE_PROVIDER, + TPM_ALG_ID::SHA256, + &z, + "IDENTITY", + &[], + &[], + 0 + ) + .is_err()); + + // An agreement that produced nothing cannot key anything, but hashing it would still + // yield output that looks like a key. + assert!(Crypto::kdfe( + &SOFTWARE_PROVIDER, + TPM_ALG_ID::SHA256, + &[], + "IDENTITY", + &[], + &[], + 256 + ) + .is_err()); + } + + fn hex_to_bytes(hex: &str) -> Vec { + let digits: Vec = hex + .bytes() + .filter(|b| !b.is_ascii_whitespace()) + .map(|b| match b { + b'0'..=b'9' => b - b'0', + b'a'..=b'f' => b - b'a' + 10, + _ => panic!("test vector is not hexadecimal"), + }) + .collect(); + + digits.chunks(2).map(|p| (p[0] << 4) | p[1]).collect() + } + #[test] fn aes_cfb_round_trips_at_every_key_size() -> Result<(), TpmError> { // AES-192 and AES-256 keys used to be handed to an AES-128 cipher, which panicked. diff --git a/TSS.Rust/src/crypto/provider.rs b/TSS.Rust/src/crypto/provider.rs index 8e2c539a..b15cbad4 100644 --- a/TSS.Rust/src/crypto/provider.rs +++ b/TSS.Rust/src/crypto/provider.rs @@ -20,7 +20,12 @@ //! identical no matter which backend is in use. use super::RsaKeyParts; -use crate::{error::TpmError, tpm_types::TPM_ALG_ID}; +use crate::{ + error::TpmError, + tpm_types::{TPM_ALG_ID, TPM_ECC_CURVE}, +}; +use std::fmt; +use zeroize::Zeroizing; /// Signature of [`CryptoProvider::hash`]. pub type HashFn = fn(alg: TPM_ALG_ID, data: &[u8]) -> Result, TpmError>; @@ -61,6 +66,57 @@ pub type RsaGenerateKeypairFn = pub type RsaPkcs1v15SignFn = fn(key: &RsaKeyParts, hash_alg: TPM_ALG_ID, digest: &[u8]) -> Result, TpmError>; +/// What one ephemeral ECDH agreement produces. +/// +/// An ECC key cannot be handed a secret the way an RSA key can be handed a ciphertext. The sender +/// instead generates a throwaway key on the peer's curve and agrees a value with it, and the peer +/// reproduces that value from its own private key. The ephemeral public point therefore travels in +/// place of a ciphertext, which is why it is returned alongside the agreed value rather than being +/// discarded with the private half. +/// +/// Every field is big endian and zero padded on the left to the curve's coordinate width, and that +/// padding is load bearing in both cases, for different reasons. +/// [`Crypto::kdfe`](super::Crypto::kdfe) hashes `z` and `ephemeral_x`, so a short encoding of +/// either derives a different key from the one the peer derives. `ephemeral_y` is never hashed and +/// reaches the peer only inside the marshalled point, but it is padded alongside `ephemeral_x` +/// because a TPM is entitled to be handed a coordinate at its curve's width. +#[derive(Clone)] +pub struct EccEphemeralAgreement { + /// The agreed value, which is the X coordinate of the agreed point. + /// + /// This is keying material rather than a public value: it is the sole input that distinguishes + /// the derived seed from something an eavesdropper could compute. It is therefore wiped when + /// dropped, and withheld from the [`Debug`] rendering below. + pub z: Zeroizing>, + + /// The ephemeral public point's X coordinate. + pub ephemeral_x: Vec, + + /// The ephemeral public point's Y coordinate. + pub ephemeral_y: Vec, +} + +/// Renders the public coordinates in full and the agreed value not at all. +/// +/// The agreed value is as sensitive as the seed derived from it, and a derived `Debug` would put +/// it into any log line that formats a provider result. +impl fmt::Debug for EccEphemeralAgreement { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("EccEphemeralAgreement") + .field("z", &format_args!("<{} bytes withheld>", self.z.len())) + .field("ephemeral_x", &self.ephemeral_x) + .field("ephemeral_y", &self.ephemeral_y) + .finish() + } +} + +/// Signature of [`EccOps::ephemeral_agree`]. +pub type EccEphemeralAgreeFn = fn( + curve: TPM_ECC_CURVE, + peer_x: &[u8], + peer_y: &[u8], +) -> Result; + /// Returns the error reported by every primitive a provider leaves unimplemented. fn unimplemented(operation: &str) -> TpmError { TpmError::NotSupported(format!( @@ -117,6 +173,38 @@ impl RsaOps { } } +/// The elliptic curve primitives a provider supplies. +/// +/// Split out from [`CryptoProvider`] for the same reason as [`RsaOps`]: a backend that offers no +/// curve arithmetic at all, or only some of the curves a TPM may nominate, starts from +/// [`EccOps::new_unimplemented`]. +#[derive(Clone, Copy, Debug)] +pub struct EccOps { + /// Generate an ephemeral key on `curve`, agree with the public point `(peer_x, peer_y)`, and + /// return the agreed value together with the ephemeral public point. + /// + /// Only the raw agreed value is returned. Deriving a key from it is defined by the TPM + /// specification rather than by the backend, so it belongs to + /// [`Crypto::kdfe`](super::Crypto::kdfe) and is deliberately not delegated here. Some platform + /// APIs offer to perform the SP800-56A concatenation themselves; that shortcut is best + /// avoided, because at least one of them silently ignores the requested hash algorithm and + /// always uses SHA-256. The result is a wrong key that no interoperability failure would + /// attribute to the KDF. + /// + /// A curve the backend cannot agree over must be reported as [`TpmError::NotSupported`] + /// rather than approximated with another curve. + pub ephemeral_agree: EccEphemeralAgreeFn, +} + +impl EccOps { + /// A set of ECC operations that all report [`TpmError::NotSupported`]. + pub const fn new_unimplemented() -> Self { + Self { + ephemeral_agree: |_, _, _| Err(unimplemented("ECDH ephemeral key agreement")), + } + } +} + /// The cryptographic primitives TSS.Rust needs from its host. #[derive(Clone, Copy, Debug)] pub struct CryptoProvider { @@ -138,6 +226,9 @@ pub struct CryptoProvider { /// The RSA primitives. pub rsa: RsaOps, + + /// The elliptic curve primitives. + pub ecc: EccOps, } impl CryptoProvider { @@ -152,6 +243,7 @@ impl CryptoProvider { aes_cfb: |_, _, _, _| Err(unimplemented("AES-CFB")), random: |_| Err(unimplemented("random number generation")), rsa: RsaOps::new_unimplemented(), + ecc: EccOps::new_unimplemented(), } } } diff --git a/TSS.Rust/src/crypto/software_provider.rs b/TSS.Rust/src/crypto/software_provider.rs index 52aa0803..6ca36afd 100644 --- a/TSS.Rust/src/crypto/software_provider.rs +++ b/TSS.Rust/src/crypto/software_provider.rs @@ -5,13 +5,19 @@ //! system already provides can disable the `software-crypto` feature and supply their own //! provider instead. -use super::provider::{CryptoProvider, RsaOps}; +use super::provider::{CryptoProvider, EccEphemeralAgreement, EccOps, RsaOps}; use super::{Crypto, RsaKeyParts}; -use crate::{error::TpmError, tpm_types::TPM_ALG_ID}; +use crate::{ + error::TpmError, + tpm_types::{TPM_ALG_ID, TPM_ECC_CURVE}, +}; use aes::{Aes128, Aes192, Aes256}; use cipher::generic_array::GenericArray; use cipher::{BlockEncrypt, BlockSizeUser, KeyInit}; +use elliptic_curve::ecdh::EphemeralSecret; +use elliptic_curve::sec1::{EncodedPoint, FromEncodedPoint, ModulusSize, ToEncodedPoint}; +use elliptic_curve::{AffinePoint, CurveArithmetic, FieldBytes, FieldBytesSize, PublicKey}; use hmac::{Hmac, Mac}; use rand::{rngs::OsRng, RngCore}; use rsa::traits::{PrivateKeyParts, PublicKeyParts}; @@ -19,6 +25,7 @@ use rsa::{BigUint, Oaep, Pkcs1v15Sign, RsaPrivateKey, RsaPublicKey}; use sha1::Sha1; use sha2::{Digest as Sha2Digest, Sha256, Sha384, Sha512}; use sm3::Sm3; +use zeroize::Zeroizing; /// The RustCrypto-backed provider. pub static SOFTWARE_PROVIDER: CryptoProvider = CryptoProvider { @@ -32,6 +39,9 @@ pub static SOFTWARE_PROVIDER: CryptoProvider = CryptoProvider { generate_keypair: rsa_generate_keypair, pkcs1v15_sign: rsa_pkcs1v15_sign, }, + ecc: EccOps { + ephemeral_agree: ecc_ephemeral_agree, + }, }; fn hash(alg: TPM_ALG_ID, data: &[u8]) -> Result, TpmError> { @@ -318,3 +328,73 @@ fn random(out: &mut [u8]) -> Result<(), TpmError> { .try_fill_bytes(out) .map_err(|e| TpmError::GenericError(format!("Failed to obtain random bytes: {e}"))) } + +/// Dispatches to the curve's own arithmetic, since each is a distinct type. +/// +/// Only the NIST prime curves appear. A TPM may also nominate Barreto-Naehrig or SM2 curves, for +/// which RustCrypto offers no ECDH implementation; they are rejected rather than approximated, +/// because agreeing over the wrong curve would silently derive a key the peer cannot reproduce. +fn ecc_ephemeral_agree( + curve: TPM_ECC_CURVE, + peer_x: &[u8], + peer_y: &[u8], +) -> Result { + match curve { + TPM_ECC_CURVE::NIST_P256 => agree_on::(peer_x, peer_y), + TPM_ECC_CURVE::NIST_P384 => agree_on::(peer_x, peer_y), + TPM_ECC_CURVE::NIST_P521 => agree_on::(peer_x, peer_y), + other => Err(TpmError::NotSupported(format!( + "This provider cannot perform ECDH over curve {other}" + ))), + } +} + +/// One ephemeral agreement over a single curve. +/// +/// The curve's own field width is used rather than a looked-up constant, so the coordinates handed +/// to the curve implementation are of exactly the length it expects and no length mismatch can +/// arise between the two. +fn agree_on(peer_x: &[u8], peer_y: &[u8]) -> Result +where + C: CurveArithmetic, + FieldBytesSize: ModulusSize, + AffinePoint: FromEncodedPoint + ToEncodedPoint, +{ + let width = FieldBytes::::default().len(); + let x = Crypto::pad_ecc_coordinate(peer_x, width)?; + let y = Crypto::pad_ecc_coordinate(peer_y, width)?; + + let encoded = EncodedPoint::::from_affine_coordinates( + FieldBytes::::from_slice(&x), + FieldBytes::::from_slice(&y), + false, + ); + + // A point off the curve, or the point at infinity, is rejected here. Agreeing with it would + // otherwise produce a value carrying no secret at all. + let peer: PublicKey = Option::from(PublicKey::::from_encoded_point(&encoded)) + .ok_or_else(|| { + TpmError::NotSupported( + "The ECC public point is not a valid point on its curve".to_string(), + ) + })?; + + let ephemeral = EphemeralSecret::::random(&mut OsRng); + let ephemeral_point = ephemeral.public_key().to_encoded_point(false); + + // Uncompressed encoding was requested above, so both coordinates are present unless the point + // is the identity, which a freshly generated key cannot be. + let missing = + || TpmError::GenericError("The ephemeral public point has no coordinates".to_string()); + let ephemeral_x = ephemeral_point.x().ok_or_else(missing)?.to_vec(); + let ephemeral_y = ephemeral_point.y().ok_or_else(missing)?.to_vec(); + + // The shared secret is the agreed point's X coordinate, already at the curve's full width. + let z = Zeroizing::new(ephemeral.diffie_hellman(&peer).raw_secret_bytes().to_vec()); + + Ok(EccEphemeralAgreement { + z, + ephemeral_x, + ephemeral_y, + }) +} diff --git a/TSS.Rust/src/tpm_type_extensions.rs b/TSS.Rust/src/tpm_type_extensions.rs index d0b1fd8b..2f6bacb5 100644 --- a/TSS.Rust/src/tpm_type_extensions.rs +++ b/TSS.Rust/src/tpm_type_extensions.rs @@ -124,52 +124,42 @@ impl TPMT_PUBLIC { } /// Implements the TPM2_MakeCredential command functionality: - /// 1. Generate random seed - /// 2. RSA-OAEP encrypt seed with label "IDENTITY" - /// 3. Derive symmetric key via KDFa - /// 4. Encrypt credential + create integrity HMAC + /// 1. Establish a seed and the secret that conveys it to the TPM + /// 2. Derive symmetric key via KDFa + /// 3. Encrypt credential + create integrity HMAC + /// + /// Both RSA and ECC storage keys are accepted. The two differ only in how the seed reaches the + /// TPM, which [`Self::produce_seed`] handles; everything after that is defined on the seed + /// alone and so is shared. pub fn create_activation( &self, crypto: &CryptoProvider, credential: &[u8], activated_name: &[u8], ) -> Result { - // Verify we have an RSA key with correct parameters - let rsa_params = if let Some(TPMU_PUBLIC_PARMS::rsaDetail(params)) = &self.parameters { - params - } else { - return Err(TpmError::NotSupported("Only RSA activation supported".to_string())); + // The wrapping scheme lives in the algorithm-specific parameters, but the constraint on it + // is the same either way, so it is checked once here. + let sym_def = match &self.parameters { + Some(TPMU_PUBLIC_PARMS::rsaDetail(params)) => ¶ms.symmetric, + Some(TPMU_PUBLIC_PARMS::eccDetail(params)) => ¶ms.symmetric, + _ => { + return Err(TpmError::NotSupported( + "Activation requires an RSA or ECC storage key".to_string(), + )) + } }; - // Check symmetric definition - let sym_def = &rsa_params.symmetric; - if sym_def.algorithm != TPM_ALG_ID::AES - || sym_def.keyBits != 128 - || sym_def.mode != TPM_ALG_ID::CFB { + if sym_def.algorithm != TPM_ALG_ID::AES + || sym_def.keyBits != 128 + || sym_def.mode != TPM_ALG_ID::CFB + { return Err(TpmError::NotSupported("Unsupported wrapping scheme".to_string())); } // The seed is the same size as the nameAlg digest, per TPM 2.0 Part 1 "Credential // Protection". TSS.NET does the same in TpmKey.CreateActivationCredentials. let name_alg_size = Crypto::digest_size_checked(self.nameAlg)?; - let mut seed = Crypto::get_random(crypto, name_alg_size)?; - - // Get RSA public key components for encrypting the seed - let rsa_pub_n = if let Some(TPMU_PUBLIC_ID::rsa(unique)) = &self.unique { - &unique.buffer - } else { - return Err(TpmError::NotSupported("Invalid RSA public key".to_string())); - }; - - // Encrypt seed with label "IDENTITY" using OAEP with the key's nameAlg - let secret = Crypto::rsa_oaep_encrypt( - crypto, - rsa_pub_n, - &rsa_params.exponent_bytes(), - self.nameAlg, - b"IDENTITY\0", - &seed, - )?; + let (mut seed, secret) = self.produce_seed(crypto, name_alg_size)?; // Make the credential blob: @@ -232,6 +222,76 @@ impl TPMT_PUBLIC { }) } + /// Establishes the activation seed and the `secret` that lets this key's TPM recover it. + /// + /// This is the whole of the difference between an RSA and an ECC activation. With RSA the seed + /// is chosen at random and the secret is that seed encrypted to the public key. With ECC no + /// value is transported at all: both sides derive the seed from an ECDH agreement, and the + /// secret is the ephemeral public point the TPM needs to repeat that agreement. + /// + /// Returns the seed and the secret, in that order. + fn produce_seed( + &self, + crypto: &CryptoProvider, + name_alg_size: usize, + ) -> Result<(Vec, Vec), TpmError> { + match (&self.parameters, &self.unique) { + (Some(TPMU_PUBLIC_PARMS::rsaDetail(params)), Some(TPMU_PUBLIC_ID::rsa(unique))) => { + let seed = Crypto::get_random(crypto, name_alg_size)?; + + // Encrypt seed with label "IDENTITY" using OAEP with the key's nameAlg + let secret = Crypto::rsa_oaep_encrypt( + crypto, + &unique.buffer, + ¶ms.exponent_bytes(), + self.nameAlg, + b"IDENTITY\0", + &seed, + )?; + + Ok((seed, secret)) + } + + (Some(TPMU_PUBLIC_PARMS::eccDetail(params)), Some(TPMU_PUBLIC_ID::ecc(point))) => { + let curve = params.curveID; + let agreement = Crypto::ecc_ephemeral_agree(crypto, curve, &point.x, &point.y)?; + + // KDFe hashes this coordinate, so one the TPM marshalled without its leading zeroes + // has to be restored to full width or the two sides hash different inputs and + // derive different seeds. + let width = Crypto::ecc_coordinate_size(curve)?; + let party_v_info = Crypto::pad_ecc_coordinate(&point.x, width)?; + + // partyU is the initiator, which is this side, and partyV the key's owner. The TPM + // makes the same assignment when it repeats the agreement, even though its own + // role is the opposite one. + let seed = Crypto::kdfe( + crypto, + self.nameAlg, + &agreement.z, + "IDENTITY", + &agreement.ephemeral_x, + &party_v_info, + name_alg_size * 8, + )?; + + // The secret is the ephemeral point marshalled as a TPMS_ECC_POINT, so each + // coordinate carries its own size. It is not a bare concatenation. + let secret = TPMS_ECC_POINT::new(&agreement.ephemeral_x, &agreement.ephemeral_y) + .toBytes()?; + + Ok((seed, secret)) + } + + _ => Err(TpmError::NotSupported(format!( + "Activation is not supported for a public area whose parameters are {:?} and \ + whose unique field is {:?}", + self.parameters.as_ref().map(std::mem::discriminant), + self.unique.as_ref().map(std::mem::discriminant), + ))), + } + } + // Performs RSA encryption of the given data using the public key pub fn encrypt( &self, @@ -493,6 +553,11 @@ impl TSS_KEY { mod tests { use super::*; use crate::crypto::software_provider::SOFTWARE_PROVIDER; + use elliptic_curve::ecdh::diffie_hellman; + use elliptic_curve::sec1::{EncodedPoint, FromEncodedPoint, ModulusSize, ToEncodedPoint}; + use elliptic_curve::{ + AffinePoint, CurveArithmetic, FieldBytes, FieldBytesSize, PublicKey, SecretKey, + }; use rand::rngs::OsRng; use rsa::traits::PublicKeyParts; use rsa::{Oaep, RsaPrivateKey}; @@ -530,29 +595,16 @@ mod tests { vec![0xab; 2 + Crypto::digestSize(name_alg)] } - /// Play the part of `TPM2_ActivateCredential` so `create_activation` can be exercised end - /// to end without a TPM. + /// Play the part of `TPM2_ActivateCredential` once the seed has been recovered. + /// + /// Everything here is defined on the seed alone, so it serves an RSA and an ECC activation + /// alike. Only the step that produces the seed differs between them. fn activate_credential( - endorsement_private: &RsaPrivateKey, + seed: &[u8], name_alg: TPM_ALG_ID, activated_name: &[u8], activation: &ActivationData, ) -> Result, TpmError> { - let padding = match name_alg { - TPM_ALG_ID::SHA1 => Oaep::new_with_label::("IDENTITY\0"), - TPM_ALG_ID::SHA256 => Oaep::new_with_label::("IDENTITY\0"), - _ => { - return Err(TpmError::NotSupported(format!( - "Unsupported nameAlg for OAEP: {:?}", - name_alg - ))) - } - }; - - let seed = endorsement_private - .decrypt(padding, &activation.secret) - .map_err(|e| TpmError::GenericError(format!("Seed decryption failed: {e}")))?; - // A TPM rejects a seed whose size is not the nameAlg digest size: TPM 2.0 Part 4, // CryptSecretDecrypt, returns TPM_RC_VALUE. Modelling that check here is what makes // this test able to catch a wrongly sized seed, because the seed itself travels inside @@ -567,11 +619,11 @@ mod tests { ))); } - let sym_key = Crypto::kdfa(&SOFTWARE_PROVIDER, name_alg, &seed, "STORAGE", activated_name, &[], 128)?; + let sym_key = Crypto::kdfa(&SOFTWARE_PROVIDER, name_alg, seed, "STORAGE", activated_name, &[], 128)?; let hmac_key = Crypto::kdfa( &SOFTWARE_PROVIDER, name_alg, - &seed, + seed, "INTEGRITY", &[], &[], @@ -611,6 +663,172 @@ mod tests { }) } + /// Recover an RSA activation's seed the way a TPM would, by decrypting it. + fn rsa_recover_seed( + endorsement_private: &RsaPrivateKey, + name_alg: TPM_ALG_ID, + secret: &[u8], + ) -> Result, TpmError> { + let padding = match name_alg { + TPM_ALG_ID::SHA1 => Oaep::new_with_label::("IDENTITY\0"), + TPM_ALG_ID::SHA256 => Oaep::new_with_label::("IDENTITY\0"), + _ => { + return Err(TpmError::NotSupported(format!( + "Unsupported nameAlg for OAEP: {:?}", + name_alg + ))) + } + }; + + endorsement_private + .decrypt(padding, secret) + .map_err(|e| TpmError::GenericError(format!("Seed decryption failed: {e}"))) + } + + /// A software stand-in for an ECC storage key, along with its public area. + fn ecc_endorsement_key( + curve: TPM_ECC_CURVE, + name_alg: TPM_ALG_ID, + ) -> Result<(SecretKey, TPMT_PUBLIC), TpmError> + where + C: CurveArithmetic, + FieldBytesSize: ModulusSize, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + { + let private_key = SecretKey::::random(&mut OsRng); + let public_area = ecc_public_area(&private_key, curve, name_alg)?; + + Ok((private_key, public_area)) + } + + /// The public area a TPM would report for an ECC key it already holds. + fn ecc_public_area( + private_key: &SecretKey, + curve: TPM_ECC_CURVE, + name_alg: TPM_ALG_ID, + ) -> Result + where + C: CurveArithmetic, + FieldBytesSize: ModulusSize, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + { + let point = private_key.public_key().to_encoded_point(false); + let missing = + || TpmError::GenericError("The generated point has no coordinates".to_string()); + + let parameters = TPMS_ECC_PARMS::new( + &TPMT_SYM_DEF_OBJECT::new(TPM_ALG_ID::AES, 128, TPM_ALG_ID::CFB), + &Some(TPMU_ASYM_SCHEME::null(TPMS_NULL_ASYM_SCHEME::default())), + curve, + &Some(TPMU_KDF_SCHEME::null(TPMS_NULL_KDF_SCHEME::default())), + ); + + Ok(TPMT_PUBLIC { + nameAlg: name_alg, + parameters: Some(TPMU_PUBLIC_PARMS::eccDetail(parameters)), + unique: Some(TPMU_PUBLIC_ID::ecc(TPMS_ECC_POINT::new( + &point.x().ok_or_else(missing)?.to_vec(), + &point.y().ok_or_else(missing)?.to_vec(), + ))), + ..Default::default() + }) + } + + /// A P-256 endorsement key whose public X coordinate is encoded short. + /// + /// A TPM is free to drop the leading zero octets of a coordinate it marshals into a `TPM2B`, + /// and restoring them is what [`Crypto::pad_ecc_coordinate`] exists for. A point built from a + /// SEC1 encoding always carries its coordinates at full width, so no generated fixture + /// exercises the restoration. + /// + /// The scalar is fixed rather than searched for. Only one key in 256 has a leading zero octet, + /// and generating that many keys costs more in an unoptimised test build than the rest of this + /// suite put together. + fn ecc_endorsement_key_with_a_short_x( + name_alg: TPM_ALG_ID, + ) -> Result<(SecretKey, TPMT_PUBLIC), TpmError> { + // Public X is 001de71052742cda097122e99b7d6e10e60ed5452c8a6de03f0ca1455b7ba892. + const SCALAR: [u8; 32] = [ + 0xad, 0x56, 0xea, 0xd1, 0xd6, 0x29, 0x0c, 0xf6, 0x9f, 0x18, 0x71, 0x82, 0xd2, 0x70, + 0xd6, 0x2f, 0xd4, 0x09, 0x2b, 0xa1, 0xda, 0x80, 0x5a, 0x64, 0x13, 0xcf, 0xfe, 0x42, + 0x8f, 0xa7, 0x34, 0xbf, + ]; + + let private_key = SecretKey::::from_slice(&SCALAR) + .map_err(|e| TpmError::GenericError(format!("The fixture scalar is invalid: {e}")))?; + let mut public_area = ecc_public_area(&private_key, TPM_ECC_CURVE::NIST_P256, name_alg)?; + + let Some(TPMU_PUBLIC_ID::ecc(point)) = &mut public_area.unique else { + return Err(TpmError::GenericError( + "The fixture is not an ECC key".to_string(), + )); + }; + + // Drop the leading zeroes, the way a TPM marshalling a TPM2B is entitled to. + let leading_zeroes = point + .x + .iter() + .position(|octet| *octet != 0) + .unwrap_or(point.x.len()); + point.x.drain(..leading_zeroes); + + Ok((private_key, public_area)) + } + + /// Recover an ECC activation's seed the way a TPM would, by repeating the agreement. + /// + /// Nothing is decrypted here, because nothing was transported. The TPM agrees its own private + /// key with the ephemeral point it was handed and derives the same seed the caller did. + fn ecc_recover_seed( + private_key: &SecretKey, + name_alg: TPM_ALG_ID, + secret: &[u8], + ) -> Result, TpmError> + where + C: CurveArithmetic, + FieldBytesSize: ModulusSize, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + { + // The secret is a marshalled TPMS_ECC_POINT, so each coordinate arrives sized. + let mut ephemeral_point = TPMS_ECC_POINT::default(); + ephemeral_point.initFromTpm(&mut TpmBuffer::from(secret))?; + + let width = FieldBytes::::default().len(); + let ephemeral_x = Crypto::pad_ecc_coordinate(&ephemeral_point.x, width)?; + let ephemeral_y = Crypto::pad_ecc_coordinate(&ephemeral_point.y, width)?; + + let encoded = EncodedPoint::::from_affine_coordinates( + FieldBytes::::from_slice(&ephemeral_x), + FieldBytes::::from_slice(&ephemeral_y), + false, + ); + let ephemeral_public: PublicKey = + Option::from(PublicKey::::from_encoded_point(&encoded)).ok_or_else(|| { + TpmError::GenericError("The ephemeral point is not on the curve".to_string()) + })?; + + let z = diffie_hellman(private_key.to_nonzero_scalar(), ephemeral_public.as_affine()); + + // The TPM is the responder, yet it still names the originator's point as partyU. Deriving + // with the roles reversed would produce a different seed in silence, which is why this + // assignment is written the same way on both sides. + let own_point = private_key.public_key().to_encoded_point(false); + let own_x = own_point + .x() + .ok_or_else(|| TpmError::GenericError("The key has no X coordinate".to_string()))? + .to_vec(); + + Crypto::kdfe( + &SOFTWARE_PROVIDER, + name_alg, + z.raw_secret_bytes(), + "IDENTITY", + &ephemeral_x, + &own_x, + Crypto::digestSize(name_alg) * 8, + ) + } + #[test] fn create_activation_round_trips_through_a_software_activate() -> Result<(), TpmError> { for name_alg in [TPM_ALG_ID::SHA1, TPM_ALG_ID::SHA256] { @@ -623,12 +841,8 @@ mod tests { &credential, &activated_name, )?; - let recovered = activate_credential( - &endorsement_private, - name_alg, - &activated_name, - &activation, - )?; + let seed = rsa_recover_seed(&endorsement_private, name_alg, &activation.secret)?; + let recovered = activate_credential(&seed, name_alg, &activated_name, &activation)?; assert_eq!(recovered, credential, "nameAlg {:?}", name_alg); } @@ -636,6 +850,170 @@ mod tests { Ok(()) } + /// The whole ECC activation, exercised against a stand-in that repeats the agreement. + /// + /// A curve is passed both as a `TPM_ECC_CURVE` and as its Rust type, so a mismatch between the + /// two would show up as a failed round trip rather than passing unnoticed. + fn ecc_round_trip(curve: TPM_ECC_CURVE, name_alg: TPM_ALG_ID) -> Result<(), TpmError> + where + C: CurveArithmetic, + FieldBytesSize: ModulusSize, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + { + let (private_key, public_area) = ecc_endorsement_key::(curve, name_alg)?; + let activated_name = activated_name(name_alg); + let credential = b"credential to activate".to_vec(); + + let activation = + public_area.create_activation(&SOFTWARE_PROVIDER, &credential, &activated_name)?; + let seed = ecc_recover_seed::(&private_key, name_alg, &activation.secret)?; + let recovered = activate_credential(&seed, name_alg, &activated_name, &activation)?; + + assert_eq!(recovered, credential, "curve {:?}, nameAlg {:?}", curve, name_alg); + Ok(()) + } + + #[test] + fn ecc_activation_round_trips_on_every_supported_curve() -> Result<(), TpmError> { + for name_alg in [TPM_ALG_ID::SHA1, TPM_ALG_ID::SHA256, TPM_ALG_ID::SHA384] { + ecc_round_trip::(TPM_ECC_CURVE::NIST_P256, name_alg)?; + ecc_round_trip::(TPM_ECC_CURVE::NIST_P384, name_alg)?; + ecc_round_trip::(TPM_ECC_CURVE::NIST_P521, name_alg)?; + } + + Ok(()) + } + + #[test] + fn ecc_activation_restores_a_coordinate_the_tpm_marshalled_short() -> Result<(), TpmError> { + let name_alg = TPM_ALG_ID::SHA256; + let (private_key, public_area) = ecc_endorsement_key_with_a_short_x(name_alg)?; + + let Some(TPMU_PUBLIC_ID::ecc(point)) = &public_area.unique else { + return Err(TpmError::GenericError( + "The fixture is not an ECC key".to_string(), + )); + }; + assert!( + point.x.len() < 32, + "the fixture is only meaningful if its X coordinate is short, got {} octets", + point.x.len() + ); + + let activated_name = activated_name(name_alg); + let credential = b"credential to activate".to_vec(); + + let activation = + public_area.create_activation(&SOFTWARE_PROVIDER, &credential, &activated_name)?; + let seed = ecc_recover_seed::(&private_key, name_alg, &activation.secret)?; + let recovered = activate_credential(&seed, name_alg, &activated_name, &activation)?; + + // KDFe hashes this coordinate, and the key's owner hashes it at its curve's full width. + // Hashing it as it arrived would derive a different seed on each side, and the credential + // would not come back. + assert_eq!(recovered, credential); + Ok(()) + } + + #[test] + fn ecc_activation_rejects_a_coordinate_wider_than_its_curve() -> Result<(), TpmError> { + let (_, mut public_area) = + ecc_endorsement_key::(TPM_ECC_CURVE::NIST_P256, TPM_ALG_ID::SHA256)?; + + if let Some(TPMU_PUBLIC_ID::ecc(point)) = &mut public_area.unique { + point.x.insert(0, 0); + } + + // A 33 octet X does not belong to P-256. Quietly trimming it to fit would agree with a + // point the key's owner never held, and the failure would only appear at the TPM. + assert!( + public_area + .create_activation( + &SOFTWARE_PROVIDER, + b"credential", + &activated_name(TPM_ALG_ID::SHA256) + ) + .is_err(), + "an oversized coordinate should be rejected" + ); + Ok(()) + } + + #[test] + fn ecc_activation_secret_is_a_marshalled_point() -> Result<(), TpmError> { + // Two sized coordinates, not a bare concatenation. A TPM parses this field as a + // TPMS_ECC_POINT, so a concatenation would be read as a single overlong X. + let (_, public_area) = + ecc_endorsement_key::(TPM_ECC_CURVE::NIST_P256, TPM_ALG_ID::SHA256)?; + let activation = public_area.create_activation( + &SOFTWARE_PROVIDER, + b"credential", + &activated_name(TPM_ALG_ID::SHA256), + )?; + + assert_eq!( + activation.secret.len(), + 2 + 32 + 2 + 32, + "P-256 point should be two sized 32 byte coordinates" + ); + + let mut point = TPMS_ECC_POINT::default(); + point.initFromTpm(&mut TpmBuffer::from(&activation.secret))?; + assert_eq!(point.x.len(), 32); + assert_eq!(point.y.len(), 32); + Ok(()) + } + + #[test] + fn ecc_activation_rejects_a_curve_without_an_implementation() -> Result<(), TpmError> { + // The registry defines these, so their coordinate width is known, but no agreement is + // available for them. Silently substituting a NIST curve would derive an unusable seed. + for curve in [TPM_ECC_CURVE::BN_P256, TPM_ECC_CURVE::SM2_P256] { + let (_, mut public_area) = ecc_endorsement_key::( + TPM_ECC_CURVE::NIST_P256, + TPM_ALG_ID::SHA256, + )?; + + if let Some(TPMU_PUBLIC_PARMS::eccDetail(params)) = &mut public_area.parameters { + params.curveID = curve; + } + + assert!( + public_area + .create_activation( + &SOFTWARE_PROVIDER, + b"credential", + &activated_name(TPM_ALG_ID::SHA256) + ) + .is_err(), + "curve {:?} should be rejected", + curve + ); + } + + Ok(()) + } + + #[test] + fn ecc_coordinate_size_agrees_with_the_curve_implementations() -> Result<(), TpmError> { + // The provider pads with the width its curve crate reports, while create_activation pads + // the peer's coordinate with the width from the registry table. The two feed the same + // KDFe, so a disagreement between them would derive mismatched seeds. + assert_eq!( + Crypto::ecc_coordinate_size(TPM_ECC_CURVE::NIST_P256)?, + FieldBytes::::default().len() + ); + assert_eq!( + Crypto::ecc_coordinate_size(TPM_ECC_CURVE::NIST_P384)?, + FieldBytes::::default().len() + ); + assert_eq!( + Crypto::ecc_coordinate_size(TPM_ECC_CURVE::NIST_P521)?, + FieldBytes::::default().len() + ); + Ok(()) + } + #[test] fn exponent_bytes_resolves_the_specification_default() { // The TPM encodes 2^16 + 1 as zero on the wire. From e8b51ac75b7b644ac0a817c22f79aaa0f5e38423 Mon Sep 17 00:00:00 2001 From: Roee Kasher Date: Thu, 13 Aug 2026 23:15:02 +0300 Subject: [PATCH 10/13] Add a CryptoProvider built on Windows CNG (#8) * Support ECC storage keys in create_activation TPMT_PUBLIC::create_activation rejected anything that was not an RSA key, so a TPM whose endorsement key is ECC could not be issued a credential at all. This adds the ECC path. The two algorithms differ only in how the seed reaches the TPM, which is now isolated in produce_seed. With RSA the seed is random and the secret is that seed under OAEP. With ECC nothing is transported: both sides derive the seed from an ECDH agreement, and the secret is the ephemeral public point the TPM needs to repeat it. Everything after the seed is defined on the seed alone and is shared unchanged. The crypto layer gains KDFe, the SP800-56A concatenation KDF that TPM 2.0 Part 1 section 11.4.10.3 defines for this derivation. It is easy to confuse with KDFa: it hashes rather than HMACs, and it does not hash the requested length. Getting either wrong yields output of the right shape and the wrong value. Only the ephemeral agreement is delegated to the provider, and it returns the raw agreed value. Deriving from it is specification behaviour rather than backend behaviour, so it stays in Crypto. Some platform APIs offer to perform the concatenation themselves, but at least one silently ignores the requested hash algorithm and always uses SHA-256, which no interoperability failure would attribute to the KDF. Coordinate width is answered by Crypto rather than by a provider, because a TPM may drop leading zero bytes from a coordinate it marshals into a TPM2B while KDFe hashes coordinates at full width. A curve outside the TCG registry is an error rather than a guess, since guessing produces a plausible key that simply does not match the peer's. The software provider implements the agreement over P-256, P-384 and P-521. Barreto-Naehrig and SM2 curves are rejected rather than approximated with a NIST curve. Tested by a round trip against a stand-in that repeats the agreement, on three curves across three nameAlgs. Mutation testing confirms the round trip fails if partyU and partyV are swapped, or if the KDFe label is changed, on one side only. It cannot catch a mistake made identically on both sides, since both ends call the same KDFe, so KDFe is additionally pinned to an independently computed vector. * Address review of the ECC create_activation change Four defects found in review of the previous commit, two of them behavioural and two in what the code claims about itself. KDFa and KDFe are specified in bits but truncated to whole octets, so a request that is not a multiple of eight returned too many significant bits instead of the leftmost bits right aligned. TSS.NET and TSS.CPP shift the stream to correct this. Both KDFs now share one helper rather than being fixed apart, since the two disagreeing about what a bit count means is worse than the original bug. KDFa was affected identically and is fixed here even though the previous commit did not touch it. This is unreachable through TPM 2.0 itself, where every KDF request is a digest or symmetric key size and therefore already octet aligned. It is fixed so that a caller using the library directly agrees with the other stacks. The shift is applied to the retained octets rather than to the whole stream, which is equivalent because the octets a full shift would produce beyond the requested length are discarded in either order. Where the request is octet aligned the operation is byte for byte the previous truncation, confirmed by forcing the shift to zero and observing that only the new test fails. The agreed ECDH value was held in an ordinary Vec and printed by a derived Debug, while the seed derived from it was being zeroized. Wrapping it in Zeroizing alone would have left the printing, since Zeroizing implements Debug whenever its contents do, so Debug is now written by hand and shows the public coordinates in full while withholding the secret. That keeps the value useful for diagnosing an encoding mismatch, which is what it is for. EccEphemeralAgreement documented all three of its fields as KDFe inputs. Only z and the ephemeral X reach the KDF; the ephemeral Y travels to the peer inside the marshalled point. The correction says why Y is still padded, since a reader told only that it is unhashed could conclude it needs no padding, and a TPM parsing the point is entitled to a full width coordinate. The same claim appeared in a comment in produce_seed and is corrected there too. Coordinate restoration had no coverage. Points built from a SEC1 encoding carry full width coordinates, so the padding was exercised only as a no op and removing it entirely passed the whole suite. A round trip is added against a key whose public X carries a leading zero, stripped from the fixture the way a TPM marshalling a TPM2B may strip it, along with a rejection case for a coordinate wider than its curve: trimming an oversized coordinate to fit would agree with a point the peer never held and fail only at the TPM. That fixture uses a fixed scalar. One key in 256 has a leading zero octet, and generating that many in an unoptimised test build cost more than the rest of the suite together. The test asserts the coordinate is short before relying on it, so a fixture that stopped being short would fail rather than quietly revert to a no op. The KDF test pins both functions at 250 bits against independently computed vectors. The two are unrelated to each other because KDFa hashes the requested length into every iteration and KDFe does not, so KDFa at 250 bits is a different stream rather than a shortened one. * Address the second review pass on the ECC activation change Wipe the KDF intermediates. Both KDFs accumulated the derived key in a plain Vec, and KDFe additionally copied the agreed value into a plain per-iteration buffer, so several copies of key material were freed unwiped. All are now Zeroizing, and both are reserved to their final size up front because a Vec that grows frees its old allocation without wiping it, which would have left copies behind despite the wrapper. KDFa's hashed input is deliberately left plain: everything in it is public and the key travels separately as the HMAC key. Give TEST_P192 its coordinate width. It was the only registry curve other than NONE falling through to the unknown arm. This function is a registry lookup, so it answers for any curve the registry names; whether a backend will agree over that curve is answered separately. The new sweep test enumerates the registry through the generated try_from rather than a hand-written list, so a curve added upstream fails the test instead of silently falling through. Stop pulling default features from the curve crates. They brought in the ECDSA and RFC6979 crates for a provider that only ever agrees. The graph goes from 70 crates to 68; the PKCS#8 and PEM crates stay, since the rsa crate needs them independently. * Qualify size_of_val to match the rest of the crate Every other use of this family is written out in full: std::mem::size_of in device.rs, tpm2_helpers.rs and twice in tpm_buffer.rs. This one line was the only unqualified use, so it now matches the other four. This is a consistency change rather than a fix. size_of_val has been in the prelude since Rust 1.80, the crate declares no MSRV below that, and the unqualified form built and passed the suite; a review comment claiming otherwise was mistaken. The _val form is kept rather than size_of::() so that the reservation follows the counter's type if it ever changes, which is what makes the reservation correct. * Add a CryptoProvider built on Windows CNG The software provider brings in fifty crates to implement primitives Windows already ships. This adds a second backend behind a cng-crypto feature that calls bcrypt.dll through the windows bindings the crate already depends on, so it adds no dependencies of its own. Building with --no-default-features --features cng-crypto takes the graph from 68 crates to 18. Seven of the nine primitives are implemented. generate_keypair and pkcs1v15_sign are not, for the reason already recorded on RsaOps: signing recovers the second prime by dividing the modulus by the first, and CNG exposes no big-integer division. They are left together because a key this provider generated but could not sign with would be a trap. Three places where the obvious CNG call is the wrong one, each documented where it is made: No algorithm provider is ever opened. Pseudo-handles cover every algorithm needed here, including AES-ECB, which also removes the chaining-mode property that would otherwise have to be set. Only key and secret handles need owning. AES-CFB is built on the ECB primitive rather than BCRYPT_CHAIN_MODE_CFB. That mode defaults to an eight bit segment rather than a full block, and rejects input that is not block aligned; a TPM credential is a digest behind a two byte size, so it never is. The agreed ECDH value comes back least significant byte first, unlike every other value CNG exports, and is reversed and left padded to the curve width here. The raw secret is exported rather than letting CNG run the SP800-56A concatenation, both because the derivation belongs to Crypto::kdfe and because that KDF ignores the hash algorithm it is handed. Thirteen tests compare the two backends primitive by primitive, and run KDFa and KDFe over both so the stack above the provider is covered too. ECDH cannot be compared that way, since each backend generates its own ephemeral key, so that test holds the peer's private half and recomputes the agreed value from the ephemeral point CNG returned; without it the byte reversal would be invisible, because a wrongly ordered value is still the right length. --- TSS.Rust/Cargo.toml | 6 +- TSS.Rust/src/crypto/cng_provider.rs | 923 ++++++++++++++++++++++++++++ TSS.Rust/src/crypto/mod.rs | 7 +- 3 files changed, 933 insertions(+), 3 deletions(-) create mode 100644 TSS.Rust/src/crypto/cng_provider.rs diff --git a/TSS.Rust/Cargo.toml b/TSS.Rust/Cargo.toml index 873b21ba..34ecff5a 100644 --- a/TSS.Rust/Cargo.toml +++ b/TSS.Rust/Cargo.toml @@ -30,6 +30,10 @@ software-crypto = [ "dep:sm3", ] +# Build the CNG-backed CryptoProvider. This adds no dependencies: it calls bcrypt.dll through the +# windows bindings the crate already uses, and it is inert on non-Windows targets. +cng-crypto = [] + [dependencies] derivative = "2.2.0" lazy_static = "1.5.0" @@ -55,7 +59,7 @@ p384 = { version = "0.13", default-features = false, features = ["ecdh"], option p521 = { version = "0.13", default-features = false, features = ["ecdh"], optional = true } [target.'cfg(windows)'.dependencies] -windows = { version = "0.61.1", features = ["Win32_Foundation", "Win32_Security", "Win32_System_TpmBaseServices", "Win32_Networking", "Win32_Networking_WinSock"] } +windows = { version = "0.61.1", features = ["Win32_Foundation", "Win32_Security", "Win32_Security_Cryptography", "Win32_System_TpmBaseServices", "Win32_Networking", "Win32_Networking_WinSock"] } [target.'cfg(unix)'.dependencies] libc = "0.2" diff --git a/TSS.Rust/src/crypto/cng_provider.rs b/TSS.Rust/src/crypto/cng_provider.rs new file mode 100644 index 00000000..c1d60e09 --- /dev/null +++ b/TSS.Rust/src/crypto/cng_provider.rs @@ -0,0 +1,923 @@ +//! A [`CryptoProvider`] built on Windows CNG. +//! +//! This backend adds no crates at all. Everything below is a call into `bcrypt.dll` through the +//! bindings the crate already depends on, so a Windows host can drop the `software-crypto` +//! feature and stop linking a second implementation of primitives the operating system already +//! ships, in FIPS validated form and under its own servicing. +//! +//! It does not replace [`software_provider`](super::software_provider) outright. Two of the nine +//! primitives are left unimplemented, for the reason recorded on +//! [`RsaOps`](super::provider::RsaOps): signing here needs the second prime recovered by dividing +//! the modulus by the first, and CNG exposes no big-integer division. A host that needs those two +//! keeps the software provider for them. +//! +//! Three things about this backend are worth knowing before reading it, because each is a place +//! where the obvious CNG call is the wrong one: +//! +//! * **No algorithm provider is ever opened.** Windows 8 introduced pseudo-handles, constants that +//! stand in for an already-open provider, and the bindings expose one for every algorithm needed +//! here. There is therefore no `BCryptOpenAlgorithmProvider`, no matching close, and no lifetime +//! to manage for them. +//! * **AES-CFB is built on ECB rather than on `BCRYPT_CHAIN_MODE_CFB`.** See [`aes_cfb`]. +//! * **The agreed ECDH value comes back byte reversed.** See [`raw_secret`]. + +use super::provider::{CryptoProvider, EccEphemeralAgreement, EccOps, RsaOps}; +use super::Crypto; +use crate::{ + error::TpmError, + tpm_types::{TPM_ALG_ID, TPM_ECC_CURVE}, +}; + +use std::ffi::c_void; + +use windows::core::PCWSTR; +use windows::Win32::Foundation::{NTSTATUS, STATUS_INVALID_SIGNATURE}; +use windows::Win32::Security::Cryptography::{ + BCryptDeriveKey, BCryptDestroyKey, BCryptDestroySecret, BCryptEncrypt, BCryptExportKey, + BCryptFinalizeKeyPair, BCryptGenRandom, BCryptGenerateKeyPair, BCryptGenerateSymmetricKey, + BCryptHash, BCryptImportKeyPair, BCryptSecretAgreement, BCryptVerifySignature, + BCRYPTGENRANDOM_FLAGS, BCRYPT_AES_ECB_ALG_HANDLE, BCRYPT_ALG_HANDLE, BCRYPT_ECCKEY_BLOB, + BCRYPT_ECCPUBLIC_BLOB, BCRYPT_ECDH_P256_ALG_HANDLE, BCRYPT_ECDH_P384_ALG_HANDLE, + BCRYPT_ECDH_P521_ALG_HANDLE, BCRYPT_ECDH_PUBLIC_P256_MAGIC, BCRYPT_ECDH_PUBLIC_P384_MAGIC, + BCRYPT_ECDH_PUBLIC_P521_MAGIC, BCRYPT_FLAGS, BCRYPT_HMAC_SHA1_ALG_HANDLE, + BCRYPT_HMAC_SHA256_ALG_HANDLE, BCRYPT_HMAC_SHA384_ALG_HANDLE, BCRYPT_HMAC_SHA512_ALG_HANDLE, + BCRYPT_KDF_RAW_SECRET, BCRYPT_KEY_HANDLE, BCRYPT_OAEP_PADDING_INFO, BCRYPT_PAD_OAEP, + BCRYPT_PAD_PKCS1, BCRYPT_PKCS1_PADDING_INFO, BCRYPT_RNG_ALG_HANDLE, BCRYPT_RSAKEY_BLOB, + BCRYPT_RSAPUBLIC_BLOB, BCRYPT_RSAPUBLIC_MAGIC, BCRYPT_RSA_ALG_HANDLE, BCRYPT_SECRET_HANDLE, + BCRYPT_SHA1_ALGORITHM, BCRYPT_SHA1_ALG_HANDLE, BCRYPT_SHA256_ALGORITHM, + BCRYPT_SHA256_ALG_HANDLE, BCRYPT_SHA384_ALGORITHM, BCRYPT_SHA384_ALG_HANDLE, + BCRYPT_SHA512_ALGORITHM, BCRYPT_SHA512_ALG_HANDLE, +}; +use zeroize::Zeroizing; + +/// The CNG-backed provider. +/// +/// `generate_keypair` and `pkcs1v15_sign` are absent deliberately and report +/// [`TpmError::NotSupported`]; see the module documentation. +pub static CNG_PROVIDER: CryptoProvider = CryptoProvider { + hash, + hmac, + aes_cfb, + random, + rsa: RsaOps { + oaep_encrypt: rsa_oaep_encrypt, + pkcs1v15_verify: rsa_pkcs1v15_verify, + ..RsaOps::new_unimplemented() + }, + ecc: EccOps { + ephemeral_agree: ecc_ephemeral_agree, + }, +}; + +/// The AES block size, which is also the CFB segment width the TPM specification requires. +const AES_BLOCK_LEN: usize = 16; + +/// Turns a failed `NTSTATUS` into an error naming both the operation and the raw status. +/// +/// The status is reported rather than the `HRESULT` the bindings would convert it to, because the +/// `NTSTATUS` is the value CNG documents and the one worth searching for. `0xC000A000` says +/// "invalid signature"; the translated `HRESULT` says considerably less. +fn check(status: NTSTATUS, operation: &str) -> Result<(), TpmError> { + if status.is_ok() { + return Ok(()); + } + + Err(TpmError::GenericError(format!( + "CNG {operation} failed with NTSTATUS 0x{:08X}", + status.0 as u32 + ))) +} + +/// Owns a `BCRYPT_KEY_HANDLE` so that every exit path destroys it. +struct KeyHandle(BCRYPT_KEY_HANDLE); + +impl Drop for KeyHandle { + fn drop(&mut self) { + // Nothing useful can be done if this fails, and it runs on the unwind path too, so the + // status is deliberately discarded rather than panicking a second time. + unsafe { + let _ = BCryptDestroyKey(self.0); + } + } +} + +/// Owns a `BCRYPT_SECRET_HANDLE` so that every exit path destroys it. +/// +/// The handle refers to an agreed value held inside CNG, so releasing it is what discards that +/// value rather than merely tidying up a bookkeeping slot. +struct SecretHandle(BCRYPT_SECRET_HANDLE); + +impl Drop for SecretHandle { + fn drop(&mut self) { + unsafe { + let _ = BCryptDestroySecret(self.0); + } + } +} + +/// The already-open provider for a hash algorithm. +/// +/// SM3 has no entry because CNG does not implement it. A TPM may nominate it, so this is a real +/// gap rather than an oversight, and it is reported as one instead of being approximated. +fn hash_alg_handle(alg: TPM_ALG_ID) -> Result { + match alg { + TPM_ALG_ID::SHA1 => Ok(BCRYPT_SHA1_ALG_HANDLE), + TPM_ALG_ID::SHA256 => Ok(BCRYPT_SHA256_ALG_HANDLE), + TPM_ALG_ID::SHA384 => Ok(BCRYPT_SHA384_ALG_HANDLE), + TPM_ALG_ID::SHA512 => Ok(BCRYPT_SHA512_ALG_HANDLE), + other => Err(TpmError::NotSupported(format!( + "CNG does not offer hash algorithm {other}" + ))), + } +} + +/// The already-open provider for an HMAC over a hash algorithm. +/// +/// These are separate pseudo-handles rather than the hash ones with a flag set, so the usual +/// `BCRYPT_ALG_HANDLE_HMAC_FLAG` dance at open time does not arise. +fn hmac_alg_handle(alg: TPM_ALG_ID) -> Result { + match alg { + TPM_ALG_ID::SHA1 => Ok(BCRYPT_HMAC_SHA1_ALG_HANDLE), + TPM_ALG_ID::SHA256 => Ok(BCRYPT_HMAC_SHA256_ALG_HANDLE), + TPM_ALG_ID::SHA384 => Ok(BCRYPT_HMAC_SHA384_ALG_HANDLE), + TPM_ALG_ID::SHA512 => Ok(BCRYPT_HMAC_SHA512_ALG_HANDLE), + other => Err(TpmError::NotSupported(format!( + "CNG does not offer HMAC over hash algorithm {other}" + ))), + } +} + +/// The name CNG knows a hash algorithm by, for the padding structures that take one by string. +fn hash_alg_name(alg: TPM_ALG_ID) -> Result { + match alg { + TPM_ALG_ID::SHA1 => Ok(BCRYPT_SHA1_ALGORITHM), + TPM_ALG_ID::SHA256 => Ok(BCRYPT_SHA256_ALGORITHM), + TPM_ALG_ID::SHA384 => Ok(BCRYPT_SHA384_ALGORITHM), + TPM_ALG_ID::SHA512 => Ok(BCRYPT_SHA512_ALGORITHM), + other => Err(TpmError::NotSupported(format!( + "CNG does not offer hash algorithm {other}" + ))), + } +} + +/// One-shot hashing, which is what `BCryptHash` is for. +/// +/// The create, update, finish and destroy sequence would be needed only to hash data arriving in +/// pieces, and the provider contract hands over one slice. +fn hash(alg: TPM_ALG_ID, data: &[u8]) -> Result, TpmError> { + let handle = hash_alg_handle(alg)?; + let mut digest = vec![0u8; Crypto::digest_size_checked(alg)?]; + + check( + unsafe { BCryptHash(handle, None, data, &mut digest) }, + "hashing", + )?; + + Ok(digest) +} + +/// HMAC, which is the same one-shot call with the key supplied as the secret. +fn hmac(alg: TPM_ALG_ID, key: &[u8], data: &[u8]) -> Result, TpmError> { + let handle = hmac_alg_handle(alg)?; + let mut mac = vec![0u8; Crypto::digest_size_checked(alg)?]; + + check( + unsafe { BCryptHash(handle, Some(key), data, &mut mac) }, + "HMAC", + )?; + + Ok(mac) +} + +fn random(out: &mut [u8]) -> Result<(), TpmError> { + check( + unsafe { BCryptGenRandom(Some(BCRYPT_RNG_ALG_HANDLE), out, BCRYPTGENRANDOM_FLAGS(0)) }, + "random number generation", + ) +} + +/// AES in cipher feedback mode over a full block segment, built on the ECB primitive. +/// +/// CNG does offer `BCRYPT_CHAIN_MODE_CFB`, and it is the wrong call twice over. Its segment +/// defaults to eight bits rather than a full block, which produces a completely different cipher +/// under a name that looks right; and it rejects input whose length is not a multiple of the block +/// size, which a TPM credential never satisfies, being a digest behind a two byte size. Driving +/// the block cipher directly avoids both. CFB is a stream mode, so consuming only the leading +/// bytes of the key stream for a trailing partial block is exactly what the mode calls for. +/// +/// Only the block *encryption* is ever needed, in both directions, because CFB encrypts its +/// feedback value rather than the data. +fn aes_cfb(encrypt: bool, key: &[u8], iv: &[u8], data: &[u8]) -> Result, TpmError> { + if iv.len() != AES_BLOCK_LEN { + return Err(TpmError::InvalidArraySize(format!( + "An AES-CFB IV must be {AES_BLOCK_LEN} bytes, not {}", + iv.len() + ))); + } + + // Rejected here rather than left to CNG, so the error names the length that was wrong. + if !matches!(key.len(), 16 | 24 | 32) { + return Err(TpmError::InvalidArraySize(format!( + "An AES key must be 16, 24 or 32 bytes, not {}", + key.len() + ))); + } + + let mut handle = BCRYPT_KEY_HANDLE::default(); + check( + unsafe { BCryptGenerateSymmetricKey(BCRYPT_AES_ECB_ALG_HANDLE, &mut handle, None, key, 0) }, + "AES key import", + )?; + let key_handle = KeyHandle(handle); + + let mut feedback = [0u8; AES_BLOCK_LEN]; + feedback.copy_from_slice(iv); + + let mut result = Vec::with_capacity(data.len()); + + for chunk in data.chunks(AES_BLOCK_LEN) { + let keystream = encrypt_block(&key_handle, &feedback)?; + + // The next feedback value is the ciphertext in both directions: when encrypting that is + // the block just produced, when decrypting it is the block just consumed. A trailing + // partial block is never fed forward, because nothing follows it. + let mut next_feedback = [0u8; AES_BLOCK_LEN]; + + for (index, &byte) in chunk.iter().enumerate() { + let out = byte ^ keystream[index]; + next_feedback[index] = if encrypt { out } else { byte }; + result.push(out); + } + + feedback = next_feedback; + } + + Ok(result) +} + +/// One raw AES block encryption. +fn encrypt_block( + key: &KeyHandle, + block: &[u8; AES_BLOCK_LEN], +) -> Result<[u8; AES_BLOCK_LEN], TpmError> { + let mut out = [0u8; AES_BLOCK_LEN]; + let mut written = 0u32; + + // No padding flag, and a whole block in, so ECB returns exactly one block. + check( + unsafe { + BCryptEncrypt( + key.0, + Some(block), + None, + None, + Some(&mut out), + &mut written, + BCRYPT_FLAGS(0), + ) + }, + "AES block encryption", + )?; + + if written as usize != AES_BLOCK_LEN { + return Err(TpmError::InvalidArraySize(format!( + "An AES block encryption returned {written} bytes rather than {AES_BLOCK_LEN}" + ))); + } + + Ok(out) +} + +/// What CNG needs to know about a curve, beyond the width the registry already defines. +/// +/// The magic is part of the key blob and identifies the curve to the provider the blob is imported +/// into, so it has to match the pseudo-handle beside it. +struct CurveParams { + provider: BCRYPT_ALG_HANDLE, + public_magic: u32, + key_bits: u32, +} + +/// Only the NIST prime curves appear, because they are the only ones CNG names a provider for. +/// +/// A Barreto-Naehrig or SM2 curve is rejected rather than approximated with a curve of similar +/// width: agreeing over the wrong curve derives a key the peer cannot reproduce, and nothing about +/// the resulting failure would point back here. +fn curve_params(curve: TPM_ECC_CURVE) -> Result { + match curve { + TPM_ECC_CURVE::NIST_P256 => Ok(CurveParams { + provider: BCRYPT_ECDH_P256_ALG_HANDLE, + public_magic: BCRYPT_ECDH_PUBLIC_P256_MAGIC, + key_bits: 256, + }), + TPM_ECC_CURVE::NIST_P384 => Ok(CurveParams { + provider: BCRYPT_ECDH_P384_ALG_HANDLE, + public_magic: BCRYPT_ECDH_PUBLIC_P384_MAGIC, + key_bits: 384, + }), + // 521 rather than 528: the key length is the curve's order in bits, while the coordinate + // width rounds that up to whole octets. + TPM_ECC_CURVE::NIST_P521 => Ok(CurveParams { + provider: BCRYPT_ECDH_P521_ALG_HANDLE, + public_magic: BCRYPT_ECDH_PUBLIC_P521_MAGIC, + key_bits: 521, + }), + other => Err(TpmError::NotSupported(format!( + "CNG cannot perform ECDH over curve {other}" + ))), + } +} + +/// The fixed part of a `BCRYPT_ECCKEY_BLOB`, which the coordinates follow immediately. +const ECC_BLOB_HEADER_LEN: usize = std::mem::size_of::(); + +fn ecc_ephemeral_agree( + curve: TPM_ECC_CURVE, + peer_x: &[u8], + peer_y: &[u8], +) -> Result { + let params = curve_params(curve)?; + let width = Crypto::ecc_coordinate_size(curve)?; + + // CNG reads a fixed width coordinate pair out of the blob, so a short encoding would be read + // as a differently valued point rather than rejected. + let x = Crypto::pad_ecc_coordinate(peer_x, width)?; + let y = Crypto::pad_ecc_coordinate(peer_y, width)?; + + // An off-curve point is rejected by the import, which is the only validation performed on the + // peer's point and the reason it happens before anything is agreed. + let peer = import_public(¶ms, width, &x, &y)?; + let ephemeral = generate_ephemeral(¶ms)?; + let (ephemeral_x, ephemeral_y) = export_public_coordinates(&ephemeral, width)?; + + let mut secret = BCRYPT_SECRET_HANDLE::default(); + check( + unsafe { BCryptSecretAgreement(ephemeral.0, peer.0, &mut secret, 0) }, + "ECDH secret agreement", + )?; + let secret = SecretHandle(secret); + + let z = raw_secret(&secret, width)?; + + Ok(EccEphemeralAgreement { + z, + ephemeral_x, + ephemeral_y, + }) +} + +/// Imports a public point that is already padded to the curve's width. +fn import_public( + params: &CurveParams, + width: usize, + x: &[u8], + y: &[u8], +) -> Result { + let mut blob = Vec::with_capacity(ECC_BLOB_HEADER_LEN + x.len() + y.len()); + blob.extend_from_slice(¶ms.public_magic.to_le_bytes()); + blob.extend_from_slice(&(width as u32).to_le_bytes()); + blob.extend_from_slice(x); + blob.extend_from_slice(y); + + let mut handle = BCRYPT_KEY_HANDLE::default(); + check( + unsafe { + BCryptImportKeyPair( + params.provider, + None, + BCRYPT_ECCPUBLIC_BLOB, + &mut handle, + &blob, + 0, + ) + }, + "ECC public key import", + )?; + + Ok(KeyHandle(handle)) +} + +/// Generates a throwaway key on the peer's curve. +fn generate_ephemeral(params: &CurveParams) -> Result { + let mut handle = BCRYPT_KEY_HANDLE::default(); + check( + unsafe { BCryptGenerateKeyPair(params.provider, &mut handle, params.key_bits, 0) }, + "ECC key generation", + )?; + + // The handle is owned from here on, so a failure to finalize still destroys it. + let key = KeyHandle(handle); + check( + unsafe { BCryptFinalizeKeyPair(key.0, 0) }, + "ECC key finalization", + )?; + + Ok(key) +} + +/// Reads a key's public point back out of CNG. +fn export_public_coordinates( + key: &KeyHandle, + width: usize, +) -> Result<(Vec, Vec), TpmError> { + let mut required = 0u32; + check( + unsafe { BCryptExportKey(key.0, None, BCRYPT_ECCPUBLIC_BLOB, None, &mut required, 0) }, + "ECC public key export sizing", + )?; + + let mut blob = vec![0u8; required as usize]; + check( + unsafe { + BCryptExportKey( + key.0, + None, + BCRYPT_ECCPUBLIC_BLOB, + Some(&mut blob), + &mut required, + 0, + ) + }, + "ECC public key export", + )?; + + let coordinates = blob + .get(ECC_BLOB_HEADER_LEN..ECC_BLOB_HEADER_LEN + 2 * width) + .ok_or_else(|| { + TpmError::InvalidArraySize(format!( + "An exported ECC key blob of {} bytes is too short for two {width} byte coordinates", + blob.len() + )) + })?; + + let (x, y) = coordinates.split_at(width); + Ok((x.to_vec(), y.to_vec())) +} + +/// The agreed value itself, in the big-endian order every caller expects it in. +/// +/// Two things about this call are easy to get wrong and silent when wrong, since both produce a +/// well formed value of the right length that simply disagrees with the peer. +/// +/// The first is the KDF. CNG offers to run the SP800-56A concatenation itself, and at least one +/// Windows release ignores the hash algorithm it is handed and always uses SHA-256. The +/// derivation the TPM defines belongs to [`Crypto::kdfe`](super::Crypto::kdfe) in any case, so +/// `BCRYPT_KDF_RAW_SECRET` is used to ask for the agreed value untouched. +/// +/// The second is the byte order. That one export hands the value back least significant byte +/// first, unlike every other value CNG exports, so it is reversed here. Left padding afterwards +/// matters for the same reason the input coordinates are padded: the value is hashed at the +/// curve's full width, and a short encoding hashes to something else entirely. +fn raw_secret(secret: &SecretHandle, width: usize) -> Result>, TpmError> { + let mut agreed = Zeroizing::new(vec![0u8; width]); + let mut written = 0u32; + + check( + unsafe { + BCryptDeriveKey( + secret.0, + BCRYPT_KDF_RAW_SECRET, + None, + Some(&mut agreed), + &mut written, + 0, + ) + }, + "ECDH raw secret export", + )?; + + let written = written as usize; + if written == 0 || written > width { + return Err(TpmError::InvalidArraySize(format!( + "An ECDH agreement over a {width} byte curve returned {written} bytes" + ))); + } + + agreed.truncate(written); + agreed.reverse(); + + if written == width { + return Ok(agreed); + } + + // `Zeroizing>` wipes the whole allocation rather than the live length, so the shorter + // buffer is still cleared when it drops at the end of this function. + let mut padded = Zeroizing::new(vec![0u8; width]); + padded[width - written..].copy_from_slice(&agreed); + Ok(padded) +} + +/// Imports an RSA public key given its big-endian components. +/// +/// The blob is a fixed header followed by the exponent and then the modulus, in that order. Both +/// prime lengths are zero, which is what marks the blob as carrying only the public half. +fn import_rsa_public(modulus: &[u8], exponent: &[u8]) -> Result { + if modulus.is_empty() || exponent.is_empty() { + return Err(TpmError::InvalidArraySize( + "An RSA public key needs both a modulus and an exponent".to_string(), + )); + } + + let header = BCRYPT_RSAKEY_BLOB { + Magic: BCRYPT_RSAPUBLIC_MAGIC, + BitLength: (modulus.len() * 8) as u32, + cbPublicExp: exponent.len() as u32, + cbModulus: modulus.len() as u32, + cbPrime1: 0, + cbPrime2: 0, + }; + + let header_len = std::mem::size_of::(); + let mut blob = Vec::with_capacity(header_len + exponent.len() + modulus.len()); + + // The header is plain old data with no padding to reproduce by hand, so it is copied out + // wholesale rather than field by field. + let header_bytes = + unsafe { std::slice::from_raw_parts(&header as *const _ as *const u8, header_len) }; + blob.extend_from_slice(header_bytes); + blob.extend_from_slice(exponent); + blob.extend_from_slice(modulus); + + let mut handle = BCRYPT_KEY_HANDLE::default(); + check( + unsafe { + BCryptImportKeyPair( + BCRYPT_RSA_ALG_HANDLE, + None, + BCRYPT_RSAPUBLIC_BLOB, + &mut handle, + &blob, + 0, + ) + }, + "RSA public key import", + )?; + + Ok(KeyHandle(handle)) +} + +fn rsa_oaep_encrypt( + modulus: &[u8], + exponent: &[u8], + hash_alg: TPM_ALG_ID, + label: &[u8], + data: &[u8], +) -> Result, TpmError> { + let key = import_rsa_public(modulus, exponent)?; + + // CNG takes the label through a mutable pointer even though it only reads it, so it needs a + // buffer of its own that outlives both calls below. The label is passed through byte for byte, + // including the trailing NUL the TPM specification puts in it. + let mut label = label.to_vec(); + let padding = BCRYPT_OAEP_PADDING_INFO { + pszAlgId: hash_alg_name(hash_alg)?, + pbLabel: label.as_mut_ptr(), + cbLabel: label.len() as u32, + }; + let padding_ptr = Some(&padding as *const _ as *const c_void); + + let mut required = 0u32; + check( + unsafe { + BCryptEncrypt( + key.0, + Some(data), + padding_ptr, + None, + None, + &mut required, + BCRYPT_PAD_OAEP, + ) + }, + "RSA-OAEP encryption sizing", + )?; + + let mut ciphertext = vec![0u8; required as usize]; + check( + unsafe { + BCryptEncrypt( + key.0, + Some(data), + padding_ptr, + None, + Some(&mut ciphertext), + &mut required, + BCRYPT_PAD_OAEP, + ) + }, + "RSA-OAEP encryption", + )?; + + ciphertext.truncate(required as usize); + Ok(ciphertext) +} + +fn rsa_pkcs1v15_verify( + modulus: &[u8], + exponent: &[u8], + hash_alg: TPM_ALG_ID, + digest: &[u8], + signature: &[u8], +) -> Result { + let key = import_rsa_public(modulus, exponent)?; + + let padding = BCRYPT_PKCS1_PADDING_INFO { + pszAlgId: hash_alg_name(hash_alg)?, + }; + + let status = unsafe { + BCryptVerifySignature( + key.0, + Some(&padding as *const _ as *const c_void), + digest, + signature, + BCRYPT_PAD_PKCS1, + ) + }; + + // A signature that does not verify is an answer rather than a failure, and is the one status + // separated out here. Anything else means the verification could not be performed at all, for + // instance because the digest length did not match the algorithm named in the padding. + if status == STATUS_INVALID_SIGNATURE { + return Ok(false); + } + + check(status, "RSA PKCS#1 v1.5 verification")?; + Ok(true) +} + +#[cfg(all(test, feature = "software-crypto"))] +mod tests { + use super::*; + use crate::crypto::software_provider::SOFTWARE_PROVIDER; + + use elliptic_curve::sec1::ToEncodedPoint; + use rand::rngs::OsRng; + use rsa::traits::PublicKeyParts; + use rsa::{Oaep, RsaPrivateKey}; + use sha2::Sha256; + + /// The hash algorithms both providers implement. + /// + /// SM3 is absent because CNG has none, which the last case below states outright rather than + /// leaving to be inferred from its absence here. + const SHARED_HASHES: [TPM_ALG_ID; 4] = [ + TPM_ALG_ID::SHA1, + TPM_ALG_ID::SHA256, + TPM_ALG_ID::SHA384, + TPM_ALG_ID::SHA512, + ]; + + #[test] + fn hashes_agree_with_the_software_provider() { + for alg in SHARED_HASHES { + for data in [b"".as_slice(), b"abc".as_slice(), &[0x5au8; 1000]] { + let theirs = (SOFTWARE_PROVIDER.hash)(alg, data).unwrap(); + let ours = (CNG_PROVIDER.hash)(alg, data).unwrap(); + assert_eq!( + ours, + theirs, + "hash mismatch for {alg:?} over {} bytes", + data.len() + ); + assert_eq!(ours.len(), Crypto::digestSize(alg)); + } + } + } + + #[test] + fn hmacs_agree_with_the_software_provider() { + // The empty key and the over-long key are the two cases HMAC defines specially: one is + // padded out to the block size, the other is hashed down to it. A backend that delegated + // either differently would disagree here rather than in some later derivation. + let keys: [&[u8]; 4] = [b"", b"key", &[0xa5; 64], &[0x3c; 200]]; + + for alg in SHARED_HASHES { + for key in keys { + let theirs = (SOFTWARE_PROVIDER.hmac)(alg, key, b"message").unwrap(); + let ours = (CNG_PROVIDER.hmac)(alg, key, b"message").unwrap(); + assert_eq!( + ours, + theirs, + "HMAC mismatch for {alg:?} under a {} byte key", + key.len() + ); + } + } + } + + #[test] + fn sm3_is_reported_as_unsupported_rather_than_approximated() { + assert!(matches!( + (CNG_PROVIDER.hash)(TPM_ALG_ID::SM3_256, b"abc"), + Err(TpmError::NotSupported(_)) + )); + } + + #[test] + fn aes_cfb_agrees_with_the_software_provider() { + let iv = [0x42u8; AES_BLOCK_LEN]; + + for key_len in [16usize, 24, 32] { + let key = vec![0x11u8; key_len]; + + // 34 bytes is the length that matters: a TPM credential is a digest behind a two byte + // size, so it is never block aligned, and the trailing partial block is where a + // backend that reached for CNG's own CFB mode would diverge. + for len in [0usize, 1, 15, 16, 17, 34, 64] { + let plaintext: Vec = (0..len).map(|i| i as u8).collect(); + + let theirs = (SOFTWARE_PROVIDER.aes_cfb)(true, &key, &iv, &plaintext).unwrap(); + let ours = (CNG_PROVIDER.aes_cfb)(true, &key, &iv, &plaintext).unwrap(); + assert_eq!( + ours, + theirs, + "AES-{}-CFB encrypt mismatch at {len} bytes", + key_len * 8 + ); + + let round_trip = (CNG_PROVIDER.aes_cfb)(false, &key, &iv, &ours).unwrap(); + assert_eq!( + round_trip, plaintext, + "AES-CFB round trip failed at {len} bytes" + ); + } + } + } + + #[test] + fn aes_cfb_rejects_a_wrong_sized_key_or_iv() { + let good_key = [0u8; 16]; + let good_iv = [0u8; AES_BLOCK_LEN]; + + assert!((CNG_PROVIDER.aes_cfb)(true, &[0u8; 20], &good_iv, b"data").is_err()); + assert!((CNG_PROVIDER.aes_cfb)(true, &good_key, &[0u8; 8], b"data").is_err()); + } + + #[test] + fn random_fills_the_whole_buffer() { + let mut buffer = [0u8; 64]; + (CNG_PROVIDER.random)(&mut buffer).unwrap(); + assert!( + buffer.iter().any(|&b| b != 0), + "the random buffer came back untouched" + ); + + // A zero length request is legal and must not be turned into an error. + (CNG_PROVIDER.random)(&mut []).unwrap(); + } + + /// Agrees with CNG against a peer key this test owns, then reproduces the agreed value + /// independently. + /// + /// This is the test that earns its keep. Two providers cannot simply be compared on ECDH, + /// because each generates its own ephemeral key, so instead the peer's private half is kept + /// here and used to recompute the same value from the ephemeral point CNG returned. That + /// covers the byte reversal in `raw_secret`, which is otherwise invisible: a value that is + /// reversed, or padded to the wrong width, is still the right length and still looks like a + /// secret. + #[test] + fn ecdh_agrees_with_a_peer_holding_the_private_half() { + let peer_secret = p256::ecdh::EphemeralSecret::random(&mut OsRng); + let peer_point = peer_secret.public_key().to_encoded_point(false); + + let agreement = (CNG_PROVIDER.ecc.ephemeral_agree)( + TPM_ECC_CURVE::NIST_P256, + peer_point.x().unwrap(), + peer_point.y().unwrap(), + ) + .unwrap(); + + assert_eq!(agreement.z.len(), 32); + assert_eq!(agreement.ephemeral_x.len(), 32); + assert_eq!(agreement.ephemeral_y.len(), 32); + + let ephemeral_point = p256::EncodedPoint::from_affine_coordinates( + p256::FieldBytes::from_slice(&agreement.ephemeral_x), + p256::FieldBytes::from_slice(&agreement.ephemeral_y), + false, + ); + let ephemeral_public = + p256::PublicKey::from_sec1_bytes(ephemeral_point.as_bytes()).unwrap(); + + let expected = peer_secret.diffie_hellman(&ephemeral_public); + assert_eq!( + agreement.z.as_slice(), + expected.raw_secret_bytes().as_slice(), + "the agreed value disagrees with the peer, so the export is being mishandled" + ); + } + + #[test] + fn ecdh_rejects_a_curve_cng_cannot_agree_over() { + assert!(matches!( + (CNG_PROVIDER.ecc.ephemeral_agree)(TPM_ECC_CURVE::SM2_P256, &[1u8; 32], &[2u8; 32]), + Err(TpmError::NotSupported(_)) + )); + } + + #[test] + fn ecdh_rejects_a_point_that_is_not_on_the_curve() { + // Coordinates picked arbitrarily are overwhelmingly unlikely to satisfy the curve + // equation, and CNG checks that on import rather than agreeing with nonsense. + assert!((CNG_PROVIDER.ecc.ephemeral_agree)( + TPM_ECC_CURVE::NIST_P256, + &[0x11u8; 32], + &[0x22u8; 32] + ) + .is_err()); + } + + #[test] + fn oaep_ciphertext_decrypts_under_the_matching_private_key() { + // OAEP is randomized, so the two providers cannot be compared on their output. Decrypting + // is the check that matters anyway, since it is what the TPM will do with this blob. + let private = RsaPrivateKey::new(&mut OsRng, 2048).unwrap(); + let modulus = private.n().to_bytes_be(); + let exponent = private.e().to_bytes_be(); + + let label = b"IDENTITY\0"; + let secret = b"the seed the credential protects"; + + let ciphertext = + (CNG_PROVIDER.rsa.oaep_encrypt)(&modulus, &exponent, TPM_ALG_ID::SHA256, label, secret) + .unwrap(); + assert_eq!(ciphertext.len(), modulus.len()); + + // The `rsa` crate models the label as a string, and takes it without the trailing NUL + // that CNG and the TPM specification both include in the hashed label. + let padding = Oaep::new_with_label::("IDENTITY\0"); + let recovered = private.decrypt(padding, &ciphertext).unwrap(); + assert_eq!(recovered, secret); + } + + #[test] + fn pkcs1v15_verification_agrees_with_the_software_provider() { + let key = (SOFTWARE_PROVIDER.rsa.generate_keypair)(2048, &[0x01, 0x00, 0x01]).unwrap(); + let digest = (SOFTWARE_PROVIDER.hash)(TPM_ALG_ID::SHA256, b"signed data").unwrap(); + let signature = + (SOFTWARE_PROVIDER.rsa.pkcs1v15_sign)(&key, TPM_ALG_ID::SHA256, &digest).unwrap(); + + let verified = (CNG_PROVIDER.rsa.pkcs1v15_verify)( + &key.modulus, + &key.exponent, + TPM_ALG_ID::SHA256, + &digest, + &signature, + ) + .unwrap(); + assert!(verified, "a good signature was rejected"); + + // A bad signature is an answer, not an error, so it must come back as `Ok(false)`. + let mut corrupted = signature.clone(); + corrupted[0] ^= 0xff; + let verified = (CNG_PROVIDER.rsa.pkcs1v15_verify)( + &key.modulus, + &key.exponent, + TPM_ALG_ID::SHA256, + &digest, + &corrupted, + ) + .unwrap(); + assert!(!verified, "a corrupted signature was accepted"); + } + + #[test] + fn the_two_unimplemented_rsa_primitives_say_so() { + assert!(matches!( + (CNG_PROVIDER.rsa.generate_keypair)(2048, &[0x01, 0x00, 0x01]), + Err(TpmError::NotSupported(_)) + )); + + let key = crate::crypto::RsaKeyParts { + modulus: vec![0xff; 256], + prime: vec![0xff; 128], + exponent: vec![0x01, 0x00, 0x01], + }; + assert!(matches!( + (CNG_PROVIDER.rsa.pkcs1v15_sign)(&key, TPM_ALG_ID::SHA256, &[0u8; 32]), + Err(TpmError::NotSupported(_)) + )); + } + + /// The KDFs sit above the provider, so running one through both backends checks the whole + /// stack rather than the primitives in isolation. + #[test] + fn the_kdfs_produce_the_same_stream_over_either_provider() { + for alg in SHARED_HASHES { + for bits in [128usize, 250, 256, 512] { + let theirs = + Crypto::kdfa(&SOFTWARE_PROVIDER, alg, b"key", "ATH", &[], &[], bits).unwrap(); + let ours = Crypto::kdfa(&CNG_PROVIDER, alg, b"key", "ATH", &[], &[], bits).unwrap(); + assert_eq!(ours, theirs, "KDFa mismatch for {alg:?} at {bits} bits"); + + let z = [0x77u8; 32]; + let theirs = + Crypto::kdfe(&SOFTWARE_PROVIDER, alg, &z, "IDENTITY", &[], &[], bits).unwrap(); + let ours = + Crypto::kdfe(&CNG_PROVIDER, alg, &z, "IDENTITY", &[], &[], bits).unwrap(); + assert_eq!(ours, theirs, "KDFe mismatch for {alg:?} at {bits} bits"); + } + } + } +} diff --git a/TSS.Rust/src/crypto/mod.rs b/TSS.Rust/src/crypto/mod.rs index 2514ebeb..baf81beb 100644 --- a/TSS.Rust/src/crypto/mod.rs +++ b/TSS.Rust/src/crypto/mod.rs @@ -1,8 +1,9 @@ //! Cryptography used to build and check TPM structures on the host. //! //! This module is split into two layers. [`provider`] defines the primitives TSS.Rust needs from -//! a crypto backend, and [`software_provider`] supplies one built on the pure-Rust RustCrypto -//! crates. +//! a crypto backend, and two implementations are supplied: [`software_provider`], built on the +//! pure-Rust RustCrypto crates and available everywhere, and [`cng_provider`], built on Windows +//! CNG and adding no crates at all. //! [`Crypto`] sits on top and adds the logic that the TPM 2.0 specification defines in terms of //! those primitives — digest sizes, KDFa, signature validation — which is the same regardless of //! which backend is in use. @@ -12,6 +13,8 @@ //! visible at the call site. [`Tpm2`](crate::tpm2_impl::Tpm2) holds the provider it was built with //! and supplies it to the command dispatch path on the caller's behalf. +#[cfg(all(feature = "cng-crypto", windows))] +pub mod cng_provider; pub mod provider; #[cfg(feature = "software-crypto")] pub mod software_provider; From dcd1f1b4a13d07d58e199359fd4f6d5b8947eca3 Mon Sep 17 00:00:00 2001 From: Roee Kasher Date: Fri, 14 Aug 2026 17:36:51 +0300 Subject: [PATCH 11/13] License and rename (#9) * Declare the crate's licence in its manifest The repository's LICENSE file has said MIT since the beginning, but the Rust manifest named no licence at all. Tooling that audits dependency licences reads the manifest rather than the file, so the crate is reported as unlicensed, and a consumer whose policy refuses unlicensed dependencies cannot take it at all. cargo-deny fails outright on this. A description and repository are added alongside. The repository points at this fork rather than microsoft/TSS.MSR, because upstream carries C, C++, Java, JavaScript, .NET and Python bindings but no Rust one, so there is as yet no upstream home to name. * Report an unusable RSA signature as invalid rather than as a failure BCryptVerifySignature answers STATUS_INVALID_SIGNATURE for a signature that does not verify, but STATUS_INVALID_PARAMETER for one it will not attempt at all, which for an attacker supplied value mostly means a signature numerically greater than the modulus or of the wrong length. Only the first was being turned into Ok(false), so a malformed signature came back as an error. That disagreed with the RustCrypto provider, which answers Ok(false) for exactly those inputs, so the two backends differed on which signatures are acceptable. A caller checking a signature off the wire wants to hear "invalid" rather than an error it then has to classify. The test that caught this was itself defective: it corrupted the signature's high byte, which pushes the value above the modulus only for some keys, and the key is generated afresh on every run. It therefore passed or failed by luck, and it passed the first time. It now covers a flipped low byte, a flipped high byte, a truncated signature and an empty one, and asserts that both backends agree on each, so the outcome no longer depends on which key was drawn. * Rename the crate to tss-msr-rs The package was named tss-rust, which is already taken on crates.io by an unrelated project, so that name is unavailable if this crate is ever published to a registry. tss-msr-rs names the repository this lives in and follows the ecosystem's -rs convention. The sibling bindings cannot be copied directly: they are Microsoft.TSS on NuGet and com.microsoft.azure:TSS.Java on Maven, both of which carry the vendor in a namespace that crates.io does not have. Claiming a microsoft- prefixed name on a flat namespace would assert an ownership this repository is not currently in a position to assert. Only the manifest and one example needed changing: the library refers to itself as `crate` throughout, so nothing internal depended on the old name. --- TSS.Rust/Cargo.lock | 2 +- TSS.Rust/Cargo.toml | 12 ++++- TSS.Rust/examples/tpm_samples.rs | 4 +- TSS.Rust/src/crypto/cng_provider.rs | 70 ++++++++++++++++++++++------- 4 files changed, 67 insertions(+), 21 deletions(-) diff --git a/TSS.Rust/Cargo.lock b/TSS.Rust/Cargo.lock index 4ef55927..c5211eb9 100644 --- a/TSS.Rust/Cargo.lock +++ b/TSS.Rust/Cargo.lock @@ -552,7 +552,7 @@ dependencies = [ ] [[package]] -name = "tss-rust" +name = "tss-msr-rs" version = "0.1.0" dependencies = [ "aes", diff --git a/TSS.Rust/Cargo.toml b/TSS.Rust/Cargo.toml index 34ecff5a..3d2112cd 100644 --- a/TSS.Rust/Cargo.toml +++ b/TSS.Rust/Cargo.toml @@ -1,7 +1,17 @@ [package] -name = "tss-rust" +name = "tss-msr-rs" version = "0.1.0" edition = "2021" +# The repository's LICENSE file has always said MIT; stating it here as well is what lets a +# consumer determine it mechanically. Tooling that audits dependency licences reads the manifest, +# not the file, so without this line the crate is reported as unlicensed and a consumer whose +# policy forbids that cannot take the dependency at all. +license = "MIT" +description = "A TPM 2.0 Software Stack (TSS) implementation for Rust." +# Points at the fork because that is where this code actually lives. The upstream TSS.MSR carries +# C, C++, Java, JavaScript, .NET and Python bindings but no Rust one, so there is as yet no +# upstream home to name here. Update this if that changes. +repository = "https://github.com/Kasher/TSS.MSR" [lints.rust] non_camel_case_types = "allow" diff --git a/TSS.Rust/examples/tpm_samples.rs b/TSS.Rust/examples/tpm_samples.rs index 7def48dc..1fb72fc3 100644 --- a/TSS.Rust/examples/tpm_samples.rs +++ b/TSS.Rust/examples/tpm_samples.rs @@ -1,4 +1,4 @@ -//! TSS.Rust sample suite. +//! TSS.Rust sample suite. //! //! # This suite mutates TPM state //! @@ -28,7 +28,7 @@ //! and compare output as a set. The crate's unit tests are the reliable signal. use std::io::{self, Write}; -use tss_rust::{ +use tss_msr_rs::{ auth_session::Session, crypto::{software_provider::SOFTWARE_PROVIDER, Crypto}, device::{TpmDevice, TpmTbsDevice}, error::TpmError, diff --git a/TSS.Rust/src/crypto/cng_provider.rs b/TSS.Rust/src/crypto/cng_provider.rs index c1d60e09..e4cee139 100644 --- a/TSS.Rust/src/crypto/cng_provider.rs +++ b/TSS.Rust/src/crypto/cng_provider.rs @@ -31,7 +31,7 @@ use crate::{ use std::ffi::c_void; use windows::core::PCWSTR; -use windows::Win32::Foundation::{NTSTATUS, STATUS_INVALID_SIGNATURE}; +use windows::Win32::Foundation::{NTSTATUS, STATUS_INVALID_PARAMETER, STATUS_INVALID_SIGNATURE}; use windows::Win32::Security::Cryptography::{ BCryptDeriveKey, BCryptDestroyKey, BCryptDestroySecret, BCryptEncrypt, BCryptExportKey, BCryptFinalizeKeyPair, BCryptGenRandom, BCryptGenerateKeyPair, BCryptGenerateSymmetricKey, @@ -635,10 +635,17 @@ fn rsa_pkcs1v15_verify( ) }; - // A signature that does not verify is an answer rather than a failure, and is the one status - // separated out here. Anything else means the verification could not be performed at all, for - // instance because the digest length did not match the algorithm named in the padding. - if status == STATUS_INVALID_SIGNATURE { + // A signature that does not verify is an answer rather than a failure, so both of the statuses + // that mean "no" are turned into one. + // + // `STATUS_INVALID_SIGNATURE` is the obvious one. `STATUS_INVALID_PARAMETER` is how CNG reports + // a signature it will not even attempt, which for an attacker-supplied value mostly means one + // numerically greater than the modulus or of the wrong length. Those are malformed signatures, + // and a caller checking a signature off the wire wants to hear "invalid" rather than an error + // it has to classify. Reporting them as failures would also disagree with every other backend: + // the RustCrypto one answers `Ok(false)` for exactly these inputs, so a provider that did not + // would make the two disagree on which signatures are acceptable. + if status == STATUS_INVALID_SIGNATURE || status == STATUS_INVALID_PARAMETER { return Ok(false); } @@ -868,18 +875,47 @@ mod tests { .unwrap(); assert!(verified, "a good signature was rejected"); - // A bad signature is an answer, not an error, so it must come back as `Ok(false)`. - let mut corrupted = signature.clone(); - corrupted[0] ^= 0xff; - let verified = (CNG_PROVIDER.rsa.pkcs1v15_verify)( - &key.modulus, - &key.exponent, - TPM_ALG_ID::SHA256, - &digest, - &corrupted, - ) - .unwrap(); - assert!(!verified, "a corrupted signature was accepted"); + // Every way a signature can be wrong has to come back as `Ok(false)` rather than as an + // error, and has to agree with the other backend on that. The first two cases are not + // interchangeable: corrupting the low byte leaves a value below the modulus, which CNG + // rejects as an invalid signature, while corrupting the high byte can push it above the + // modulus, which CNG rejects as an invalid *parameter*. Testing only one of them left the + // outcome depending on which key was generated, and the test passed or failed by luck. + let mut low_byte_flipped = signature.clone(); + *low_byte_flipped.last_mut().unwrap() ^= 0xff; + + let mut high_byte_flipped = signature.clone(); + high_byte_flipped[0] ^= 0xff; + + let truncated = signature[..signature.len() - 1].to_vec(); + let empty = Vec::new(); + + for (description, bad) in [ + ("a flipped low byte", low_byte_flipped), + ("a flipped high byte", high_byte_flipped), + ("a truncated signature", truncated), + ("an empty signature", empty), + ] { + let ours = (CNG_PROVIDER.rsa.pkcs1v15_verify)( + &key.modulus, + &key.exponent, + TPM_ALG_ID::SHA256, + &digest, + &bad, + ) + .unwrap_or_else(|e| panic!("{description} was reported as a failure rather than as an invalid signature: {e:?}")); + assert!(!ours, "{description} was accepted"); + + let theirs = (SOFTWARE_PROVIDER.rsa.pkcs1v15_verify)( + &key.modulus, + &key.exponent, + TPM_ALG_ID::SHA256, + &digest, + &bad, + ) + .unwrap(); + assert_eq!(ours, theirs, "the backends disagree about {description}"); + } } #[test] From 71b41020ac9036a65fd1d0374a55606750e65fad Mon Sep 17 00:00:00 2001 From: Roee Kasher Date: Sun, 16 Aug 2026 12:38:28 +0300 Subject: [PATCH 12/13] Harden TSS.Rust: policy digests, session authorization, and resource safety (#10) * Report absent union fields as an error instead of panicking TargetLang.UnionMember emitted `.unwrap().` for Rust, so serializing a struct whose union selector is not its first marshaled field panicked instead of returning an error. TPMS_ATTEST derives Default and TPMS_ATTEST::new(..., &None) is public, so TPMS_ATTEST::default().toBytes() was a panic reachable from safe, documented public API. Emit `.ok_or(TpmError::InvalidUnion)?.` instead. Both serialize and deserialize already return Result<(), TpmError>, so no signatures change. The first-field guard is retained: it is a load-bearing "empty object" convention that lets a default-constructed TPMT_SENSITIVE marshal as a zero-size sized object, which LoadExternal and PolicySigned rely on. It is also emitted for the other five target languages. Verified: TPMS_ATTEST::default().toBytes() now returns Err; the TPMS_CAPABILITY_DATA, TPMT_SENSITIVE and TPMT_PUBLIC defaults still return Ok(0 bytes). Regeneration is byte-for-byte reproducible and the generated diff contains only this substitution. Non-Rust generator branches are unchanged. * Fix the non-Windows build and close a TBS context leak The crate did not compile off Windows at all. Three independent causes: - `windows` was declared in the platform-agnostic [dependencies], and it unconditionally pulls windows-future, which does not build off Windows. This is the blocking failure; no amount of cfg-gating in device.rs alone would have fixed it. The cfg(windows) block already declares the crate with a superset of features. - device.rs imported windows::Win32::System::TpmBaseServices with no cfg, unlike the imports bracketing it. - The non-Windows branch of create_tpm_with_crypto referenced TpmTcpDevice, which is entirely commented out, and passed a device by value where Box is required. The Linux path also used TcpStream, Read and Write without importing them. macOS and the BSDs now get a documented NotSupported stub rather than silently having no device. Separately, TpmTbsDevice acquired a TBS context but had no Drop, so the context leaked on every drop and on every early return; TSS.CPP closes it in its destructor. The handle now lives in an owning TbsContext type whose Drop closes it, which also collapses the scattered null checks into an Option. Borrowed contexts are still not closed, and that invariant is now asserted rather than merely documented. The Linux socket read path bounded its allocation by a peer-supplied length prefix; it is now capped by MAX_RESPONSE_SIZE, and read and write timeouts are set on connect. Verified: cargo check and clippy --all-targets --all-features -D warnings both pass for x86_64-unknown-linux-gnu and aarch64-apple-darwin, and fail on the parent commit. * Fix out-of-bounds panic selecting PCR 24 or above TPMS_PCR_SELECTION::new_from_pcr_u32 divided pcr_bytes by 8 a second time in its growth check, comparing the wrong quantity. The selection vector therefore never grew below PCR 192, so indexing it for PCR 24 -- the first PCR outside the standard 0-23 range -- panicked. Compare pcr_bytes + 1 against the current size instead. PCRs 0-23 keep their historical three-byte pcrSelect exactly; this is a wire format, so a change there would silently invalidate existing PCR policies. A test pins that. new_from_pcrs_vec was audited for the same defect and does not have it: it sizes the vector with a single division and clamps to the standard range. * Say where an unusable signature falls in the verify contract RsaOps::pkcs1v15_verify already says that `false` means the signature did not verify and that `Err` means the verification could not be performed, "for instance because the key or the hash algorithm was rejected". It did not say where a signature that is not a candidate at all falls: one whose length differs from the modulus, or whose value is at or above it. Neither the key nor the hash algorithm is at fault in that case, and those are what `Err` is reserved for, so both shapes are `false`. That follows from the existing sentence rather than adding to it, but it is worth stating, because both are chosen by whoever supplied the signature: a backend that reported them as failures would divert a caller such as validate_certify out of its `false` branch on input a remote party controls, and would disagree with the other backend about which signatures are acceptable. The software provider gets those shapes as a test. It answers them with `Ok(false)` because the `rsa` crate folds every verification error into one; the CNG provider, which sits on an API that distinguishes them, folds them in itself and is covered by its own tests. * Withhold and zeroize secret material in Debug output Session derived Debug over session_key -- the key that authorizes every command on the session and keys parameter encryption -- and is cloned on essentially every command. For a password session sess_in.hmac holds the raw authValue. RsaKeyParts derived Debug over prime, a private RSA factor sitting next to its own modulus. Both now have hand-written Debug impls that withhold the secret, and hand-written Drop impls that zeroize it. This follows the pattern EccEphemeralAgreement already uses in crypto/provider.rs. session_key is left as Vec rather than Zeroizing> deliberately: Zeroizing does not deref-coerce on assignment, so it would force edits inside Session::new, from_tpm_response and calc_session_key. The hand-written Drop wipes the same material and additionally covers sess_in.hmac, which Zeroizing could not reach because TPMS_AUTH_COMMAND is generated. TSS_KEY::create_key moved fields out of RsaKeyParts, which Drop forbids; it now uses std::mem::take. * Fix policy digest computation and session authorization Policy digests -------------- Three defects each produced a digest no TPM session could satisfy, so objects sealed against them were permanently unusable. All three are checked against TSS.CPP TpmPolicy.cpp and TSS.NET PolicyAces.cs, and the new tests pin externally derived vectors rather than our own output. - policy_update skipped its second extend when arg3 was empty, despite its own doc comment saying the extend is unconditional. This hit PolicySigned, PolicySecret and PolicyAuthorize with the common empty policyRef. - PolicyNv delegated to policy_update and so performed two extends where TPM2_PolicyNV defines exactly one. - PolicyPcr::execute sent the first raw PCR value as pcrDigest instead of the digest computed a few lines above, and indexed [0] unchecked. An empty pcrDigest makes the TPM skip the comparison entirely, so this could silently produce a session that did not check PCRs. Both paths now share one pcr_digest() and empty input is rejected. Session authorization --------------------- The response HMAC was verified only for HMAC sessions and policy sessions running PolicyAuthValue, leaving every other policy session's response parameters unauthenticated. The rule is now the TPM's own: authorization is expected unless the session is PWAP or has run TPM2_PolicyPassword. Both a missing and an unexpected authorization are errors, and the tag is compared in constant time. The command side needed the same rule. Probing a real TPM showed a policy session carrying only PolicyCommandCode returning an empty response authorization, because this client sent an empty command auth and triggered the TPM's "key empty and input empty" shortcut. Sending a computed HMAC for every non-PWAP, non-password session -- mirroring includeAuth in the reference implementation -- also fixes a pre-existing bug: salted and bound policy sessions were unusable, failing with TPM_RC_BAD_AUTH. The next command's session attributes were taken from the response, so an adversary could clear encrypt/decrypt and silently downgrade the following command to cleartext. The caller's attributes are now authoritative and a differing echo is an error. Salted sessions and parameter encryption ---------------------------------------- start_auth_session_ex read the salt key's public area over the very channel the salt protects, so a man in the middle could supply its own key, learn the salt and forge both HMACs undetectably. It now takes a caller-pinned TrustedPublic and the internal ReadPublic is removed. The salt is generated internally at the digest size. TrustedPublic pairs a public area with its locally derived name and makes the trust decision explicit at the call site. Its documentation states that this is caller-asserted trust: it is not channel authentication and not proof of TPM residency. Parameter encryption on an unsalted, unbound session derived its key from nothing but the two cleartext nonces. It is now refused at construction and again in param_xcrypt. The gate is a secret_key_material flag rather than an emptiness check, because a session bound to an entity with an empty authValue has a non-empty session key that is still a pure function of public data. Tests ----- Adds a mock TpmDevice, so tpm2_impl.rs has executed coverage for the first time, and six hardware round trips behind #[ignore]. * Use a single extend for the assertions that take one Making policy_update's second extend unconditional was right for the TPM's PolicyUpdate helper, which PolicySigned, PolicySecret and PolicyAuthorize use. But eight assertions were routing through that helper with an empty reference and relying on the removed guard to get a single extend, so they began producing a digest no TPM session could satisfy. PolicyCommandCode, PolicyPcr, PolicyAuthValue, PolicyPassword, PolicyCpHash, PolicyNameHash, PolicyCounterTimer and PolicyDuplicationSelect each extend once, as their counterparts in TSS.CPP TpmPolicy.cpp do. They now go through a single-extend helper, and policy_update is defined in terms of it. PolicyLocality, PolicyNv and PolicyOr already extended once by hand and are routed through the same helper without changing their bytes. The PolicyPcr test vector was itself the two-extend value, which is why it agreed with the defect instead of catching it. It is re-derived from PolicyPcr::UpdatePolicyDigest, the old value is kept as a negative assertion, and every other assertion gains a vector taken from its own matching C++ function rather than from the shared helper. Separately, the generated session salt was sized to the digest of the session's hash algorithm; the TPM sizes it to the digest of the salt key's nameAlg, so a SHA-1 salt key was sent a 32-byte salt and answered TPM_RC_VALUE. Two hardware tests added alongside it were also wrong: a restricted decryption key was given a signing scheme, and a PCR selection was a single all-zero byte. Verified on a physical TPM: the policy tree sample reports every digest matching its trial session, and all six hardware round trips pass. * Decode format-1 response codes, fix retry, check returned Names Response codes -------------- process_response ran the raw code through the generated exhaustive TPM_RC match, whose fallback is InvalidEnumValue. Format-1 codes embed a handle, parameter or session index in bits 8-11, so they are not bare enum members: TPM_RC_SIZE against parameter 1 arrives as 0x1D5 and was absent from the match, as were 0x1C5, 0x18B, 0x98E and others. Ordinary TPM failures therefore surfaced as "Invalid enum value" with the real code discarded and last_response_code never set. The code is now read as a raw u32 and split into its base TPM_RC and an index. The masks match TSS.NET Tpm2.cs and TSS.CPP Tpm2.cpp. The two private helpers written for this and left unreachable behind the `?` are folded into the new decoder. TpmCommandError was declared, given Display, Error and From, stored in last_error and exposed by last_error() -- but never constructed, so last_error() always returned None. It now carries the raw code and index and is actually built. Retry ----- TPM_RC::RETRY returned without clearing current_cmd_code, so the resend always failed with "Pending async command must be completed" after an unconditional one second sleep. The invocation state is now cleared, resends are bounded, and the stall is replaced by a short doubling backoff. Returned Names -------------- Object Names were taken verbatim from the response and never recomputed. They are now checked against the public area. This is documented strictly as a consistency check. It catches a malfunctioning or inconsistent TPM or resource manager. It is not authentication, does not defeat an adversary who supplies both a public area and a matching Name, and is not proof of TPM residency; callers who need that pin an expected Name out of band via TrustedPublic::from_pinned_name. Only CreatePrimary and CreateLoaded return the public area. Load and LoadExternal take it as a command input -- LoadExternalResponse carries only a handle and a name -- so for those the Name is checked against the caller's own public area, which is the stronger comparison. * Make validate_certify state its precondition and fail closed validate_certify moves onto TrustedPublic, so the trust decision in the signing key is present at every call site rather than implied. The signing key's provenance is a precondition, not a result. The attestation, the signature and the signing key's own objectAttributes all reach this function from the same untrusted source, so an adversary who fabricates a public area and an attestation to match satisfies every check at once. The documentation says so plainly: this authenticates no channel and shows nothing about where the private half lives. Callers establish provenance out of band, by credential activation against an endorsement key or by an attestation key certificate, and the new from_activated_credential constructor covers the first of those -- with a real check rather than a relabelling, verifying both that the credential came back intact and that the public area belongs to the object the credential was bound to. Given that provenance, the added restricted, sign, fixedTPM and fixedParent checks are defense in depth. restricted is the load-bearing one: it is what gives the magic == TPM_GENERATED_VALUE check content, because an unrestricted key will sign a hand-written TPMS_ATTEST and reduce that check to a test of whether the attacker remembered a constant. A non-RSASSA signature was delegated to validate_signature with an empty digest, skipping the magic, extraData and Name checks entirely; it was unexploitable only because validate_signature independently rejects such keys. Those checks now run before the algorithm dispatch, so no future branch can bypass them, and an unsupported algorithm returns NotSupported. The verdict was a Result that callers could and did drop with `?`. It is now Result<()> with a distinct VerificationFailed error. The sample had the signing key certify itself against a public area read from the TPM being attested, which is circular trust demonstrated as usage; it now certifies a second key. * Close leaks, correct overclaims, and make the tests pin their fixes A re-review of the preceding commits found resource leaks, one real authorization defect, and several claims that were stronger than the code behind them. Leaks ----- start_auth_session_ex flushed nothing when session construction failed after the TPM had already loaded the session, and a sample triggered that path deliberately on every run. The Name consistency check leaked a loaded object when it rejected one. TbsContext skipped its close under cfg(test) while the hardware tests opened real contexts, so a test run leaked one per test; the close is now reached through a function pointer that only the dangling-handle unit test replaces, and a probe over 1000 connect/drop cycles shows no handle growth where it previously showed 1000. Authorization ------------- Every PolicyAssertion::execute returned tpm.last_session(). For PolicySecret and PolicyNV the TPM auto-creates a password session for their auth handle, so that is what came back, and the next assertion in the tree then sent TPM_RS_PW as its policySession. Against an object with userWithAuth and an empty authValue the command would succeed by password while the caller believed a policy was enforced. All fourteen sites now select the session by handle. Overclaims corrected -------------------- expects_response_auth said skipping verification left responses unauthenticated "even though the session had the key material". An unsalted, unbound policy session has an empty session key, so the tag is forgeable by anyone on the wire: verification there detects corruption, not tampering. The second TPM behaviour it cites was observed on hardware, and now says so instead of implying the reference implementation. The samples reached for TrustedPublic::assume_trusted where a real check was free, teaching the weak form of an API whose documentation is careful; they now pin the Name the surrounding code already verified. A sample still described the session salt as sized to the session hash, which an earlier commit had corrected, and claimed no channel existed between the process and a locally created key -- the resource manager is that channel. TSS_KEY now zeroizes its private prime on drop. Its derived Debug still prints it, and TPM_HANDLE::auth_value has the same problem; both need a generator change and are documented as such rather than described as fixed. Tests ----- Ten tests asserted outcomes that also held before the fix they named. The salt-sizing regression, which reached hardware, still had no test at all. Session HMAC assertions keyed on the session key the code under test derived, so a KDFa label or nonce-order change stayed green. Added: an external KDFa vector, a salt-length test, digest vectors for the two assertions that legitimately extend twice, and rewrites of the tests that could not fail. Each added or repaired test was checked against a revert of the fix it covers. Also: consistent session-to-handle association between command and response, a bounds check on provider-supplied key material, checked arithmetic on a response length, two broken intra-doc links, and the removal of ~440 lines of commented-out transport code together with the cdylib output and dependencies that only it used. * Pin the rejection shapes over bytes that do not change between runs pkcs1v15_verification_agrees_with_the_software_provider draws a fresh key on every run, so it can only ever say that today's key was fine. Those shapes are the regression test for a provider that answered some of them with `Err`, which is worth stating over bytes that are the same every time: this test either always passes or always fails, and a failure is reproducible by running it again. It needs no private half, because a value of the right width below the modulus stands in for a signature perfectly well when every shape derived from it is meant to be rejected. Two of the shapes are not covered elsewhere. A signature with every byte set is at or above any modulus of the same width, which is how CNG comes to answer STATUS_INVALID_PARAMETER for a reason other than length; flipping the leading byte of a generated signature reaches that only for some keys, and how often depends on the modulus drawn. A signature one byte too long is the other side of the truncated one. verification_still_fails_rather_than_rejects_when_it_cannot_be_performed pins what is left of `Err` now that both statuses meaning "no" are folded into `Ok(false)`: a key CNG cannot import, and a hash algorithm it does not offer, both fail ahead of the status map rather than through it, so the order of the three steps in rsa_pkcs1v15_verify is what keeps them errors. It is read against a call differing in neither respect that comes back as a verdict, so it cannot be satisfied by a provider that simply errored on everything. * Stop the Rust generator deriving Debug over secret key material TSS_KEY::privatePart (an RSA prime) and TPM_HANDLE::auth_value (the caller's authorization value) were wiped or not, but either way printable: CGenRust emitted #[derive(Debug, Clone, Derivative)] for every struct, so any log line or error path that formatted one rendered the secret in full. CGenRust now carries a named list of structs it withholds Debug from, and the redacting implementations are hand-written in tpm_type_extensions.rs. The list is not inferred from the AST on purpose: whether a field is secret is not in the specification tables, and TPM_HANDLE::auth_value is injected from tpm_extensions.rs.snips so the generator never sees it. To keep a missing implementation from being a silent gap, the generator also emits a compile-time assertion requiring Debug for every listed type. A type with no implementation and no other use fails the build and is named, so the list and the implementations cannot drift apart. Beyond the two reported types, the survey added the two structures that carry a sensitive area in the clear (TPMT_SENSITIVE, TPMS_SENSITIVE_CREATE) and the five TPMU_SENSITIVE_COMPOSITE members, none of which is used anywhere else in the binding. Left alone deliberately: TPM2B_AUTH, which is a type alias for TPM2B_DIGEST and could not be redacted without redacting every public digest; the TPM-encrypted blobs TPM2B_PRIVATE, TPM2B_ENCRYPTED_SECRET and TPM2B_ID_OBJECT; and TPM2B_SENSITIVE, whose only field redacts itself. TPM_HANDLE still has no zeroizing Drop, so its auth value is no longer printable but is still left in freed heap. That is stated in the type's documentation rather than implied. * Narrow the empty-object marshaling exception to TPMT_SENSITIVE CodeGenBase emitted an early `return Ok(())` for every structure whose union selector is its first marshaled field, so TPMS_CAPABILITY_DATA, TPMT_SIG_SCHEME, TPMT_PUBLIC and eleven others serialized to an empty buffer when their required union was absent, bypassing the `ok_or(TpmError::InvalidUnion)` introduced in c789038. Only TPMT_SENSITIVE needs the exception: TPM2_LoadExternal loads a public area alone by sending a zero-size inPrivate sized object. Gate the early return on a new EmptyMarshalingStructs list, matched on the structure's spec name, which CGenRust threads in through a lambda over the outermost struct so base-class fields are attributed to the type being serialized. The condition is `!TargetLang.Rust || `, so C++, Java, JS, Python and .NET keep the old behavior; regenerating all six languages touches only tpm_types.rs, removing 14 guards and keeping TPMT_SENSITIVE's. absent_union_marshaling in tpm_structure.rs pins the contract: TPMT_SENSITIVE still marshals to nothing, all fourteen others and TPMS_ATTEST now return InvalidUnion, and a public-key-only TPM2_LoadExternal request still puts a zero-size inPrivate ahead of the public area. On the unmodified generated output the leading-union test fails with "TPMS_CAPABILITY_DATA with an absent union marshaled as Ok([])". * Wipe secrets on overwrite, bound PCR selections, and name the check that failed Three review comments, all correct. Wipe a secret before overwriting it, not only when its owner dies. `TSS_KEY::create_key` assigned the newly generated prime straight over `privatePart`. That drops the previous `Vec`, and `Vec`'s `Drop` only frees; `Drop for TSS_KEY` runs when the whole key goes out of scope, so a second `create_key` left the first prime in freed heap. Every write to the field now goes through `TSS_KEY::set_private_part`, which zeroizes first. The same shape existed on `Session::set_auth_value`, whose `sess_in.hmac` is the caller's auth value verbatim, and defensively on `Session::calc_session_key`. `publicPart.unique` is left alone: the modulus is public. The wipe is observable, and is observed. A `GlobalAlloc` is handed a still-valid pointer to a block on its way out, so a test-only allocator wrapper inspects the one block whose address it was armed with, reads only the bytes that block had initialized, and records whether they were zero. Removing either `zeroize` makes both new tests fail with the prime still in the freed block. Report a Name mismatch as a failed verification, not as a generic error. `TPMT_PUBLIC::verify_name` returned `GenericError`, so a caller could not tell an untrusted public area from an operational failure without matching on the message -- unlike the activation and certification checks beside it. It now returns `VerificationFailed`, and so does the Name-consistency check in `Tpm2::update_resp_handle`, which is that same error re-wrapped. The response authorization checks in `dispatch` are deliberately left as they are: they are transport authentication rather than public-area trust, and reclassifying some of them and not others would be worse than leaving all of them, since an adversary chooses which path they trip. Bound a PCR selection instead of letting it size an allocation. Fixing the out-of-bounds panic on PCR 24 replaced it with an unbounded allocation: `u32::MAX` asked for half a gigabyte. `pcrSelect` is marshalled behind a one-byte size prefix, so it holds at most 255 bytes and PCR 2039 is the largest index any selection can name. `new_from_pcr_u32` and `new_from_pcrs_vec` now check the index before allocating and return `Result`; `get_selection_array` carries the same bound. PCRs 0-23 still produce the identical three-byte selection, which is a wire format and is pinned by test. * Decide the next command's session attributes bit by bit Making the caller's requested TPMA_SESSION authoritative fixed a real downgrade -- a response could clear encrypt/decrypt and have the next command's first parameter go out in the clear -- but it was applied to the whole byte, including bits that are not the caller's to keep. auditReset and auditExclusive are conditions on the one command that carries them. Resending auditReset re-initialises the session's audit digest before every later command, so a session audit only ever covered the most recent one instead of accumulating; resending auditExclusive turns a one-off precondition into a standing one. They are consumed here rather than by trusting the response, because the reference implementation echoes auditReset back and reports auditExclusive SET for an exclusive session. continueSession is the one bit the TPM answers rather than echoes: CLEAR means it flushed the session when the command completed. Such a session is no longer offered through last_session()/last_sessions(), which is what the comment there always claimed and the code never did. encrypt, decrypt and audit stay exactly as the caller asked, and the strict encrypt/decrypt echo check is untouched. * Assert the session-attribute rule on the wire, not the accessor The test read the retained session's attributes back through last_session(), which shows what the client stored rather than what it would send. It now takes the reuse path a caller would take and asserts against the device's command log, so the assertion lands on the bytes the TPM would see. --- TSS.Rust/Cargo.lock | 2 +- TSS.Rust/Cargo.toml | 11 +- TSS.Rust/examples/tpm_samples.rs | 147 +- TSS.Rust/src/auth_session.rs | 646 +++++- TSS.Rust/src/crypto/cng_provider.rs | 201 ++ TSS.Rust/src/crypto/mod.rs | 128 +- TSS.Rust/src/crypto/provider.rs | 20 +- TSS.Rust/src/device.rs | 925 ++++----- TSS.Rust/src/error.rs | 4 + TSS.Rust/src/policy.rs | 1167 ++++++++++- TSS.Rust/src/tpm2_impl.rs | 2805 +++++++++++++++++++++++++-- TSS.Rust/src/tpm_structure.rs | 93 + TSS.Rust/src/tpm_type_extensions.rs | 1698 ++++++++++++++-- TSS.Rust/src/tpm_types.rs | 371 ++-- TssCodeGen/src/CGenRust.cs | 83 +- TssCodeGen/src/CodeGenBase.cs | 18 +- TssCodeGen/src/TargetLang.cs | 4 +- 17 files changed, 7135 insertions(+), 1188 deletions(-) diff --git a/TSS.Rust/Cargo.lock b/TSS.Rust/Cargo.lock index c5211eb9..e95a4a3b 100644 --- a/TSS.Rust/Cargo.lock +++ b/TSS.Rust/Cargo.lock @@ -561,7 +561,6 @@ dependencies = [ "elliptic-curve", "hmac", "lazy_static", - "libc", "p256", "p384", "p521", @@ -570,6 +569,7 @@ dependencies = [ "sha1", "sha2", "sm3", + "subtle", "windows", "zeroize", ] diff --git a/TSS.Rust/Cargo.toml b/TSS.Rust/Cargo.toml index 3d2112cd..eb3890a4 100644 --- a/TSS.Rust/Cargo.toml +++ b/TSS.Rust/Cargo.toml @@ -17,9 +17,6 @@ repository = "https://github.com/Kasher/TSS.MSR" non_camel_case_types = "allow" unused-parens = "allow" -[lib] -crate-type = ["cdylib", "lib"] - [features] default = ["software-crypto"] @@ -47,7 +44,8 @@ cng-crypto = [] [dependencies] derivative = "2.2.0" lazy_static = "1.5.0" -windows = "0.61.1" +# Constant-time comparison of authorization HMAC tags. +subtle = "2.6" zeroize = "1.8" # Used only by the software-crypto provider. @@ -69,10 +67,7 @@ p384 = { version = "0.13", default-features = false, features = ["ecdh"], option p521 = { version = "0.13", default-features = false, features = ["ecdh"], optional = true } [target.'cfg(windows)'.dependencies] -windows = { version = "0.61.1", features = ["Win32_Foundation", "Win32_Security", "Win32_Security_Cryptography", "Win32_System_TpmBaseServices", "Win32_Networking", "Win32_Networking_WinSock"] } - -[target.'cfg(unix)'.dependencies] -libc = "0.2" +windows = { version = "0.61.1", features = ["Win32_Foundation", "Win32_Security", "Win32_Security_Cryptography", "Win32_System_TpmBaseServices"] } [[example]] name = "tpm_samples" diff --git a/TSS.Rust/examples/tpm_samples.rs b/TSS.Rust/examples/tpm_samples.rs index 1fb72fc3..a920667a 100644 --- a/TSS.Rust/examples/tpm_samples.rs +++ b/TSS.Rust/examples/tpm_samples.rs @@ -33,7 +33,7 @@ use tss_msr_rs::{ crypto::{software_provider::SOFTWARE_PROVIDER, Crypto}, device::{TpmDevice, TpmTbsDevice}, error::TpmError, policy::{self, PolicyTree, PolicyCommandCode, PolicyLocality, PolicyOr, PolicyPassword}, - tpm2_impl::*, tpm_structure::{TpmEnum}, tpm_types::* + tpm2_impl::*, tpm_structure::{TpmEnum}, tpm_type_extensions::TrustedPublic, tpm_types::* }; lazy_static::lazy_static! { @@ -235,7 +235,7 @@ fn attestation(tpm: &mut Tpm2) -> Result<(), TpmError> { // Set up PCR selection for the quote let pcrs_to_quote = TPMS_PCR_SELECTION::get_selection_array( - TPM_ALG_ID::SHA1, 7 ); + TPM_ALG_ID::SHA1, 7 )?; // Do an event to make sure the value is non-zero tpm.PCR_Event(&TPM_HANDLE::pcr(7), &vec![1, 2, 3])?; @@ -278,11 +278,19 @@ fn attestation(tpm: &mut Tpm2) -> Result<(), TpmError> { return Err(TpmError::InvalidParameter); } ; - // Get a key attestation. For simplicity we have the signingKey self-certify b + // Get a key attestation. The key that signs the attestation and the key being attested must + // be different: a key certifying itself says only that whoever produced the public area also + // produced the attestation over it, which is no evidence at all. let key_nonce: Vec = vec![0, 9, 1, 1, 2, 3]; println!(">> Key Quoting, using nonce {:?}", key_nonce); - let key_quote = tpm.Certify(&sig_key, &sig_key, &key_nonce, &TPMU_SIG_SCHEME::create(TPM_ALG_ID::NULL)?)?; + let key_to_certify = make_child_signing_key(tpm, &primary_key, false)?; + + // The primary was only ever needed to create these two children, and a TPM guarantees room + // for no more than three transient objects at once. + tpm.FlushContext(&primary_key)?; + + let key_quote = tpm.Certify(&key_to_certify, &sig_key, &key_nonce, &TPMU_SIG_SCHEME::create(TPM_ALG_ID::NULL)?)?; if let Some(TPMU_ATTEST::certify(certify_attest)) = &key_quote.certifyInfo.attested { println!("Key certification obtained successfully"); @@ -295,15 +303,26 @@ fn attestation(tpm: &mut Tpm2) -> Result<(), TpmError> { return Err(TpmError::InvalidParameter); } ; - let pub_key = tpm.ReadPublic(&sig_key)?; + let certified_public = tpm.ReadPublic(&key_to_certify)?.outPublic; + let signing_public = tpm.ReadPublic(&sig_key)?.outPublic; - if (pub_key.outPublic.validate_certify(&SOFTWARE_PROVIDER, &pub_key.outPublic, &key_nonce, &key_quote)?) { - println!("Key certification signature verification SUCCESSFUL! "); - } else { - println!("Key certification signature verification FAILED! "); - } + // Validating an attestation says nothing until the attestation key's provenance has been + // established somewhere else. There is something to establish it against here: TPM2_Load + // returned this key's Name, and this library checked that Name against the public area it + // sent, so the Name is already in `sig_key`. Pinning against it costs nothing and is a real + // check - it rejects a resource manager that answers this ReadPublic with a different key. + // + // Code attesting a TPM it does not own has to obtain that Name from somewhere else entirely: + // activate a credential against an endorsement key with a manufacturer certificate, or + // validate an AK certificate chain, and pass the Name that yields to + // `TrustedPublic::from_activated_credential` or `TrustedPublic::from_pinned_name`. + let signing_key = TrustedPublic::from_pinned_name(signing_public, &sig_key.get_name()?, &SOFTWARE_PROVIDER)?; + + signing_key.validate_certify(&SOFTWARE_PROVIDER, &certified_public, &key_nonce, &key_quote)?; + println!("Key certification signature verification SUCCESSFUL! "); // // Clean up - flush keys from TPM + tpm.FlushContext(&key_to_certify)?; tpm.FlushContext(&sig_key)?; println!("Cleaned up keys from TPM"); @@ -468,7 +487,7 @@ fn pcr_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { println!("PCR 16 reset"); // Read the PCR value (should be all zeros after reset) - let pcr_selection = TPMS_PCR_SELECTION::get_selection_array(TPM_ALG_ID::SHA256, 16); + let pcr_selection = TPMS_PCR_SELECTION::get_selection_array(TPM_ALG_ID::SHA256, 16)?; let pcr_vals = tpm.PCR_Read(&pcr_selection)?; println!("PCR 16 after reset: {:?}", pcr_vals.pcrValues); @@ -1101,7 +1120,7 @@ fn unseal_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { tpm.PCR_Event(&TPM_HANDLE::pcr(pcr), &vec![1, 2, 3, 4])?; // Read the current PCR value - let pcr_selection = TPMS_PCR_SELECTION::get_selection_array(bank, pcr); + let pcr_selection = TPMS_PCR_SELECTION::get_selection_array(bank, pcr)?; let pcr_vals = tpm.PCR_Read(&pcr_selection)?; println!("PCR {} value: {:?}", pcr, pcr_vals.pcrValues); @@ -1201,7 +1220,7 @@ fn policy_or_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { // Set PCR to a known value tpm.PCR_Event(&TPM_HANDLE::pcr(pcr), &vec![1, 2, 3, 4])?; - let pcr_selection = TPMS_PCR_SELECTION::get_selection_array(bank, pcr); + let pcr_selection = TPMS_PCR_SELECTION::get_selection_array(bank, pcr)?; let pcr_vals = tpm.PCR_Read(&pcr_selection)?; // Compute the PCR digest @@ -1699,7 +1718,7 @@ fn policy_pcr_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { // Set PCR to a known value tpm.PCR_Event(&TPM_HANDLE::pcr(pcr), &vec![1, 2, 3, 4])?; - let pcr_selection = TPMS_PCR_SELECTION::get_selection_array(bank, pcr); + let pcr_selection = TPMS_PCR_SELECTION::get_selection_array(bank, pcr)?; let pcr_vals = tpm.PCR_Read(&pcr_selection)?; // Compute the PCR digest @@ -2067,13 +2086,42 @@ fn async_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { fn session_encryption_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { announce("SessionEncryption Sample"); - // Session encryption is transparent to the application programmer. - // Create a session with decrypt/encrypt attributes and the library handles - // the AES-CFB encryption/decryption of the first parameter automatically. + // Session encryption is transparent to the application programmer: set decrypt/encrypt on + // the session and the library handles the AES-CFB of the first parameter. + // + // What is NOT transparent, and is the point of this sample, is where the encryption key + // comes from. It is KDFa(hashAlg, sessionKey, "CFB", nonceNewer, nonceOlder). Both nonces + // travel in the clear, so unless `sessionKey` itself was derived from a secret, the key is a + // pure function of values anyone watching the bus already has. An unsalted, unbound session + // is exactly that case, and this library now refuses it rather than pretending to encrypt. + // + // So: salt the session. The salt is generated inside the library, encrypted to a key we + // nominate, and never appears on the wire in the clear. + let salt_key = make_storage_primary(tpm)?; + let salt_key_public = tpm.ReadPublic(&salt_key)?.outPublic; + // TPM2_CreatePrimary already returned this key's Name, and this library checked it against + // the public area the same command returned, so there is something to pin against and no + // reason to assert trust bare. `from_pinned_name` recomputes the Name of what ReadPublic + // answered and rejects it unless it matches. Adopting a key this process did not create means + // obtaining its Name from outside the channel - an enrolment record, a signed manifest. + let salt_key_public = TrustedPublic::from_pinned_name(salt_key_public, &salt_key.get_name()?, &SOFTWARE_PROVIDER)?; + + // Show what the library now refuses, so the reason is on the page rather than buried in a + // doc comment somewhere. + let vacuous = tpm.start_auth_session_full( + TPM_SE::HMAC, TPM_ALG_ID::SHA256, + TPMA_SESSION::continueSession | TPMA_SESSION::decrypt, + TPMT_SYM_DEF::new(TPM_ALG_ID::AES, 128, TPM_ALG_ID::CFB), + ); + match vacuous { + Err(e) => println!("Unsalted, unbound parameter encryption correctly refused: {}", e), + Ok(_) => println!("Warning: an unsalted, unbound encrypting session was allowed"), + } // Part 1: Encrypt commands TO the TPM (decrypt attribute) println!(">> Encrypt commands to TPM (TPMA_SESSION::decrypt)"); - let sess = tpm.start_auth_session_full( + let sess = tpm.start_salted_auth_session( + &salt_key, &salt_key_public, TPM_SE::HMAC, TPM_ALG_ID::SHA256, TPMA_SESSION::continueSession | TPMA_SESSION::decrypt, TPMT_SYM_DEF::new(TPM_ALG_ID::AES, 128, TPM_ALG_ID::CFB), @@ -2094,21 +2142,19 @@ fn session_encryption_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { // Part 2: Encrypt responses FROM the TPM (encrypt attribute) println!("\n>> Encrypt responses from TPM (TPMA_SESSION::encrypt)"); - // Create a primary key so we have something to read - let storage_primary = make_storage_primary(tpm)?; - // Read public key without encryption - let plaintext_read = tpm.ReadPublic(&storage_primary)?; + let plaintext_read = tpm.ReadPublic(&salt_key)?; // Make an encrypting session for response - let enc_sess = tpm.start_auth_session_full( + let enc_sess = tpm.start_salted_auth_session( + &salt_key, &salt_key_public, TPM_SE::HMAC, TPM_ALG_ID::SHA256, TPMA_SESSION::continueSession | TPMA_SESSION::encrypt, TPMT_SYM_DEF::new(TPM_ALG_ID::AES, 128, TPM_ALG_ID::CFB), )?; // ReadPublic with encrypted response - the library should decrypt automatically - let encrypted_read = tpm.with_session(enc_sess.clone()).ReadPublic(&storage_primary)?; + let encrypted_read = tpm.with_session(enc_sess.clone()).ReadPublic(&salt_key)?; let enc_sess = tpm.last_session().unwrap(); // Compare: the decrypted response should match the plaintext @@ -2121,7 +2167,7 @@ fn session_encryption_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { } tpm.FlushContext(&session_handle(&enc_sess))?; - tpm.FlushContext(&storage_primary)?; + tpm.FlushContext(&salt_key)?; println!("SessionEncryption sample completed successfully"); Ok(()) @@ -2154,7 +2200,9 @@ fn policy_signed_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { })), unique: Some(TPMU_PUBLIC_ID::rsa(TPM2B_PUBLIC_KEY_RSA::default())), }, - ..Default::default() + // Spelled out rather than filled in from Default::default(): TSS_KEY zeroizes + // privatePart on drop, and a type with a Drop cannot have fields moved out of it. + privatePart: Vec::new(), }; sw_key.create_key(&SOFTWARE_PROVIDER)?; println!("Created software RSA-2048 signing key"); @@ -2263,7 +2311,9 @@ fn policy_authorize_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { })), unique: Some(TPMU_PUBLIC_ID::rsa(TPM2B_PUBLIC_KEY_RSA::default())), }, - ..Default::default() + // Spelled out rather than filled in from Default::default(): TSS_KEY zeroizes + // privatePart on drop, and a type with a Drop cannot have fields moved out of it. + privatePart: Vec::new(), }; sw_key.create_key(&SOFTWARE_PROVIDER)?; println!("Created authorizing SW key"); @@ -2534,30 +2584,42 @@ fn policy_tree_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { Ok(()) } -/// Demonstrates a salted (seeded) auth session. The salt is RSA-OAEP encrypted -/// to a storage primary's public key, providing protection even when authValues -/// are known or can be inferred. +/// Demonstrates a salted (seeded) auth session. The salt is generated inside +/// `start_salted_auth_session`, sized to the digest of the salt key's `nameAlg` -- the size the +/// TPM requires, which is not necessarily the session hash -- and RSA-OAEP encrypted to a storage +/// primary's public key. That gives the session key an input an eavesdropper does not have, which +/// is what parameter encryption and HMAC integrity need. fn seeded_session_sample(tpm: &mut Tpm2) -> Result<(), TpmError> { announce("SeededSession"); // Create a storage primary to use as the salt-encryption key let salt_key = make_storage_primary(tpm)?; - // Generate a random salt - let salt = Crypto::get_random(&SOFTWARE_PROVIDER, 20)?; - println!("Salt ({} bytes): {:?}", salt.len(), &salt[..8]); - - // Start a salted HMAC session. - // start_auth_session_ex will ReadPublic on the salt key, encrypt the salt - // with RSA-OAEP (label "SECRET"), and derive the session key via KDFa. - let sess = tpm.start_auth_session_ex( - &salt_key, // tpmKey for salt encryption - &TPM_HANDLE::new(TPM_RH::NULL.get_value()), // no binding + // The salt is encrypted to whatever public area we nominate here, so nominating one we read + // over the same channel we are trying to protect would be pointless: a man in the middle who + // answers the ReadPublic learns the salt and forges every HMAC afterwards. This library + // therefore will not read it for us -- the trust decision has to be made explicitly. + // + // TPM2_CreatePrimary already returned this key's Name, so the decision here can rest on a + // check rather than on an assertion: `from_pinned_name` rejects a ReadPublic answered with a + // different key. Be precise about what that is worth. This is a key this process created + // moments ago on a locally attached TPM, and on Windows a resource manager still sits between + // this process and the chip -- it was equally present when the key was created, so a + // compromised one could have answered both. What the pinning buys is that the two answers + // must agree; what makes the residual risk acceptable is that an adversary in that position + // already has privileged local access. Code adopting a key it did not create has to get the + // Name from outside the channel entirely and pin against that. + let salt_key_public = tpm.ReadPublic(&salt_key)?.outPublic; + let salt_key_public = TrustedPublic::from_pinned_name(salt_key_public, &salt_key.get_name()?, &SOFTWARE_PROVIDER)?; + println!("Pinned salt key Name: {:?}", &salt_key_public.name()[..8]); + + let sess = tpm.start_salted_auth_session( + &salt_key, + &salt_key_public, TPM_SE::HMAC, TPM_ALG_ID::SHA256, TPMA_SESSION::continueSession, TPMT_SYM_DEF::new(TPM_ALG_ID::AES, 128, TPM_ALG_ID::CFB), - &salt, )?; println!("Started salted HMAC session: {:?}", session_handle(&sess)); @@ -2626,13 +2688,12 @@ fn bound_session_inner(tpm: &mut Tpm2, owner_auth: &[u8]) -> Result<(), TpmError owner_handle.auth_value = owner_auth.to_vec(); let sess = tpm.start_auth_session_ex( - &TPM_HANDLE::new(TPM_RH::NULL.get_value()), // no salt + None, // unsalted &owner_handle, // bound to OWNER TPM_SE::HMAC, TPM_ALG_ID::SHA256, TPMA_SESSION::continueSession, TPMT_SYM_DEF::default(), - &[], // no salt )?; println!("Started bound session (bound to OWNER): {:?}", session_handle(&sess)); diff --git a/TSS.Rust/src/auth_session.rs b/TSS.Rust/src/auth_session.rs index f5866cfd..71f1304f 100644 --- a/TSS.Rust/src/auth_session.rs +++ b/TSS.Rust/src/auth_session.rs @@ -1,9 +1,11 @@ use crate::crypto::{provider::CryptoProvider, Crypto}; use crate::error::TpmError; use crate::{tpm_structure::TpmEnum, tpm_types::*}; +use std::fmt; +use zeroize::Zeroize; /// Authentication session for TPM commands -#[derive(Debug, Default, Clone)] +#[derive(Default, Clone)] pub struct Session { pub sess_in: TPMS_AUTH_COMMAND, pub sess_out: TPMS_AUTH_RESPONSE, @@ -15,8 +17,20 @@ pub struct Session { pub needs_password: bool, /// Derived session key (from KDFa with "ATH" label) + /// + /// This authorizes every command issued on the session and keys its parameter encryption, so + /// it is wiped when dropped and withheld from the [`Debug`] rendering below. pub session_key: Vec, + /// Whether `session_key` was derived from anything an eavesdropper does not already have. + /// + /// A session key is only worth something if the KDFa that produced it took a secret input: + /// the salt, or the authValue of the bind entity. An unsalted session bound to an entity + /// whose authValue is empty produces a perfectly non-empty `session_key` that is a pure + /// function of the two nonces — both of which travel in the clear. Emptiness of + /// `session_key` therefore is not the property that matters; this flag is. + secret_key_material: bool, + /// Symmetric algorithm for parameter encryption pub symmetric: TPMT_SYM_DEF, @@ -24,6 +38,48 @@ pub struct Session { pub bind_handle: u32, } +/// Renders what identifies a session and none of what authorizes it. +/// +/// A derived `Debug` would print `session_key`, and for a password session `sess_in.hmac`, which +/// holds the caller's auth value verbatim. A session is formatted wherever a command is traced or +/// an error reports the session it was issued on, so a derived implementation would put both into +/// ordinary log output. +impl fmt::Debug for Session { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Session") + .field( + "session_handle", + &format_args!("0x{:08x}", self.sess_in.sessionHandle.handle), + ) + .field("session_type", &self.session_type) + .field("hash_alg", &self.hash_alg) + .field("attributes", &self.sess_in.sessionAttributes) + .field("symmetric", &self.symmetric) + .field("needs_hmac", &self.needs_hmac) + .field("needs_password", &self.needs_password) + .field("bind_handle", &format_args!("0x{:08x}", self.bind_handle)) + .field("nonce_caller", &self.sess_in.nonce) + .field("nonce_tpm", &self.sess_out.nonce) + .field("session_key", &format_args!("")) + .field("auth", &format_args!("")) + .finish() + } +} + +/// Wipes the session key and the auth value, so that a session that has gone out of scope is not +/// left in freed heap. +/// +/// The session is cloned on essentially every command, so the copies matter as much as the +/// original; each one is wiped by this same implementation. `sess_in.hmac` is wiped here rather +/// than by its own type because `TPMS_AUTH_COMMAND` is generated from the TPM 2.0 specification +/// and cannot carry hand-written behaviour. +impl Drop for Session { + fn drop(&mut self) { + self.session_key.zeroize(); + self.sess_in.hmac.zeroize(); + } +} + impl Session { pub fn new( session_handle: TPM_HANDLE, @@ -38,16 +94,13 @@ impl Session { session_attributes, &Vec::new(), ), - sess_out: TPMS_AUTH_RESPONSE::new( - &nonce_tpm.to_vec(), - session_attributes, - &Vec::new(), - ), + sess_out: TPMS_AUTH_RESPONSE::new(&nonce_tpm.to_vec(), session_attributes, &Vec::new()), hash_alg: TPM_ALG_ID::SHA256, session_type: TPM_SE::HMAC, needs_hmac: true, needs_password: false, session_key: Vec::new(), + secret_key_material: false, symmetric: TPMT_SYM_DEF::default(), bind_handle: TPM_RH::NULL.get_value(), } @@ -93,24 +146,53 @@ impl Session { attributes, &Vec::new(), ), - sess_out: TPMS_AUTH_RESPONSE::new( - &nonce_tpm, - attributes, - &Vec::new(), - ), + sess_out: TPMS_AUTH_RESPONSE::new(&nonce_tpm, attributes, &Vec::new()), hash_alg, session_type, needs_hmac: session_type == TPM_SE::HMAC, needs_password: false, session_key: Vec::new(), + secret_key_material: false, symmetric, bind_handle: bind_object.handle, }; sess.calc_session_key(crypto, salt, bind_object)?; + sess.reject_vacuous_param_encryption(attributes)?; Ok(sess) } + /// Refuse `TPMA_SESSION::encrypt` / `decrypt` on a session with no secret key material. + /// + /// Parameter encryption derives its AES-CFB key with + /// `KDFa(hashAlg, sessionKey, "CFB", nonceNewer, nonceOlder)`. On an unsalted *and* unbound + /// session `sessionKey` is empty, so every input to that derivation — both nonces — travels + /// over the wire in the clear. Anyone who sees the exchange derives the same key and reads + /// the "encrypted" parameter. It is not weak encryption, it is no encryption, and it is + /// worse than none because the caller believes the parameter is protected. + /// + /// The same is true, less obviously, of a session bound to an entity with an empty + /// authValue: `sessionKey` is then non-empty but is still a deterministic function of the + /// two public nonces. `secret_key_material` is what distinguishes the two cases. + /// + /// Salt the session ([`crate::tpm2_impl::Tpm2::start_salted_auth_session`]) or bind it to an + /// entity with a non-empty authValue, and the derivation gains an input an observer does not + /// have. + fn reject_vacuous_param_encryption(&self, attributes: TPMA_SESSION) -> Result<(), TpmError> { + let xcrypt = TPMA_SESSION::encrypt.get_value() | TPMA_SESSION::decrypt.get_value(); + if (attributes.get_value() & xcrypt) != 0 && !self.secret_key_material { + return Err(TpmError::GenericError( + "Parameter encryption was requested on a session with no secret key material. \ + An unsalted session that is unbound (or bound to an entity with an empty \ + authValue) derives its encryption key entirely from nonces that travel in the \ + clear, so the encryption protects nothing. Salt the session or bind it to an \ + entity with a non-empty authValue." + .to_string(), + )); + } + Ok(()) + } + /// Derive the session key using KDFa with label "ATH". /// SessionKey = KDFa(hashAlg, bindAuth || salt, "ATH", nonceTPM, nonceCaller, hashBits) fn calc_session_key( @@ -136,14 +218,23 @@ impl Session { } hmac_key.extend_from_slice(salt); + // The KDFa below runs regardless, because the TPM runs it too and the two keys must + // agree. What it produces is only *secret* if something secret went into it. + self.secret_key_material = !hmac_key.is_empty(); + let hash_bits = Crypto::digest_size_checked(self.hash_alg)? * 8; + // Wipe before overwriting. `Drop for Session` runs only when the session goes out of + // scope, so a key this method replaces would otherwise be dropped unwiped. Today the + // only caller derives into a session it has just built, so there is nothing to wipe; + // the wipe is here so that stays true of any later caller. + self.session_key.zeroize(); self.session_key = Crypto::kdfa( crypto, self.hash_alg, &hmac_key, "ATH", - &self.sess_out.nonce, // nonceTPM - &self.sess_in.nonce, // nonceCaller + &self.sess_out.nonce, // nonceTPM + &self.sess_in.nonce, // nonceCaller hash_bits, )?; @@ -155,9 +246,39 @@ impl Session { self.sess_in.sessionHandle.handle == TPM_RH::PW.get_value() } + /// Whether the TPM reported this session's context as closed in the last response it + /// appeared in. + /// + /// `continueSession` CLEAR in a response is the TPM saying it closed the session and freed + /// the context when the command completed (TPM 2.0 Part 2, `TPMA_SESSION.continueSession`, + /// which also warns that "a session created after another session is ended may have the same + /// handle but logically is not the same session"). The reference implementation flushes on + /// exactly this condition — `SessionFlush` in `BuildResponseSession`, ms-tpm-20-ref + /// `SessionProcess.c` — so the handle is dead and may later belong to someone else. + /// + /// A password authorization has no context to close: the TPM SETs the attribute in the + /// response whatever the command asked for, and this client never reads a PWAP session's + /// response attributes, so one is never reported closed. + /// + /// This reflects the last response, so it is only meaningful once the session has been used; + /// on a session that has not been through a command it merely restates the attributes it was + /// constructed with. + pub fn is_terminated(&self) -> bool { + !self.is_pwap() + && (self.sess_out.sessionAttributes.get_value() + & TPMA_SESSION::continueSession.get_value()) + == 0 + } + /// Set authorization value for HMAC calculation + /// + /// The value it replaces is wiped first. `sess_in.hmac` on a password session is the + /// caller's authorization value verbatim, and `Drop for Session` only wipes it when the + /// whole session goes out of scope, so a second call would otherwise leave the first auth + /// value in freed heap. pub fn set_auth_value(&mut self, auth_value: Vec) { if self.is_pwap() { + self.sess_in.hmac.zeroize(); self.sess_in.hmac = auth_value; } } @@ -167,6 +288,92 @@ impl Session { self.hash_alg } + /// Whether the authValue of the entity being authorized is folded into the HMAC key. + /// + /// This mirrors `session->attributes.includeAuth` in the TPM reference implementation + /// (`SessionProcess.c`, `CheckAuthSession`): + /// + /// * policy session — include only when `TPM2_PolicyAuthValue` or `TPM2_PolicyPassword` has + /// run, i.e. when the TPM's `isAuthValueNeeded` / `isPasswordNeeded` is SET; + /// * HMAC session — include unless the session is bound to this very entity, in which case + /// the authValue is already inside `sessionKey`. + fn includes_auth_value(&self, associated_handle: Option<&TPM_HANDLE>) -> bool { + if self.session_type == TPM_SE::POLICY { + return self.needs_hmac || self.needs_password; + } + + match associated_handle { + None => false, + Some(handle) => { + let bound_to_this_entity = self.bind_handle != TPM_RH::NULL.get_value() + && self.bind_handle != 0 + && handle.handle == self.bind_handle; + !bound_to_this_entity + } + } + } + + /// `hmacKey = sessionKey || authValue`, the key both the command and the response HMAC use. + fn auth_hmac_key(&self, associated_handle: Option<&TPM_HANDLE>) -> Vec { + let mut key = self.session_key.clone(); + if self.includes_auth_value(associated_handle) { + if let Some(handle) = associated_handle { + key.extend_from_slice(&trim_trailing_zeros(&handle.auth_value)); + } + } + key + } + + /// Whether this session's key was derived from a secret (salt, or a non-empty bind + /// authValue). Sessions without it cannot be used for parameter encryption. + pub fn has_secret_key_material(&self) -> bool { + self.secret_key_material + } + + /// Whether the TPM will place an authorization HMAC in the response for this session. + /// + /// The TPM's rule, from `BuildSingleResponseAuth` in the reference implementation: + /// a password session carries no response auth, and neither does a policy session on which + /// `TPM2_PolicyPassword` has run — in both cases the TPM returns an empty `hmac` field. + /// Every other session gets one, and this client checks it rather than ignoring it. + /// + /// What that check is worth depends on the session, and the difference is worth stating + /// plainly rather than glossing. The response tag is + /// `HMAC(hashAlg, sessionKey ‖ authValue, ...)`, so it authenticates the response only when + /// one of those two parts is secret: + /// + /// * a salted session, or one bound to an entity with a non-empty authValue, has a + /// `sessionKey` derived from something an observer does not have — see + /// [`Session::has_secret_key_material`]; + /// * a session that folds in an authValue — an HMAC session authorizing an entity it is not + /// bound to, or a policy session on which `TPM2_PolicyAuthValue` has run — is keyed on + /// that authValue. + /// + /// A policy session that is unsalted, unbound and has run neither `PolicyAuthValue` nor + /// `PolicyPassword` has neither: `calc_session_key` returns before deriving anything, so + /// `session_key` is empty, and `includes_auth_value` is false. Its HMAC key is the empty + /// string, which anyone watching the exchange can key an HMAC with. Verifying that tag is a + /// corruption check, not authentication, and no amount of checking makes it more than that + /// — only salting or binding the session does. + /// + /// The rule is the same for all of them, because it has to be: which sessions carry a tag is + /// the TPM's decision, and a client that skipped the check for the cases above would also + /// skip it for every salted or `PolicyAuthValue` policy session, where the tag is the only + /// thing standing behind the response parameters. + /// + /// (The TPM has one further shortcut, observed on hardware rather than read out of the + /// reference implementation: an empty field also comes back when the HMAC key is empty *and* + /// the command's auth field was empty. This client never sends an empty auth field for such + /// a session, so the shortcut is not taken and there is always a tag to check.) + pub fn expects_response_auth(&self) -> bool { + !self.is_pwap() && !self.needs_password + } + + /// Whether a command using this session carries a computed HMAC rather than a password. + pub fn sends_command_hmac(&self) -> bool { + !self.is_pwap() && !self.needs_password + } + /// Generate an HMAC for authorization. /// hmacKey = sessionKey || authValue /// hmac = HMAC(hashAlg, hmacKey, parmHash || nonceNewer || nonceOlder || nonceDec || nonceEnc || sessionAttrs) @@ -203,26 +410,7 @@ impl Session { vec![self.sess_out.sessionAttributes.get_value()] }; - // Get auth value from the associated handle - let mut auth = Vec::new(); - if let Some(handle) = associated_handle { - // For bound sessions: if the handle IS the bound entity, skip auth - // (it's already incorporated in the session key via KDFa). - let is_bound = self.bind_handle != TPM_RH::NULL.get_value() - && self.bind_handle != 0 - && handle.handle == self.bind_handle; - - if is_bound { - // Bound to same entity: auth already in session key, don't add again - } else if self.session_type != TPM_SE::POLICY || self.needs_hmac { - auth = trim_trailing_zeros(&handle.auth_value); - } - } - - // hmacKey = sessionKey || auth - let mut hmac_key = Vec::new(); - hmac_key.extend_from_slice(&self.session_key); - hmac_key.extend_from_slice(&auth); + let hmac_key = self.auth_hmac_key(associated_handle); // Buffer to HMAC: parmHash || nonceNewer || nonceOlder || nonceDec || nonceEnc || sessionAttrs let mut buf_to_hmac = Vec::new(); @@ -249,6 +437,17 @@ impl Session { return Ok(Vec::new()); } + // Refuse to derive an encryption key from public values alone. See + // `reject_vacuous_param_encryption`: this is the second gate, so that a `Session` + // assembled by hand rather than by `from_tpm_response` cannot slip past the first. + if !self.secret_key_material { + return Err(TpmError::GenericError( + "Refusing parameter encryption on a session with no secret key material: the \ + AES-CFB key would be derived entirely from nonces that travel in the clear." + .to_string(), + )); + } + // Only AES-128/256 CFB is supported if self.symmetric.algorithm != TPM_ALG_ID::AES || self.symmetric.mode != TPM_ALG_ID::CFB { return Err(TpmError::GenericError( @@ -258,9 +457,10 @@ impl Session { let key_bits = self.symmetric.keyBits as usize; if key_bits != 128 && key_bits != 256 { - return Err(TpmError::GenericError( - format!("Unsupported AES key size: {} bits", key_bits), - )); + return Err(TpmError::GenericError(format!( + "Unsupported AES key size: {} bits", + key_bits + ))); } let key_size = key_bits / 8; @@ -275,7 +475,7 @@ impl Session { // Derive key material: KDFa(hashAlg, sessionKey, "CFB", nonceNewer, nonceOlder, 256) // Produces key_size + 16 bytes (key + IV) - let num_bits = (key_size + 16) * 8; + let num_bits = (key_size + CFB_IV_SIZE) * 8; let key_info = Crypto::kdfa( crypto, self.hash_alg, @@ -286,8 +486,7 @@ impl Session { num_bits, )?; - let aes_key = &key_info[..key_size]; - let iv = &key_info[key_size..key_size + 16]; + let (aes_key, iv) = split_cfb_key_material(&key_info, key_size)?; // For requests: encrypt (TPM will decrypt) // For responses: decrypt (TPM encrypted it) @@ -303,3 +502,372 @@ fn trim_trailing_zeros(data: &[u8]) -> Vec { } result } + +/// The AES-CFB initialisation vector is one AES block, whatever the key size. +const CFB_IV_SIZE: usize = 16; + +/// Split the KDFa stream that keys parameter encryption into the AES key and the CFB +/// initialisation vector. +/// +/// The split is checked rather than sliced outright. KDFa is asked for exactly +/// `key_size + CFB_IV_SIZE` octets and the in-crate implementation returns exactly that, so with +/// the providers bundled here this can never come up short. [`CryptoProvider`] is a public struct +/// of function pointers, though: KDFa is built on a caller-supplied HMAC, and a backend that +/// returned fewer octets than it should would turn these two slices into a panic in a library +/// whose every other failure is a [`TpmError`]. +fn split_cfb_key_material(key_info: &[u8], key_size: usize) -> Result<(&[u8], &[u8]), TpmError> { + let needed = key_size + CFB_IV_SIZE; + if key_info.len() < needed { + return Err(TpmError::GenericError(format!( + "Key derivation produced {} B of parameter encryption key material, but {} B are \ + needed for an AES-{} key and its initialization vector. The configured crypto \ + provider is not returning full length HMACs.", + key_info.len(), + needed, + key_size * 8 + ))); + } + Ok((&key_info[..key_size], &key_info[key_size..needed])) +} + +#[cfg(test)] +mod secret_redaction_tests { + use super::*; + + /// Bytes chosen so that neither their decimal nor their hexadecimal rendering is a substring + /// of anything the redacted `Debug` legitimately prints. + const SECRET: [u8; 6] = [0xA7, 0xB3, 0xC9, 0xD1, 0xE5, 0xF2]; + + fn assert_withholds_secret(rendered: &str, secret: &[u8]) { + for byte in secret { + assert!( + !rendered.contains(&byte.to_string()), + "debug rendering {rendered} leaks byte {byte} in decimal" + ); + assert!( + !rendered.to_lowercase().contains(&format!("{byte:02x}")), + "debug rendering {rendered} leaks byte {byte} in hex" + ); + } + assert!( + !rendered.contains(&format!("{:?}", secret)), + "debug rendering {rendered} leaks the secret verbatim" + ); + } + + #[test] + fn session_debug_withholds_the_session_key() { + let mut session = Session::default(); + session.session_key = SECRET.to_vec(); + + let rendered = format!("{:?}", session); + + assert_withholds_secret(&rendered, &SECRET); + + // The fields that identify the session stay legible, which is the point of hand writing + // the rendering rather than dropping `Debug` altogether. + assert!(rendered.contains("session_handle")); + assert!(rendered.contains("session_type")); + assert!(rendered.contains("hash_alg")); + assert!(rendered.contains("attributes")); + assert!(rendered.contains("session_key: ")); + } + + #[test] + fn session_debug_withholds_the_password_auth_value() { + // A PWAP session carries the caller's auth value in `sess_in.hmac`, in the clear. + let session = Session::pw(Some(SECRET.to_vec())); + + let rendered = format!("{:?}", session); + + assert_withholds_secret(&rendered, &SECRET); + assert!(rendered.contains("auth: ")); + } + + #[test] + fn session_still_defaults_and_clones() { + let mut session = Session::default(); + assert!(session.session_key.is_empty()); + + session.session_key = SECRET.to_vec(); + let copy = session.clone(); + + assert_eq!(copy.session_key, session.session_key); + assert_eq!( + copy.sess_in.sessionHandle.handle, + session.sess_in.sessionHandle.handle + ); + assert_eq!(copy.hash_alg, session.hash_alg); + } +} + +#[cfg(all(test, feature = "software-crypto"))] +mod tests { + use super::*; + use crate::crypto::software_provider::SOFTWARE_PROVIDER; + + const SALT: &[u8] = b"a thirty-two byte session salt.."; + + fn start( + attributes: TPMA_SESSION, + salt: &[u8], + bind: &TPM_HANDLE, + ) -> Result { + Session::from_tpm_response( + &SOFTWARE_PROVIDER, + TPM_HANDLE::new(0x02000000), + TPM_SE::HMAC, + TPM_ALG_ID::SHA256, + vec![0xAA; 32], + vec![0xBB; 32], + attributes, + TPMT_SYM_DEF::new(TPM_ALG_ID::AES, 128, TPM_ALG_ID::CFB), + salt, + bind, + ) + } + + fn null_handle() -> TPM_HANDLE { + TPM_HANDLE::new(TPM_RH::NULL.get_value()) + } + + #[test] + fn unsalted_unbound_session_rejects_parameter_encryption() { + // KDFa(hash, , "CFB", nonceNewer, nonceOlder) is a function of two values that + // both travelled in the clear. Anyone who saw the exchange derives the same AES-CFB key. + let err = start( + TPMA_SESSION::continueSession | TPMA_SESSION::decrypt, + &[], + &null_handle(), + ) + .expect_err("parameter encryption with no key material must be refused"); + assert!( + format!("{}", err).contains("no secret key material"), + "unexpected error: {}", + err + ); + + let err = start( + TPMA_SESSION::continueSession | TPMA_SESSION::encrypt, + &[], + &null_handle(), + ) + .expect_err("the encrypt direction is no better than the decrypt direction"); + assert!(format!("{}", err).contains("no secret key material")); + } + + #[test] + fn session_bound_to_an_entity_with_an_empty_auth_rejects_parameter_encryption() { + // Less obvious than the unbound case and just as vacuous: KDFa runs, so `session_key` is + // non-empty, but its only inputs are the two public nonces. + let mut bound = TPM_HANDLE::new(0x81000001); + bound.set_auth(&[]); + + let err = start( + TPMA_SESSION::continueSession | TPMA_SESSION::decrypt, + &[], + &bound, + ) + .expect_err("an empty bind authValue contributes no secret"); + assert!(format!("{}", err).contains("no secret key material")); + } + + #[test] + fn an_unencrypted_unsalted_session_is_still_allowed() { + // The rejection is scoped to parameter encryption. Plain authorization over an unsalted, + // unbound session remains legitimate and is what most callers use. + let sess = start(TPMA_SESSION::continueSession, &[], &null_handle()).unwrap(); + assert!(sess.session_key.is_empty()); + assert!(!sess.has_secret_key_material()); + } + + #[test] + fn a_salted_session_allows_parameter_encryption() { + let sess = start( + TPMA_SESSION::continueSession | TPMA_SESSION::decrypt, + SALT, + &null_handle(), + ) + .expect("a salted session has a secret input and may encrypt parameters"); + assert!(sess.has_secret_key_material()); + assert_eq!(sess.session_key.len(), 32); + assert!(sess + .param_xcrypt(&SOFTWARE_PROVIDER, &[1, 2, 3, 4], true) + .is_ok()); + } + + #[test] + fn a_session_bound_to_a_non_empty_auth_allows_parameter_encryption() { + let mut bound = TPM_HANDLE::new(0x81000001); + bound.set_auth(b"bind-auth"); + + let sess = start( + TPMA_SESSION::continueSession | TPMA_SESSION::decrypt, + &[], + &bound, + ) + .expect("a non-empty bind authValue is a secret an observer does not have"); + assert!(sess.has_secret_key_material()); + } + + #[test] + fn param_xcrypt_refuses_a_session_without_secret_key_material() { + // The second gate: a `Session` assembled by hand rather than through + // `from_tpm_response` must not be able to reach the vacuous derivation either. + let mut sess = Session::new( + TPM_HANDLE::new(0x02000000), + &[0xBB; 32], + TPMA_SESSION::continueSession, + &[0xAA; 32], + ); + sess.symmetric = TPMT_SYM_DEF::new(TPM_ALG_ID::AES, 128, TPM_ALG_ID::CFB); + + let err = sess + .param_xcrypt(&SOFTWARE_PROVIDER, &[1, 2, 3, 4], true) + .expect_err("no key material means no encryption"); + assert!(format!("{}", err).contains("no secret key material")); + } + + #[test] + fn a_password_session_expects_no_response_auth() { + let sess = Session::pw(Some(b"auth".to_vec())); + assert!(sess.is_pwap()); + assert!(!sess.expects_response_auth()); + } + + #[test] + fn a_policy_session_without_policy_password_expects_a_response_auth() { + // The rule is `!is_pwap && !needs_password`, not "HMAC session or PolicyAuthValue ran". + // A policy session driven by PolicyPCR alone still gets an authenticated response. + let mut sess = start(TPMA_SESSION::continueSession, SALT, &null_handle()).unwrap(); + sess.session_type = TPM_SE::POLICY; + sess.needs_hmac = false; + sess.needs_password = false; + assert!(sess.expects_response_auth()); + } + + #[test] + fn an_unsalted_unbound_policy_session_authenticates_nothing() { + // What `expects_response_auth` documents, stated as an assertion. This session gets a + // response tag and this client checks it, but the key it checks with is the empty + // string: `calc_session_key` returned before deriving anything, and no authValue is + // folded in because neither PolicyAuthValue nor PolicyPassword has run. Anyone on the + // wire can produce a tag that verifies, so the check finds corruption, not forgery. + let mut sess = start(TPMA_SESSION::continueSession, &[], &null_handle()).unwrap(); + sess.session_type = TPM_SE::POLICY; + sess.needs_hmac = false; + sess.needs_password = false; + + let mut authorized = TPM_HANDLE::new(0x81000001); + authorized.set_auth(b"object-auth"); + + assert!(sess.expects_response_auth()); + assert!(!sess.has_secret_key_material()); + assert!(!sess.includes_auth_value(Some(&authorized))); + assert!( + sess.auth_hmac_key(Some(&authorized)).is_empty(), + "an unsalted, unbound policy session keys its HMAC on nothing at all" + ); + + // The contrast, so that this does not read as a claim about policy sessions in general: + // salt the same session and the key is a secret an observer does not have. + let salted = start(TPMA_SESSION::continueSession, SALT, &null_handle()).unwrap(); + assert!(salted.has_secret_key_material()); + assert!(!salted.auth_hmac_key(Some(&authorized)).is_empty()); + } + + /// Two bytes of hex per octet, for the vectors below. + fn hex(text: &str) -> Vec { + (0..text.len() / 2) + .map(|i| u8::from_str_radix(&text[2 * i..2 * i + 2], 16).unwrap()) + .collect() + } + + /// The session key against values computed outside this crate. + /// + /// Every other HMAC assertion in this repository keys itself on `session.session_key`, which + /// comes from `calc_session_key` — the code under test. Those tests agree with the client no + /// matter what it derives: swap the two nonces, or change the label, and they all still + /// pass. These vectors were produced independently from the formula in TPM 2.0 Part 1, + /// §11.4.10.2 and §19.6.8: + /// + /// ```text + /// sessionKey := KDFa(hashAlg, bindAuth ‖ salt, "ATH", nonceTPM, nonceCaller, bits) + /// KDFa(alg, key, label, contextU, contextV, bits) := + /// HMAC_alg(key, BE32(counter) ‖ label ‖ 0x00 ‖ contextU ‖ contextV ‖ BE32(bits)) + /// ``` + /// + /// so they pin the KDFa construction itself: the nonce *order* (nonceTPM is contextU, the + /// caller's nonce contextV), the label, its NUL terminator, and the trailing bit count. + #[test] + fn the_session_key_matches_an_independently_computed_kdfa_vector() { + // KDFa(SHA256, SALT, "ATH", [0xBB; 32], [0xAA; 32], 256), where the two nonces are the + // ones `start` hands to `Session::from_tpm_response`. + let salted = start(TPMA_SESSION::continueSession, SALT, &null_handle()).unwrap(); + assert_eq!( + salted.session_key, + hex("39a0d74e4c4cc9d54088ec9565944c5e3332594b4a98c35be52ae224c86ab367") + ); + + // The same derivation with the nonces the other way round. It is here to show what the + // vector above rules out: a client that fed nonceCaller as contextU would agree with + // every HMAC test in this repository and with no TPM at all. + assert_ne!( + salted.session_key, + hex("12ed2216d596138fe107ef74730c868bbfd2b6e0d25c8801e60688585668c62e"), + "nonceTPM is contextU and nonceCaller is contextV, not the other way round" + ); + + // And with the "CFB" label, which is what parameter encryption derives with. A session + // key derived under the wrong label is the same length and useless. + assert_ne!( + salted.session_key, + hex("ad195ab7d2e025c8e96aa8b9e961ab0d8ee3b8f7650def7dec93427ec5d56772"), + "the session key is derived under the \"ATH\" label" + ); + + // bindAuth ‖ salt, with the bind entity's authValue first: + // KDFa(SHA256, b"bind-auth" ‖ SALT, "ATH", [0xBB; 32], [0xAA; 32], 256). + let mut bound = TPM_HANDLE::new(0x81000001); + bound.set_auth(b"bind-auth"); + let bound = start(TPMA_SESSION::continueSession, SALT, &bound).unwrap(); + assert_eq!( + bound.session_key, + hex("8ac20ea98b54559b4697be91175c84851ef430023f264e87c379bf6d6301edd9") + ); + } +} + +#[cfg(test)] +mod cfb_key_material_tests { + use super::*; + + #[test] + fn key_material_shorter_than_the_key_and_iv_is_an_error_not_a_panic() { + // Unreachable through the KDFa in this crate, which always returns exactly the number of + // octets it was asked for. It is reachable through a `CryptoProvider` supplied by + // someone else, and the answer there has to be an error rather than a panicking slice. + let err = split_cfb_key_material(&[0u8; 31], 16) + .expect_err("16 B of key and 16 B of IV do not fit in 31 B"); + assert!( + format!("{}", err).contains("parameter encryption key material"), + "unexpected error: {}", + err + ); + + assert!(split_cfb_key_material(&[0u8; 47], 32).is_err()); + } + + #[test] + fn key_material_is_split_into_the_key_and_then_the_iv() { + let stream: Vec = (0..48u8).collect(); + + let (key, iv) = split_cfb_key_material(&stream, 16).unwrap(); + assert_eq!(key, &stream[..16]); + assert_eq!(iv, &stream[16..32]); + + let (key, iv) = split_cfb_key_material(&stream, 32).unwrap(); + assert_eq!(key, &stream[..32]); + assert_eq!(iv, &stream[32..48]); + } +} diff --git a/TSS.Rust/src/crypto/cng_provider.rs b/TSS.Rust/src/crypto/cng_provider.rs index e4cee139..3051db16 100644 --- a/TSS.Rust/src/crypto/cng_provider.rs +++ b/TSS.Rust/src/crypto/cng_provider.rs @@ -858,6 +858,207 @@ mod tests { assert_eq!(recovered, secret); } + /// A 2048-bit RSA modulus that never changes between runs. + /// + /// It is a real generated modulus rather than an invented number, because CNG imports it as a + /// public key and a value that is not a plausible key would be rejected on import rather than + /// on the signature. Its only job is to make the rejection shapes below the same bytes every + /// time; nothing here needs the private half. + const FIXED_MODULUS: [u8; 256] = [ + 0xc0, 0x79, 0x3f, 0xce, 0x4e, 0x17, 0xf3, 0xee, 0x11, 0xfd, 0x1b, 0x27, 0xfb, 0xf9, 0x28, + 0xd7, 0xee, 0x96, 0xe8, 0x4a, 0x5a, 0x15, 0x09, 0x4f, 0xba, 0xf9, 0x4b, 0x73, 0x4f, 0x73, + 0xcb, 0x0f, 0x4b, 0x23, 0x8a, 0x05, 0x25, 0x07, 0xb2, 0x9f, 0x0b, 0xf4, 0xf7, 0x35, 0x3c, + 0xe9, 0xa4, 0xab, 0x77, 0x2a, 0x8b, 0x80, 0x70, 0xaf, 0x9b, 0xa6, 0x38, 0x98, 0x3a, 0xee, + 0xd1, 0xcf, 0xf0, 0x99, 0x16, 0xdc, 0x7c, 0xcd, 0x42, 0x86, 0xd0, 0x5d, 0x2c, 0xa6, 0x98, + 0xc1, 0x8b, 0xff, 0xd2, 0x0f, 0x2d, 0x1a, 0x04, 0x15, 0x93, 0xd2, 0xb6, 0xab, 0x68, 0x60, + 0xe8, 0x3c, 0xa3, 0xb7, 0x6c, 0x5b, 0xf2, 0x09, 0x92, 0xf8, 0xed, 0x67, 0xf8, 0x18, 0xb5, + 0xee, 0x71, 0x62, 0x66, 0x93, 0xdb, 0xd5, 0xfc, 0x8f, 0xa6, 0xce, 0x1b, 0x1e, 0x63, 0xe6, + 0x79, 0xcf, 0xa8, 0xe7, 0xf9, 0x29, 0xf9, 0xf5, 0xcb, 0x51, 0xa0, 0xc4, 0x41, 0xfd, 0xd8, + 0xd0, 0xcb, 0x2e, 0xc2, 0x83, 0x8b, 0xda, 0x9b, 0xfb, 0x1f, 0x38, 0x4b, 0x46, 0x14, 0xe1, + 0x54, 0xbd, 0x82, 0xc1, 0x67, 0xe5, 0x94, 0x4a, 0xdb, 0xf3, 0x88, 0x94, 0xe7, 0x45, 0xa4, + 0x42, 0xbc, 0x7c, 0xed, 0x33, 0x45, 0xa5, 0xf9, 0x54, 0xe4, 0x9f, 0x7c, 0x6d, 0xf4, 0x8d, + 0x1e, 0x91, 0x7e, 0x35, 0x96, 0x3e, 0xfa, 0xbb, 0x85, 0xb7, 0x58, 0x3f, 0xa7, 0x10, 0x17, + 0x0d, 0x4a, 0xbc, 0xf2, 0x1f, 0x25, 0xae, 0xe0, 0x7e, 0x9c, 0x8c, 0x5d, 0xcf, 0x30, 0xfd, + 0x27, 0x62, 0xb7, 0x66, 0xc6, 0x97, 0x16, 0x30, 0x68, 0x33, 0x79, 0x79, 0xc2, 0xfe, 0xa1, + 0xbb, 0x5b, 0x92, 0x86, 0x56, 0x02, 0xe9, 0x31, 0x48, 0x08, 0x22, 0x82, 0x36, 0x27, 0x5e, + 0x84, 0x17, 0x37, 0x06, 0xc5, 0xa5, 0xac, 0x91, 0xe8, 0x40, 0x74, 0x76, 0x23, 0x4d, 0xd4, + 0x9b, + ]; + + /// The public exponent the fixed-input RSA cases use. + const EXPONENT: [u8; 3] = [0x01, 0x00, 0x01]; + + /// Both backends, so a shape is asserted against each in turn. + fn providers() -> [(&'static str, &'static CryptoProvider); 2] { + [ + ("the software provider", &SOFTWARE_PROVIDER), + ("CNG", &CNG_PROVIDER), + ] + } + + /// The signature shapes both backends must answer with `Ok(false)`. + /// + /// Listing them in one place is what makes a new case cheap. The two backends reach the same + /// answer through entirely different code, which is the whole reason to check: the `rsa` crate + /// folds every verification error into one, while CNG distinguishes a signature that does not + /// verify from one it will not attempt at all, and this provider folds those two statuses back + /// together itself. + /// + /// Every shape here must be certain to be rejected, for every modulus and signature that can + /// reach it, or this becomes a test that fails once in a while for a reason that is not a + /// defect. Each is argued below, and all of them rest on `modulus` being a real RSA modulus: + /// full width with its top bit set, which [`FIXED_MODULUS`] is by construction and which a + /// caller passing a generated modulus would have to check rather than assume. + fn rejected_signatures(modulus: &[u8], signature: &[u8]) -> Vec<(&'static str, Vec)> { + assert_eq!( + signature.len(), + modulus.len(), + "the shapes below are derived from a signature at the modulus width" + ); + + // Flipping the least significant byte moves the value by at most 255, so it stays below + // the modulus, and it always changes the value. This is the case where CNG genuinely + // answers STATUS_INVALID_SIGNATURE. + let mut in_range = signature.to_vec(); + if let Some(last) = in_range.last_mut() { + *last ^= 0xff; + } + + // Changing the most significant byte has to leave a value that is both different from the + // signature and still below the modulus, which clearing that byte unconditionally does + // not: a signature is zero padded to the modulus width, so roughly one signature in 256 + // already begins with a zero byte, and clearing it would reproduce the signature exactly + // and be accepted. Both branches below are distinct from the signature by construction, + // and both are below the modulus, whose leading byte is at least 0x80: the result is under + // two units of the leading byte's place value, and the modulus is at least 128 of them. + let mut leading_byte_changed = signature.to_vec(); + leading_byte_changed[0] = if signature[0] == 0 { 1 } else { 0 }; + + // Every byte set is the largest value of this width and so is at or above any modulus of + // the same width. This is the case CNG reports as STATUS_INVALID_PARAMETER, and it is here + // as fixed bytes because flipping the leading byte of a generated signature lands on it + // only for some keys: how often depends on the leading byte of the modulus drawn, so a + // test that relied on that alone would exercise this status on some runs and not others. + let out_of_range = vec![0xffu8; modulus.len()]; + + let one_byte_short = signature[1..].to_vec(); + let one_byte_long = [&[0u8][..], signature].concat(); + + vec![ + ("a corrupted in-range signature", in_range), + ("a changed leading byte", leading_byte_changed), + ("a signature not below the modulus", out_of_range), + ("a signature one byte short", one_byte_short), + ("a signature one byte long", one_byte_long), + ("an empty signature", Vec::new()), + ] + } + + /// Runs every rejection shape through both backends, reporting which backend and which shape. + /// + /// `digest` is the one the signature was made over, where there is one, so that the corrupted + /// in-range shape is judged against a digest its uncorrupted form would verify under. A shape + /// that were accidentally a no-op would otherwise still pass here. + fn assert_every_shape_is_rejected( + modulus: &[u8], + exponent: &[u8], + digest: &[u8], + signature: &[u8], + ) { + for (backend, provider) in providers() { + for (description, candidate) in rejected_signatures(modulus, signature) { + let verified = (provider.rsa.pkcs1v15_verify)( + modulus, + exponent, + TPM_ALG_ID::SHA256, + digest, + &candidate, + ) + .unwrap_or_else(|e| { + panic!("{backend} reported {description} as a failure rather than rejecting it: {e}") + }); + + // A signature that will not verify is an answer rather than a failure, whichever + // backend is answering. A backend that returns `Err` here diverts a caller such as + // `validate_certify` from its `false` branch into error handling, on input a + // remote party chooses. + assert!(!verified, "{backend} accepted {description}"); + } + } + } + + /// The rejection shapes over bytes that are identical on every run. + /// + /// Nothing here is generated, so this test either always passes or always fails, and a failure + /// is reproducible by running it again. That matters because the shapes are the regression + /// test for a provider that answered some of them with `Err`, and a test that samples a fresh + /// key each run can only ever say that today's key was fine. + #[test] + fn pkcs1v15_rejections_are_the_same_on_every_run() { + // Halving the leading byte of the modulus gives a value of the right width that is + // certainly below it, which is all a rejection shape needs. Standing one in for a real + // signature is what lets this test fix every byte without holding a private key. + let mut signature_shaped = FIXED_MODULUS.to_vec(); + signature_shaped[0] >>= 1; + + assert_every_shape_is_rejected(&FIXED_MODULUS, &EXPONENT, &[0x5au8; 32], &signature_shaped); + } + + /// The boundary the status map leaves in place. + /// + /// `rsa_pkcs1v15_verify` answers both `STATUS_INVALID_SIGNATURE` and + /// `STATUS_INVALID_PARAMETER` with `Ok(false)`, so no verdict on a signature comes back as an + /// error. What is still an error is a verification that never reached the signature: the key + /// has to import and the hash algorithm has to have a CNG name before `BCryptVerifySignature` + /// is called at all, and both of those fail ahead of the status map rather than through it. + /// That is the distinction `Err` still carries, and it is the order of the three steps in + /// `rsa_pkcs1v15_verify` that carries it, so it is asserted rather than assumed. + /// + /// Nothing here claims that a signature CNG refuses to attempt is an error. Under the status + /// map it is not, which is what `pkcs1v15_rejections_are_the_same_on_every_run` pins from the + /// other side. + #[test] + fn verification_still_fails_rather_than_rejects_when_it_cannot_be_performed() { + let signature = [0x01u8; 256]; + let digest = [0x5au8; 32]; + + // The contrast the two cases below are read against: this call is a verdict on the + // signature rather than an error, and each of them differs from it in one respect only. + // Without it they would pass just as well against a provider that errored on everything. + let verified = (CNG_PROVIDER.rsa.pkcs1v15_verify)( + &FIXED_MODULUS, + &EXPONENT, + TPM_ALG_ID::SHA256, + &digest, + &signature, + ) + .expect("a signature below the modulus is judged rather than refused"); + assert!(!verified, "a signature that cannot verify was accepted"); + + assert!( + (CNG_PROVIDER.rsa.pkcs1v15_verify)( + &[], + &EXPONENT, + TPM_ALG_ID::SHA256, + &digest, + &signature + ) + .is_err(), + "a key CNG cannot import was reported as a bad signature" + ); + assert!( + (CNG_PROVIDER.rsa.pkcs1v15_verify)( + &FIXED_MODULUS, + &EXPONENT, + TPM_ALG_ID::SM3_256, + &digest, + &signature + ) + .is_err(), + "a hash algorithm CNG does not offer was reported as a bad signature" + ); + } + #[test] fn pkcs1v15_verification_agrees_with_the_software_provider() { let key = (SOFTWARE_PROVIDER.rsa.generate_keypair)(2048, &[0x01, 0x00, 0x01]).unwrap(); diff --git a/TSS.Rust/src/crypto/mod.rs b/TSS.Rust/src/crypto/mod.rs index baf81beb..e3f86e95 100644 --- a/TSS.Rust/src/crypto/mod.rs +++ b/TSS.Rust/src/crypto/mod.rs @@ -21,7 +21,8 @@ pub mod software_provider; use crate::{error::TpmError, tpm_types::*}; use provider::{CryptoProvider, EccEphemeralAgreement}; -use zeroize::Zeroizing; +use std::fmt; +use zeroize::{Zeroize, Zeroizing}; /// The RSA public exponent the TPM 2.0 specification defines as the default (65537, "F4"). /// @@ -34,16 +35,102 @@ pub const RSA_DEFAULT_EXPONENT: [u8; 3] = [0x01, 0x00, 0x01]; /// plus the public exponent needed to reconstruct the key. /// /// The second prime is recovered by dividing the modulus by the first, so it is not stored. -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct RsaKeyParts { + /// The modulus, which is public. pub modulus: Vec, + + /// The first prime factor, which is the whole of the private key. + /// + /// It sits beside the modulus, so the second prime, and from it the private exponent, follow + /// from a single division. It is therefore wiped when dropped, and withheld from the [`Debug`] + /// rendering below. Because the wipe is a `Drop`, this field cannot be moved out of the + /// struct: take it with [`std::mem::take`] instead. pub prime: Vec, + /// The public exponent, big-endian and without leading zeros. Callers holding a /// `TPMS_RSA_PARMS` should populate this with `TPMS_RSA_PARMS::exponent_bytes`, which /// resolves the specification's zero-means-65537 encoding. pub exponent: Vec, } +/// Renders the public parts of the key in full and the prime not at all. +/// +/// A derived `Debug` would put the private key into any log line that formats a generated or +/// reconstructed key, which includes every error path that reports the key it was working on. +impl fmt::Debug for RsaKeyParts { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RsaKeyParts") + .field("modulus", &self.modulus) + .field("prime", &format_args!("")) + .field("exponent", &self.exponent) + .finish() + } +} + +/// Wipes the prime, so that a key that has gone out of scope is not left in freed heap. +/// +/// `Clone` copies the prime, and every copy is wiped by this same implementation. +impl Drop for RsaKeyParts { + fn drop(&mut self) { + self.prime.zeroize(); + } +} + +#[cfg(test)] +mod secret_redaction_tests { + use super::*; + + #[test] + fn rsa_key_parts_debug_withholds_the_private_prime() { + // Bytes chosen so that neither their decimal nor their hexadecimal rendering is a + // substring of anything the redacted `Debug` legitimately prints. + let prime = vec![0xA7u8, 0xB3, 0xC9, 0xD1, 0xE5, 0xF2]; + let key = RsaKeyParts { + modulus: vec![0x11, 0x22], + prime: prime.clone(), + exponent: RSA_DEFAULT_EXPONENT.to_vec(), + }; + + let rendered = format!("{:?}", key); + + for byte in &prime { + assert!( + !rendered.contains(&byte.to_string()), + "debug rendering {rendered} leaks prime byte {byte} in decimal" + ); + assert!( + !rendered.to_lowercase().contains(&format!("{byte:02x}")), + "debug rendering {rendered} leaks prime byte {byte} in hex" + ); + } + assert!( + !rendered.contains(&format!("{:?}", prime)), + "debug rendering {rendered} leaks the prime verbatim" + ); + + // The public parts stay legible, which is the point of hand writing the rendering rather + // than dropping `Debug` altogether. + assert!(rendered.contains(&format!("{:?}", key.modulus))); + assert!(rendered.contains(&format!("{:?}", key.exponent))); + } + + #[test] + fn rsa_key_parts_still_clones() { + let key = RsaKeyParts { + modulus: vec![0x11, 0x22], + prime: vec![0xA7, 0xB3], + exponent: RSA_DEFAULT_EXPONENT.to_vec(), + }; + + let copy = key.clone(); + + assert_eq!(copy.modulus, key.modulus); + assert_eq!(copy.prime, key.prime); + assert_eq!(copy.exponent, key.exponent); + } +} + pub struct Crypto; impl Crypto { @@ -574,6 +661,43 @@ mod tests { Ok(()) } + #[test] + fn rsa_verify_rejects_a_malformed_signature_rather_than_failing() -> Result<(), TpmError> { + let key = Crypto::rsa_generate_keypair(&SOFTWARE_PROVIDER, 2048, &RSA_DEFAULT_EXPONENT)?; + let digest = Sha256::digest(b"malformed signature rejection").to_vec(); + + // A signature that cannot verify is an answer rather than a failure, so each of these is + // `Ok(false)` and none of them is `Err`. None is reachable only by mistake either: a + // signature arrives from whoever sent it, and nothing stops it being short or numerically + // at or above the modulus. The CNG provider is held to the same by + // `pkcs1v15_verification_agrees_with_the_software_provider`, and the two backends are + // interchangeable only while both answer this way. + let not_below_modulus = vec![0xffu8; key.modulus.len()]; + let one_byte_short = vec![0x01u8; key.modulus.len() - 1]; + let one_byte_long = vec![0x01u8; key.modulus.len() + 1]; + + let candidates: [(&str, Vec); 4] = [ + ("a signature not below the modulus", not_below_modulus), + ("a signature one byte short", one_byte_short), + ("a signature one byte long", one_byte_long), + ("an empty signature", Vec::new()), + ]; + + for (description, candidate) in candidates { + let verified = Crypto::rsa_pkcs1v15_verify( + &SOFTWARE_PROVIDER, + &key.modulus, + &RSA_DEFAULT_EXPONENT, + TPM_ALG_ID::SHA256, + &digest, + &candidate, + )?; + assert!(!verified, "the software provider accepted {description}"); + } + + Ok(()) + } + #[test] fn rsa_sign_rejects_a_zero_prime_instead_of_dividing_by_it() { let key = RsaKeyParts { diff --git a/TSS.Rust/src/crypto/provider.rs b/TSS.Rust/src/crypto/provider.rs index b15cbad4..ea71abfa 100644 --- a/TSS.Rust/src/crypto/provider.rs +++ b/TSS.Rust/src/crypto/provider.rs @@ -10,10 +10,12 @@ //! through a call chain costs no more than passing a pointer. This mirrors how `jsonwebtoken` //! models its own pluggable backend. //! -//! Deliberately, there is no process-wide default provider. TSS.Rust is built as a `cdylib` as -//! well as an `rlib`, and hosts that load and unload it repeatedly would have to reason about the -//! lifetime of any global. Requiring the provider at the call site also lets a single process use -//! two backends at once, which is what makes cross-provider equivalence testing possible. +//! Deliberately, there is no process-wide default provider. A global has to be installed by +//! whoever gets to it first, and in a library that is not a decision any one caller owns: an +//! application and a dependency that both use TSS.Rust would race to set it, and the loser would +//! silently run against a backend it did not choose. Requiring the provider at the call site also +//! lets a single process use two backends at once, which is what makes cross-provider equivalence +//! testing possible. //! //! Only primitives belong here. Logic defined by the TPM 2.0 specification — digest sizes, KDFa, //! signature validation — is built on top of these primitives by [`Crypto`](super::Crypto) and is @@ -143,6 +145,16 @@ pub struct RsaOps { /// /// A `false` result means the signature did not verify. An `Err` means the verification could /// not be performed at all, for instance because the key or the hash algorithm was rejected. + /// + /// A signature that is not a candidate at all — one whose length differs from the modulus, or + /// whose value is at or above it — is `false` rather than `Err`. This follows from the + /// sentence above rather than adding to it: neither the key nor the hash algorithm is at + /// fault in that case, and those are what `Err` is reserved for. Both shapes are chosen by + /// whoever supplied the signature and say nothing about the caller, so a backend that + /// reported them as failures would divert a caller such as + /// [`TrustedPublic::validate_certify`](crate::tpm_type_extensions::TrustedPublic::validate_certify) + /// out of its `false` branch on input a remote party controls. A backend layered on an API + /// that distinguishes these from an ordinary bad signature has to fold them in itself. pub pkcs1v15_verify: RsaPkcs1v15VerifyFn, /// Generate an RSA key pair, returning the modulus and the first prime. diff --git a/TSS.Rust/src/device.rs b/TSS.Rust/src/device.rs index 0e69c106..d0fdd32e 100644 --- a/TSS.Rust/src/device.rs +++ b/TSS.Rust/src/device.rs @@ -11,12 +11,19 @@ use crate::error::TpmError; use std::os::raw::c_void; #[cfg(target_os = "windows")] use std::ptr; +// The `Win32_System_TpmBaseServices` feature of the `windows` crate is only requested for Windows +// targets, so this module does not exist anywhere else. +#[cfg(target_os = "windows")] use windows::Win32::System::TpmBaseServices::*; #[cfg(target_os = "linux")] use std::fs::{File, OpenOptions}; #[cfg(target_os = "linux")] -use std::os::unix::io::AsRawFd; +use std::io::{Read, Write}; +#[cfg(target_os = "linux")] +use std::net::TcpStream; +#[cfg(target_os = "linux")] +use std::time::Duration; /// Defines the TPM connection information flags #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -156,280 +163,153 @@ pub trait TpmDevice { fn get_tpm_info(&self) -> u32; } -// /// TPM device implementation for TCP connection (simulator) -// pub struct TpmTcpDevice { -// host_name: String, -// port: u16, -// command_socket: Option, -// signal_socket: Option, -// locality: u8, -// tpm_info: u32, -// } - -// impl TpmTcpDevice { -// /// Create a new TpmTcpDevice -// pub fn new(host_name: String, port: u16) -> Self { -// TpmTcpDevice { -// host_name, -// port, -// command_socket: None, -// signal_socket: None, -// locality: 0, -// tpm_info: 0, -// } -// } - -// /// Set the target for the TCP connection -// pub fn set_target(&mut self, host_name: String, port: u16) { -// self.host_name = host_name; -// self.port = port; -// self.locality = 0; -// } - -// /// Connect to the specified host and port -// pub fn connect_to(&mut self, host_name: String, port: u16) -> Result { -// self.set_target(host_name, port); -// self.connect() -// } - -// // Helper function to send an integer in network byte order -// fn send_int(socket: &mut TcpStream, value: u32) -> Result<(), TpmError> { -// let value_bytes = value.to_be_bytes(); -// socket -// .write_all(&value_bytes) -// .map_err(|e| TpmError::IoError(e.to_string())) -// } - -// // Helper function to receive an integer in network byte order -// fn receive_int(socket: &mut TcpStream) -> Result { -// let mut buffer = [0u8; 4]; -// socket -// .read_exact(&mut buffer) -// .map_err(|e| TpmError::IoError(e.to_string()))?; -// Ok(u32::from_be_bytes(buffer)) -// } - -// // Helper function to get acknowledgement from server -// fn get_ack(socket: &mut TcpStream) -> Result<(), TpmError> { -// let end_tag = Self::receive_int(socket)?; - -// if end_tag != 0 { -// if end_tag == 1 { -// return Err(TpmError::CommandFailed); -// } else { -// return Err(TpmError::BadEndTag); -// } -// } - -// Ok(()) -// } - -// // Helper function to send a command and get acknowledgement -// fn send_cmd_and_get_ack(socket: &mut TcpStream, cmd: TcpTpmCommand) -> Result<(), TpmError> { -// Self::send_int(socket, cmd as u32)?; -// Self::get_ack(socket) -// } - -// // Helper function to receive a variable-length array -// fn recv_var_array(socket: &mut TcpStream) -> Result, TpmError> { -// let len = Self::receive_int(socket)? as usize; -// let mut buffer = vec![0u8; len]; - -// socket -// .read_exact(&mut buffer) -// .map_err(|e| TpmError::IoError(e.to_string()))?; - -// Ok(buffer) -// } -// } - -// impl TpmDevice for TpmTcpDevice { -// fn connect(&mut self) -> Result { -// // Close any existing connections -// self.close(); - -// // Connect to the signal port first -// let signal_addr = format!("{}:{}", self.host_name, self.port + 1); -// let signal_socket = TcpStream::connect(signal_addr) -// .map_err(|e| TpmError::IoError(format!("Failed to connect to signal port: {}", e)))?; - -// // Connect to the command port -// let command_addr = format!("{}:{}", self.host_name, self.port); -// let command_socket = TcpStream::connect(command_addr) -// .map_err(|e| TpmError::IoError(format!("Failed to connect to command port: {}", e)))?; - -// // Set read and write timeouts -// command_socket -// .set_read_timeout(Some(Duration::from_secs(5))) -// .map_err(|e| TpmError::IoError(e.to_string()))?; -// signal_socket -// .set_read_timeout(Some(Duration::from_secs(5))) -// .map_err(|e| TpmError::IoError(e.to_string()))?; - -// // Store the sockets -// self.command_socket = Some(command_socket); -// self.signal_socket = Some(signal_socket); - -// // Make sure the TPM protocol is running -// if let Some(mut cmd_socket) = self.command_socket.as_ref().map(|s| s.try_clone().unwrap()) { -// // Client version is 1 -// const CLIENT_VERSION: u32 = 1; - -// Self::send_int(&mut cmd_socket, TcpTpmCommand::RemoteHandshake as u32)?; -// Self::send_int(&mut cmd_socket, CLIENT_VERSION)?; - -// let endpoint_ver = Self::receive_int(&mut cmd_socket)?; -// if endpoint_ver != CLIENT_VERSION { -// return Err(TpmError::IncompatibleTpm); -// } - -// // Get the endpoint TPM properties -// self.tpm_info = Self::receive_int(&mut cmd_socket)?; - -// Self::get_ack(&mut cmd_socket)?; - -// Ok(true) -// } else { -// Err(TpmError::NotConnected) -// } -// } - -// fn close(&mut self) { -// // Close command socket if open -// if let Some(_) = self.command_socket.take() { -// // Socket will be closed when dropped -// } - -// // Close signal socket if open -// if let Some(_) = self.signal_socket.take() { -// // Socket will be closed when dropped -// } -// } - -// fn dispatch_command(&mut self, cmd_buf: &[u8]) -> Result<(), TpmError> { -// if let Some(mut socket) = self.command_socket.as_ref().map(|s| s.try_clone().unwrap()) { -// // Send the command header -// Self::send_int(&mut socket, TcpTpmCommand::SendCommand as u32)?; -// socket -// .write_all(&[self.locality]) -// .map_err(|e| TpmError::IoError(e.to_string()))?; -// Self::send_int(&mut socket, cmd_buf.len() as u32)?; - -// // Send the command data -// socket -// .write_all(cmd_buf) -// .map_err(|e| TpmError::IoError(e.to_string()))?; - -// Ok(()) -// } else { -// Err(TpmError::NotConnected) -// } -// } - -// fn get_response(&mut self) -> Result, TpmError> { -// if let Some(mut socket) = self.command_socket.as_ref().map(|s| s.try_clone().unwrap()) { -// // Get the response -// let resp = Self::recv_var_array(&mut socket)?; - -// // Get the terminating ACK -// let ack = Self::receive_int(&mut socket)?; -// if ack != 0 { -// return Err(TpmError::BadEndTag); -// } - -// Ok(resp) -// } else { -// Err(TpmError::NotConnected) -// } -// } - -// fn response_is_ready(&self) -> Result { -// if let Some(socket) = &self.command_socket { -// // Create a read set with just this socket -// let mut read_set = [socket -// .try_clone() -// .map_err(|e| TpmError::IoError(e.to_string()))?]; - -// // Check if there's data to read with a zero timeout -// match socket::select( -// &mut read_set, -// &mut [], -// &mut [], -// Some(&Duration::from_secs(0)), -// ) { -// Ok(1) => Ok(true), -// Ok(_) => Ok(false), -// Err(e) => Err(TpmError::IoError(e.to_string())), -// } -// } else { -// Err(TpmError::NotConnected) -// } -// } - -// fn power_ctl(&mut self, on: bool) -> Result<(), TpmError> { -// if let Some(mut socket) = self.signal_socket.as_ref().map(|s| s.try_clone().unwrap()) { -// let power_cmd = if on { -// TcpTpmCommand::SignalPowerOn -// } else { -// TcpTpmCommand::SignalPowerOff -// }; - -// let nv_cmd = if on { -// TcpTpmCommand::SignalNvOn -// } else { -// TcpTpmCommand::SignalNvOff -// }; - -// Self::send_cmd_and_get_ack(&mut socket, power_cmd)?; -// Self::send_cmd_and_get_ack(&mut socket, nv_cmd)?; - -// Ok(()) -// } else { -// Err(TpmError::NotConnected) -// } -// } - -// fn assert_physical_presence(&mut self, on: bool) -> Result<(), TpmError> { -// if let Some(mut socket) = self.signal_socket.as_ref().map(|s| s.try_clone().unwrap()) { -// let pp_cmd = if on { -// TcpTpmCommand::SignalPPOn -// } else { -// TcpTpmCommand::SignalPPOff -// }; - -// Self::send_cmd_and_get_ack(&mut socket, pp_cmd) -// } else { -// Err(TpmError::NotConnected) -// } -// } - -// fn set_locality(&mut self, locality: u32) -> Result<(), TpmError> { -// if locality > 255 { -// return Err(TpmError::InvalidParameter); -// } - -// self.locality = locality as u8; -// Ok(()) -// } - -// fn platform_available(&self) -> bool { -// self.has_flag(TpmConnInfo::TpmPlatformAvailable as u32) -// } - -// fn has_flag(&self, flag: u32) -> bool { -// (self.tpm_info & flag) != 0 -// } - -// fn get_tpm_info(&self) -> u32 { -// self.tpm_info -// } -// } +/// How a [`TbsContext`] closes the handle it owns. +/// +/// The close is reached through a function pointer rather than called directly so that the unit +/// tests, which wrap handles TBS has never issued, can substitute a recorder for that one handle +/// instead of compiling the close out of the whole build. Every context TBS did issue carries +/// [`tbs_context_close`] and is therefore closed for real, in test builds as well as in +/// production ones. +#[cfg(target_os = "windows")] +type TbsCloseFn = unsafe fn(*mut c_void) -> u32; + +/// Closes a TBS context. The default [`TbsCloseFn`] of every [`TbsContext`]. +/// +/// # Safety +/// +/// `handle` must be a context returned by a successful `Tbsi_Context_Create` that has not been +/// closed already. +#[cfg(target_os = "windows")] +unsafe fn tbs_context_close(handle: *mut c_void) -> u32 { + // SAFETY: forwarded from this function's own contract. + unsafe { Tbsip_Context_Close(handle) } +} + +/// A TBS (TPM Base Services) context handle together with its ownership. +/// +/// Keeping the handle and the ownership flag in one type means the two cannot drift apart, and it +/// gives the handle a [`Drop`] of its own: an owned context is closed as soon as the value holding +/// it goes away, including on an early return or an unwind. A borrowed context is never closed. +#[cfg(target_os = "windows")] +struct TbsContext { + handle: *mut c_void, + owned: bool, + /// Applied to `handle` on drop when `owned`. Both constructors set the real TBS close; only a + /// unit test, hand-building a context over a handle of its own, substitutes anything else. + close: TbsCloseFn, +} + +#[cfg(target_os = "windows")] +impl TbsContext { + /// Opens a new TBS context. The returned value owns it and closes it on drop. + fn create() -> Result { + let mut params = TBS_CONTEXT_PARAMS2 { + version: TBS_CONTEXT_VERSION_TWO, + ..Default::default() + }; + params.Anonymous.Anonymous._bitfield = 4; + params.Anonymous.asUINT32 = 4; + + let mut handle: *mut c_void = ptr::null_mut(); + // SAFETY: `params` is a fully initialized TBS_CONTEXT_PARAMS2 whose `version` field marks + // it as the version-two layout TBS expects behind the TBS_CONTEXT_PARAMS pointer, and + // `handle` is a live local that TBS only writes to. Both pointers outlive the call. + let res = unsafe { + Tbsi_Context_Create( + ¶ms as *const TBS_CONTEXT_PARAMS2 as *const TBS_CONTEXT_PARAMS, + &mut handle, + ) + }; + + if res != TBS_SUCCESS { + return Err(TpmError::TbsError(format!( + "Failed to connect to TBS: {:?}", + res + ))); + } + if handle.is_null() { + return Err(TpmError::TbsError( + "TBS reported success but returned no context".to_string(), + )); + } + + Ok(Self { + handle, + owned: true, + close: tbs_context_close, + }) + } + + /// Wraps a context owned by the caller. The returned value never closes it. + /// + /// # Safety + /// + /// `handle` must be a valid TBS context that outlives the returned value. + unsafe fn borrowed(handle: *mut c_void) -> Result { + if handle.is_null() { + return Err(TpmError::InvalidParameter); + } + + Ok(Self { + handle, + owned: false, + close: tbs_context_close, + }) + } + + fn handle(&self) -> *mut c_void { + self.handle + } +} + +#[cfg(target_os = "windows")] +impl Drop for TbsContext { + fn drop(&mut self) { + if !self.owned { + return; + } + + // SAFETY: `handle` came from a successful `Tbsi_Context_Create` in `create`, the only + // constructor that sets `owned` on a context carrying the real close; a context carrying + // any other close came from a unit test that built it over a handle of its own. + // `TbsContext` is neither `Clone` nor `Copy`, so this is the only value holding that + // handle, and `Drop` runs at most once - meeting the TBS requirement of exactly one close + // per created context. + unsafe { + (self.close)(self.handle); + } + } +} + +/// The [`TbsCloseFn`] the unit tests substitute for handles TBS has never issued: it records the +/// close and touches nothing. +#[cfg(all(test, target_os = "windows"))] +mod tbs_close_log { + use std::cell::Cell; + use std::os::raw::c_void; + + thread_local! { + static CLOSES: Cell = const { Cell::new(0) }; + } + + /// # Safety + /// + /// None: `handle` is never dereferenced, and no TBS call is made. The signature exists only + /// to match [`super::TbsCloseFn`]. + pub(super) unsafe fn record_close(_handle: *mut c_void) -> u32 { + CLOSES.with(|closes| closes.set(closes.get() + 1)); + super::TBS_SUCCESS + } + + pub(super) fn count() -> usize { + CLOSES.with(|closes| closes.get()) + } +} // Windows TBS (TPM Base Services) implementation #[cfg(target_os = "windows")] pub struct TpmTbsDevice { - context: *mut c_void, - owns_context: bool, + context: Option, result_buffer: [u8; 4096], res_size: u32, tpm_info: u32, @@ -446,8 +326,7 @@ impl Default for TpmTbsDevice { impl TpmTbsDevice { pub fn new() -> Self { TpmTbsDevice { - context: ptr::null_mut(), - owns_context: false, + context: None, result_buffer: [0; 4096], res_size: 0, tpm_info: 0, @@ -456,21 +335,20 @@ impl TpmTbsDevice { /// Creates a TPM device that submits commands through a caller-owned TBS context. /// - /// The context is borrowed and will not be closed by [`TpmDevice::close`] or when the device - /// is dropped. + /// The context is borrowed: it is closed neither by [`TpmDevice::close`] nor when the device + /// is dropped. A context opened by [`TpmDevice::connect`], by contrast, is owned by the device + /// and is closed by either. /// /// # Safety /// /// `context` must be a valid TBS context and must remain valid until this device is closed or /// dropped. The caller must synchronize any other use of the context. pub unsafe fn from_borrowed_context(context: *mut c_void) -> Result { - if context.is_null() { - return Err(TpmError::InvalidParameter); - } + // SAFETY: forwarded from this function's own contract. + let context = unsafe { TbsContext::borrowed(context) }?; Ok(Self { - context, - owns_context: false, + context: Some(context), result_buffer: [0; 4096], res_size: 0, tpm_info: TpmConnInfo::TpmTbsConn as u32, @@ -481,35 +359,18 @@ impl TpmTbsDevice { #[cfg(target_os = "windows")] impl TpmDevice for TpmTbsDevice { fn connect(&mut self) -> Result { - if !self.context.is_null() { + if self.context.is_some() { return Ok(true); // Already connected } - let mut params = TBS_CONTEXT_PARAMS2 { - version: TBS_CONTEXT_VERSION_TWO, - ..Default::default() - }; - params.Anonymous.Anonymous._bitfield = 4; - params.Anonymous.asUINT32 = 4; - - let context_ptr = &mut self.context as *mut *mut c_void; - let res = unsafe { - Tbsi_Context_Create( - ¶ms as *const TBS_CONTEXT_PARAMS2 as *const TBS_CONTEXT_PARAMS, - context_ptr, - ) - }; - - if res != TBS_SUCCESS { - return Err(TpmError::TbsError(format!( - "Failed to connect to TBS: {:?}", - res - ))); - } - self.owns_context = true; + // Held locally until the device is known to be usable: every early return below drops it, + // which closes the context. + let context = TbsContext::create()?; // Get device info to check if TPM 2.0 is available let mut info = TPM_DEVICE_INFO::default(); + // SAFETY: the size passed is the size of the very buffer being passed, `info` is live for + // the duration of the call, and TBS only writes to it. let res = unsafe { Tbsi_GetDeviceInfo( std::mem::size_of::() as u32, @@ -518,15 +379,15 @@ impl TpmDevice for TpmTbsDevice { }; if res != TBS_SUCCESS { - self.close(); return Err(TpmError::TbsError("Failed to get device info".to_string())); } else if info.tpmVersion != TPM_VERSION_20 { - self.close(); return Err(TpmError::TbsError( "Platform does not contain a TPM 2.0".to_string(), )); } + self.context = Some(context); + // Set appropriate flags self.tpm_info = TpmConnInfo::TpmTbsConn as u32; @@ -534,27 +395,30 @@ impl TpmDevice for TpmTbsDevice { } fn close(&mut self) { - if self.owns_context && !self.context.is_null() { - unsafe { Tbsip_Context_Close(self.context) }; - } - self.context = ptr::null_mut(); - self.owns_context = false; + // Dropping the context closes it, but only if this device owns it. + self.context = None; self.res_size = 0; self.tpm_info = 0; } fn dispatch_command(&mut self, cmd_buf: &[u8]) -> Result<(), TpmError> { - if self.context.is_null() { - return Err(TpmError::NotConnected); - } + // Copied out so that the rest of the method can borrow `self` mutably. + let context = match &self.context { + Some(context) => context.handle(), + None => return Err(TpmError::NotConnected), + }; // Reset result buffer size self.res_size = self.result_buffer.len() as u32; // Submit command to TBS + // SAFETY: `context` is a live TBS context (dropping the device or calling `close` clears + // `self.context`, so it cannot outlive its close). `result_buffer` and `res_size` are + // fields of `self`, borrowed mutably here and so not aliased, and `res_size` is set to the + // buffer's true length just above, which is what bounds what TBS writes. let res = unsafe { Tbsip_Submit_Command( - self.context, + context, TBS_COMMAND_LOCALITY_ZERO, TBS_COMMAND_PRIORITY_NORMAL, cmd_buf, @@ -578,14 +442,17 @@ impl TpmDevice for TpmTbsDevice { return Err(TpmError::NoResponse); } - let resp = self.result_buffer[0..self.res_size as usize].to_vec(); + // TBS wrote this length, and it is bounded by the buffer length handed to it, but the + // clamp costs nothing and keeps a wrong length from panicking here. + let res_size = (self.res_size as usize).min(self.result_buffer.len()); + let resp = self.result_buffer[0..res_size].to_vec(); self.res_size = 0; Ok(resp) } fn response_is_ready(&self) -> Result { - if self.context.is_null() { + if self.context.is_none() { return Err(TpmError::NotConnected); } @@ -612,6 +479,39 @@ mod windows_tests { use super::*; + /// A pointer that is never dereferenced: the tests below only ever check whether it is + /// carried around and whether a close was attempted on it. + fn fake_context() -> *mut c_void { + NonNull::::dangling().as_ptr() + } + + fn owned_device(context: *mut c_void) -> TpmTbsDevice { + TpmTbsDevice { + context: Some(TbsContext { + handle: context, + owned: true, + // The handle above is not a TBS context, so it must not reach TBS. This is the + // only place that substitutes anything for the real close. + close: tbs_close_log::record_close, + }), + result_buffer: [0; 4096], + res_size: 0, + tpm_info: TpmConnInfo::TpmTbsConn as u32, + } + } + + /// The substitution above is confined to contexts a test builds by hand: anything TBS itself + /// issued goes through a constructor, and a constructor always installs the real close. + #[test] + fn constructed_contexts_close_through_tbs() { + let context = unsafe { TbsContext::borrowed(fake_context()) }.unwrap(); + + assert!(std::ptr::fn_addr_eq( + context.close, + tbs_context_close as TbsCloseFn + )); + } + #[test] fn borrowed_context_rejects_null() { let result = unsafe { TpmTbsDevice::from_borrowed_context(ptr::null_mut()) }; @@ -620,11 +520,74 @@ mod windows_tests { #[test] fn borrowed_context_is_not_owned() { - let context = NonNull::::dangling().as_ptr(); + let context = fake_context(); let device = unsafe { TpmTbsDevice::from_borrowed_context(context) }.unwrap(); - assert_eq!(device.context, context); - assert!(!device.owns_context); + let held = device.context.as_ref().unwrap(); + assert_eq!(held.handle(), context); + assert!(!held.owned); + } + + #[test] + fn borrowed_context_is_not_closed_on_drop() { + let closes = tbs_close_log::count(); + + let device = unsafe { TpmTbsDevice::from_borrowed_context(fake_context()) }.unwrap(); + drop(device); + + assert_eq!(tbs_close_log::count(), closes); + } + + #[test] + fn borrowed_context_is_not_closed_by_close() { + let closes = tbs_close_log::count(); + + let mut device = unsafe { TpmTbsDevice::from_borrowed_context(fake_context()) }.unwrap(); + device.close(); + + assert_eq!(tbs_close_log::count(), closes); + assert!(device.context.is_none()); + assert_eq!(device.get_tpm_info(), 0); + } + + #[test] + fn owned_context_is_closed_on_drop() { + let closes = tbs_close_log::count(); + + let device = owned_device(fake_context()); + drop(device); + + assert_eq!(tbs_close_log::count(), closes + 1); + } + + #[test] + fn owned_context_is_closed_by_close() { + let closes = tbs_close_log::count(); + + let mut device = owned_device(fake_context()); + device.close(); + + assert_eq!(tbs_close_log::count(), closes + 1); + assert!(device.context.is_none()); + assert_eq!(device.get_tpm_info(), 0); + + // Dropping the already-closed device must not close a second time. + drop(device); + assert_eq!(tbs_close_log::count(), closes + 1); + } + + #[test] + fn disconnected_device_rejects_commands() { + let mut device = TpmTbsDevice::new(); + + assert!(matches!( + device.dispatch_command(&[0u8; 12]), + Err(TpmError::NotConnected) + )); + assert!(matches!( + device.response_is_ready(), + Err(TpmError::NotConnected) + )); } } @@ -636,6 +599,28 @@ pub struct TpmTbsDevice { tpm_info: u32, } +/// Upper bound on the size of a response frame accepted from a socket peer. +/// +/// The length prefix of a socket response is attacker-controlled, so it is checked against this +/// bound before it is used to size an allocation. The value is the reference implementation's +/// `MAX_RESPONSE_SIZE`, which is also the fixed buffer the `/dev/tpm*` path reads into. +#[cfg(target_os = "linux")] +const MAX_SOCKET_RESPONSE_SIZE: usize = + crate::tpm_types::Implementation::MAX_RESPONSE_SIZE.0 as usize; + +/// How long a single socket read or write may block before it is failed. +/// +/// Without this a wedged peer holds the calling thread forever. +#[cfg(target_os = "linux")] +const SOCKET_TIMEOUT: Duration = Duration::from_secs(5); + +#[cfg(target_os = "linux")] +impl Default for TpmTbsDevice { + fn default() -> Self { + Self::new() + } +} + #[cfg(target_os = "linux")] impl TpmTbsDevice { pub fn new() -> Self { @@ -662,8 +647,14 @@ impl TpmTbsDevice { } // Connect to user mode TRM - let mut socket = TcpStream::connect("127.0.0.1:2323") + let socket = TcpStream::connect("127.0.0.1:2323") .map_err(|e| TpmError::IoError(format!("Failed to connect to user TRM: {}", e)))?; + socket + .set_read_timeout(Some(SOCKET_TIMEOUT)) + .map_err(|e| TpmError::IoError(format!("Failed to set read timeout: {}", e)))?; + socket + .set_write_timeout(Some(SOCKET_TIMEOUT)) + .map_err(|e| TpmError::IoError(format!("Failed to set write timeout: {}", e)))?; // No handshake needed with user mode TRM @@ -684,41 +675,38 @@ impl TpmTbsDevice { #[cfg(target_os = "linux")] impl TpmDevice for TpmTbsDevice { fn connect(&mut self) -> Result { - if self.tpm_info != 0 { + // Connectedness is the presence of the handle commands travel over, which is the same + // test the Windows implementation makes on its TBS context. `tpm_info` describes a + // connection; it is not the connection itself. + if self.dev_tpm.is_some() || self.socket.is_some() { return Ok(true); // Already connected } // Try to open the direct TPM device - match OpenOptions::new().read(true).write(true).open("/dev/tpm0") { - Ok(file) => { - self.dev_tpm = Some(file); - self.tpm_info = TpmConnInfo::TpmTbsConn as u32 - | TpmConnInfo::TpmNoPowerCtl as u32 - | TpmConnInfo::TpmNoLocalityCtl as u32; - return Ok(true); - } - Err(_) => { - // Try TPM resource manager - match OpenOptions::new() - .read(true) - .write(true) - .open("/dev/tpmrm0") - { - Ok(file) => { - self.dev_tpm = Some(file); - self.tpm_info = TpmConnInfo::TpmTbsConn as u32 - | TpmConnInfo::TpmUsesTrm as u32 - | TpmConnInfo::TpmNoPowerCtl as u32 - | TpmConnInfo::TpmNoLocalityCtl as u32; - return Ok(true); - } - Err(_) => { - // Try user mode TRM - return self.connect_to_linux_user_mode_trm(); - } - } - } + if let Ok(file) = OpenOptions::new().read(true).write(true).open("/dev/tpm0") { + self.dev_tpm = Some(file); + self.tpm_info = TpmConnInfo::TpmTbsConn as u32 + | TpmConnInfo::TpmNoPowerCtl as u32 + | TpmConnInfo::TpmNoLocalityCtl as u32; + return Ok(true); } + + // Try TPM resource manager + if let Ok(file) = OpenOptions::new() + .read(true) + .write(true) + .open("/dev/tpmrm0") + { + self.dev_tpm = Some(file); + self.tpm_info = TpmConnInfo::TpmTbsConn as u32 + | TpmConnInfo::TpmUsesTrm as u32 + | TpmConnInfo::TpmNoPowerCtl as u32 + | TpmConnInfo::TpmNoLocalityCtl as u32; + return Ok(true); + } + + // Try user mode TRM + self.connect_to_linux_user_mode_trm() } fn close(&mut self) { @@ -786,6 +774,14 @@ impl TpmDevice for TpmTbsDevice { .map_err(|e| TpmError::IoError(e.to_string()))?; let len = u32::from_be_bytes(len_buf) as usize; + // The peer chooses this length, so refuse to allocate on its word alone. + if len > MAX_SOCKET_RESPONSE_SIZE { + return Err(TpmError::IoError(format!( + "TPM response of {} bytes exceeds the {} byte maximum", + len, MAX_SOCKET_RESPONSE_SIZE + ))); + } + // Read the response data let mut resp = vec![0u8; len]; socket @@ -853,173 +849,62 @@ impl TpmDevice for TpmTbsDevice { } } -// /// Socket utility module -// mod socket { -// use std::io; -// use std::net::TcpStream; -// use std::time::Duration; - -// #[cfg(unix)] -// pub fn select( -// read: &mut [TcpStream], -// write: &mut [TcpStream], -// except: &mut [TcpStream], -// timeout: Option<&Duration>, -// ) -> io::Result { -// use libc::{fd_set, select, timeval, FD_ISSET, FD_SET, FD_ZERO}; -// use std::os::unix::io::AsRawFd; - -// unsafe { -// let mut read_fds: fd_set = std::mem::zeroed(); -// let mut write_fds: fd_set = std::mem::zeroed(); -// let mut except_fds: fd_set = std::mem::zeroed(); - -// FD_ZERO(&mut read_fds); -// FD_ZERO(&mut write_fds); -// FD_ZERO(&mut except_fds); - -// let mut max_fd = 0; - -// for stream in read.iter() { -// let fd = stream.as_raw_fd(); -// FD_SET(fd, &mut read_fds); -// max_fd = std::cmp::max(max_fd, fd); -// } - -// for stream in write.iter() { -// let fd = stream.as_raw_fd(); -// FD_SET(fd, &mut write_fds); -// max_fd = std::cmp::max(max_fd, fd); -// } - -// for stream in except.iter() { -// let fd = stream.as_raw_fd(); -// FD_SET(fd, &mut except_fds); -// max_fd = std::cmp::max(max_fd, fd); -// } - -// let mut tv: timeval = std::mem::zeroed(); -// let tv_ptr = if let Some(timeout) = timeout { -// tv.tv_sec = timeout.as_secs() as _; -// tv.tv_usec = (timeout.subsec_micros()) as _; -// &mut tv as *mut timeval -// } else { -// std::ptr::null_mut() -// }; - -// let result = select( -// max_fd + 1, -// &mut read_fds, -// &mut write_fds, -// &mut except_fds, -// tv_ptr, -// ); - -// if result < 0 { -// return Err(io::Error::last_os_error()); -// } - -// // Count how many are ready -// let mut ready_count = 0; - -// for stream in read.iter() { -// if FD_ISSET(stream.as_raw_fd(), &read_fds) { -// ready_count += 1; -// } -// } - -// for stream in write.iter() { -// if FD_ISSET(stream.as_raw_fd(), &write_fds) { -// ready_count += 1; -// } -// } - -// for stream in except.iter() { -// if FD_ISSET(stream.as_raw_fd(), &except_fds) { -// ready_count += 1; -// } -// } - -// Ok(ready_count) -// } -// } - -// #[cfg(windows)] -// pub fn select( -// read: &mut [TcpStream], -// write: &mut [TcpStream], -// except: &mut [TcpStream], -// timeout: Option<&Duration>, -// ) -> io::Result { -// use std::os::windows::io::AsRawSocket; -// use windows::Win32::Networking::WinSock::{ -// fd_set, select, timeval, FD_ISSET, FD_SET, FD_ZERO, -// }; - -// unsafe { -// let mut read_fds: fd_set = std::mem::zeroed(); -// let mut write_fds: fd_set = std::mem::zeroed(); -// let mut except_fds: fd_set = std::mem::zeroed(); - -// FD_ZERO(&mut read_fds); -// FD_ZERO(&mut write_fds); -// FD_ZERO(&mut except_fds); - -// for stream in read.iter() { -// FD_SET(stream.as_raw_socket(), &mut read_fds); -// } - -// for stream in write.iter() { -// FD_SET(stream.as_raw_socket(), &mut write_fds); -// } - -// for stream in except.iter() { -// FD_SET(stream.as_raw_socket(), &mut except_fds); -// } - -// let mut tv: timeval = std::mem::zeroed(); -// let tv_ptr = if let Some(timeout) = timeout { -// tv.tv_sec = timeout.as_secs() as i32; -// tv.tv_usec = (timeout.subsec_micros()) as i32; -// &mut tv as *mut timeval -// } else { -// std::ptr::null_mut() -// }; - -// let result = select( -// 0, // ignored on Windows -// &mut read_fds, -// &mut write_fds, -// &mut except_fds, -// tv_ptr, -// ); - -// if result == -1 { -// return Err(io::Error::last_os_error()); -// } - -// // Count how many are ready -// let mut ready_count = 0; - -// for stream in read.iter() { -// if FD_ISSET(stream.as_raw_socket(), &read_fds) { -// ready_count += 1; -// } -// } - -// for stream in write.iter() { -// if FD_ISSET(stream.as_raw_socket(), &write_fds) { -// ready_count += 1; -// } -// } - -// for stream in except.iter() { -// if FD_ISSET(stream.as_raw_socket(), &except_fds) { -// ready_count += 1; -// } -// } - -// Ok(ready_count as usize) -// } -// } -// } +// Placeholder implementation for platforms with no system TPM interface of their own. +// +// Windows reaches its TPM through TBS and Linux through `/dev/tpm*` or a user-mode resource +// manager; nothing equivalent is implemented for macOS or the BSDs. Rather than leave the crate +// without a `TpmTbsDevice` there - which fails to build with an error that points at the wrong +// place - the type exists everywhere and reports the platform as unsupported at run time. Callers +// on such a platform can still drive a TPM by passing their own [`TpmDevice`] to `Tpm2::new`. +#[cfg(not(any(target_os = "windows", target_os = "linux")))] +pub struct TpmTbsDevice; + +#[cfg(not(any(target_os = "windows", target_os = "linux")))] +impl Default for TpmTbsDevice { + fn default() -> Self { + Self::new() + } +} + +#[cfg(not(any(target_os = "windows", target_os = "linux")))] +impl TpmTbsDevice { + pub fn new() -> Self { + TpmTbsDevice + } + + fn unsupported(operation: &str) -> Result { + Err(TpmError::NotSupported(format!( + "{}: this platform has no built-in TPM device; supply a TpmDevice implementation", + operation + ))) + } +} + +#[cfg(not(any(target_os = "windows", target_os = "linux")))] +impl TpmDevice for TpmTbsDevice { + fn connect(&mut self) -> Result { + Self::unsupported("connect") + } + + fn close(&mut self) {} + + fn dispatch_command(&mut self, _cmd_buf: &[u8]) -> Result<(), TpmError> { + Self::unsupported("dispatch_command") + } + + fn get_response(&mut self) -> Result, TpmError> { + Self::unsupported("get_response") + } + + fn response_is_ready(&self) -> Result { + Self::unsupported("response_is_ready") + } + + fn has_flag(&self, _flag: u32) -> bool { + false + } + + fn get_tpm_info(&self) -> u32 { + 0 + } +} diff --git a/TSS.Rust/src/error.rs b/TSS.Rust/src/error.rs index e6937144..2f67bbd2 100644 --- a/TSS.Rust/src/error.rs +++ b/TSS.Rust/src/error.rs @@ -39,6 +39,9 @@ pub enum TpmError { /// Operation not supported NotSupported(String), + /// A cryptographic or structural check on attacker-reachable data did not pass + VerificationFailed(String), + /// TPM device not connected NotConnected, @@ -86,6 +89,7 @@ impl fmt::Display for TpmError { Self::DeviceError(msg) => write!(f, "Device error: {}", msg), Self::GenericError(msg) => write!(f, "TPM error: {}", msg), Self::NotSupported(operation) => write!(f, "Operation not supported: {}", operation), + Self::VerificationFailed(reason) => write!(f, "Verification failed: {}", reason), Self::NotConnected => write!(f, "TPM device not connected"), Self::BadEndTag => write!(f, "Bad end tag received from TPM"), Self::CommandFailed => write!(f, "TPM command failed"), diff --git a/TSS.Rust/src/policy.rs b/TSS.Rust/src/policy.rs index 5becfd2b..a6b0c418 100644 --- a/TSS.Rust/src/policy.rs +++ b/TSS.Rust/src/policy.rs @@ -40,8 +40,66 @@ pub trait PolicyAssertion { // Helper: PolicyUpdate - shared digest update logic per TPM spec // --------------------------------------------------------------------------- +/// One `TPM_HASH::Extend`: `policyDigest = H(policyDigest || data)`. +fn policy_extend( + crypto: &CryptoProvider, + hash_alg: TPM_ALG_ID, + accumulator: &mut Vec, + data: &[u8], +) -> Result<(), TpmError> { + let mut buf = Vec::with_capacity(accumulator.len() + data.len()); + buf.extend_from_slice(accumulator); + buf.extend_from_slice(data); + *accumulator = Crypto::hash(crypto, hash_alg, &buf)?; + Ok(()) +} + +/// A **single-extend** policy digest update: `policyDigest = H(policyDigest || commandCode || arg2)`. +/// +/// This — not [`policy_update`] — is the shape of *most* policy assertions. In +/// `TSS.CPP/Src/TpmPolicy.cpp` these are the `UpdatePolicyDigest` bodies that build a +/// `TpmBuffer` and end in exactly one `accumulator.Extend(buf.trim())`; in +/// `TSS.NET/TSS.Net/PolicyAces.cs` they are the ones ending in a single `.Extend(...)`, of +/// which this function is the direct analogue of `PolicyAce.PolicyUpdate1`. +/// +/// Assertions that use this shape: `TPM2_PolicyCommandCode`, `TPM2_PolicyPCR`, +/// `TPM2_PolicyAuthValue`, `TPM2_PolicyPassword`, `TPM2_PolicyCpHash`, +/// `TPM2_PolicyNameHash`, `TPM2_PolicyCounterTimer`, `TPM2_PolicyLocality`, +/// `TPM2_PolicyDuplicationSelect`, `TPM2_PolicyNV` and `TPM2_PolicyOR` (the last two after a +/// reset of the accumulator). +/// +/// Routing one of these through [`policy_update`] instead adds a second extend over an empty +/// `arg3` and produces a digest no policy session can ever satisfy. +fn policy_update1( + crypto: &CryptoProvider, + hash_alg: TPM_ALG_ID, + accumulator: &mut Vec, + command_code: TPM_CC, + arg2: &[u8], +) -> Result<(), TpmError> { + let mut buf = Vec::with_capacity(4 + arg2.len()); + buf.extend_from_slice(&command_code.get_value().to_be_bytes()); + buf.extend_from_slice(arg2); + policy_extend(crypto, hash_alg, accumulator, &buf) +} + +/// The TPM 2.0 `PolicyUpdate()` function (Part 1, "Policy Digest Update Function"). +/// /// `policyDigest = H(policyDigest || commandCode || arg2)` /// Then: `policyDigest = H(policyDigest || arg3)` +/// +/// Both extends are unconditional. The second one is *not* skipped when `arg3` is empty: an +/// empty `policyRef` is the common case for `TPM2_PolicySigned`, `TPM2_PolicySecret` and +/// `TPM2_PolicyAuthorize`, and the TPM still performs the extend for it, producing +/// `H(policyDigest)` rather than leaving the digest alone. Skipping it yields a digest no +/// policy session can ever satisfy. `TSS.CPP/Src/TpmPolicy.cpp` (`PABase::PolicyUpdate`) and +/// `TSS.NET/TSS.Net/PolicyAces.cs` (`PolicyAce.PolicyUpdate`) both extend unconditionally. +/// +/// **Only four assertions are built on this function**, and they are exactly the four whose +/// `UpdatePolicyDigest` in `TSS.CPP/Src/TpmPolicy.cpp` calls `PABase::PolicyUpdate`: +/// `TPM2_PolicySigned`, `TPM2_PolicySecret`, `TPM2_PolicyAuthorize` (after a reset) and +/// `TPM2_PolicyTicket` (not implemented here). Every other assertion is a single extend — +/// use [`policy_update1`]. fn policy_update( crypto: &CryptoProvider, hash_alg: TPM_ALG_ID, @@ -50,21 +108,8 @@ fn policy_update( arg2: &[u8], arg3: &[u8], ) -> Result<(), TpmError> { - // First extend: H(accumulator || CC || arg2) - let mut buf = Vec::new(); - buf.extend_from_slice(accumulator); - buf.extend_from_slice(&command_code.get_value().to_be_bytes()); - buf.extend_from_slice(arg2); - *accumulator = Crypto::hash(crypto, hash_alg, &buf)?; - - // Second extend (if arg3 is non-empty): H(accumulator || arg3) - if !arg3.is_empty() { - let mut buf2 = Vec::new(); - buf2.extend_from_slice(accumulator); - buf2.extend_from_slice(arg3); - *accumulator = Crypto::hash(crypto, hash_alg, &buf2)?; - } - Ok(()) + policy_update1(crypto, hash_alg, accumulator, command_code, arg2)?; + policy_extend(crypto, hash_alg, accumulator, arg3) } /// Helper to get session handle from a Session @@ -72,6 +117,36 @@ fn sess_handle(s: &Session) -> TPM_HANDLE { s.sess_in.sessionHandle.clone() } +/// The policy session as it stands after an assertion's command, which is emphatically **not** +/// `Tpm2::last_session()`. +/// +/// A `TPM2_PolicyXXX` command takes the policy session as an ordinary *handle parameter*; it never +/// appears in the command's authorization area, so nothing about it comes back in +/// `completed_sessions`. What does come back is whatever authorized the command — and +/// `dispatch_command` manufactures a PWAP session for every auth handle a command declares. +/// `TPM2_PolicySecret` and `TPM2_PolicyNV` each declare one (`authHandle`), so +/// `last_session()` there is a password session on `TPM_RS_PW`. Returning it as "the updated +/// policy session" made [`PolicyTree::execute`] address `TPM_RS_PW` as the `policySession` of +/// every later assertion and hand the caller a password session at the end: the caller then +/// authorized with a password while believing a policy had been enforced. That fails closed +/// against an object with a real authValue, but succeeds — silently, and with no policy +/// evaluated — against one with `userWithAuth` set and an empty authValue. +/// +/// So match on the handle: a session that genuinely was in the authorization area comes back with +/// its rolled nonce and is returned, and anything else leaves the caller's session untouched, +/// which is what the TPM did to it. +fn updated_policy_session(tpm: &Tpm2, session: &Session) -> Session { + let policy_handle = session.sess_in.sessionHandle.handle; + tpm.last_sessions() + .and_then(|completed| { + completed + .iter() + .find(|s| s.sess_in.sessionHandle.handle == policy_handle) + .cloned() + }) + .unwrap_or_else(|| session.clone()) +} + // --------------------------------------------------------------------------- // PolicyTree // --------------------------------------------------------------------------- @@ -90,7 +165,9 @@ impl Default for PolicyTree { impl PolicyTree { /// Create an empty policy tree. pub fn new() -> Self { - Self { assertions: Vec::new() } + Self { + assertions: Vec::new(), + } } /// Add a policy assertion to the tree. Assertions execute in order (first added = first executed). @@ -157,14 +234,17 @@ impl PolicyAssertion for PolicyCommandCode { hash_alg: TPM_ALG_ID, acc: &mut Vec, ) -> Result<(), TpmError> { + // `PolicyCommandCode::UpdatePolicyDigest` (TpmPolicy.cpp:333) is a *single* extend: + // H(policyDigest || TPM_CC_PolicyCommandCode || commandCode) + // It does not go through `PABase::PolicyUpdate`. let mut buf = Vec::new(); buf.extend_from_slice(&self.command_code.get_value().to_be_bytes()); - policy_update(crypto, hash_alg, acc, TPM_CC::PolicyCommandCode, &buf, &[]) + policy_update1(crypto, hash_alg, acc, TPM_CC::PolicyCommandCode, &buf) } fn execute(&self, tpm: &mut Tpm2, session: &Session) -> Result { tpm.PolicyCommandCode(&sess_handle(session), self.command_code)?; - Ok(tpm.last_session().unwrap_or_else(|| session.clone())) + Ok(updated_policy_session(tpm, session)) } } @@ -186,18 +266,21 @@ impl PolicyAssertion for PolicyLocality { hash_alg: TPM_ALG_ID, acc: &mut Vec, ) -> Result<(), TpmError> { - // PolicyLocality: H(acc || TPM_CC_PolicyLocality || locality_byte) - let mut buf = Vec::new(); - buf.extend_from_slice(acc); - buf.extend_from_slice(&TPM_CC::PolicyLocality.get_value().to_be_bytes()); - buf.push(self.locality.get_value()); - *acc = Crypto::hash(crypto, hash_alg, &buf)?; - Ok(()) + // `PolicyLocality::UpdatePolicyDigest` (TpmPolicy.cpp:239) is a single extend: + // H(policyDigest || TPM_CC_PolicyLocality || locality) + // `TPMA_LOCALITY` is one byte on the wire. + policy_update1( + crypto, + hash_alg, + acc, + TPM_CC::PolicyLocality, + &[self.locality.get_value()], + ) } fn execute(&self, tpm: &mut Tpm2, session: &Session) -> Result { tpm.PolicyLocality(&sess_handle(session), self.locality)?; - Ok(tpm.last_session().unwrap_or_else(|| session.clone())) + Ok(updated_policy_session(tpm, session)) } } @@ -209,7 +292,37 @@ pub struct PolicyPcr { impl PolicyPcr { pub fn new(pcr_values: Vec, pcr_selections: Vec) -> Self { - Self { pcr_values, pcr_selections } + Self { + pcr_values, + pcr_selections, + } + } + + /// The `pcrDigest` this assertion asserts: `H(pcrValue[0] || pcrValue[1] || ...)`. + /// + /// This is the value that goes into the policy digest *and* the value sent as the + /// `pcrDigest` argument of `TPM2_PolicyPCR`; the two must be the same digest or the session + /// cannot satisfy the policy. It mirrors `Helpers::HashPcrs` in + /// `TSS.CPP/Src/TpmHelpers.cpp` and `PcrValueCollection.GetSelectionHash` in TSS.NET. + /// + /// An empty `pcr_values` is rejected rather than hashed. The TPM treats an *empty* + /// `pcrDigest` as "do not compare the PCRs at all", so a caller that supplied no expected + /// values has almost certainly made a mistake, and quietly turning that into a digest over + /// no data would hide it. + pub fn pcr_digest( + &self, + crypto: &CryptoProvider, + hash_alg: TPM_ALG_ID, + ) -> Result, TpmError> { + if self.pcr_values.is_empty() { + return Err(TpmError::InvalidParameter); + } + + let mut pcr_data = Vec::new(); + for v in &self.pcr_values { + pcr_data.extend_from_slice(&v.buffer); + } + Crypto::hash(crypto, hash_alg, &pcr_data) } } @@ -220,12 +333,7 @@ impl PolicyAssertion for PolicyPcr { hash_alg: TPM_ALG_ID, acc: &mut Vec, ) -> Result<(), TpmError> { - // Concatenate all PCR values and hash them - let mut pcr_data = Vec::new(); - for v in &self.pcr_values { - pcr_data.extend_from_slice(&v.buffer); - } - let pcr_digest = Crypto::hash(crypto, hash_alg, &pcr_data)?; + let pcr_digest = self.pcr_digest(crypto, hash_alg)?; // Marshal PCR selections let mut sel_buf = TpmBuffer::new(None); @@ -237,12 +345,20 @@ impl PolicyAssertion for PolicyPcr { let mut arg2 = Vec::new(); arg2.extend_from_slice(sel_buf.trim()); arg2.extend_from_slice(&pcr_digest); - policy_update(crypto, hash_alg, acc, TPM_CC::PolicyPCR, &arg2, &[]) + // `PolicyPcr::UpdatePolicyDigest` (TpmPolicy.cpp:312) is a *single* extend: + // H(policyDigest || TPM_CC_PolicyPCR || count || selections || pcrDigest) + // It does not go through `PABase::PolicyUpdate`. + policy_update1(crypto, hash_alg, acc, TPM_CC::PolicyPCR, &arg2) } fn execute(&self, tpm: &mut Tpm2, session: &Session) -> Result { - tpm.PolicyPCR(&sess_handle(session), &self.pcr_values[0].buffer, &self.pcr_selections)?; - Ok(tpm.last_session().unwrap_or_else(|| session.clone())) + // The same digest that went into the policy digest, not the first raw PCR value. + // `pcr_digest` also rejects an empty `pcr_values`, which both keeps this off the + // panicking `self.pcr_values[0]` path and makes it impossible to send the empty + // `pcrDigest` that tells the TPM to skip the PCR comparison entirely. + let pcr_digest = self.pcr_digest(tpm.crypto(), session.get_hash_alg())?; + tpm.PolicyPCR(&sess_handle(session), &pcr_digest, &self.pcr_selections)?; + Ok(updated_policy_session(tpm, session)) } } @@ -256,7 +372,9 @@ impl Default for PolicyPassword { } impl PolicyPassword { - pub fn new() -> Self { Self } + pub fn new() -> Self { + Self + } } impl PolicyAssertion for PolicyPassword { @@ -266,14 +384,20 @@ impl PolicyAssertion for PolicyPassword { hash_alg: TPM_ALG_ID, acc: &mut Vec, ) -> Result<(), TpmError> { - // PolicyPassword uses the same digest as PolicyAuthValue per spec - policy_update(crypto, hash_alg, acc, TPM_CC::PolicyAuthValue, &[], &[]) + // `PolicyPassword::UpdatePolicyDigest` (TpmPolicy.cpp:425) is a single extend of the + // *PolicyAuthValue* command code and nothing else — identical to PolicyAuthValue, so + // that a policy can be satisfied either way. No `PABase::PolicyUpdate`. + policy_update1(crypto, hash_alg, acc, TPM_CC::PolicyAuthValue, &[]) } fn execute(&self, tpm: &mut Tpm2, session: &Session) -> Result { tpm.PolicyPassword(&sess_handle(session))?; - let mut sess = tpm.last_session().unwrap_or_else(|| session.clone()); + let mut sess = updated_policy_session(tpm, session); + // TPM2_PolicyPassword SETs isPasswordNeeded and CLEARs isAuthValueNeeded; mirror both, + // because the two flags select different authorization encodings and the TPM will only + // honour the one it last recorded. sess.needs_password = true; + sess.needs_hmac = false; Ok(sess) } } @@ -288,7 +412,9 @@ impl Default for PolicyAuthValue { } impl PolicyAuthValue { - pub fn new() -> Self { Self } + pub fn new() -> Self { + Self + } } impl PolicyAssertion for PolicyAuthValue { @@ -298,13 +424,18 @@ impl PolicyAssertion for PolicyAuthValue { hash_alg: TPM_ALG_ID, acc: &mut Vec, ) -> Result<(), TpmError> { - policy_update(crypto, hash_alg, acc, TPM_CC::PolicyAuthValue, &[], &[]) + // `PolicyAuthValue::UpdatePolicyDigest` (TpmPolicy.cpp:411) is the whole function: + // accumulator.Extend(Int32ToTpm(TPM_CC::PolicyAuthValue)); + // A single extend of the command code, with no second extend. + policy_update1(crypto, hash_alg, acc, TPM_CC::PolicyAuthValue, &[]) } fn execute(&self, tpm: &mut Tpm2, session: &Session) -> Result { tpm.PolicyAuthValue(&sess_handle(session))?; - let mut sess = tpm.last_session().unwrap_or_else(|| session.clone()); + let mut sess = updated_policy_session(tpm, session); + // TPM2_PolicyAuthValue SETs isAuthValueNeeded and CLEARs isPasswordNeeded. sess.needs_hmac = true; + sess.needs_password = false; Ok(sess) } } @@ -327,12 +458,14 @@ impl PolicyAssertion for PolicyCpHash { hash_alg: TPM_ALG_ID, acc: &mut Vec, ) -> Result<(), TpmError> { - policy_update(crypto, hash_alg, acc, TPM_CC::PolicyCpHash, &self.cp_hash, &[]) + // `PolicyCpHash::UpdatePolicyDigest` (TpmPolicy.cpp:349) is a single extend: + // H(policyDigest || TPM_CC_PolicyCpHash || cpHashA) + policy_update1(crypto, hash_alg, acc, TPM_CC::PolicyCpHash, &self.cp_hash) } fn execute(&self, tpm: &mut Tpm2, session: &Session) -> Result { tpm.PolicyCpHash(&sess_handle(session), &self.cp_hash)?; - Ok(tpm.last_session().unwrap_or_else(|| session.clone())) + Ok(updated_policy_session(tpm, session)) } } @@ -354,12 +487,20 @@ impl PolicyAssertion for PolicyNameHash { hash_alg: TPM_ALG_ID, acc: &mut Vec, ) -> Result<(), TpmError> { - policy_update(crypto, hash_alg, acc, TPM_CC::PolicyNameHash, &self.name_hash, &[]) + // `PolicyNameHash::UpdatePolicyDigest` (TpmPolicy.cpp:395) is a single extend: + // H(policyDigest || TPM_CC_PolicyNameHash || nameHash) + policy_update1( + crypto, + hash_alg, + acc, + TPM_CC::PolicyNameHash, + &self.name_hash, + ) } fn execute(&self, tpm: &mut Tpm2, session: &Session) -> Result { tpm.PolicyNameHash(&sess_handle(session), &self.name_hash)?; - Ok(tpm.last_session().unwrap_or_else(|| session.clone())) + Ok(updated_policy_session(tpm, session)) } } @@ -372,12 +513,20 @@ pub struct PolicyCounterTimer { impl PolicyCounterTimer { pub fn new(operand_b: Vec, offset: u16, operation: TPM_EO) -> Self { - Self { operand_b, offset, operation } + Self { + operand_b, + offset, + operation, + } } /// Convenience: create from a u64 value (marshalled as 8 big-endian bytes). pub fn from_u64(value: u64, offset: u16, operation: TPM_EO) -> Self { - Self { operand_b: value.to_be_bytes().to_vec(), offset, operation } + Self { + operand_b: value.to_be_bytes().to_vec(), + offset, + operation, + } } } @@ -394,14 +543,19 @@ impl PolicyAssertion for PolicyCounterTimer { inner.extend_from_slice(&self.offset.to_be_bytes()); inner.extend_from_slice(&self.operation.get_value().to_be_bytes()); let arg_hash = Crypto::hash(crypto, hash_alg, &inner)?; - policy_update(crypto, hash_alg, acc, TPM_CC::PolicyCounterTimer, &arg_hash, &[]) + // `PolicyCounterTimer::UpdatePolicyDigest` (TpmPolicy.cpp:379) is a single extend: + // H(policyDigest || TPM_CC_PolicyCounterTimer || H(operandB || offset || operation)) + policy_update1(crypto, hash_alg, acc, TPM_CC::PolicyCounterTimer, &arg_hash) } fn execute(&self, tpm: &mut Tpm2, session: &Session) -> Result { tpm.PolicyCounterTimer( - &sess_handle(session), &self.operand_b, self.offset, self.operation, + &sess_handle(session), + &self.operand_b, + self.offset, + self.operation, )?; - Ok(tpm.last_session().unwrap_or_else(|| session.clone())) + Ok(updated_policy_session(tpm, session)) } } @@ -436,7 +590,16 @@ impl PolicyAssertion for PolicySecret { hash_alg: TPM_ALG_ID, acc: &mut Vec, ) -> Result<(), TpmError> { - policy_update(crypto, hash_alg, acc, TPM_CC::PolicySecret, &self.auth_object_name, &self.policy_ref) + // `PolicySecret` is one of the assertions genuinely built on `PABase::PolicyUpdate` + // (TpmPolicy.cpp:226) — two extends, the second over `policyRef`. + policy_update( + crypto, + hash_alg, + acc, + TPM_CC::PolicySecret, + &self.auth_object_name, + &self.policy_ref, + ) } fn execute(&self, tpm: &mut Tpm2, session: &Session) -> Result { @@ -446,10 +609,16 @@ impl PolicyAssertion for PolicySecret { vec![] }; tpm.PolicySecret( - &self.auth_handle, &sess_handle(session), - &nonce_tpm, &self.cp_hash_a, &self.policy_ref, self.expiration, + &self.auth_handle, + &sess_handle(session), + &nonce_tpm, + &self.cp_hash_a, + &self.policy_ref, + self.expiration, )?; - Ok(tpm.last_session().unwrap_or_else(|| session.clone())) + // `TPM2_PolicySecret` declares one auth handle, so the session the client just used is a + // PWAP session for `authHandle`, not this policy session. See `updated_policy_session`. + Ok(updated_policy_session(tpm, session)) } } @@ -496,7 +665,16 @@ impl PolicyAssertion for PolicySigned { acc: &mut Vec, ) -> Result<(), TpmError> { let key_name = self.public_key.get_name(crypto)?; - policy_update(crypto, hash_alg, acc, TPM_CC::PolicySigned, &key_name, &self.policy_ref) + // `PolicySigned::UpdatePolicyDigest` (TpmPolicy.cpp:462) calls `PABase::PolicyUpdate`, + // so this is genuinely a two-extend assertion. + policy_update( + crypto, + hash_alg, + acc, + TPM_CC::PolicySigned, + &key_name, + &self.policy_ref, + ) } fn execute(&self, tpm: &mut Tpm2, session: &Session) -> Result { @@ -509,15 +687,16 @@ impl PolicyAssertion for PolicySigned { }; // Determine hash alg from the key's scheme - let hash_alg = if let Some(TPMU_PUBLIC_PARMS::rsaDetail(ref params)) = self.public_key.parameters { - if let Some(TPMU_ASYM_SCHEME::rsassa(ref scheme)) = params.scheme { - scheme.hashAlg + let hash_alg = + if let Some(TPMU_PUBLIC_PARMS::rsaDetail(ref params)) = self.public_key.parameters { + if let Some(TPMU_ASYM_SCHEME::rsassa(ref scheme)) = params.scheme { + scheme.hashAlg + } else { + self.public_key.nameAlg + } } else { self.public_key.nameAlg - } - } else { - self.public_key.nameAlg - }; + }; // Compute aHash = Hash(nonceTPM || expiration || cpHashA || policyRef) let mut to_hash = Vec::new(); @@ -528,7 +707,9 @@ impl PolicyAssertion for PolicySigned { let a_hash = Crypto::hash(&crypto, hash_alg, &to_hash)?; let sw_key = self.sw_key.as_ref().ok_or_else(|| { - TpmError::GenericError("PolicySigned: no SW key set (callbacks not yet supported)".into()) + TpmError::GenericError( + "PolicySigned: no SW key set (callbacks not yet supported)".into(), + ) })?; let signature = sw_key.sign(&crypto, &a_hash, hash_alg)?; @@ -540,14 +721,18 @@ impl PolicyAssertion for PolicySigned { )?; let result = tpm.PolicySigned( - &pub_key_handle, &sess_handle(session), - &nonce_tpm, &self.cp_hash_a, &self.policy_ref, self.expiration, + &pub_key_handle, + &sess_handle(session), + &nonce_tpm, + &self.cp_hash_a, + &self.policy_ref, + self.expiration, &signature.signature, ); tpm.FlushContext(&pub_key_handle)?; result?; - Ok(tpm.last_session().unwrap_or_else(|| session.clone())) + Ok(updated_policy_session(tpm, session)) } } @@ -570,7 +755,14 @@ impl PolicyNv { offset: u16, operation: TPM_EO, ) -> Self { - Self { operand_b, offset, operation, nv_index_name, auth_handle, nv_index } + Self { + operand_b, + offset, + operation, + nv_index_name, + auth_handle, + nv_index, + } } } @@ -581,21 +773,39 @@ impl PolicyAssertion for PolicyNv { hash_alg: TPM_ALG_ID, acc: &mut Vec, ) -> Result<(), TpmError> { - // arg2 = H(operandB || offset || operation) + // `PolicyNV::UpdatePolicyDigest` (TpmPolicy.cpp:439) is a single extend, with the + // Name folded into the same extend rather than into a second one: + // + // policyDigest := H(policyDigest || TPM_CC_PolicyNV || args || nvIndex.Name) + // where args = H(operandB || offset || operation) + // + // Delegating to `policy_update` with the Name as `arg3` would produce two extends and + // a digest no session can satisfy. `TpmPolicyNV.GetPolicyDigest` in + // `TSS.NET/TSS.Net/PolicyAces.cs` extends once as well. let mut inner = Vec::new(); inner.extend_from_slice(&self.operand_b); inner.extend_from_slice(&self.offset.to_be_bytes()); inner.extend_from_slice(&self.operation.get_value().to_be_bytes()); let args_hash = Crypto::hash(crypto, hash_alg, &inner)?; - policy_update(crypto, hash_alg, acc, TPM_CC::PolicyNV, &args_hash, &self.nv_index_name) + + let mut arg2 = Vec::new(); + arg2.extend_from_slice(&args_hash); + arg2.extend_from_slice(&self.nv_index_name); + policy_update1(crypto, hash_alg, acc, TPM_CC::PolicyNV, &arg2) } fn execute(&self, tpm: &mut Tpm2, session: &Session) -> Result { tpm.PolicyNV( - &self.auth_handle, &self.nv_index, &sess_handle(session), - &self.operand_b, self.offset, self.operation, + &self.auth_handle, + &self.nv_index, + &sess_handle(session), + &self.operand_b, + self.offset, + self.operation, )?; - Ok(tpm.last_session().unwrap_or_else(|| session.clone())) + // As for `PolicySecret`: `TPM2_PolicyNV` declares one auth handle, so what authorized the + // command was a PWAP session for `authHandle`. See `updated_policy_session`. + Ok(updated_policy_session(tpm, session)) } } @@ -612,9 +822,7 @@ impl PolicyOr { /// Convenience: create a two-branch PolicyOR from PolicyTrees. pub fn from_trees(trees: Vec) -> Self { - let branches = trees.into_iter() - .map(|t| t.assertions) - .collect(); + let branches = trees.into_iter().map(|t| t.assertions).collect(); Self { branches } } } @@ -626,17 +834,18 @@ impl PolicyAssertion for PolicyOr { hash_alg: TPM_ALG_ID, acc: &mut Vec, ) -> Result<(), TpmError> { - // PolicyOR: accumulator = H(0...0 || TPM_CC_PolicyOR || digest1 || digest2 || ...) + // `PolicyOr::UpdatePolicyDigest` (TpmPolicy.cpp:268) resets the accumulator and then + // performs a single extend: + // policyDigest := 0...0 + // policyDigest := H(policyDigest || TPM_CC_PolicyOR || digest1 || digest2 || ...) let hash_len = Crypto::digest_size_checked(hash_alg)?; - let mut buf = Vec::new(); - buf.extend_from_slice(&vec![0u8; hash_len]); // reset to zero - buf.extend_from_slice(&TPM_CC::PolicyOR.get_value().to_be_bytes()); + let mut arg2 = Vec::new(); for branch in &self.branches { let branch_digest = compute_digest(crypto, branch, hash_alg)?; - buf.extend_from_slice(&branch_digest); + arg2.extend_from_slice(&branch_digest); } - *acc = Crypto::hash(crypto, hash_alg, &buf)?; - Ok(()) + *acc = vec![0u8; hash_len]; + policy_update1(crypto, hash_alg, acc, TPM_CC::PolicyOR, &arg2) } fn execute(&self, tpm: &mut Tpm2, session: &Session) -> Result { @@ -649,7 +858,7 @@ impl PolicyAssertion for PolicyOr { hash_list.push(TPM2B_DIGEST { buffer: digest }); } tpm.PolicyOR(&sess_handle(session), &hash_list)?; - Ok(tpm.last_session().unwrap_or_else(|| session.clone())) + Ok(updated_policy_session(tpm, session)) } } @@ -668,7 +877,12 @@ impl PolicyAuthorize { authorizing_key: TPMT_PUBLIC, signature: TPMT_SIGNATURE, ) -> Self { - Self { approved_policy, policy_ref, authorizing_key, signature } + Self { + approved_policy, + policy_ref, + authorizing_key, + signature, + } } } @@ -680,10 +894,18 @@ impl PolicyAssertion for PolicyAuthorize { acc: &mut Vec, ) -> Result<(), TpmError> { let key_name = self.authorizing_key.get_name(crypto)?; - // PolicyAuthorize resets the digest, then does PolicyUpdate + // `PolicyAuthorize::UpdatePolicyDigest` (TpmPolicy.cpp:509) resets the accumulator and + // then calls `PABase::PolicyUpdate`, so this is a reset plus two extends. let hash_len = Crypto::digest_size_checked(hash_alg)?; *acc = vec![0u8; hash_len]; - policy_update(crypto, hash_alg, acc, TPM_CC::PolicyAuthorize, &key_name, &self.policy_ref) + policy_update( + crypto, + hash_alg, + acc, + TPM_CC::PolicyAuthorize, + &key_name, + &self.policy_ref, + ) } fn execute(&self, tpm: &mut Tpm2, session: &Session) -> Result { @@ -704,9 +926,7 @@ impl PolicyAssertion for PolicyAuthorize { a_hash_data.extend_from_slice(&self.policy_ref); let a_hash = Crypto::hash(&crypto, self.authorizing_key.nameAlg, &a_hash_data)?; - let check_ticket = tpm.VerifySignature( - &key_handle, &a_hash, &self.signature.signature, - )?; + let check_ticket = tpm.VerifySignature(&key_handle, &a_hash, &self.signature.signature)?; let result = tpm.PolicyAuthorize( &sess_handle(session), @@ -718,7 +938,7 @@ impl PolicyAssertion for PolicyAuthorize { tpm.FlushContext(&key_handle)?; result?; - Ok(tpm.last_session().unwrap_or_else(|| session.clone())) + Ok(updated_policy_session(tpm, session)) } } @@ -731,7 +951,11 @@ pub struct PolicyDuplicationSelect { impl PolicyDuplicationSelect { pub fn new(object_name: Vec, new_parent_name: Vec, include_object: bool) -> Self { - Self { object_name, new_parent_name, include_object } + Self { + object_name, + new_parent_name, + include_object, + } } } @@ -748,7 +972,16 @@ impl PolicyAssertion for PolicyDuplicationSelect { } arg2.extend_from_slice(&self.new_parent_name); arg2.push(if self.include_object { 1 } else { 0 }); - policy_update(crypto, hash_alg, acc, TPM_CC::PolicyDuplicationSelect, &arg2, &[]) + // `PolicyDuplicationSelect::UpdatePolicyDigest` (TpmPolicy.cpp:565) is a single extend: + // H(policyDigest || TPM_CC_PolicyDuplicationSelect + // || [objectName] || newParentName || includeObject) + policy_update1( + crypto, + hash_alg, + acc, + TPM_CC::PolicyDuplicationSelect, + &arg2, + ) } fn execute(&self, tpm: &mut Tpm2, session: &Session) -> Result { @@ -758,6 +991,750 @@ impl PolicyAssertion for PolicyDuplicationSelect { &self.new_parent_name, if self.include_object { 1 } else { 0 }, )?; - Ok(tpm.last_session().unwrap_or_else(|| session.clone())) + Ok(updated_policy_session(tpm, session)) + } +} + +#[cfg(all(test, feature = "software-crypto"))] +mod tests { + use super::*; + use crate::crypto::software_provider::SOFTWARE_PROVIDER; + use crate::tpm2_impl::mock_device::{MockResponse, MockTpmDevice}; + + /// Every expected digest below is a literal produced outside this crate, by transcribing the + /// algorithm from `TSS.CPP/Src/TpmPolicy.cpp` (cross-checked against + /// `TSS.NET/TSS.Net/PolicyAces.cs`) into a short independent script. Asserting against a + /// value this implementation computed would only show that it agrees with itself, which is + /// precisely the failure mode these tests exist to catch. + /// + /// Each vector must be transcribed from the `UpdatePolicyDigest` of the *matching* + /// assertion, not from `PABase::PolicyUpdate`. Most assertions are a single extend and only + /// `PolicySigned`, `PolicySecret`, `PolicyAuthorize` and `PolicyTicket` use `PolicyUpdate`; + /// deriving a single-extend assertion's vector from `PolicyUpdate` produces a test that + /// passes against a double-extending implementation a real TPM rejects. + fn hex(s: &str) -> Vec { + (0..s.len()) + .step_by(2) + .map(|i| u8::from_str_radix(&s[i..i + 2], 16).unwrap()) + .collect() + } + + fn zero_digest() -> Vec { + vec![0u8; 32] + } + + // ----------------------------------------------------------------------------------- + // Item 1: PolicyUpdate's second extend is unconditional. + // ----------------------------------------------------------------------------------- + + #[test] + fn policy_update_extends_unconditionally_with_empty_policy_ref() { + // `PABase::PolicyUpdate` (TpmPolicy.cpp:226) is + // policyDigest.Extend(commandCode ‖ arg2); + // policyDigest.Extend(arg3); + // with no test on arg3. For TPM_CC_PolicySecret against TPM_RH_OWNER with an empty + // policyRef — the common case — that is + // H( H(0^32 ‖ 0x00000151 ‖ 0x40000001) ‖ ) + let expected = hex("0d84f55daf6e43ac97966e62c9bb989d3397777d25c5f749868055d65394f952"); + // What the guarded version produced: the first extend only, and therefore a digest no + // policy session could ever reach. + let single_extend_only = + hex("478cf794da0e0531f4117344277d77d086259043f037b6d67f63b132a08bfc27"); + + let mut acc = zero_digest(); + policy_update( + &SOFTWARE_PROVIDER, + TPM_ALG_ID::SHA256, + &mut acc, + TPM_CC::PolicySecret, + &TPM_RH::OWNER.get_value().to_be_bytes(), + &[], + ) + .unwrap(); + + assert_eq!(acc, expected); + assert_ne!(acc, single_extend_only); + } + + #[test] + fn policy_update_with_a_non_empty_policy_ref_is_unchanged() { + // The non-empty branch was always right; pin it so the fix cannot silently alter it. + let policy_ref = b"reference".to_vec(); + let mut acc = zero_digest(); + policy_update( + &SOFTWARE_PROVIDER, + TPM_ALG_ID::SHA256, + &mut acc, + TPM_CC::PolicySecret, + &TPM_RH::OWNER.get_value().to_be_bytes(), + &policy_ref, + ) + .unwrap(); + + let first = Crypto::hash( + &SOFTWARE_PROVIDER, + TPM_ALG_ID::SHA256, + &[ + zero_digest().as_slice(), + &TPM_CC::PolicySecret.get_value().to_be_bytes(), + &TPM_RH::OWNER.get_value().to_be_bytes(), + ] + .concat(), + ) + .unwrap(); + let expected = Crypto::hash( + &SOFTWARE_PROVIDER, + TPM_ALG_ID::SHA256, + &[first.as_slice(), policy_ref.as_slice()].concat(), + ) + .unwrap(); + assert_eq!(acc, expected); + } + + // ----------------------------------------------------------------------------------- + // Item 2: TPM2_PolicyNV takes exactly one extend. + // ----------------------------------------------------------------------------------- + + #[test] + fn policy_nv_uses_a_single_extend() { + // `PolicyNV::UpdatePolicyDigest` (TpmPolicy.cpp:439) extends once, with the Name inside + // the same extend: + // H(0^32 ‖ 0x00000149 ‖ H(operandB ‖ offset ‖ operation) ‖ nvIndex.Name) + let expected = hex("8be05d12a9bbbcb4858fafe713814c5d5fb1611ed8c22769ced2ee987b3ca078"); + // What delegating to PolicyUpdate produced: two extends, and an unsatisfiable digest. + let two_extends = hex("6dd4cb20c2431ca98c146169d750d4862cd8d4b8b4b4b2949bb992b016efabc5"); + + let nv_name: Vec = [0x00u8, 0x0B].iter().copied().chain(0u8..32).collect(); + let policy = PolicyNv::new( + TPM_HANDLE::new(TPM_RH::OWNER.get_value()), + TPM_HANDLE::new(0x01800001), + nv_name, + vec![1, 2, 3, 4], + 0, + TPM_EO::EQ, + ); + + let mut acc = zero_digest(); + policy + .update_policy_digest(&SOFTWARE_PROVIDER, TPM_ALG_ID::SHA256, &mut acc) + .unwrap(); + + assert_eq!(acc, expected); + assert_ne!(acc, two_extends); + } + + // ----------------------------------------------------------------------------------- + // Item 3: TPM2_PolicyPCR is sent the computed digest, not the first raw PCR value. + // ----------------------------------------------------------------------------------- + + fn two_pcr_values() -> Vec { + vec![ + TPM2B_DIGEST::new(&vec![0xAAu8; 32]), + TPM2B_DIGEST::new(&vec![0xBBu8; 32]), + ] + } + + fn one_selection() -> Vec { + vec![TPMS_PCR_SELECTION::new(TPM_ALG_ID::SHA256, &vec![0x03u8])] + } + + #[test] + fn policy_pcr_digest_matches_hash_pcrs() { + // `Helpers::HashPcrs` — H over the concatenated PCR values, here H(0xAA*32 ‖ 0xBB*32). + let expected = hex("e2d80f78d79027556d6619a1400605abbdca6bb6eb24e0831e33ecd5466fa5f6"); + let policy = PolicyPcr::new(two_pcr_values(), one_selection()); + assert_eq!( + policy + .pcr_digest(&SOFTWARE_PROVIDER, TPM_ALG_ID::SHA256) + .unwrap(), + expected + ); + } + + #[test] + fn policy_pcr_policy_digest_matches_the_cpp_reference() { + // `PolicyPcr::UpdatePolicyDigest` (TpmPolicy.cpp:312) is a SINGLE extend: + // H(0^32 ‖ 0x0000017F ‖ count ‖ selections ‖ HashPcrs(values)) + // The previous literal here was transcribed from `PABase::PolicyUpdate`'s two-extend + // shape instead, so it agreed with a PolicyPCR that double-extended. A real TPM does + // not. + let expected = hex("5ac44e92d0326eb3afec6049aa2391f17693707874c2cc260541238ae3906e13"); + // The two-extend value, i.e. the old (wrong) literal. + let two_extends = hex("797f02987199a628dc6f8d86a79999a356bec0ecfb211ec17fdadc4b91582bd0"); + let policy = PolicyPcr::new(two_pcr_values(), one_selection()); + + let mut acc = zero_digest(); + policy + .update_policy_digest(&SOFTWARE_PROVIDER, TPM_ALG_ID::SHA256, &mut acc) + .unwrap(); + assert_eq!(acc, expected); + assert_ne!(acc, two_extends); + } + + #[test] + fn policy_pcr_sends_the_computed_digest_not_the_first_value() { + // Drive `execute` against a mock device and read the pcrDigest argument straight out of + // the command bytes. `TPM2_PolicyPCR` has no auth handle and no sessions, so the command + // is tag ‖ size ‖ commandCode ‖ policySession ‖ pcrDigest(TPM2B) ‖ pcrs. + let expected_digest = + hex("e2d80f78d79027556d6619a1400605abbdca6bb6eb24e0831e33ecd5466fa5f6"); + + // TPM_ST_NO_SESSIONS, 10 bytes, TPM_RC_SUCCESS, no parameters. + let ok = vec![0x80, 0x01, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00]; + let device = MockTpmDevice::new(vec![MockResponse::Canned(ok)]); + let log = device.command_log(); + let mut tpm = Tpm2::with_software_crypto(Box::new(device)); + + let session = Session::new( + TPM_HANDLE::new(0x03000000), + &[0u8; 32], + TPMA_SESSION::continueSession, + &[0u8; 32], + ); + let policy = PolicyPcr::new(two_pcr_values(), one_selection()); + policy.execute(&mut tpm, &session).unwrap(); + + let cmd = log.lock().unwrap()[0].clone(); + let digest_len = u16::from_be_bytes([cmd[14], cmd[15]]) as usize; + let sent = cmd[16..16 + digest_len].to_vec(); + + assert_eq!( + sent, expected_digest, + "TPM2_PolicyPCR must be sent the same digest that went into the policy digest" + ); + assert_ne!( + sent, + vec![0xAAu8; 32], + "sending pcr_values[0] verbatim is the defect this test pins" + ); + assert!( + !sent.is_empty(), + "an empty pcrDigest tells the TPM to skip the PCR comparison entirely" + ); + } + + #[test] + fn policy_pcr_rejects_empty_pcr_values() { + // Indexing pcr_values[0] used to panic here. Erroring matters beyond the panic: an + // empty pcrDigest is meaningful to the TPM — it means "do not compare the PCRs" — so + // quietly hashing nothing would produce a policy session that checks no PCRs at all. + let policy = PolicyPcr::new(Vec::new(), one_selection()); + + assert!(matches!( + policy.pcr_digest(&SOFTWARE_PROVIDER, TPM_ALG_ID::SHA256), + Err(TpmError::InvalidParameter) + )); + + let mut acc = zero_digest(); + assert!(matches!( + policy.update_policy_digest(&SOFTWARE_PROVIDER, TPM_ALG_ID::SHA256, &mut acc), + Err(TpmError::InvalidParameter) + )); + + let device = MockTpmDevice::new(Vec::new()); + let mut tpm = Tpm2::with_software_crypto(Box::new(device)); + let session = Session::new( + TPM_HANDLE::new(0x03000000), + &[0u8; 32], + TPMA_SESSION::continueSession, + &[0u8; 32], + ); + assert!(matches!( + policy.execute(&mut tpm, &session), + Err(TpmError::InvalidParameter) + )); + } + + // ----------------------------------------------------------------------------------- + // The two assertions that tell the session how the TPM will authorize it. + // ----------------------------------------------------------------------------------- + + #[test] + fn policy_password_and_policy_auth_value_are_mutually_exclusive_on_a_session() { + // The TPM's `isPasswordNeeded` and `isAuthValueNeeded` are mutually exclusive: each + // command CLEARs the other (TPM 2.0 Part 3, TPM2_PolicyPassword / TPM2_PolicyAuthValue). + // They select different response behaviour — a PolicyPassword session gets no response + // authorization at all — so leaving a stale flag set makes the client expect the wrong + // thing. + let ok = vec![0x80, 0x01, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00]; + let device = MockTpmDevice::new(vec![ + MockResponse::Canned(ok.clone()), + MockResponse::Canned(ok), + ]); + let mut tpm = Tpm2::with_software_crypto(Box::new(device)); + let session = Session::new( + TPM_HANDLE::new(0x03000000), + &[0u8; 32], + TPMA_SESSION::continueSession, + &[0u8; 32], + ); + + let after_password = PolicyPassword::new().execute(&mut tpm, &session).unwrap(); + assert!(after_password.needs_password); + assert!(!after_password.needs_hmac); + assert!(!after_password.expects_response_auth()); + + let after_auth_value = PolicyAuthValue::new() + .execute(&mut tpm, &after_password) + .unwrap(); + assert!(after_auth_value.needs_hmac); + assert!(!after_auth_value.needs_password); + assert!(after_auth_value.expects_response_auth()); + } + + // ----------------------------------------------------------------------------------- + // The assertions that carry an authorization of their own must still return the *policy* + // session. + // + // `TPM2_PolicySecret` and `TPM2_PolicyNV` are the only two implemented here that declare an + // auth handle, so `dispatch_command` manufactures a PWAP session for it and + // `Tpm2::last_session()` is that password session, not the policy session — which these + // commands take as a plain handle parameter and never put in the authorization area. + // ----------------------------------------------------------------------------------- + + const POLICY_SESSION_HANDLE: u32 = 0x0300_0000; + + fn be32(buf: &[u8], pos: usize) -> u32 { + u32::from_be_bytes([buf[pos], buf[pos + 1], buf[pos + 2], buf[pos + 3]]) + } + + fn policy_session() -> Session { + Session::new( + TPM_HANDLE::new(POLICY_SESSION_HANDLE), + &[0u8; 32], + TPMA_SESSION::continueSession, + &[0u8; 32], + ) + } + + /// `TPM_ST_NO_SESSIONS ‖ 10 ‖ TPM_RC_SUCCESS`: the entire response to a policy command that + /// declares no auth handle and returns no parameters. + fn success_without_sessions() -> Vec { + vec![0x80, 0x01, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00] + } + + /// The response to a command that carried one authorization session: + /// `TPM_ST_SESSIONS ‖ responseSize ‖ TPM_RC_SUCCESS ‖ parameterSize ‖ params ‖ authArea`. + /// The auth area is the empty nonce, `continueSession` and the empty HMAC that a PWAP + /// session's response must carry. + fn success_with_one_pwap_session(params: &[u8]) -> Vec { + let mut resp = vec![0x80, 0x02]; + let size = 2 + 4 + 4 + 4 + params.len() + 5; + resp.extend_from_slice(&(size as u32).to_be_bytes()); + resp.extend_from_slice(&0u32.to_be_bytes()); + resp.extend_from_slice(&(params.len() as u32).to_be_bytes()); + resp.extend_from_slice(params); + resp.extend_from_slice(&[0x00, 0x00, 0x01, 0x00, 0x00]); + resp + } + + /// `TPM2_PolicySecret`'s response parameters: an empty `timeout` and a NULL `TPMT_TK_AUTH` + /// (`TPM_ST_AUTH_SECRET ‖ TPM_RH_NULL ‖ empty digest`). + fn policy_secret_params() -> Vec { + vec![ + 0x00, 0x00, // timeout + 0x80, 0x23, // policyTicket.tag = TPM_ST_AUTH_SECRET + 0x40, 0x00, 0x00, 0x07, // policyTicket.hierarchy = TPM_RH_NULL + 0x00, 0x00, // policyTicket.digest + ] + } + + fn a_name() -> Vec { + [0x00u8, 0x0B].iter().copied().chain(0u8..32).collect() + } + + #[test] + fn policy_secret_returns_the_policy_session_not_the_password_session_it_authorized_with() { + let device = MockTpmDevice::new(vec![MockResponse::Canned(success_with_one_pwap_session( + &policy_secret_params(), + ))]); + let log = device.command_log(); + let mut tpm = Tpm2::with_software_crypto(Box::new(device)); + + let session = policy_session(); + let assertion = PolicySecret::new(a_name(), TPM_HANDLE::new(TPM_RH::OWNER.get_value())); + let updated = assertion.execute(&mut tpm, &session).unwrap(); + + // The command itself addressed the policy session — handles are + // `authHandle ‖ policySession`, at offsets 10 and 14. + let cmd = log.lock().unwrap()[0].clone(); + assert_eq!(be32(&cmd, 10), TPM_RH::OWNER.get_value()); + assert_eq!(be32(&cmd, 14), POLICY_SESSION_HANDLE); + + assert_eq!( + updated.sess_in.sessionHandle.handle, POLICY_SESSION_HANDLE, + "execute must return the policy session it was given" + ); + assert_ne!( + updated.sess_in.sessionHandle.handle, + TPM_RH::PW.get_value(), + "returning the auto-created PWAP session hands the caller a password session" + ); + assert!( + !updated.is_pwap(), + "a password session cannot satisfy the policy the caller believes it built" + ); + } + + #[test] + fn policy_nv_returns_the_policy_session_not_the_password_session_it_authorized_with() { + let device = MockTpmDevice::new(vec![MockResponse::Canned(success_with_one_pwap_session( + &[], + ))]); + let log = device.command_log(); + let mut tpm = Tpm2::with_software_crypto(Box::new(device)); + + let session = policy_session(); + let assertion = PolicyNv::new( + TPM_HANDLE::new(TPM_RH::OWNER.get_value()), + TPM_HANDLE::new(0x0180_0001), + a_name(), + vec![1, 2, 3, 4], + 0, + TPM_EO::EQ, + ); + let updated = assertion.execute(&mut tpm, &session).unwrap(); + + // Handles are `authHandle ‖ nvIndex ‖ policySession`, at offsets 10, 14 and 18. + let cmd = log.lock().unwrap()[0].clone(); + assert_eq!(be32(&cmd, 18), POLICY_SESSION_HANDLE); + + assert_eq!( + updated.sess_in.sessionHandle.handle, POLICY_SESSION_HANDLE, + "execute must return the policy session it was given" + ); + assert_ne!( + updated.sess_in.sessionHandle.handle, + TPM_RH::PW.get_value(), + "returning the auto-created PWAP session hands the caller a password session" + ); + } + + #[test] + fn a_tree_keeps_addressing_the_policy_session_after_an_assertion_that_authorizes() { + // The consequence of the defect, one assertion further on: `PolicyTree::execute` feeds + // each assertion the session the previous one returned, so a PWAP session returned here + // becomes the `policySession` handle of every later `TPM2_PolicyXXX` — extending the + // password session instead of the policy session, and handing the caller the former at + // the end. Against an object with `userWithAuth` set and an empty authValue the + // subsequent command then succeeds by password, with no policy evaluated at all. + let device = MockTpmDevice::new(vec![ + MockResponse::Canned(success_with_one_pwap_session(&policy_secret_params())), + MockResponse::Canned(success_without_sessions()), + ]); + let log = device.command_log(); + let mut tpm = Tpm2::with_software_crypto(Box::new(device)); + + let tree = PolicyTree::new() + .add(PolicySecret::new( + a_name(), + TPM_HANDLE::new(TPM_RH::OWNER.get_value()), + )) + .add(PolicyCommandCode::new(TPM_CC::Sign)); + let final_session = tree.execute(&mut tpm, policy_session()).unwrap(); + + let commands = log.lock().unwrap().clone(); + assert_eq!(commands.len(), 2); + // `TPM2_PolicyCommandCode` has one handle, at offset 10. + assert_eq!( + be32(&commands[1], 10), + POLICY_SESSION_HANDLE, + "the assertion after PolicySecret must extend the policy session, not TPM_RS_PW" + ); + assert_eq!( + final_session.sess_in.sessionHandle.handle, POLICY_SESSION_HANDLE, + "the session handed back to the caller must be the policy session" + ); + } + + // ----------------------------------------------------------------------------------- + // Item 4: every assertion uses the digest shape of its `TSS.CPP` counterpart. + // + // The regression these pin: routing a single-extend assertion through `policy_update` + // adds an extend over an empty `arg3`. Nothing in software notices; a real TPM produces a + // different `policyDigest` and every session against it fails. + // ----------------------------------------------------------------------------------- + + fn digest_of(assertion: &dyn PolicyAssertion) -> Vec { + let mut acc = zero_digest(); + assertion + .update_policy_digest(&SOFTWARE_PROVIDER, TPM_ALG_ID::SHA256, &mut acc) + .unwrap(); + acc + } + + #[test] + fn policy_command_code_uses_a_single_extend() { + // `PolicyCommandCode::UpdatePolicyDigest` (TpmPolicy.cpp:333): + // H(0^32 ‖ 0x0000016C ‖ 0x0000015B) [TPM_CC_HMAC_Start] + // This is the digest a real TPM reported when `policy_tree_sample` caught the + // double-extend. + let expected = hex("2c9437859508d8f2905a6fc9cc50eab46f7682ce7cd2a8714f67a92bf142dc36"); + let two_extends = hex("076e80efc2aae5ca7961d4e331bcf2cba1a84588a1502f176ce5507eb360fefa"); + + let acc = digest_of(&PolicyCommandCode::new(TPM_CC::HMAC_Start)); + assert_eq!(acc, expected); + assert_ne!(acc, two_extends); + } + + #[test] + fn policy_auth_value_and_policy_password_share_one_single_extend_digest() { + // `PolicyAuthValue::UpdatePolicyDigest` (TpmPolicy.cpp:411) and + // `PolicyPassword::UpdatePolicyDigest` (:425) are both, in their entirety, + // accumulator.Extend(Int32ToTpm(TPM_CC::PolicyAuthValue)); + // i.e. H(0^32 ‖ 0x0000016B). PolicyPassword deliberately uses the PolicyAuthValue + // command code so one policy can be satisfied either way. + let expected = hex("8fcd2169ab92694e0c633f1ab772842b8241bbc20288981fc7ac1eddc1fddb0e"); + let two_extends = hex("202ca3645e334dfdf79bf341aca5451a735037951d4f532794059870c597e64c"); + + let auth_value = digest_of(&PolicyAuthValue::new()); + let password = digest_of(&PolicyPassword::new()); + assert_eq!(auth_value, expected); + assert_eq!(password, expected); + assert_ne!(auth_value, two_extends); + } + + #[test] + fn policy_cp_hash_uses_a_single_extend() { + // `PolicyCpHash::UpdatePolicyDigest` (TpmPolicy.cpp:349): + // H(0^32 ‖ 0x0000016E ‖ cpHashA) + let expected = hex("52dc88a57fccbb92568bed93ff793b1c7a4fff0f20af825a9d1b06f903b0d87f"); + let cp_hash: Vec = (0x10u8..0x30).collect(); + assert_eq!(digest_of(&PolicyCpHash::new(cp_hash)), expected); + } + + #[test] + fn policy_name_hash_uses_a_single_extend() { + // `PolicyNameHash::UpdatePolicyDigest` (TpmPolicy.cpp:395): + // H(0^32 ‖ 0x00000170 ‖ nameHash) + let expected = hex("0b20d273d44c8f5ecd30dfe8cf4f441bc069f9b5daada74d94506b4d7bafbfc0"); + let name_hash: Vec = (0x40u8..0x60).collect(); + assert_eq!(digest_of(&PolicyNameHash::new(name_hash)), expected); + } + + #[test] + fn policy_counter_timer_uses_a_single_extend() { + // `PolicyCounterTimer::UpdatePolicyDigest` (TpmPolicy.cpp:379): + // H(0^32 ‖ 0x0000016D ‖ H(operandB ‖ offset ‖ operation)) + let expected = hex("8ac1c2b12b4ea0df1c08b7b20d6199cee877e25fe29af227124b3f77d8ce89f2"); + let policy = PolicyCounterTimer::from_u64(1234, 8, TPM_EO::UNSIGNED_GT); + assert_eq!(digest_of(&policy), expected); + } + + #[test] + fn policy_locality_uses_a_single_extend() { + // `PolicyLocality::UpdatePolicyDigest` (TpmPolicy.cpp:239): + // H(0^32 ‖ 0x0000016F ‖ 0x01) - TPMA_LOCALITY is one byte on the wire. + let expected = hex("ddee6af14bf3c4e8127ced87bcf9a57e1c0c8ddb5e67735c8505f96f07b8dbb8"); + assert_eq!( + digest_of(&PolicyLocality::new(TPMA_LOCALITY::LOC_ZERO)), + expected + ); + } + + #[test] + fn policy_duplication_select_uses_a_single_extend() { + // `PolicyDuplicationSelect::UpdatePolicyDigest` (TpmPolicy.cpp:565): + // H(0^32 ‖ 0x00000188 ‖ [objectName] ‖ newParentName ‖ includeObject) + // The object Name is in the digest only when includeObject is set; the flag byte is + // always there. + let obj_name: Vec = [0x00u8, 0x0B].iter().copied().chain(0x80u8..0xA0).collect(); + let parent_name: Vec = [0x00u8, 0x0B].iter().copied().chain(0xA0u8..0xC0).collect(); + + let with_object = hex("8947e4ab30b2738ba1ce93e886fa290c7184867f5a1d600d28dacbcf81a91320"); + let without_object = + hex("10dbd0e9ac9f6f4170dac0ea69df9e7667c7b6becb0dee8097a6f79f95b59fa6"); + + assert_eq!( + digest_of(&PolicyDuplicationSelect::new( + obj_name.clone(), + parent_name.clone(), + true + )), + with_object + ); + assert_eq!( + digest_of(&PolicyDuplicationSelect::new(obj_name, parent_name, false)), + without_object + ); + } + + #[test] + fn policy_or_resets_the_accumulator_then_single_extends() { + // `PolicyOr::UpdatePolicyDigest` (TpmPolicy.cpp:268): + // accumulator.Reset(); accumulator.Extend(0x00000171 ‖ digest1 ‖ digest2) + // with each branch digest computed from its own zero accumulator. + let expected = hex("8adcb4e659bf6cd70a892987b08fc8e021be1c8c390d99940d209dfdae62b4ed"); + + let branches: Vec>> = vec![ + vec![Box::new(PolicyCommandCode::new(TPM_CC::HMAC_Start))], + vec![Box::new(PolicyCommandCode::new(TPM_CC::Sign))], + ]; + let policy = PolicyOr::new(branches); + assert_eq!(digest_of(&policy), expected); + + // The Reset() is load-bearing: whatever came before must be discarded. + let mut acc = vec![0xFFu8; 32]; + policy + .update_policy_digest(&SOFTWARE_PROVIDER, TPM_ALG_ID::SHA256, &mut acc) + .unwrap(); + assert_eq!(acc, expected); + } + + #[test] + fn policy_tree_chains_assertions_in_the_order_they_were_added() { + // Two single-extend assertions in sequence: + // H(H(0^32 ‖ 0x0000016F ‖ 0x01) ‖ 0x0000016C ‖ 0x0000015D) + // This is the `PolicyLocality` + `PolicyCommandCode(Sign)` chain that + // `policy_tree_sample` checks against a TPM trial session. + let expected = hex("13e423a4dc7783a2f2f858ee32b576011e7f9f2111ead871bc10da2258a4b969"); + let tree = PolicyTree::new() + .add(PolicyLocality::new(TPMA_LOCALITY::LOC_ZERO)) + .add(PolicyCommandCode::new(TPM_CC::Sign)); + assert_eq!( + tree.get_policy_digest(&SOFTWARE_PROVIDER, TPM_ALG_ID::SHA256) + .unwrap(), + expected + ); + } + + #[test] + fn policy_authorize_resets_the_accumulator_then_uses_policy_update() { + // `PolicyAuthorize::UpdatePolicyDigest` (TpmPolicy.cpp:509) is + // accumulator.Reset(); + // PolicyUpdate(accumulator, TPM_CC::PolicyAuthorize, key.GetName(), PolicyRef); + // so it is one of the four genuine two-extend assertions, preceded by a reset. The key + // Name is an input here, not a value under test; the shape is what is asserted. + let parameters = TPMU_PUBLIC_PARMS::keyedHashDetail(TPMS_KEYEDHASH_PARMS::new(&Some( + TPMU_SCHEME_KEYEDHASH::hmac(TPMS_SCHEME_HMAC { + hashAlg: TPM_ALG_ID::SHA256, + }), + ))); + let key = TPMT_PUBLIC::new( + TPM_ALG_ID::SHA256, + TPMA_OBJECT::sign | TPMA_OBJECT::userWithAuth, + &vec![], + &Some(parameters), + &Some(TPMU_PUBLIC_ID::keyedHash(TPM2B_DIGEST_KEYEDHASH::default())), + ); + let policy_ref = b"reference".to_vec(); + let policy = PolicyAuthorize::new( + vec![0x11u8; 32], + policy_ref.clone(), + key.clone(), + TPMT_SIGNATURE::default(), + ); + + let name = key.get_name(&SOFTWARE_PROVIDER).unwrap(); + let first = Crypto::hash( + &SOFTWARE_PROVIDER, + TPM_ALG_ID::SHA256, + &[ + zero_digest().as_slice(), + &TPM_CC::PolicyAuthorize.get_value().to_be_bytes(), + name.as_slice(), + ] + .concat(), + ) + .unwrap(); + let expected = Crypto::hash( + &SOFTWARE_PROVIDER, + TPM_ALG_ID::SHA256, + &[first.as_slice(), policy_ref.as_slice()].concat(), + ) + .unwrap(); + + assert_eq!(digest_of(&policy), expected); + + // Reset: a non-zero starting accumulator must not change the result. + let mut acc = vec![0x5Au8; 32]; + policy + .update_policy_digest(&SOFTWARE_PROVIDER, TPM_ALG_ID::SHA256, &mut acc) + .unwrap(); + assert_eq!(acc, expected); + } + + // ----------------------------------------------------------------------------------- + // The other two assertions that genuinely double-extend. + // + // `PolicySecret` and `PolicySigned` are `PolicyUpdate` assertions, and the single-extend + // correction must not be over-applied to them — that would be the same mistake as the one + // this module fixed, in the opposite direction, and until now nothing here would have caught + // it: the only `policy_update` vectors exercised the free function, not these methods. + // ----------------------------------------------------------------------------------- + + #[test] + fn policy_secret_uses_policy_update_with_an_empty_policy_ref() { + // `PolicySecret::UpdatePolicyDigest` (TpmPolicy.h:533) is, in its entirety, + // PolicyUpdate(accumulator, TPM_CC::PolicySecret, AuthObjectName, PolicyRef); + // so with an empty policyRef the digest is + // H( H(0^32 ‖ 0x00000151 ‖ authObjectName) ) + // over the 34-byte Name `000b` ‖ 00..1f. Computed outside this crate, with .NET's + // SHA-256 over those bytes. + let expected = hex("f4644163827e379c0376c37ef6a6d8265c6658f94fdad477a8992bc606d3219b"); + // What a single extend would leave behind, i.e. what over-applying `policy_update1` to + // this assertion would produce: a digest no policy session can ever reach. + let single_extend_only = + hex("ff36ccf0020cc982a65323d96907aacc6aa3413e385bf38a10d25df99a58118c"); + + let policy = PolicySecret::new(a_name(), TPM_HANDLE::new(TPM_RH::OWNER.get_value())); + assert!(policy.policy_ref.is_empty()); + + let acc = digest_of(&policy); + assert_eq!(acc, expected); + assert_ne!(acc, single_extend_only); + } + + #[test] + fn policy_signed_uses_policy_update_with_an_empty_policy_ref() { + // `PolicySigned::UpdatePolicyDigest` (TpmPolicy.cpp:462) is, in its entirety, + // PolicyUpdate(accumulator, TPM_CC::PolicySigned, PublicKey.GetName(), PolicyRef); + // The key Name is an input here rather than a value under test — as in + // `policy_authorize_resets_the_accumulator_then_uses_policy_update` — so the vector is + // built from the two extends `PABase::PolicyUpdate` performs, spelled out with plain + // hashes rather than by calling the function under test. + let parameters = TPMU_PUBLIC_PARMS::rsaDetail(TPMS_RSA_PARMS::new( + &TPMT_SYM_DEF_OBJECT::default(), + &Some(TPMU_ASYM_SCHEME::rsassa(TPMS_SIG_SCHEME_RSASSA { + hashAlg: TPM_ALG_ID::SHA256, + })), + 2048, + 65537, + )); + let key = TPMT_PUBLIC::new( + TPM_ALG_ID::SHA256, + TPMA_OBJECT::sign | TPMA_OBJECT::userWithAuth, + &vec![], + &Some(parameters), + &Some(TPMU_PUBLIC_ID::rsa(TPM2B_PUBLIC_KEY_RSA { + buffer: vec![0xcd; 256], + })), + ); + + let policy = PolicySigned::new(key.clone()); + assert!(policy.policy_ref.is_empty()); + + let name = key.get_name(&SOFTWARE_PROVIDER).unwrap(); + let single_extend_only = Crypto::hash( + &SOFTWARE_PROVIDER, + TPM_ALG_ID::SHA256, + &[ + zero_digest().as_slice(), + &TPM_CC::PolicySigned.get_value().to_be_bytes(), + name.as_slice(), + ] + .concat(), + ) + .unwrap(); + // The second extend is over the empty policyRef, and is not skipped for being empty. + let expected = + Crypto::hash(&SOFTWARE_PROVIDER, TPM_ALG_ID::SHA256, &single_extend_only).unwrap(); + + let acc = digest_of(&policy); + assert_eq!(acc, expected); + assert_ne!( + acc, single_extend_only, + "PolicySigned double-extends; collapsing it to one extend is unsatisfiable" + ); } } diff --git a/TSS.Rust/src/tpm2_impl.rs b/TSS.Rust/src/tpm2_impl.rs index 208776b8..39fa7e7e 100644 --- a/TSS.Rust/src/tpm2_impl.rs +++ b/TSS.Rust/src/tpm2_impl.rs @@ -9,27 +9,191 @@ use crate::device::TpmDevice; use crate::error::TpmError; use crate::tpm_buffer::{TpmBuffer, TpmMarshaller}; use crate::tpm_structure::{CmdStructure, ReqStructure, RespStructure, TpmEnum}; +use crate::tpm_type_extensions::TrustedPublic; use crate::tpm_types::{ - TPMA_SESSION, TPMS_AUTH_COMMAND, TPMS_AUTH_RESPONSE, TPMT_HA, TPMT_SYM_DEF, TPM_ALG_ID, - TPM_CC, TPM_HANDLE, TPM_HT, TPM_RC, TPM_RH, TPM_SE, TPM_ST, + CreateLoadedResponse, CreatePrimaryResponse, TPM2_LoadExternal_REQUEST, TPM2_Load_REQUEST, + TPMA_SESSION, TPMS_AUTH_COMMAND, TPMS_AUTH_RESPONSE, TPMT_HA, TPMT_PUBLIC, TPMT_SYM_DEF, + TPM_ALG_ID, TPM_CC, TPM_HANDLE, TPM_HT, TPM_RC, TPM_RH, TPM_SE, TPM_ST, }; +use std::any::Any; +use std::time::Duration; +use subtle::ConstantTimeEq; +use zeroize::Zeroizing; + +/// The command element that a format-1 response code blames. +/// +/// TPM 2.0 Part 1, §39.4: a format-1 code carries a 4-bit number in bits 8-11 alongside the +/// error itself. `RC_P` (bit 6) makes that number a parameter index; otherwise it is a handle +/// index, or a session index when `RC_S` (bit 11) is set. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +pub enum RcIndex { + /// A format-0 code, or a format-1 code that blames nothing in particular. + #[default] + Unspecified, + /// Index of the command handle at fault. + Handle(u32), + /// Index of the command parameter at fault, counting from 1. + Parameter(u32), + /// Index of the authorization session at fault. + Session(u32), +} + +impl std::fmt::Display for RcIndex { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + RcIndex::Unspecified => write!(f, "no particular command element"), + RcIndex::Handle(index) => write!(f, "handle {}", index), + RcIndex::Parameter(index) => write!(f, "parameter {}", index), + RcIndex::Session(index) => write!(f, "session {}", index), + } + } +} + +/// A TPM response code as it arrives on the wire, split into the error it names and the command +/// element it blames. +/// +/// Response codes come in two shapes (TPM 2.0 Part 1, §39.4). A format-0 code is a bare value. +/// A format-1 code — bit 7 set — folds a parameter, handle or session index into bits 6 and +/// 8-11, so what arrives is not a member of the `TPM_RC` enumeration at all: `TPM_RC_SIZE` +/// blamed on the first parameter arrives as `0x1D5`, not `0x095`. Those bits have to be +/// stripped before the value means anything, which is why a raw response code must never be fed +/// straight to `TPM_RC::try_from` — most of the errors a TPM actually returns are absent from +/// the generated match and would decode as "Invalid enum value", discarding the real error. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct ResponseCode { + raw: u32, + code: TPM_RC, + index: RcIndex, +} + +impl ResponseCode { + /// Bit 7, set on a format-1 code. + const RC_FMT1: u32 = 0x080; + /// Bit 6 of a format-1 code: the number field is a parameter index. + const RC_P: u32 = 0x040; + /// Bit 11 of a format-1 code: the number field is a session index, not a handle index. + const RC_S: u32 = 0x800; + /// Bits 8-11 of a format-1 code: the parameter, handle or session number. + const RC_N_MASK: u32 = 0xF00; + const RC_N_SHIFT: u32 = 8; + /// What survives masking a format-1 code: the F bit and the 6-bit error number. + const FMT1_ERROR_MASK: u32 = 0x0BF; + /// What survives masking a format-0 code: the error number, the V bit and the S bit. + const FMT0_ERROR_MASK: u32 = 0x97F; + + /// Decode a response code straight off the wire. + pub fn decode(raw: u32) -> Self { + if Self::is_comm_medium_error(raw) { + // Not a TPM response code at all — the TSS communication layer generated it, so + // none of the TPM's bit assignments apply and there is nothing to strip. + return Self { + raw, + code: TPM_RC(raw), + index: RcIndex::Unspecified, + }; + } + + if raw & Self::RC_FMT1 == 0 { + return Self { + raw, + code: TPM_RC(raw & Self::FMT0_ERROR_MASK), + index: RcIndex::Unspecified, + }; + } + + let number = (raw & Self::RC_N_MASK) >> Self::RC_N_SHIFT; + let index = if raw & Self::RC_P != 0 { + if number == 0 { + RcIndex::Unspecified + } else { + RcIndex::Parameter(number) + } + } else if raw & Self::RC_S != 0 { + // The RC_S marker occupies the top bit of the number field; the session number is + // what is left of it. + RcIndex::Session(number & 0x7) + } else if number == 0 { + RcIndex::Unspecified + } else { + RcIndex::Handle(number) + }; + + Self { + raw, + code: TPM_RC(raw & Self::FMT1_ERROR_MASK), + index, + } + } + + /// Whether the response code was generated by the TSS.Rust implementation rather than by + /// the TPM. + fn is_comm_medium_error(raw: u32) -> bool { + raw & 0xFFFF0000 == 0x80280000 + } + + /// The code exactly as it arrived, index bits included. + pub fn raw(&self) -> u32 { + self.raw + } + + /// The error itself, with any format-1 index bits masked off. + pub fn code(&self) -> TPM_RC { + self.code + } + + /// The command element the TPM blamed for the error. + pub fn index(&self) -> RcIndex { + self.index + } + + /// Whether the TPM reported success. + pub fn is_success(&self) -> bool { + self.code == TPM_RC::SUCCESS + } +} + +impl std::fmt::Display for ResponseCode { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self.index { + RcIndex::Unspecified => write!(f, "raw response code 0x{:03X}", self.raw), + index => write!(f, "raw response code 0x{:03X}, {}", self.raw, index), + } + } +} /// A TPM error with associated command and context information #[derive(Debug, Clone)] pub struct TpmCommandError { - /// Response code returned by the TPM + /// Response code returned by the TPM, with any format-1 index bits masked off pub response_code: TPM_RC, + /// The response code exactly as it arrived, index bits included + pub raw_response_code: u32, + /// The command element the TPM blamed, for a format-1 response code + pub index: RcIndex, /// Command code that triggered the error pub command_code: TPM_CC, /// Description of the error pub message: String, } +impl TpmCommandError { + /// The error for a command the TPM answered with a failure code. + fn from_response(command_code: TPM_CC, response: ResponseCode) -> Self { + TpmCommandError { + response_code: response.code(), + raw_response_code: response.raw(), + index: response.index(), + command_code, + message: response.to_string(), + } + } +} + impl std::fmt::Display for TpmCommandError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, - "TPM command {:?} failed with response code {:?}: {}", + "TPM command {} failed with TPM_RC::{}: {}", self.command_code, self.response_code, self.message ) } @@ -82,12 +246,24 @@ pub struct Tpm2 { /// Input handles for current command in_handles: Vec, + /// How many of `in_handles` the current command authorizes, which is not always all of them: + /// `TPM2_Duplicate` names a new parent it does not authorize, `TPM2_PolicyNV` an NV index and + /// a policy session it does not authorize. Session *i* authorizes handle *i* only while *i* + /// is below this count (TPM 2.0 Part 1, §19.6.4), and both the command and the response HMAC + /// have to agree on that or they fold in different authValues. + num_auth_handles: u16, + /// Auth value for objects object_in_auth: Vec, /// Name for objects object_in_name: Vec, + /// The public area the current command supplies for the object it creates, for the commands + /// that take one as an input rather than returning it (`TPM2_Load`, `TPM2_LoadExternal`). + /// Kept so that the Name the TPM reports for the new object can be checked against it. + command_object_public: Option, + /// Admin authorization handles with auth values admin_platform: TPM_HANDLE, admin_owner: TPM_HANDLE, @@ -141,8 +317,10 @@ impl Tpm2 { current_session_tag: None, pending_command: None, in_handles: Vec::new(), + num_auth_handles: 0, object_in_auth: Vec::new(), object_in_name: Vec::new(), + command_object_public: None, admin_platform: TPM_HANDLE::new(0), admin_owner: TPM_HANDLE::new(0), admin_endorsement: TPM_HANDLE::new(0), @@ -175,60 +353,79 @@ impl Tpm2 { &self.crypto } - /// Checks whether the response code is generated by the TSS.Rust implementation - fn is_comm_medium_error(code: TPM_RC) -> bool { - // Check if error is in the TSS communication layer rather than TPM itself - (code.get_value()) & 0xFFFF0000 == 0x80280000 - } - - /// Cleans the raw response code from the TPM - fn response_code_from_tpm_error(raw_response: TPM_RC) -> TPM_RC { - if Self::is_comm_medium_error(raw_response) { - return raw_response; - } - - let raw_response_u32 = raw_response.get_value(); - let is_fmt = (raw_response_u32 & TPM_RC::RC_FMT1.get_value()) != 0; - - let mask: u32 = if is_fmt { 0xBF } else { 0x97F }; + /// How many times [`Tpm2::dispatch`] resends a command the TPM answered with `TPM_RC_RETRY` + /// before giving up on it. + /// + /// Public because [`Tpm2::dispatch`] documents its own behaviour in terms of it: a caller + /// budgeting for the worst case a command can cost needs the bound, not a promise that one + /// exists. + pub const MAX_RETRIES: u32 = 8; - TPM_RC(raw_response_u32 & mask) - } + /// How long to wait before resending a command the TPM answered with `TPM_RC_RETRY`. It + /// doubles on each further resend, up to [`Tpm2::RETRY_MAX_DELAY`], so the whole sequence + /// costs well under a second rather than the flat second per attempt it used to. + const RETRY_INITIAL_DELAY: Duration = Duration::from_millis(2); + const RETRY_MAX_DELAY: Duration = Duration::from_millis(200); /// Send a TPM command to the underlying TPM device. - pub fn dispatch( + /// + /// `TPM_RC_RETRY` means the TPM was busy and did not act on the command, so the command is + /// resent — up to [`Tpm2::MAX_RETRIES`] times, after which a TPM that never stops saying + /// "retry" produces an error instead of an unbounded loop. + pub fn dispatch( &mut self, cmd_code: TPM_CC, req: R, resp: &mut S, ) -> Result<(), TpmError> { + let mut retries = 0u32; + let mut delay = Self::RETRY_INITIAL_DELAY; + loop { - let process_phase_two = match self.dispatch_command(cmd_code, &req) { + let dispatched = match self.dispatch_command(cmd_code, &req) { Ok(v) => v, Err(e) => { - self.current_cmd_code = None; + self.clear_invocation_state(); return Err(e); } }; + + if !dispatched { + // Nothing was sent to the TPM: this invocation only computed a cpHash for the + // caller, and there is no response to process. + return Ok(()); + } + match self.process_response(cmd_code, resp) { - Ok(done) => { - if !process_phase_two || done { - break; - } - } + Ok(true) => return Ok(()), + // TPM_RC_RETRY. The TPM did not act on the command, so resending it is both safe + // and the only way to make progress. `process_response` has cleared the + // invocation state, without which `dispatch_command` would refuse to run again. + Ok(false) => {} Err(e) => { - self.current_cmd_code = None; + self.clear_invocation_state(); return Err(e); } } - std::thread::sleep(std::time::Duration::from_millis(1000)); - } - Ok(()) + retries += 1; + if retries > Self::MAX_RETRIES { + self.clear_invocation_state(); + self.sessions = None; + return Err(TpmError::GenericError(format!( + "TPM answered {} with TPM_RC::RETRY {} times running; giving up", + cmd_code, + Self::MAX_RETRIES + 1 + ))); + } + + std::thread::sleep(delay); + delay = (delay * 2).min(Self::RETRY_MAX_DELAY); + } } /// Internal method to dispatch a command to the TPM - pub fn dispatch_command( + pub fn dispatch_command( &mut self, cmd_code: TPM_CC, req: &R, @@ -250,6 +447,7 @@ impl Tpm2 { // Determine session tag based on whether we need authorization let num_auth_handles = req.num_auth_handles(); + self.num_auth_handles = num_auth_handles; let has_sessions = num_auth_handles > 0 || self.sessions.is_some(); self.current_session_tag = if has_sessions { Some(TPM_ST::SESSIONS) @@ -268,7 +466,13 @@ impl Tpm2 { self.in_handles = req.get_handles(); // Set auth values for well-known admin handles (OWNER, LOCKOUT, ENDORSEMENT, PLATFORM) for h in self.in_handles.iter_mut() { - Self::set_rh_auth_value_static(h, &self.admin_owner, &self.admin_endorsement, &self.admin_platform, &self.admin_lockout); + Self::set_rh_auth_value_static( + h, + &self.admin_owner, + &self.admin_endorsement, + &self.admin_platform, + &self.admin_lockout, + ); } for handle in self.in_handles.iter() { handle.toTpm(&mut cmd_buf)?; @@ -280,6 +484,11 @@ impl Tpm2 { param_buf.trim(); self.last_cmd_params = param_buf.buffer().clone(); + // The public area of the object this command loads, for the commands that take one as an + // input. It does not come back in the response, so it is kept here for the Name check in + // `update_resp_handle`. + self.command_object_public = Self::request_object_public(cmd_code, req); + // Process authorization sessions if present let mut cp_hash_data = Vec::new(); @@ -385,7 +594,11 @@ impl Tpm2 { } /// Process the TPM response and update the response structure - pub fn process_response( + /// + /// Returns `true` when the command completed, and `false` when the TPM answered + /// `TPM_RC_RETRY` and the command has to be resent — in which case the invocation state is + /// cleared so that the caller can do exactly that. + pub fn process_response( &mut self, cmd_code: TPM_CC, resp_struct: &mut T, @@ -425,7 +638,13 @@ impl Tpm2 { // Read the response header let resp_tag = TPM_ST::try_from(resp_buf.readShort())?; let resp_size = resp_buf.readInt(); - let resp_code = TPM_RC::try_from(resp_buf.readInt())?; + // The response code is decoded rather than converted. A format-1 code carries a + // parameter, handle or session index in bits that belong to no TPM_RC enumerator, so + // `TPM_RC::try_from` would reject the majority of the errors a TPM actually returns and + // report "Invalid enum value" in place of the real one. + let resp_code = ResponseCode::decode(resp_buf.readInt()); + self.last_response_code = resp_code.code(); + self.last_error = None; let act_resp_size = resp_buf.size(); if resp_size as usize != act_resp_size { @@ -435,13 +654,15 @@ impl Tpm2 { ))); } - if resp_code == TPM_RC::RETRY { + if resp_code.code() == TPM_RC::RETRY { + // The TPM was busy and did not act on the command. Clear the invocation state so + // that the command can be dispatched again: leaving `current_cmd_code` set made + // every resend fail with "Pending async command must be completed", which meant the + // retry path could never succeed. + self.clear_invocation_state(); return Ok(false); } - // Clean and store the response code - self.last_response_code = Self::response_code_from_tpm_error(resp_code); - // Figure out our reaction to the received response. This logic depends on: // errors_allowed - no exception, regardless of success or failure @@ -449,15 +670,13 @@ impl Tpm2 { let audit_command = self.audit_command; // Handle errors and clean up invocation state - if resp_code != TPM_RC::SUCCESS { + if !resp_code.is_success() { self.clear_invocation_state(); self.sessions = None; - // Return error - return Err(TpmError::GenericError(format!( - "TPM Error - TPM_RC::{:?}", - self.last_response_code - ))); + let error = TpmCommandError::from_response(cmd_code, resp_code); + self.last_error = Some(error.clone()); + return Err(error.into()); } // A check for the session tag consistency across the command invocation @@ -593,8 +812,24 @@ impl Tpm2 { return Err(e); } - // Preserve sessions with continueSession for reuse, otherwise clear - self.completed_sessions = self.sessions.take(); + // Offer the sessions back for reuse -- except any the TPM reported closed, which is + // what the comment here has always said and what the code did not do. A response with + // `continueSession` CLEAR means the TPM flushed the session when the command completed + // (TPM 2.0 Part 2, `TPMA_SESSION.continueSession`), whether because the caller asked for + // a one-shot session or because the TPM ended it. Its handle is dead and the TPM may + // hand the same one to an unrelated session later, so handing the session object back + // through `last_session()` would invite the caller to authorize a command with it. + // Dropping it here also wipes its session key, by `Drop for Session`. + self.completed_sessions = self + .sessions + .take() + .map(|sessions| { + sessions + .into_iter() + .filter(|session| !session.is_terminated()) + .collect::>() + }) + .filter(|sessions| !sessions.is_empty()); self.clear_invocation_state(); Ok(true) @@ -633,20 +868,30 @@ impl Tpm2 { /// Get the updated session after the last command completed. /// This is needed when reusing HMAC/policy sessions across commands, /// since the TPM updates nonces after each command. + /// + /// Sessions the TPM reported as closed (`continueSession` CLEAR in the response) are not + /// included: their contexts are gone, so there is nothing to reuse. That means the sessions + /// here do not necessarily line up one for one with the ones handed to + /// [`Tpm2::with_sessions`] — match on `sess_in.sessionHandle` rather than on position. pub fn last_sessions(&self) -> Option<&Vec> { self.completed_sessions.as_ref() } /// Get the first updated session from the last completed command. /// Convenience method for the common single-session case. + /// + /// `None` if the TPM closed the session, so a session that has been flushed is never handed + /// back for another command. pub fn last_session(&self) -> Option { - self.completed_sessions.as_ref() + self.completed_sessions + .as_ref() .and_then(|s| s.first().cloned()) } pub fn connect(&mut self) -> Result<(), TpmError> { self.device.connect()?; self.last_response_code = TPM_RC::SUCCESS; + self.last_error = None; Ok(()) } @@ -672,6 +917,9 @@ impl Tpm2 { } /// Start an auth session with explicit attributes and symmetric definition. + /// + /// The session is neither salted nor bound, so it has no secret key material. It cannot be + /// used for parameter encryption — see [`Tpm2::start_salted_auth_session`] for that. pub fn start_auth_session_full( &mut self, session_type: TPM_SE, @@ -682,44 +930,97 @@ impl Tpm2 { let null_handle = TPM_HANDLE::new(TPM_RH::NULL.get_value()); self.start_auth_session_ex( - &null_handle, // tpmKey (no salt) - &null_handle, // bind (no binding) + None, // no salt key + &null_handle, session_type, auth_hash, attributes, symmetric, - &[], // no salt ) } - /// Start an auth session with full control (salt key, bind object, etc.). + /// Start a session salted to `salt_key`, the straightforward way to get a session that can + /// carry parameter encryption. + /// + /// `salt_key_public` must be the public area of `salt_key` as a [`TrustedPublic`] — see + /// [`Tpm2::start_auth_session_ex`] for why this client will not fetch it for you. + pub fn start_salted_auth_session( + &mut self, + salt_key: &TPM_HANDLE, + salt_key_public: &TrustedPublic, + session_type: TPM_SE, + auth_hash: TPM_ALG_ID, + attributes: TPMA_SESSION, + symmetric: TPMT_SYM_DEF, + ) -> Result { + let null_handle = TPM_HANDLE::new(TPM_RH::NULL.get_value()); + + self.start_auth_session_ex( + Some((salt_key, salt_key_public)), + &null_handle, + session_type, + auth_hash, + attributes, + symmetric, + ) + } + + /// Start an auth session with full control over salting and binding. + /// + /// # Salting + /// + /// Pass `Some((handle, public))` to salt the session. The salt is generated here, at the + /// digest size of the salt key's `nameAlg` — the size the TPM requires — and encrypted to + /// `public`, which the caller supplies as a + /// [`TrustedPublic`], having already decided that this public area is the one it means. + /// + /// This function deliberately does **not** call `TPM2_ReadPublic` on the salt key. Doing so + /// would encrypt the salt to whatever public area came back over the very channel the salt + /// exists to protect: an adversary in the middle answers the `ReadPublic` with a key it + /// holds the private half of, learns the salt, derives the session key, and from then on + /// produces and verifies both command and response HMACs. Nothing downstream would notice, + /// because every check would use the adversary's key. The trust decision has to be made from + /// something other than the channel, so it is the caller's to make. + /// + /// Note also what salting does *not* buy you. It gives the session key an input an + /// eavesdropper does not have, which is what parameter encryption and HMAC integrity need. + /// It does not authenticate the peer. If the pinned Name came from the same untrusted + /// channel — or if [`TrustedPublic::assume_trusted`] was used on a public area read over + /// it — the session is salted and still unauthenticated. // The parameter list mirrors the TPM2_StartAuthSession command parameters. #[allow(clippy::too_many_arguments)] pub fn start_auth_session_ex( &mut self, - tpm_key: &TPM_HANDLE, + salt_key: Option<(&TPM_HANDLE, &TrustedPublic)>, bind: &TPM_HANDLE, session_type: TPM_SE, auth_hash: TPM_ALG_ID, attributes: TPMA_SESSION, symmetric: TPMT_SYM_DEF, - salt: &[u8], ) -> Result { let nonce_size = Crypto::digest_size_checked(auth_hash)?; let nonce_caller = Crypto::get_random(&self.crypto, nonce_size)?; - // For salted sessions, encrypt the salt to the tpmKey's public area - let encrypted_salt = if !salt.is_empty() { - let pub_info = self.ReadPublic(tpm_key)?; - pub_info - .outPublic - .encrypt_session_salt(&self.crypto, salt)? - } else { - Vec::new() + let null_handle = TPM_HANDLE::new(TPM_RH::NULL.get_value()); + let (tpm_key, salt, encrypted_salt) = match salt_key { + Some((handle, trusted)) => { + // The salt must be exactly the digest size of the salt key's *nameAlg*, not of + // the session hash. The TPM recovers the salt with OAEP under the key's nameAlg + // and then rejects anything whose length does not match that digest size + // (TPM_RC_VALUE on `encryptedSalt`), so a SHA-256 session salted to a SHA-1 key + // fails outright if the session hash is used to size it. + let salt = Zeroizing::new(Crypto::get_random( + &self.crypto, + Crypto::digest_size_checked(trusted.public().nameAlg)?, + )?); + let encrypted = trusted.public().encrypt_session_salt(&self.crypto, &salt)?; + (handle.clone(), salt, encrypted) + } + None => (null_handle, Zeroizing::new(Vec::new()), Vec::new()), }; let resp = self.StartAuthSession( - tpm_key, + &tpm_key, bind, &nonce_caller, &encrypted_salt, @@ -728,18 +1029,33 @@ impl Tpm2 { auth_hash, )?; - Session::from_tpm_response( + // From here on the TPM holds a loaded session, so every exit has to account for it. + // `Session::from_tpm_response` still has two ways to fail — `calc_session_key` rejects a + // hash algorithm with no digest size, and the constructor refuses parameter encryption + // on a session with no secret key material — and both leave the session occupying one of + // the two or three slots a TPM typically has for loaded sessions, with no handle left + // anywhere for the caller to flush. That refusal is not hypothetical: the sample in + // `examples/tpm_samples.rs` provokes it deliberately on every run and then loads two + // more sessions. + let handle = resp.handle; + match Session::from_tpm_response( &self.crypto, - resp.handle, + handle.clone(), session_type, auth_hash, nonce_caller, resp.nonceTPM, attributes, symmetric, - salt, + &salt, bind, - ) + ) { + Ok(session) => Ok(session), + Err(err) => { + self.flush_orphaned_handle(&handle); + Err(err) + } + } } /// Set a session on this Tpm2 for the next command. @@ -768,9 +1084,39 @@ impl Tpm2 { fn clear_invocation_state(&mut self) { self.current_cmd_code = None; self.current_session_tag = None; + self.command_object_public = None; + self.num_auth_handles = 0; // Clear other command-specific state } + /// Flush an object or session the TPM has loaded but this client is about to lose the handle + /// to, on a path that is failing for some other reason. + /// + /// A TPM has room for only a handful of loaded sessions and transient objects, and nothing + /// reclaims one whose handle no caller ever sees: it occupies its slot until the TPM is + /// reset. Two paths here can produce exactly that — a `TPM2_StartAuthSession` whose response + /// this client then refuses to build a `Session` from, and a `TPM2_Load` or + /// `TPM2_CreatePrimary` whose reported Name fails the consistency check — and in both the + /// command itself succeeded, so the TPM has already done the loading. + /// + /// The flush is best effort. It is issued for its side effect on the TPM, and its outcome + /// must not displace the failure that is on its way to the caller, so the invocation state + /// it needs is cleared first and the error reporting it would otherwise overwrite is put + /// back afterwards. + fn flush_orphaned_handle(&mut self, handle: &TPM_HANDLE) { + let response_code = self.last_response_code; + let error = self.last_error.take(); + + // `FlushContext` dispatches a command of its own, which refuses to run while another + // command is still marked as in flight. + self.clear_invocation_state(); + self.sessions = None; + let _ = self.FlushContext(handle); + + self.last_response_code = response_code; + self.last_error = error; + } + /// Set the auth value for an admin hierarchy handle. /// Use this when the TPM's hierarchy auth was set externally (e.g., recovering from a /// previous run that changed auth but failed to reset it). @@ -788,20 +1134,49 @@ impl Tpm2 { } /// Set auth values for well-known admin handles (avoids borrow issues) - fn set_rh_auth_value_static(h: &mut TPM_HANDLE, admin_owner: &TPM_HANDLE, admin_endorsement: &TPM_HANDLE, admin_platform: &TPM_HANDLE, admin_lockout: &TPM_HANDLE) { + fn set_rh_auth_value_static( + h: &mut TPM_HANDLE, + admin_owner: &TPM_HANDLE, + admin_endorsement: &TPM_HANDLE, + admin_platform: &TPM_HANDLE, + admin_lockout: &TPM_HANDLE, + ) { match h.handle { val if val == TPM_RH::OWNER.get_value() => h.set_auth(&admin_owner.auth_value), val if val == TPM_RH::ENDORSEMENT.get_value() => { h.set_auth(&admin_endorsement.auth_value) } - val if val == TPM_RH::PLATFORM.get_value() => { - h.set_auth(&admin_platform.auth_value) - } + val if val == TPM_RH::PLATFORM.get_value() => h.set_auth(&admin_platform.auth_value), val if val == TPM_RH::LOCKOUT.get_value() => h.set_auth(&admin_lockout.auth_value), _ => {} // No auth value change needed } } + /// The handle whose authValue session `index` folds into its HMAC key, if any. + /// + /// A command's handle area starts with the handles it authorizes and may continue with + /// handles it does not: `TPM2_Duplicate`'s `newParentHandle`, `TPM2_PolicyNV`'s `nvIndex` + /// and `policySession`. Session *i* is the authorization for handle *i* only while *i* is + /// below `num_auth_handles`; a session past that point authorizes nothing and folds in no + /// authValue, whatever handle happens to sit at its index. + /// + /// The command HMAC and the response HMAC are keyed identically, so both sides call this. + /// They used not to: the response side asked only whether index *i* named some handle, so a + /// command with more handles than authorizations, driven with a session per handle, produced + /// a response HMAC key with an authValue in it that the command's did not have. The + /// verification then failed on a response that was perfectly correct. + fn authorized_handle( + handles: &[TPM_HANDLE], + num_auth_handles: u16, + index: usize, + ) -> Option<&TPM_HANDLE> { + if index < num_auth_handles as usize { + handles.get(index) + } else { + None + } + } + /// Get CpHash data for parameter encryption fn get_cp_hash_data(&self, cmd_code: TPM_CC, cmd_params: &[u8]) -> Result, TpmError> { let mut buf = TpmBuffer::new(None); @@ -861,20 +1236,27 @@ impl Tpm2 { } // For non-PWAP sessions, we need more complex processing - let mut h_copy = None; - - if i < num_auth_handles as usize && i < self.in_handles.len() { - // Set appropriate auth value on handle - h_copy = Some(self.in_handles[i].clone()); - } + let h_copy = + Self::authorized_handle(&self.in_handles, num_auth_handles, i).cloned(); auth_cmd.nonce = session.sess_in.nonce.clone(); auth_cmd.sessionHandle = session.sess_in.sessionHandle.clone(); auth_cmd.sessionAttributes = session.sess_in.sessionAttributes; - if session.session_type == TPM_SE::HMAC || session.needs_hmac { + // Mirrors the TPM's own dispatch rule (`SessionProcess.c`: `if (PWAP || + // isPasswordNeeded) CheckPWAuthSession else CheckSessionHMAC`). Note the order: + // a policy session on which TPM2_PolicyPassword ran sends the authValue in the + // clear, every other non-PWAP session sends a computed HMAC — including a policy + // session that has run no PolicyAuthValue, which used to send an empty field and + // so could not be salted or bound at all. + if session.needs_password { + if i < self.in_handles.len() { + auth_cmd.hmac = self.in_handles[i].auth_value.clone(); + } + } else { // Calculate HMAC based on CpHash - let cp_hash = Crypto::hash(&self.crypto, session.get_hash_alg(), &cp_hash_data)?; + let cp_hash = + Crypto::hash(&self.crypto, session.get_hash_alg(), &cp_hash_data)?; auth_cmd.hmac = session.get_auth_hmac( &self.crypto, cp_hash, @@ -883,8 +1265,6 @@ impl Tpm2 { &self.nonce_tpm_enc, h_copy.as_ref(), )?; - } else if session.needs_password { - auth_cmd.hmac = self.in_handles[i].auth_value.clone(); } auth_cmd.toTpm(cmd_buf)?; @@ -1045,6 +1425,59 @@ impl Tpm2 { Crypto::hash(&self.crypto, hash_alg, data_to_hash) } + /// The session attributes to carry into the next command on a session, given what the caller + /// asked for and what the TPM answered. + /// + /// This is decided bit by bit, because `TPMA_SESSION` (TPM 2.0 Part 2, §8.4) is not one + /// decision: + /// + /// * `encrypt` (0x40), `decrypt` (0x20) and `audit` (0x80) say how the caller intends to use + /// the session, and hold until the caller says otherwise. They are kept exactly as + /// requested and are never sourced from the response, which is attacker-reachable where + /// the request is not: a response that cleared `encrypt`/`decrypt` would otherwise have + /// this client send the next command's first parameter in the clear, and one that cleared + /// `audit` would silently stop a session audit that the caller believes is running. + /// Part 2 has the TPM echo all three ("in a response, the attribute is copied from the + /// request", "if SET in the command, then this attribute will be SET in the response"), so + /// the response is at most a confirmation; for `encrypt`/`decrypt` the caller checks it + /// above and refuses to continue if it disagrees. + /// + /// * `auditReset` (0x4) and `auditExclusive` (0x2) are conditions on the single command that + /// carried them, not properties of the session. `auditReset` tells the TPM to initialize + /// the session's audit digest, so resending it would re-initialize that digest before + /// every later command and the session audit would only ever cover the most recent one + /// instead of accumulating over the session (TPM 2.0 Part 1, §21, audit; ms-tpm-20-ref + /// `SessionProcess.c`, `UpdateAuditSessionStatus`, calls `InitAuditSession` whenever the + /// bit is set). + /// `auditExclusive` asks the TPM to run the command only if the session is exclusive at + /// its start, and resending it turns a one-off precondition into a standing one that fails + /// with TPM_RC_EXCLUSIVE as soon as another audited command intervenes. Both are cleared + /// here. + /// + /// They cannot be consumed by taking the response's byte instead. `auditExclusive` in a + /// response is the TPM's report of whether the session *is* exclusive and is normally SET + /// there, and `auditReset`, which Part 2 says "is always CLEAR in a response", is in fact + /// echoed back verbatim by the reference implementation (ms-tpm-20-ref rewrites only + /// `auditExclusive` before marshaling the response attributes) — that is, by the simulator + /// this client is tested against. Consuming them here does not depend on either. + /// + /// * `continueSession` (0x1) is the one bit the TPM answers rather than echoes: CLEAR in a + /// response means it closed the session and freed the context when the command completed. + /// Keeping it SET would claim a session that no longer exists, so the response decides it. + /// See also [`Session::is_terminated`], which is what keeps such a session from being + /// handed back for reuse. + fn next_command_attributes(requested: TPMA_SESSION, returned: TPMA_SESSION) -> TPMA_SESSION { + let one_shot = + TPMA_SESSION::auditReset.get_value() | TPMA_SESSION::auditExclusive.get_value(); + let continue_session = TPMA_SESSION::continueSession.get_value(); + + let mut next = requested.get_value() & !one_shot; + if (returned.get_value() & continue_session) == 0 { + next &= !continue_session; + } + TPMA_SESSION(next) + } + /// Process response sessions fn process_resp_sessions( &mut self, @@ -1054,13 +1487,26 @@ impl Tpm2 { resp_params_size: usize, ) -> Result { let mut rp_ready = false; - resp_buf.set_current_pos(resp_params_pos + resp_params_size); + // The size came off the wire as a `u32`. On a 32-bit target the sum can wrap, and a + // wrapped position looks in bounds to `set_current_pos` and then panics the raw slice + // that computes rpHash further down. + let resp_params_end = resp_params_pos + .checked_add(resp_params_size) + .ok_or_else(|| { + TpmError::GenericError(format!( + "TPM response claims a {} B parameter area at offset {}, which is not a position \ + in any buffer", + resp_params_size, resp_params_pos + )) + })?; + resp_buf.set_current_pos(resp_params_end); resp_buf.check_status()?; // Pre-compute values needed for HMAC verification to avoid borrow conflicts let nonce_tpm_dec = self.nonce_tpm_dec.clone(); let nonce_tpm_enc = self.nonce_tpm_enc.clone(); let in_handles = self.in_handles.clone(); + let num_auth_handles = self.num_auth_handles; if let Some(ref mut sessions) = self.sessions { for (j, session) in sessions.iter_mut().enumerate() { @@ -1078,55 +1524,109 @@ impl Tpm2 { continue; } - // Non-PWAP session handling - let associated_handle = if j < in_handles.len() { - Some(&in_handles[j]) - } else { - None - }; + // Non-PWAP session handling. The predicate is the command side's, because the + // two HMAC keys have to be identical -- see `Tpm2::authorized_handle`. + let associated_handle = Self::authorized_handle(&in_handles, num_auth_handles, j); - // Update session data based on what the TPM just told us - session.sess_out.nonce = auth_response.nonce; + // Update session data based on what the TPM just told us. + // + // The response nonce and the response attributes are both inputs to the response + // HMAC, so they have to be in place before it is checked; if either was tampered + // with, the HMAC verification below is what catches it. + session.sess_out.nonce = auth_response.nonce.clone(); session.sess_out.sessionAttributes = auth_response.sessionAttributes; - // Update command attributes for next use - session.sess_in.sessionAttributes = auth_response.sessionAttributes; - - if session.session_type == TPM_SE::HMAC - || (session.session_type == TPM_SE::POLICY && session.needs_hmac) - { - // Compute rpHash inline to avoid borrow conflict with self - let rp_hash = { - let rp_header_size = 8; - let rp_hash_data_pos = resp_params_pos - rp_header_size; - - if !rp_ready { - let orig_cur_pos = resp_buf.current_pos(); - resp_buf.set_current_pos(rp_hash_data_pos); - resp_buf.writeInt(TPM_RC::SUCCESS.get_value()); - resp_buf.writeInt(cmd_code.get_value()); - resp_buf.set_current_pos(orig_cur_pos); - } - let data_to_hash = &resp_buf.buffer() - [rp_hash_data_pos..(rp_hash_data_pos + rp_header_size + resp_params_size)]; - Crypto::hash(&self.crypto, session.get_hash_alg(), data_to_hash)? - }; - rp_ready = true; + // What is NOT done here is copying the response attributes into `sess_in` for + // the next command. The response is attacker-reachable; the caller's requested + // attributes are not. Sourcing the next command's attributes from the response + // lets an adversary clear `encrypt`/`decrypt` and have this client send the next + // command's first parameter in the clear, while the calling code goes on + // believing the session encrypts. The caller's request stays authoritative. + // + // The TPM echoes `encrypt`/`decrypt` verbatim, so a differing echo means either + // tampering or a TPM that is not doing what was asked. Either way, stop. + let xcrypt_mask = + TPMA_SESSION::encrypt.get_value() | TPMA_SESSION::decrypt.get_value(); + let requested_xcrypt = session.sess_in.sessionAttributes.get_value() & xcrypt_mask; + let echoed_xcrypt = auth_response.sessionAttributes.get_value() & xcrypt_mask; + if requested_xcrypt != echoed_xcrypt { + return Err(TpmError::GenericError(format!( + "Session {} response echoed encrypt/decrypt attributes 0x{:02x} but \ + 0x{:02x} was requested", + j, echoed_xcrypt, requested_xcrypt + ))); + } - let expected_hmac = session.get_auth_hmac( - &self.crypto, - rp_hash, - false, - &nonce_tpm_dec, - &nonce_tpm_enc, - associated_handle, - )?; + // Not every bit is the caller's to keep, though: `TPMA_SESSION` is a byte of + // separate decisions, and only some of them describe the session rather than the + // one command that has just been answered. + session.sess_in.sessionAttributes = Self::next_command_attributes( + session.sess_in.sessionAttributes, + auth_response.sessionAttributes, + ); + + // The TPM returns an authorization HMAC for every session except a password + // session and a policy session on which TPM2_PolicyPassword has run; for those + // two it returns an empty field (`BuildSingleResponseAuth`). Everything else — + // an HMAC session, and equally a policy session driven by PolicyAuthValue, + // PolicyPCR, PolicySecret or nothing at all — is authenticated and must be + // verified. Skipping the policy cases left every response parameter they carried + // unauthenticated. This mirrors the command-side rule above. + if !session.expects_response_auth() { + if !auth_response.hmac.is_empty() { + return Err(TpmError::GenericError(format!( + "Session {} returned an authorization HMAC where none was expected", + j + ))); + } + continue; + } - if expected_hmac != auth_response.hmac { - return Err(TpmError::GenericError( - format!("Invalid TPM response HMAC (session {})", j), - )); + // Compute rpHash inline to avoid borrow conflict with self + let rp_hash = { + let rp_header_size = 8; + let rp_hash_data_pos = resp_params_pos - rp_header_size; + + if !rp_ready { + let orig_cur_pos = resp_buf.current_pos(); + resp_buf.set_current_pos(rp_hash_data_pos); + resp_buf.writeInt(TPM_RC::SUCCESS.get_value()); + resp_buf.writeInt(cmd_code.get_value()); + resp_buf.set_current_pos(orig_cur_pos); } + + let data_to_hash = &resp_buf.buffer() + [rp_hash_data_pos..(rp_hash_data_pos + rp_header_size + resp_params_size)]; + Crypto::hash(&self.crypto, session.get_hash_alg(), data_to_hash)? + }; + rp_ready = true; + + let expected_hmac = session.get_auth_hmac( + &self.crypto, + rp_hash, + false, + &nonce_tpm_dec, + &nonce_tpm_enc, + associated_handle, + )?; + + if auth_response.hmac.is_empty() { + return Err(TpmError::GenericError(format!( + "Session {} returned no authorization HMAC where one was expected", + j + ))); + } + + // Length first, because `ct_eq` is only defined for equal-length slices, and + // then a constant-time compare so that a wrong tag leaks nothing about how much + // of it was right. + let tag_ok = expected_hmac.len() == auth_response.hmac.len() + && bool::from(expected_hmac.ct_eq(&auth_response.hmac)); + if !tag_ok { + return Err(TpmError::GenericError(format!( + "Invalid TPM response HMAC (session {})", + j + ))); } } } @@ -1141,10 +1641,7 @@ impl Tpm2 { } /// Update request handles based on command - fn update_request_handles( - &mut self, - cmd_code: TPM_CC, - ) -> Result<(), TpmError> { + fn update_request_handles(&mut self, cmd_code: TPM_CC) -> Result<(), TpmError> { // Reset state self.object_in_name.clear(); @@ -1153,7 +1650,9 @@ impl Tpm2 { TPM_CC::HierarchyChangeAuth => { // Extract newAuth from the serialized parameters (TPM2B: 2-byte size + data) if self.last_cmd_params.len() >= 2 { - let size = u16::from_be_bytes([self.last_cmd_params[0], self.last_cmd_params[1]]) as usize; + let size = + u16::from_be_bytes([self.last_cmd_params[0], self.last_cmd_params[1]]) + as usize; if self.last_cmd_params.len() >= 2 + size { self.object_in_auth = self.last_cmd_params[2..2 + size].to_vec(); } @@ -1175,7 +1674,9 @@ impl Tpm2 { TPM_CC::NV_ChangeAuth => { // Extract newAuth from the serialized parameters (TPM2B: 2-byte size + data) if self.last_cmd_params.len() >= 2 { - let size = u16::from_be_bytes([self.last_cmd_params[0], self.last_cmd_params[1]]) as usize; + let size = + u16::from_be_bytes([self.last_cmd_params[0], self.last_cmd_params[1]]) + as usize; if self.last_cmd_params.len() >= 2 + size { self.object_in_auth = self.last_cmd_params[2..2 + size].to_vec(); } @@ -1185,7 +1686,9 @@ impl Tpm2 { TPM_CC::ObjectChangeAuth => { // Extract newAuth from the serialized parameters (TPM2B: 2-byte size + data) if self.last_cmd_params.len() >= 2 { - let size = u16::from_be_bytes([self.last_cmd_params[0], self.last_cmd_params[1]]) as usize; + let size = + u16::from_be_bytes([self.last_cmd_params[0], self.last_cmd_params[1]]) + as usize; if self.last_cmd_params.len() >= 2 + size { self.object_in_auth = self.last_cmd_params[2..2 + size].to_vec(); } @@ -1220,7 +1723,9 @@ impl Tpm2 { TPM_CC::HashSequenceStart => { // Extract auth from the serialized parameters (TPM2B: 2-byte size + data) if self.last_cmd_params.len() >= 2 { - let size = u16::from_be_bytes([self.last_cmd_params[0], self.last_cmd_params[1]]) as usize; + let size = + u16::from_be_bytes([self.last_cmd_params[0], self.last_cmd_params[1]]) + as usize; if self.last_cmd_params.len() >= 2 + size { self.object_in_auth = self.last_cmd_params[2..2 + size].to_vec(); } @@ -1290,8 +1795,80 @@ impl Tpm2 { } } - /// Update response handle with name and auth value - fn update_resp_handle( + /// The public area a command supplies for the object it loads. + /// + /// `TPM2_Load` and `TPM2_LoadExternal` take the public area as an input and return only the + /// handle and the Name, so this is the only place it can be had from. + fn request_object_public( + cmd_code: TPM_CC, + req: &R, + ) -> Option { + let req = req as &dyn Any; + match cmd_code { + TPM_CC::Load => req + .downcast_ref::() + .map(|r| r.inPublic.clone()), + TPM_CC::LoadExternal => req + .downcast_ref::() + .map(|r| r.inPublic.clone()), + _ => None, + } + } + + /// The public area a response carries for the object the command created. + fn response_object_public( + cmd_code: TPM_CC, + resp: &T, + ) -> Option<&TPMT_PUBLIC> { + let resp = resp as &dyn Any; + match cmd_code { + TPM_CC::CreatePrimary => resp + .downcast_ref::() + .map(|r| &r.outPublic), + TPM_CC::CreateLoaded => resp + .downcast_ref::() + .map(|r| &r.outPublic), + _ => None, + } + } + + /// Bind the response handle to the new object's Name, recomputing that Name wherever this + /// client holds the public area it is derived from. + /// + /// The Name of a TPM object is `nameAlg || H_nameAlg(publicArea)` (TPM 2.0 Part 1, §16), so + /// it is a value this client can derive for itself instead of taking the TPM's word for it. + /// Recomputing it is a **consistency check**: it catches a TPM, resource manager or + /// transport that reports a Name which does not belong to the public area it reported + /// alongside it, and it stops that inconsistent Name from being written into the handle and + /// silently folded into every later cpHash, policy digest and Name comparison. + /// + /// It is **not** authentication, **not** a defence against an active man in the middle, and + /// **not** evidence that the object lives in a TPM. An adversary who supplies the public + /// area supplies the Name that matches it and the check passes: the Name is a digest over + /// bytes the adversary chose. Its worth beyond catching malfunctions is as a building block + /// for a caller who knows which Name to expect — pinned out of band, from an enrolment + /// record or a signed manifest — and [`TrustedPublic::from_pinned_name`] is where that + /// comparison belongs. + /// + /// The check runs after the command has succeeded, so a failure means the TPM has loaded an + /// object this client is about to refuse to hand back. `flush_orphaned_handle` flushes it, + /// rather than leaving a transient slot occupied by an object no caller can name. + /// + /// What is available to check against differs by command, and the difference is not + /// cosmetic: + /// + /// * `TPM2_CreatePrimary` and `TPM2_CreateLoaded` return `outPublic`, so the Name is checked + /// against the response's own public area. + /// * `TPM2_Load` and `TPM2_LoadExternal` do not: the public area is a command *input*, and + /// the response carries only the handle and the Name. Those two are checked against the + /// `inPublic` the caller passed, captured at dispatch time — a stronger check than the + /// first two, since the public area it compares against is the caller's own. + /// * A caller that reaches [`Tpm2::dispatch`] with its own request or response type, rather + /// than the generated one, gets no check: there is nothing to recover the public area + /// from, and the Name is then taken on the TPM's word. + /// * `TPM2_HashSequenceStart` and `TPM2_HMAC_Start` return handles to objects that have no + /// public area and no Name, so there is nothing to check. + fn update_resp_handle( &mut self, cmd_code: TPM_CC, resp: &mut T, @@ -1299,6 +1876,36 @@ impl Tpm2 { match cmd_code { TPM_CC::Load | TPM_CC::CreatePrimary | TPM_CC::LoadExternal | TPM_CC::CreateLoaded => { let name = resp.get_resp_name(); + + let public = match cmd_code { + TPM_CC::CreatePrimary | TPM_CC::CreateLoaded => { + Self::response_object_public(cmd_code, resp).cloned() + } + _ => self.command_object_public.take(), + }; + + if let Some(public) = public { + // An object loaded with a nameAlg of TPM_ALG_NULL has no digest-based Name; + // TPM2_LoadExternal permits exactly that, and there is nothing to recompute. + if public.nameAlg != TPM_ALG_ID::NULL { + if let Err(err) = public.verify_name(&name, &self.crypto) { + // The command succeeded, so the object is loaded and occupying a + // transient slot. The caller is about to be handed an error instead + // of the handle, so this is the last point at which anything can + // flush it — and a TPM that reports a Name inconsistent with its own + // public area is not one to leave holding an unreachable object. + let handle = resp.get_handle(); + self.flush_orphaned_handle(&handle); + + return Err(TpmError::VerificationFailed(format!( + "{} returned an object Name that fails the consistency check \ + against its public area: {}", + cmd_code, err + ))); + } + } + } + if !name.is_empty() { let mut handle = resp.get_handle(); handle.set_name(&name)?; @@ -1306,9 +1913,7 @@ impl Tpm2 { } Ok(()) } - TPM_CC::HashSequenceStart | TPM_CC::HMAC_Start => { - Ok(()) - } + TPM_CC::HashSequenceStart | TPM_CC::HMAC_Start => Ok(()), _ => Ok(()), } } @@ -1316,27 +1921,13 @@ impl Tpm2 { /// Factory function to create a new TPM implementation based on the available platform, /// performing its host-side crypto with `crypto`. +/// +/// The platform is [`TpmTbsDevice`](crate::device::TpmTbsDevice)'s own concern — TBS on Windows, +/// `/dev/tpm*` or a resource manager socket on Linux, and elsewhere a stub that reports at +/// `connect` time that there is no TPM to talk to — so there is nothing to select between here. pub fn create_tpm_with_crypto(crypto: CryptoProvider) -> Tpm2 { - #[cfg(target_os = "windows")] - { - use crate::device::TpmTbsDevice; - Tpm2::new(Box::new(TpmTbsDevice::new()), crypto) - } - #[cfg(not(target_os = "windows"))] - { - use crate::device::{TpmTbsDevice, TpmTcpDevice}; - - // Try to create a TBS device first (for Linux/Unix), falling back to TCP simulator - let mut tbs_device = TpmTbsDevice::new(); - match tbs_device.connect() { - Ok(_) => Tpm2::new(tbs_device, crypto), - Err(_) => { - // Fall back to TCP simulator - let tcp_device = TpmTcpDevice::new("127.0.0.1".to_string(), 2321); - Tpm2::new(Box::new(tcp_device), crypto) - } - } - } + use crate::device::TpmTbsDevice; + Tpm2::new(Box::new(TpmTbsDevice::new()), crypto) } /// Factory function to create a new TPM implementation based on the available platform, using @@ -1354,3 +1945,1895 @@ pub fn create_tpm() -> Tpm2 { pub fn create_tpm_with_device(device: Box) -> Tpm2 { Tpm2::with_software_crypto(device) } + +/// An in-memory [`TpmDevice`] that replays canned response bytes. +/// +/// Without it nothing in this module is reachable from a test: the only real `TpmDevice` talks to +/// Windows TBS, so every session and authorization path here has historically been exercised only +/// by hand against hardware. +/// +/// Note what a mock device can and cannot establish. It can show that this client *reacts* +/// correctly to a given response — verifies what it should verify, refuses what it should refuse. +/// It cannot establish that a digest this client computes is the digest the TPM computes, because +/// the canned bytes are ours too. Tests of the second kind have to pin their expectations to +/// something outside this crate; see the `spec_*` helpers below, which are transcribed from the +/// TPM 2.0 specification rather than obtained from the code under test. +#[cfg(test)] +pub(crate) mod mock_device { + use super::*; + use std::collections::VecDeque; + use std::sync::{Arc, Mutex}; + + /// The bytes a [`MockTpmDevice`] returns for one response, derived from the command that was + /// just dispatched. + pub type Responder = Box Vec + Send>; + + /// Where a [`MockTpmDevice`] gets the bytes for one response. + pub enum MockResponse { + /// Fixed bytes, returned verbatim. + Canned(Vec), + /// Bytes derived from the command just dispatched. Needed whenever the response has to + /// be well formed with respect to values the client picked at random — the nonceCaller, + /// and the authorization HMAC computed over it. + Computed(Responder), + } + + pub struct MockTpmDevice { + responses: VecDeque, + commands: Arc>>>, + pending: Option>, + } + + impl MockTpmDevice { + pub fn new(responses: Vec) -> Self { + MockTpmDevice { + responses: responses.into_iter().collect(), + commands: Arc::new(Mutex::new(Vec::new())), + pending: None, + } + } + + /// A handle on the commands this device is sent, live for as long as the device is. + pub fn command_log(&self) -> Arc>>> { + Arc::clone(&self.commands) + } + } + + impl TpmDevice for MockTpmDevice { + fn connect(&mut self) -> Result { + Ok(true) + } + + fn close(&mut self) {} + + fn dispatch_command(&mut self, cmd_buf: &[u8]) -> Result<(), TpmError> { + self.commands.lock().unwrap().push(cmd_buf.to_vec()); + let response = self.responses.pop_front().ok_or_else(|| { + TpmError::GenericError("MockTpmDevice: no queued response".to_string()) + })?; + self.pending = Some(match response { + MockResponse::Canned(bytes) => bytes, + MockResponse::Computed(f) => f(cmd_buf), + }); + Ok(()) + } + + fn get_response(&mut self) -> Result, TpmError> { + self.pending.take().ok_or_else(|| { + TpmError::GenericError("MockTpmDevice: no response pending".to_string()) + }) + } + + fn response_is_ready(&self) -> Result { + Ok(self.pending.is_some()) + } + + fn has_flag(&self, _flag: u32) -> bool { + false + } + + fn get_tpm_info(&self) -> u32 { + 0 + } + } +} + +#[cfg(all(test, feature = "software-crypto"))] +mod tests { + use super::mock_device::{MockResponse, MockTpmDevice}; + use super::*; + use crate::crypto::software_provider::SOFTWARE_PROVIDER; + use crate::tpm_types::*; + use rand::rngs::OsRng; + use rsa::traits::PublicKeyParts; + use rsa::{Oaep, RsaPrivateKey}; + use sha1::Sha1; + use std::sync::{Arc, Mutex}; + + const LOCKOUT_AUTH: &[u8] = b"lockout-auth"; + const SALT: &[u8] = b"a thirty-two byte session salt.."; + + fn be16(buf: &[u8], pos: usize) -> u16 { + u16::from_be_bytes([buf[pos], buf[pos + 1]]) + } + + fn be32(buf: &[u8], pos: usize) -> u32 { + u32::from_be_bytes([buf[pos], buf[pos + 1], buf[pos + 2], buf[pos + 3]]) + } + + /// The first authorization area of a command. Layout from TPM 2.0 Part 1, §18.2: + /// `tag ‖ commandSize ‖ commandCode ‖ handles ‖ authorizationSize ‖ authorizationArea`. + struct CommandAuth { + nonce_caller: Vec, + attributes: u8, + hmac: Vec, + /// Offset just past the authorization area, which is where the command parameters start. + area_end: usize, + } + + /// Parse the single authorization area of a command with `num_handles` handles. + fn parse_command_auth(cmd: &[u8], num_handles: usize) -> CommandAuth { + let mut p = 2 + 4 + 4 + 4 * num_handles; // tag, commandSize, commandCode, handles + let auth_size = be32(cmd, p) as usize; + p += 4; + let auth_end = p + auth_size; + + p += 4; // sessionHandle + let nonce_len = be16(cmd, p) as usize; + p += 2; + let nonce_caller = cmd[p..p + nonce_len].to_vec(); + p += nonce_len; + let attributes = cmd[p]; + p += 1; + let hmac_len = be16(cmd, p) as usize; + p += 2; + let hmac = cmd[p..p + hmac_len].to_vec(); + p += hmac_len; + + assert_eq!( + p, auth_end, + "authorization area size does not match its contents" + ); + + CommandAuth { + nonce_caller, + attributes, + hmac, + area_end: auth_end, + } + } + + /// The authorization area of a `TPM2_Clear`, which has a single handle and no parameters. + fn parse_clear_command_auth(cmd: &[u8]) -> CommandAuth { + let auth = parse_command_auth(cmd, 1); + assert_eq!( + auth.area_end, + cmd.len(), + "TPM2_Clear should have no parameters" + ); + auth + } + + /// A `TPM_ST_SESSIONS` response for a command with no response handles, carrying `params` as + /// its response parameters and exactly one authorization area. + fn build_response_with_params( + params: &[u8], + nonce_tpm: &[u8], + attributes: u8, + hmac: &[u8], + ) -> Vec { + let mut auth = Vec::new(); + auth.extend_from_slice(&(nonce_tpm.len() as u16).to_be_bytes()); + auth.extend_from_slice(nonce_tpm); + auth.push(attributes); + auth.extend_from_slice(&(hmac.len() as u16).to_be_bytes()); + auth.extend_from_slice(hmac); + + let mut resp = Vec::new(); + resp.extend_from_slice(&TPM_ST::SESSIONS.get_value().to_be_bytes()); + resp.extend_from_slice(&((2 + 4 + 4 + 4 + params.len() + auth.len()) as u32).to_be_bytes()); + resp.extend_from_slice(&TPM_RC::SUCCESS.get_value().to_be_bytes()); // responseCode + resp.extend_from_slice(&(params.len() as u32).to_be_bytes()); // parameterSize + resp.extend_from_slice(params); + resp.extend_from_slice(&auth); + resp + } + + /// A `TPM_ST_SESSIONS` response for a command with no response handles and no response + /// parameters, carrying exactly one authorization area. + fn build_response(nonce_tpm: &[u8], attributes: u8, hmac: &[u8]) -> Vec { + build_response_with_params(&[], nonce_tpm, attributes, hmac) + } + + /// TPM 2.0 Part 1, §19.6.5 and §19.6.6: + /// ```text + /// rpHash := H_sessionAlg(responseCode ‖ commandCode ‖ parameters) + /// authHMAC := HMAC_sessionAlg(sessionKey ‖ authValue, + /// rpHash ‖ nonceTPM ‖ nonceCaller ‖ sessionAttributes) + /// ``` + /// (`nonceTPM` is the newer nonce on the response side, `nonceCaller` the older.) + fn spec_response_hmac_over( + key: &[u8], + cmd_code: TPM_CC, + params: &[u8], + nonce_tpm: &[u8], + nonce_caller: &[u8], + attributes: u8, + ) -> Vec { + let mut rp = Vec::new(); + rp.extend_from_slice(&TPM_RC::SUCCESS.get_value().to_be_bytes()); + rp.extend_from_slice(&cmd_code.get_value().to_be_bytes()); + rp.extend_from_slice(params); + let rp_hash = Crypto::hash(&SOFTWARE_PROVIDER, TPM_ALG_ID::SHA256, &rp).unwrap(); + + let mut buf = Vec::new(); + buf.extend_from_slice(&rp_hash); + buf.extend_from_slice(nonce_tpm); + buf.extend_from_slice(nonce_caller); + buf.push(attributes); + Crypto::hmac(&SOFTWARE_PROVIDER, TPM_ALG_ID::SHA256, key, &buf).unwrap() + } + + /// The TPM 2.0 response authorization HMAC, transcribed from the specification rather than + /// obtained from the code under test, for a response with no parameters. + fn spec_response_hmac( + key: &[u8], + cmd_code: TPM_CC, + nonce_tpm: &[u8], + nonce_caller: &[u8], + attributes: u8, + ) -> Vec { + spec_response_hmac_over(key, cmd_code, &[], nonce_tpm, nonce_caller, attributes) + } + + /// The TPM 2.0 command authorization HMAC, likewise transcribed from the specification. + /// + /// TPM 2.0 Part 1, §19.6.5, for a command with no parameters and no separate + /// encrypt/decrypt sessions: + /// ```text + /// cpHash := H_sessionAlg(commandCode ‖ name(s) ‖ parameters) + /// authHMAC := HMAC_sessionAlg(sessionKey ‖ authValue, + /// cpHash ‖ nonceCaller ‖ nonceTPM ‖ sessionAttributes) + /// ``` + fn spec_command_hmac( + key: &[u8], + cmd_code: TPM_CC, + handle_names: &[Vec], + nonce_caller: &[u8], + nonce_tpm: &[u8], + attributes: u8, + ) -> Vec { + let mut cp = Vec::new(); + cp.extend_from_slice(&cmd_code.get_value().to_be_bytes()); + for name in handle_names { + cp.extend_from_slice(name); + } + let cp_hash = Crypto::hash(&SOFTWARE_PROVIDER, TPM_ALG_ID::SHA256, &cp).unwrap(); + + let mut buf = Vec::new(); + buf.extend_from_slice(&cp_hash); + buf.extend_from_slice(nonce_caller); + buf.extend_from_slice(nonce_tpm); + buf.push(attributes); + Crypto::hmac(&SOFTWARE_PROVIDER, TPM_ALG_ID::SHA256, key, &buf).unwrap() + } + + /// A session as `TPM2_StartAuthSession` would have left it, built directly so that the test + /// knows the salt and therefore the session key. + fn make_session(session_type: TPM_SE, salt: &[u8]) -> Session { + Session::from_tpm_response( + &SOFTWARE_PROVIDER, + TPM_HANDLE::new(0x03000000), + session_type, + TPM_ALG_ID::SHA256, + vec![0xAA; 32], + vec![0xBB; 32], + TPMA_SESSION::continueSession, + TPMT_SYM_DEF::default(), + salt, + &TPM_HANDLE::new(TPM_RH::NULL.get_value()), + ) + .unwrap() + } + + /// A `Tpm2` over a mock device, with the lockout authValue set so that `TPM2_Clear` has a + /// non-empty authValue to fold into its HMAC key. + fn tpm_with(responses: Vec) -> (Tpm2, Arc>>>) { + let device = MockTpmDevice::new(responses); + let log = device.command_log(); + let mut tpm = Tpm2::with_software_crypto(Box::new(device)); + tpm.set_admin_auth(TPM_RH::LOCKOUT, LOCKOUT_AUTH); + (tpm, log) + } + + /// A responder that answers a `TPM2_Clear` with a correctly authenticated response. + /// + /// `key_for` turns the parsed command into the HMAC key the TPM would have used, so each + /// test states for itself what it believes the key is. + fn correct_responder( + nonce_tpm: Vec, + resp_attributes_of: fn(u8) -> u8, + key: Vec, + ) -> MockResponse { + MockResponse::Computed(Box::new(move |cmd: &[u8]| { + let auth = parse_clear_command_auth(cmd); + let resp_attrs = resp_attributes_of(auth.attributes); + let hmac = spec_response_hmac( + &key, + TPM_CC::Clear, + &nonce_tpm, + &auth.nonce_caller, + resp_attrs, + ); + build_response(&nonce_tpm, resp_attrs, &hmac) + })) + } + + fn echo(attrs: u8) -> u8 { + attrs + } + + // --------------------------------------------------------------------------------------- + // Item 7(a): which sessions carry a response authorization, and whether it is verified. + // --------------------------------------------------------------------------------------- + + #[test] + fn response_auth_is_verified_for_a_policy_session_without_policy_password() { + // A policy session that has run no PolicyAuthValue and no PolicyPassword. The TPM still + // authenticates the response with the session key, and this client used to skip the + // check entirely for exactly this case. + let session = make_session(TPM_SE::POLICY, SALT); + let key = session.session_key.clone(); + assert!(!key.is_empty(), "the salted session should have a key"); + assert!( + session.expects_response_auth(), + "the TPM authenticates this response, so the client has to check it" + ); + + let (mut tpm, _log) = tpm_with(vec![correct_responder(vec![0xC1; 32], echo, key.clone())]); + tpm.with_session(session.clone()); + + tpm.Clear(&TPM_HANDLE::new(TPM_RH::LOCKOUT.get_value())) + .expect("a correctly authenticated response should be accepted"); + + // The same session against a response whose tag is well formed, the right length, and + // keyed on the right session key -- but computed over a different nonceTPM from the one + // the response carries. Only a verifier that actually consumes nonceTPM rejects this, + // and a verifier that skips policy sessions altogether accepts it. + let sent_nonce = vec![0xC2; 32]; + let hmac_nonce = vec![0xC3; 32]; + let responder = MockResponse::Computed(Box::new(move |cmd: &[u8]| { + let auth = parse_clear_command_auth(cmd); + let hmac = spec_response_hmac( + &key, + TPM_CC::Clear, + &hmac_nonce, + &auth.nonce_caller, + auth.attributes, + ); + build_response(&sent_nonce, auth.attributes, &hmac) + })); + let (mut tpm, _log) = tpm_with(vec![responder]); + tpm.with_session(session); + + let err = tpm + .Clear(&TPM_HANDLE::new(TPM_RH::LOCKOUT.get_value())) + .expect_err("a tag computed over a nonce the response does not carry is not valid"); + assert!( + format!("{}", err).contains("Invalid TPM response HMAC"), + "unexpected error: {}", + err + ); + } + + #[test] + fn tampered_response_hmac_is_rejected() { + // The same exchange as above with one bit flipped in the tag. If verification were + // skipped — as it was — this would pass silently. + let session = make_session(TPM_SE::POLICY, SALT); + let key = session.session_key.clone(); + let nonce_tpm = vec![0xC1; 32]; + + let responder = MockResponse::Computed(Box::new(move |cmd: &[u8]| { + let auth = parse_clear_command_auth(cmd); + let mut hmac = spec_response_hmac( + &key, + TPM_CC::Clear, + &nonce_tpm, + &auth.nonce_caller, + auth.attributes, + ); + hmac[31] ^= 0x01; + build_response(&nonce_tpm, auth.attributes, &hmac) + })); + + let (mut tpm, _log) = tpm_with(vec![responder]); + tpm.with_session(session); + + let err = tpm + .Clear(&TPM_HANDLE::new(TPM_RH::LOCKOUT.get_value())) + .expect_err("a tampered response HMAC must be rejected"); + assert!( + format!("{:?}", err).contains("Invalid TPM response HMAC"), + "unexpected error: {:?}", + err + ); + } + + #[test] + fn response_auth_is_not_expected_after_policy_password() { + // TPM2_PolicyPassword makes the TPM authenticate the command with the authValue in the + // clear and return an empty response authorization (`BuildSingleResponseAuth`). Demanding + // one here would break every legitimate PolicyPassword session. + let mut session = make_session(TPM_SE::POLICY, SALT); + session.needs_password = true; + session.needs_hmac = false; + + let nonce_tpm = vec![0xC2; 32]; + let responder = MockResponse::Computed(Box::new(move |cmd: &[u8]| { + let auth = parse_clear_command_auth(cmd); + build_response(&nonce_tpm, auth.attributes, &[]) + })); + + let (mut tpm, _log) = tpm_with(vec![responder]); + tpm.with_session(session); + + tpm.Clear(&TPM_HANDLE::new(TPM_RH::LOCKOUT.get_value())) + .expect("an empty response auth is correct after TPM2_PolicyPassword"); + } + + #[test] + fn unexpected_response_auth_after_policy_password_is_rejected() { + let mut session = make_session(TPM_SE::POLICY, SALT); + session.needs_password = true; + session.needs_hmac = false; + + let nonce_tpm = vec![0xC3; 32]; + let responder = MockResponse::Computed(Box::new(move |cmd: &[u8]| { + let auth = parse_clear_command_auth(cmd); + build_response(&nonce_tpm, auth.attributes, &[0x00; 32]) + })); + + let (mut tpm, _log) = tpm_with(vec![responder]); + tpm.with_session(session); + + let err = tpm + .Clear(&TPM_HANDLE::new(TPM_RH::LOCKOUT.get_value())) + .expect_err("an authorization the TPM cannot have produced must be rejected"); + assert!( + format!("{:?}", err).contains("where none was expected"), + "unexpected error: {:?}", + err + ); + } + + #[test] + fn missing_response_auth_is_rejected_for_an_hmac_session() { + let session = make_session(TPM_SE::HMAC, SALT); + let nonce_tpm = vec![0xC4; 32]; + let responder = MockResponse::Computed(Box::new(move |cmd: &[u8]| { + let auth = parse_clear_command_auth(cmd); + build_response(&nonce_tpm, auth.attributes, &[]) + })); + + let (mut tpm, _log) = tpm_with(vec![responder]); + tpm.with_session(session); + + let err = tpm + .Clear(&TPM_HANDLE::new(TPM_RH::LOCKOUT.get_value())) + .expect_err("stripping the response authorization must not go unnoticed"); + assert!( + format!("{:?}", err).contains("no authorization HMAC where one was expected"), + "unexpected error: {:?}", + err + ); + } + + // --------------------------------------------------------------------------------------- + // Item 7(b): which session attributes the next command inherits, and from where. + // --------------------------------------------------------------------------------------- + + /// Run two `TPM2_Clear` commands on one session, the second on whatever `last_session()` + /// hands back, and return the session attribute byte each command carried. + /// + /// `resp_attributes_of` is what the TPM does to the request's attribute byte on the way + /// back, so a test can model a TPM that echoes a bit as readily as one that rewrites it. + fn attributes_of_two_commands( + requested: TPMA_SESSION, + resp_attributes_of: fn(u8) -> u8, + ) -> (u8, u8) { + let mut session = make_session(TPM_SE::HMAC, SALT); + session.sess_in.sessionAttributes = requested; + let key = { + let mut k = session.session_key.clone(); + k.extend_from_slice(LOCKOUT_AUTH); + k + }; + // `TPM2_Clear` sets lockoutAuth to the Empty Buffer, and this client follows the TPM in + // that (`complete_update_request_handles`), so the second command folds no authValue + // into its HMAC key and the key is the session key alone. + let key_after_clear = session.session_key.clone(); + + let (mut tpm, log) = tpm_with(vec![ + correct_responder(vec![0xD1; 32], resp_attributes_of, key), + correct_responder(vec![0xD2; 32], resp_attributes_of, key_after_clear), + ]); + + tpm.with_session(session); + tpm.Clear(&TPM_HANDLE::new(TPM_RH::LOCKOUT.get_value())) + .expect("the first command should be accepted"); + + let reused = tpm + .last_session() + .expect("the TPM left the session open, so it should come back for reuse"); + tpm.with_session(reused); + tpm.Clear(&TPM_HANDLE::new(TPM_RH::LOCKOUT.get_value())) + .expect("the second command should be accepted"); + + let commands = log.lock().unwrap(); + assert_eq!(commands.len(), 2, "both commands should have been sent"); + ( + parse_clear_command_auth(&commands[0]).attributes, + parse_clear_command_auth(&commands[1]).attributes, + ) + } + + #[test] + fn the_per_bit_attribute_policy_keeps_what_is_the_callers_and_consumes_what_is_not() { + let attrs = |bits: u8| TPMA_SESSION(bits); + let next = |requested: u8, returned: u8| { + Tpm2::next_command_attributes(attrs(requested), attrs(returned)).get_value() + }; + + let continue_session = TPMA_SESSION::continueSession.get_value(); + let audit_exclusive = TPMA_SESSION::auditExclusive.get_value(); + let audit_reset = TPMA_SESSION::auditReset.get_value(); + let decrypt = TPMA_SESSION::decrypt.get_value(); + let encrypt = TPMA_SESSION::encrypt.get_value(); + let audit = TPMA_SESSION::audit.get_value(); + + // How the caller means to use the session holds across commands. + let persistent = continue_session | decrypt | encrypt | audit; + assert_eq!(next(persistent, persistent), persistent); + + // The one-shot bits are consumed by the command that carried them, even when the TPM + // hands them straight back -- which is what the reference implementation does. + assert_eq!( + next( + continue_session | audit | audit_reset | audit_exclusive, + continue_session | audit | audit_reset | audit_exclusive, + ), + continue_session | audit, + ); + + // continueSession is the TPM's answer: CLEAR means it closed the session. + assert_eq!(next(continue_session | encrypt, encrypt), encrypt); + + // And nothing the response says can add an attribute to the next command. + assert_eq!(next(continue_session, 0xFF), continue_session); + } + + #[test] + fn session_attributes_are_not_taken_from_the_response() { + // The response is attacker-reachable and the request is not, so the caller's request + // decides the bits that describe the session. Here the TPM answers with auditExclusive + // SET -- its report that the session is exclusive, which is exactly what a TPM returns + // for an audit session that holds exclusivity (TPM 2.0 Part 2: "in a response, it + // indicates that the session is exclusive"). That report must not become the next + // command's "execute only if exclusive" precondition. + let mut session = make_session(TPM_SE::HMAC, SALT); + session.sess_in.sessionAttributes = TPMA_SESSION::continueSession | TPMA_SESSION::audit; + let requested = session.sess_in.sessionAttributes.get_value(); + let key = { + let mut k = session.session_key.clone(); + k.extend_from_slice(LOCKOUT_AUTH); + k + }; + let returned = requested | TPMA_SESSION::auditExclusive.get_value(); + + let (mut tpm, _log) = tpm_with(vec![correct_responder( + vec![0xC5; 32], + |attrs| attrs | TPMA_SESSION::auditExclusive.get_value(), + key, + )]); + tpm.with_session(session); + + tpm.Clear(&TPM_HANDLE::new(TPM_RH::LOCKOUT.get_value())) + .expect("a session the TPM reports as exclusive is still a usable session"); + + let after = tpm.last_session().expect("session should be retained"); + assert_eq!( + after.sess_in.sessionAttributes.get_value(), + requested, + "the next command's attributes must come from the caller, not the response" + ); + assert_eq!( + after.sess_out.sessionAttributes.get_value(), + returned, + "what the TPM actually returned should still be observable" + ); + } + + #[test] + fn audit_reset_is_not_resent_on_the_following_command() { + // auditReset tells the TPM to initialize the session's audit digest. It belongs to the + // one command that asked for it: resending it would re-initialize the digest before + // every later command, so the audit would only ever cover the most recent one instead of + // accumulating over the session. + // + // The TPM here echoes the bit back, which is what the reference implementation does + // (ms-tpm-20-ref rewrites only auditExclusive before marshaling the response + // attributes) even though Part 2 says the bit is always CLEAR in a response. So the + // client cannot rely on the response to consume it, and this test would pass for the + // wrong reason against a TPM that did clear it. + let requested = + TPMA_SESSION::continueSession | TPMA_SESSION::audit | TPMA_SESSION::auditReset; + + let (first, second) = attributes_of_two_commands(requested, echo); + + assert_eq!( + first, + requested.get_value(), + "the first command carries what the caller asked for" + ); + assert_eq!( + second, + (TPMA_SESSION::continueSession | TPMA_SESSION::audit).get_value(), + "auditReset is consumed by the command that carried it; audit and continueSession \ + are the caller's and stay" + ); + } + + #[test] + fn audit_exclusive_is_not_resent_on_the_following_command() { + // auditExclusive asks the TPM to run this one command only if the session is exclusive + // at its start. Carried forward it becomes a standing precondition the caller never + // asked for, and one that fails with TPM_RC_EXCLUSIVE the moment another audited + // command intervenes. The TPM here reports the session as exclusive, i.e. it answers + // with the bit SET, so consuming it cannot come from the response either. + let requested = + TPMA_SESSION::continueSession | TPMA_SESSION::audit | TPMA_SESSION::auditExclusive; + + let (first, second) = attributes_of_two_commands(requested, |attrs| { + attrs | TPMA_SESSION::auditExclusive.get_value() + }); + + assert_eq!( + first, + requested.get_value(), + "the first command carries what the caller asked for" + ); + assert_eq!( + second, + (TPMA_SESSION::continueSession | TPMA_SESSION::audit).get_value(), + "auditExclusive is a condition on one command, not a property of the session" + ); + } + + #[test] + fn encrypt_and_decrypt_survive_into_the_following_command() { + // The counterpart to the one-shot bits: parameter encryption is a standing decision of + // the caller's, and consuming or dropping it would silently send the next command's + // first parameter in the clear. + let requested = + TPMA_SESSION::continueSession | TPMA_SESSION::encrypt | TPMA_SESSION::decrypt; + + let (first, second) = attributes_of_two_commands(requested, echo); + + assert_eq!(first, requested.get_value()); + assert_eq!( + second, + requested.get_value(), + "encrypt/decrypt must still be set on the second command" + ); + } + + #[test] + fn a_session_the_tpm_closed_is_not_handed_back_for_reuse() { + // continueSession CLEAR in a response is the TPM saying it flushed the session when the + // command completed. The context is gone and the handle may later belong to an + // unrelated session, so there is nothing left to reuse and the client must not offer it. + let session = make_session(TPM_SE::HMAC, SALT); + let key = { + let mut k = session.session_key.clone(); + k.extend_from_slice(LOCKOUT_AUTH); + k + }; + + let (mut tpm, log) = tpm_with(vec![correct_responder(vec![0xC5; 32], |_| 0x00, key)]); + tpm.with_session(session); + + tpm.Clear(&TPM_HANDLE::new(TPM_RH::LOCKOUT.get_value())) + .expect("a TPM closing the session is a well formed response, not an error"); + + assert!( + tpm.last_session().is_none(), + "a session the TPM flushed must not come back for another command" + ); + assert!( + tpm.last_sessions().is_none(), + "and it must not come back through the plural accessor either" + ); + + // And take the reuse path a caller would take, so the assertion lands on the wire and + // not only on the accessor: with nothing handed back there is no second command, and + // the device's log would record one if there were -- it logs a command before it looks + // for a response to it, so this holds even with no second response queued. + if let Some(stale) = tpm.last_session() { + tpm.with_session(stale); + let _ = tpm.Clear(&TPM_HANDLE::new(TPM_RH::LOCKOUT.get_value())); + } + let commands = log.lock().unwrap(); + assert_eq!( + commands.len(), + 1, + "no command may go out on a session handle the TPM has flushed" + ); + } + + #[test] + fn a_response_that_adds_an_encrypt_attribute_is_rejected() { + // The echo check is not only about bits going missing. A response that claims the TPM + // encrypted a response parameter the caller never asked it to encrypt disagrees with + // the request just as much, and a client that took its attributes from the response + // would go on to encrypt the next command's first parameter on a session the caller + // never nominated for it. + let mut session = make_session(TPM_SE::HMAC, SALT); + session.sess_in.sessionAttributes = TPMA_SESSION::continueSession; + let key = { + let mut k = session.session_key.clone(); + k.extend_from_slice(LOCKOUT_AUTH); + k + }; + + let (mut tpm, _log) = tpm_with(vec![correct_responder( + vec![0xC7; 32], + |attrs| attrs | TPMA_SESSION::encrypt.get_value(), + key, + )]); + tpm.with_session(session); + + let err = tpm + .Clear(&TPM_HANDLE::new(TPM_RH::LOCKOUT.get_value())) + .expect_err("an encrypt/decrypt echo that disagrees with the request is rejected"); + assert!( + format!("{:?}", err).contains("echoed encrypt/decrypt attributes"), + "unexpected error: {:?}", + err + ); + } + + #[test] + fn a_response_that_drops_the_encrypt_attribute_is_rejected() { + // Stripping `encrypt` from the echo is how an adversary would try to talk this client + // out of encrypting the next command's first parameter. + let mut session = make_session(TPM_SE::HMAC, SALT); + session.sess_in.sessionAttributes = TPMA_SESSION::continueSession | TPMA_SESSION::encrypt; + let key = { + let mut k = session.session_key.clone(); + k.extend_from_slice(LOCKOUT_AUTH); + k + }; + + let (mut tpm, _log) = tpm_with(vec![correct_responder( + vec![0xC6; 32], + |attrs| attrs & !TPMA_SESSION::encrypt.get_value(), + key, + )]); + tpm.with_session(session); + + let err = tpm + .Clear(&TPM_HANDLE::new(TPM_RH::LOCKOUT.get_value())) + .expect_err("a downgraded encrypt/decrypt echo must be rejected"); + assert!( + format!("{:?}", err).contains("echoed encrypt/decrypt attributes"), + "unexpected error: {:?}", + err + ); + } + + // --------------------------------------------------------------------------------------- + // Command side: the rule the response side mirrors. + // --------------------------------------------------------------------------------------- + + #[test] + fn a_policy_session_without_policy_password_sends_a_command_hmac() { + // Previously this sent an empty authorization field, which is why a salted or bound + // policy session could not be used at all: the TPM computed an HMAC over its session key + // and got nothing to compare it with. + let session = make_session(TPM_SE::POLICY, SALT); + let key = session.session_key.clone(); + let expected_key = key.clone(); + + let (mut tpm, log) = tpm_with(vec![correct_responder(vec![0xC7; 32], echo, key)]); + tpm.with_session(session); + tpm.Clear(&TPM_HANDLE::new(TPM_RH::LOCKOUT.get_value())) + .unwrap(); + + let cmd = log.lock().unwrap()[0].clone(); + let auth = parse_clear_command_auth(&cmd); + // TPM2_Clear's one handle is TPM_RH_LOCKOUT, whose Name is the four-byte handle value + // (TPM 2.0 Part 1, §16: for a permanent handle the Name is the handle). + let name = TPM_RH::LOCKOUT.get_value().to_be_bytes().to_vec(); + assert_eq!( + auth.hmac, + spec_command_hmac( + &expected_key, + TPM_CC::Clear, + &[name], + &auth.nonce_caller, + &[0xBB; 32], + auth.attributes, + ), + "a policy session with no PolicyAuthValue keys its command HMAC on the session key \ + alone, with no authValue folded in" + ); + } + + #[test] + fn a_policy_password_session_sends_the_auth_value_in_the_command() { + let mut session = make_session(TPM_SE::POLICY, SALT); + session.needs_password = true; + session.needs_hmac = false; + + let nonce_tpm = vec![0xC8; 32]; + let responder = MockResponse::Computed(Box::new(move |cmd: &[u8]| { + let auth = parse_clear_command_auth(cmd); + build_response(&nonce_tpm, auth.attributes, &[]) + })); + + let (mut tpm, log) = tpm_with(vec![responder]); + tpm.with_session(session); + tpm.Clear(&TPM_HANDLE::new(TPM_RH::LOCKOUT.get_value())) + .unwrap(); + + let cmd = log.lock().unwrap()[0].clone(); + let auth = parse_clear_command_auth(&cmd); + assert_eq!( + auth.hmac, LOCKOUT_AUTH, + "after TPM2_PolicyPassword the authValue is sent in the clear, not HMAC'd" + ); + } + + #[test] + fn an_hmac_session_folds_the_auth_value_into_its_command_key() { + let session = make_session(TPM_SE::HMAC, SALT); + let mut key = session.session_key.clone(); + key.extend_from_slice(LOCKOUT_AUTH); + let responder_key = key.clone(); + + let (mut tpm, log) = tpm_with(vec![correct_responder(vec![0xC9; 32], echo, responder_key)]); + tpm.with_session(session); + tpm.Clear(&TPM_HANDLE::new(TPM_RH::LOCKOUT.get_value())) + .unwrap(); + + let cmd = log.lock().unwrap()[0].clone(); + let auth = parse_clear_command_auth(&cmd); + let name = TPM_RH::LOCKOUT.get_value().to_be_bytes().to_vec(); + assert_eq!( + auth.hmac, + spec_command_hmac( + &key, + TPM_CC::Clear, + &[name], + &auth.nonce_caller, + &[0xBB; 32], + auth.attributes, + ) + ); + } + + #[test] + fn a_non_empty_password_session_response_auth_is_rejected() { + // A password session's response authorization is fixed: empty nonce, empty HMAC. There + // is no key to check anything else with, so a response that fills either field did not + // come from a TPM applying the rules, and the only answer available is to refuse it. + // `a_password_session_expects_no_response_auth` in `auth_session` pins the flag; this + // pins what dispatch does when the flag says "nothing to check" and something arrives. + let cases: [(&[u8], &[u8]); 3] = [ + (&[], &[0x11; 32]), // an HMAC where none can exist + (&[0x22; 16], &[]), // a nonce a password session never has + (&[0x22; 16], &[0x11; 32]), // both + ]; + + for (nonce, hmac) in cases { + let (mut tpm, _log) = tpm_with(vec![MockResponse::Canned(build_response( + nonce, + TPMA_SESSION::continueSession.get_value(), + hmac, + ))]); + + let err = tpm + .Clear(&TPM_HANDLE::new(TPM_RH::LOCKOUT.get_value())) + .expect_err("a password session's response carries no authorization to check"); + assert!( + format!("{}", err).contains("Bad value in PWAP session response"), + "unexpected error for nonce {:?} hmac {:?}: {}", + nonce, + hmac, + err + ); + } + } + + #[test] + fn a_handle_the_command_does_not_authorize_is_absent_from_the_response_hmac_key() { + // TPM2_ContextSave names one handle and authorizes none: saving a context needs no + // authorization, so a session attached to it is there for auditing or parameter + // encryption, not to authorize `saveHandle`. Its HMAC key is the session key alone, even + // though the handle beside it carries an authValue -- the caller set one because the + // object needs it for every *other* command. + // + // The command side has always applied that rule. The response side keyed on whichever + // handle sat at the session's index, authorized or not, so it folded in an authValue the + // command's key did not have and rejected a correct response. The same disagreement is + // reachable with a second session on TPM2_Duplicate, whose newParentHandle the command + // does not authorize. + let session = make_session(TPM_SE::HMAC, SALT); + let key = session.session_key.clone(); + + let mut save_handle = TPM_HANDLE::new(OBJECT_HANDLE); + save_handle + .set_name(&name_of(&sample_public(0x88))) + .unwrap(); + save_handle.set_auth(b"object-auth"); + + let params = ContextSaveResponse { + context: TPMS_CONTEXT::new( + 7, + &TPM_HANDLE::new(OBJECT_HANDLE), + &TPM_HANDLE::new(TPM_RH::OWNER.get_value()), + &TPMS_CONTEXT_DATA::default(), + ), + } + .toBytes() + .unwrap(); + + let nonce_tpm = vec![0xCB; 32]; + let responder = MockResponse::Computed(Box::new(move |cmd: &[u8]| { + let auth = parse_command_auth(cmd, 1); + let hmac = spec_response_hmac_over( + &key, + TPM_CC::ContextSave, + ¶ms, + &nonce_tpm, + &auth.nonce_caller, + auth.attributes, + ); + build_response_with_params(¶ms, &nonce_tpm, auth.attributes, &hmac) + })); + + let (mut tpm, _log) = tpm_with(vec![responder]); + tpm.with_session(session); + + tpm.ContextSave(&save_handle) + .expect("the response HMAC key must be the one the command's HMAC was keyed on"); + } + + // --------------------------------------------------------------------------------------- + // Response code decoding: the shape of an ordinary TPM failure. + // --------------------------------------------------------------------------------------- + /// A response with the given code and body. `TPM_ST_NO_SESSIONS` is the tag a TPM uses for + /// an error response, and for any command dispatched without an authorization session. + fn response(tag: TPM_ST, response_code: u32, body: &[u8]) -> Vec { + let mut resp = Vec::new(); + resp.extend_from_slice(&tag.get_value().to_be_bytes()); + resp.extend_from_slice(&((10 + body.len()) as u32).to_be_bytes()); + resp.extend_from_slice(&response_code.to_be_bytes()); + resp.extend_from_slice(body); + resp + } + + fn error_response(response_code: u32) -> MockResponse { + MockResponse::Canned(response(TPM_ST::NO_SESSIONS, response_code, &[])) + } + + /// A `TPM2_GetRandom` response carrying `bytes`. + fn get_random_response(bytes: &[u8]) -> MockResponse { + let mut body = Vec::new(); + body.extend_from_slice(&(bytes.len() as u16).to_be_bytes()); + body.extend_from_slice(bytes); + MockResponse::Canned(response(TPM_ST::NO_SESSIONS, 0, &body)) + } + + #[test] + fn format_one_response_codes_decode_to_their_base_error_and_index() { + // Every one of these is a value a TPM puts on the wire, and none of them is a member of + // the generated TPM_RC enumeration: a format-1 code folds a parameter, handle or session + // number into the value, so running it through `TPM_RC::try_from` reports "Invalid enum + // value" and throws the real error away. + for raw in [0x1D5u32, 0x1C5, 0x18B, 0x98E, 0xD5, 0xC4] { + assert!( + TPM_RC::try_from(raw).is_err(), + "0x{:X} is deliberately absent from the generated TPM_RC match", + raw + ); + } + + // TPM_RC_SIZE (0x095) against parameter 1: RC_FMT1 | RC_P | RC_1. + let size_of_parm_1 = ResponseCode::decode(0x1D5); + assert_eq!(size_of_parm_1.raw(), 0x1D5); + assert_eq!(size_of_parm_1.code(), TPM_RC::SIZE); + assert_eq!(size_of_parm_1.index(), RcIndex::Parameter(1)); + + // TPM_RC_HIERARCHY (0x085) against parameter 1. + let hierarchy_of_parm_1 = ResponseCode::decode(0x1C5); + assert_eq!(hierarchy_of_parm_1.code(), TPM_RC::HIERARCHY); + assert_eq!(hierarchy_of_parm_1.index(), RcIndex::Parameter(1)); + + // TPM_RC_HANDLE (0x08B) against handle 1: RC_FMT1 | RC_1, with RC_P clear. + let handle_1 = ResponseCode::decode(0x18B); + assert_eq!(handle_1.code(), TPM_RC::HANDLE); + assert_eq!(handle_1.index(), RcIndex::Handle(1)); + + // TPM_RC_AUTH_FAIL (0x08E) against session 1: RC_FMT1 | RC_S | RC_1. + let auth_fail_of_session_1 = ResponseCode::decode(0x98E); + assert_eq!(auth_fail_of_session_1.code(), TPM_RC::AUTH_FAIL); + assert_eq!(auth_fail_of_session_1.index(), RcIndex::Session(1)); + + // A format-1 code with no number field names no particular element. + assert_eq!(ResponseCode::decode(0xD5).code(), TPM_RC::SIZE); + assert_eq!(ResponseCode::decode(0xD5).index(), RcIndex::Unspecified); + } + + #[test] + fn format_zero_response_codes_are_left_alone() { + // Format-0 codes carry no index, and must survive decoding unchanged. + for (raw, expected) in [ + (0x000u32, TPM_RC::SUCCESS), + (0x101, TPM_RC::FAILURE), + (0x921, TPM_RC::LOCKOUT), + (0x922, TPM_RC::RETRY), + ] { + let decoded = ResponseCode::decode(raw); + assert_eq!(decoded.code(), expected, "0x{:X}", raw); + assert_eq!(decoded.index(), RcIndex::Unspecified, "0x{:X}", raw); + assert_eq!(decoded.raw(), raw); + } + assert!(ResponseCode::decode(0).is_success()); + + // A code the TSS communication layer generated is not a TPM response code and none of + // the TPM's bit assignments apply to it. + let comm_error = ResponseCode::decode(0x80280002); + assert_eq!(comm_error.code(), TPM_RC(0x80280002)); + assert_eq!(comm_error.index(), RcIndex::Unspecified); + } + + #[test] + fn a_format_one_error_surfaces_as_the_error_the_tpm_reported() { + let (mut tpm, _log) = tpm_with(vec![error_response(0x1D5)]); + + let err = tpm + .GetRandom(20) + .expect_err("the TPM reported a failure code"); + let text = format!("{}", err); + assert!( + !text.contains("Invalid enum value"), + "the real response code must not be discarded: {}", + text + ); + assert!(text.contains("SIZE"), "unexpected error: {}", text); + assert!(text.contains("parameter 1"), "unexpected error: {}", text); + + assert_eq!(tpm.last_response_code(), TPM_RC::SIZE); + + let last = tpm + .last_error() + .expect("last_error() must be populated for a TPM failure"); + assert_eq!(last.response_code, TPM_RC::SIZE); + assert_eq!( + last.raw_response_code, 0x1D5, + "the code as it arrived must be preserved, not just its masked form" + ); + assert_eq!(last.index, RcIndex::Parameter(1)); + assert_eq!(last.command_code, TPM_CC::GetRandom); + } + + #[test] + fn last_error_is_cleared_by_a_command_that_succeeds() { + let (mut tpm, _log) = + tpm_with(vec![error_response(0x1D5), get_random_response(&[0xAB; 8])]); + + assert!(tpm.GetRandom(20).is_err()); + assert!(tpm.last_error().is_some()); + + assert_eq!(tpm.GetRandom(8).unwrap(), vec![0xAB; 8]); + assert_eq!(tpm.last_response_code(), TPM_RC::SUCCESS); + assert!( + tpm.last_error().is_none(), + "a successful command must not leave the previous failure behind" + ); + } + + // --------------------------------------------------------------------------------------- + // TPM_RC_RETRY: the TPM was busy and did not act on the command. + // --------------------------------------------------------------------------------------- + + #[test] + fn a_command_the_tpm_asks_to_retry_is_resent_and_can_succeed() { + let (mut tpm, log) = tpm_with(vec![ + error_response(TPM_RC::RETRY.get_value()), + get_random_response(&[0xAB; 8]), + ]); + + // This used to be impossible: the retry path left `current_cmd_code` set, so the resend + // failed with "Pending async command must be completed before issuing the next command." + let out = tpm + .GetRandom(8) + .expect("a command the TPM asked to retry should be able to complete"); + assert_eq!(out, vec![0xAB; 8]); + + let commands = log.lock().unwrap(); + assert_eq!( + commands.len(), + 2, + "the command should have been resent once" + ); + assert_eq!( + commands[0], commands[1], + "the resend should be the same command, byte for byte" + ); + } + + #[test] + fn a_tpm_that_never_stops_retrying_terminates_with_an_error() { + let responses = (0..64) + .map(|_| error_response(TPM_RC::RETRY.get_value())) + .collect(); + let (mut tpm, log) = tpm_with(responses); + + let start = std::time::Instant::now(); + let err = tpm + .GetRandom(8) + .expect_err("an unending retry must not loop forever"); + let elapsed = start.elapsed(); + + assert!( + format!("{}", err).contains("RETRY"), + "the caller should be told why: {}", + err + ); + assert_eq!( + log.lock().unwrap().len() as u32, + Tpm2::MAX_RETRIES + 1, + "the command should be sent once and then retried a bounded number of times" + ); + assert!( + elapsed < std::time::Duration::from_secs(3), + "a bounded backoff, not a flat second of blocking per attempt: {:?}", + elapsed + ); + } + + #[test] + fn a_retried_command_with_a_password_session_is_resent_unchanged() { + // The resend re-marshals the request, including the authorization area. A password + // session has no nonce to roll and no HMAC to recompute, so its authorization area is a + // constant and the second command is byte for byte the first. That is a property of + // password sessions specifically -- see the HMAC session case below. + let public = sample_public(0x77); + let name = name_of(&public); + let (mut tpm, log) = tpm_with(vec![ + error_response(TPM_RC::RETRY.get_value()), + create_primary_response(&public, &name), + ]); + + create_primary(&mut tpm, &public).expect("the resend should carry a valid authorization"); + + let commands = log.lock().unwrap(); + assert_eq!( + commands.len(), + 2, + "the command should have been resent once" + ); + assert_eq!( + commands[0], commands[1], + "the resend should be the same command, authorization area included" + ); + } + + #[test] + fn a_retried_command_with_an_hmac_session_rerolls_its_nonce_and_still_verifies() { + // `dispatch_command` calls `roll_nonces` on every attempt, so a session with a real + // nonce does not resend the same bytes: nonceCaller is fresh and the command HMAC is + // recomputed over it. What has to survive the retry is not the encoding but the + // authorization -- the second attempt must be one the TPM accepts, and its response must + // still verify against the nonce that attempt actually sent. + let session = make_session(TPM_SE::HMAC, SALT); + let mut key = session.session_key.clone(); + key.extend_from_slice(LOCKOUT_AUTH); + + let (mut tpm, log) = tpm_with(vec![ + error_response(TPM_RC::RETRY.get_value()), + correct_responder(vec![0xCC; 32], echo, key.clone()), + ]); + tpm.with_session(session); + + tpm.Clear(&TPM_HANDLE::new(TPM_RH::LOCKOUT.get_value())) + .expect("the resent command and its response authorization must agree"); + + let commands = log.lock().unwrap(); + assert_eq!( + commands.len(), + 2, + "the command should have been resent once" + ); + assert_ne!( + commands[0], commands[1], + "a session with a nonce cannot resend the same bytes" + ); + + let first = parse_clear_command_auth(&commands[0]); + let second = parse_clear_command_auth(&commands[1]); + assert_ne!( + first.nonce_caller, second.nonce_caller, + "each attempt gets a fresh nonceCaller" + ); + let name = TPM_RH::LOCKOUT.get_value().to_be_bytes().to_vec(); + assert_eq!( + second.hmac, + spec_command_hmac( + &key, + TPM_CC::Clear, + &[name], + &second.nonce_caller, + &[0xBB; 32], + second.attributes, + ), + "the retry's HMAC must be over the nonce the retry sent" + ); + } + + // --------------------------------------------------------------------------------------- + // Object Names: a consistency check between the Name a command reports and the public area + // that Name is a digest over. Not authentication, and no defence against an adversary who + // supplies both -- see `Tpm2::update_resp_handle`. + // --------------------------------------------------------------------------------------- + + /// A minimal keyed-hash public area, distinguished by its `unique` field so that two of them + /// have different Names. + fn sample_public(unique: u8) -> TPMT_PUBLIC { + let parameters = TPMU_PUBLIC_PARMS::keyedHashDetail(TPMS_KEYEDHASH_PARMS::new(&Some( + TPMU_SCHEME_KEYEDHASH::hmac(TPMS_SCHEME_HMAC { + hashAlg: TPM_ALG_ID::SHA256, + }), + ))); + let unique = TPMU_PUBLIC_ID::keyedHash(TPM2B_DIGEST_KEYEDHASH { + buffer: vec![unique; 32], + }); + TPMT_PUBLIC::new( + TPM_ALG_ID::SHA256, + TPMA_OBJECT::sign | TPMA_OBJECT::userWithAuth, + &Vec::new(), + &Some(parameters), + &Some(unique), + ) + } + + fn name_of(public: &TPMT_PUBLIC) -> Vec { + public.get_name(&SOFTWARE_PROVIDER).unwrap() + } + + const OBJECT_HANDLE: u32 = 0x80000001; + + /// A `TPM2_LoadExternal` response: a transient object handle and the object's Name. + fn load_external_response(name: &[u8]) -> MockResponse { + let mut body = Vec::new(); + body.extend_from_slice(&OBJECT_HANDLE.to_be_bytes()); + body.extend_from_slice(&(name.len() as u16).to_be_bytes()); + body.extend_from_slice(name); + MockResponse::Canned(response(TPM_ST::NO_SESSIONS, 0, &body)) + } + + fn load_external(tpm: &mut Tpm2, public: &TPMT_PUBLIC) -> Result { + tpm.LoadExternal( + &TPMT_SENSITIVE::default(), + public, + &TPM_HANDLE::new(TPM_RH::NULL.get_value()), + ) + } + + /// A `TPM2_CreatePrimary` response, authorized by the password session the client creates + /// for the one auth handle: empty nonce, empty HMAC. + fn create_primary_response(public: &TPMT_PUBLIC, name: &[u8]) -> MockResponse { + let params = CreatePrimaryResponse { + outPublic: public.clone(), + creationHash: vec![0u8; 32], + creationTicket: TPMT_TK_CREATION::new( + &TPM_HANDLE::new(TPM_RH::OWNER.get_value()), + &vec![0u8; 32], + ), + name: name.to_vec(), + ..Default::default() + }; + let params = params.toBytes().unwrap(); + + let mut body = Vec::new(); + body.extend_from_slice(&OBJECT_HANDLE.to_be_bytes()); + body.extend_from_slice(&(params.len() as u32).to_be_bytes()); + body.extend_from_slice(¶ms); + body.extend_from_slice(&0u16.to_be_bytes()); // nonce + body.push(TPMA_SESSION::continueSession.get_value()); + body.extend_from_slice(&0u16.to_be_bytes()); // hmac + MockResponse::Canned(response(TPM_ST::SESSIONS, 0, &body)) + } + + fn create_primary(tpm: &mut Tpm2, public: &TPMT_PUBLIC) -> Result { + tpm.CreatePrimary( + &TPM_HANDLE::new(TPM_RH::OWNER.get_value()), + &TPMS_SENSITIVE_CREATE::new(&Vec::new(), &Vec::new()), + public, + &Vec::new(), + &Vec::new(), + ) + .map(|resp| resp.handle) + } + + #[test] + fn create_primary_accepts_a_name_that_matches_the_public_area_it_returned() { + let public = sample_public(0x11); + let name = name_of(&public); + let (mut tpm, _log) = tpm_with(vec![create_primary_response(&public, &name)]); + + let handle = create_primary(&mut tpm, &public) + .expect("a Name consistent with outPublic must be accepted"); + assert_eq!(handle.get_name().unwrap(), name); + } + + #[test] + fn create_primary_rejects_a_name_that_disagrees_with_the_public_area_it_returned() { + // The Name of a different public area: the inconsistency a malfunctioning TPM or + // resource manager produces, and which used to be copied into the handle unexamined. + let public = sample_public(0x11); + let wrong_name = name_of(&sample_public(0x22)); + let (mut tpm, _log) = tpm_with(vec![create_primary_response(&public, &wrong_name)]); + + let err = create_primary(&mut tpm, &public) + .expect_err("a Name that is not a digest over the returned public area is bogus"); + assert!( + format!("{}", err).contains("consistency check"), + "unexpected error: {}", + err + ); + } + + #[test] + fn load_external_accepts_a_name_that_matches_the_public_area_it_was_given() { + // TPM2_LoadExternal returns only a handle and a Name -- the public area was a command + // input -- so the Name is checked against the caller's own `inPublic`. + let public = sample_public(0x33); + let name = name_of(&public); + let (mut tpm, _log) = tpm_with(vec![load_external_response(&name)]); + + let handle = load_external(&mut tpm, &public).expect("a consistent Name must be accepted"); + assert_eq!(handle.get_name().unwrap(), name); + } + + #[test] + fn load_external_rejects_a_name_that_disagrees_with_the_public_area_it_was_given() { + let public = sample_public(0x33); + let wrong_name = name_of(&sample_public(0x44)); + let (mut tpm, _log) = tpm_with(vec![load_external_response(&wrong_name)]); + + let err = load_external(&mut tpm, &public) + .expect_err("the TPM's Name must agree with the public area it was handed"); + assert!( + format!("{}", err).contains("consistency check"), + "unexpected error: {}", + err + ); + } + + /// A `TPM2_FlushContext` response: no handles, no parameters, no sessions. + fn flush_context_response() -> MockResponse { + MockResponse::Canned(response(TPM_ST::NO_SESSIONS, 0, &[])) + } + + /// Assert that `cmd` is a `TPM2_FlushContext` for `handle`. + /// + /// `flushHandle` is a *parameter* of TPM2_FlushContext rather than a handle-area handle, so + /// it follows the header directly: `tag ‖ commandSize ‖ commandCode ‖ flushHandle`. + fn assert_flush_of(cmd: &[u8], handle: u32) { + assert_eq!( + be32(cmd, 6), + TPM_CC::FlushContext.get_value(), + "expected a TPM2_FlushContext" + ); + assert_eq!(be32(cmd, 10), handle, "flushed the wrong handle"); + assert_eq!(cmd.len(), 14, "TPM2_FlushContext takes one handle value"); + } + + #[test] + fn a_create_primary_name_is_checked_against_its_own_public_area() { + // Two commands supply the public area a Name is checked against in opposite ways: + // TPM2_LoadExternal takes it as an input, which the client captures at dispatch, while + // TPM2_CreatePrimary returns it in the response. A CreatePrimary must be checked + // against its own `outPublic` and never against a public area some earlier command + // captured. + // + // The sequence below is the one that would expose the confusion: a LoadExternal that + // captures `first`, then a command that supplies no public area at all, then a + // CreatePrimary that returns `second` but reports the Name of `first`. If the captured + // input area were what CreatePrimary compared the Name against, that response would be + // accepted. Today `dispatch_command` overwrites the captured area on every command, so + // this pins the rule rather than catching a live leak -- but the rule is what keeps a + // Name check meaningful, and both halves of it (per-command capture, and the choice of + // which area to compare against) have to hold for it to stay that way. + let first = sample_public(0x55); + let second = sample_public(0x66); + let (mut tpm, log) = tpm_with(vec![ + load_external_response(&name_of(&first)), + get_random_response(&[0xAB; 8]), + create_primary_response(&second, &name_of(&first)), + flush_context_response(), + ]); + + load_external(&mut tpm, &first).expect("the load is consistent with its own public area"); + assert!( + tpm.command_object_public.is_none(), + "a captured input public area belongs to the command that supplied it and must not \ + outlive it" + ); + + tpm.GetRandom(8) + .expect("a command that supplies no public area at all"); + assert!( + tpm.command_object_public.is_none(), + "a command that supplies no public area must leave none behind either" + ); + + let err = create_primary(&mut tpm, &second).expect_err( + "the Name belongs to a public area this response did not return, so it is bogus", + ); + assert!( + format!("{}", err).contains("consistency check"), + "unexpected error: {}", + err + ); + + let commands = log.lock().unwrap(); + assert_eq!(commands.len(), 4, "the rejected object should be flushed"); + assert_flush_of(&commands[3], OBJECT_HANDLE); + } + + #[test] + fn an_object_whose_name_fails_the_consistency_check_is_flushed() { + // TPM2_LoadExternal has already succeeded, so the TPM holds a transient object. Its + // handle reaches no caller -- the Name check rejects the response -- so unless it is + // flushed here it occupies a transient slot until the TPM is reset. A TPM reporting a + // Name inconsistent with the public area it was handed is the last one to leave holding + // an object nobody can name. + let public = sample_public(0x33); + let wrong_name = name_of(&sample_public(0x44)); + let (mut tpm, log) = tpm_with(vec![ + load_external_response(&wrong_name), + flush_context_response(), + ]); + + load_external(&mut tpm, &public).expect_err("the Name does not match the public area"); + + let commands = log.lock().unwrap(); + assert_eq!( + commands.len(), + 2, + "the loaded object must be flushed, not abandoned" + ); + assert_flush_of(&commands[1], OBJECT_HANDLE); + } + + // --------------------------------------------------------------------------------------- + // Sessions the TPM has loaded: what happens when the client will not use them. + // --------------------------------------------------------------------------------------- + + const SESSION_HANDLE: u32 = 0x02000000; + + /// A `TPM2_StartAuthSession` response: the session handle and the TPM's nonce. + fn start_auth_session_response(handle: u32, nonce_tpm: &[u8]) -> MockResponse { + let mut body = Vec::new(); + body.extend_from_slice(&handle.to_be_bytes()); + body.extend_from_slice(&(nonce_tpm.len() as u16).to_be_bytes()); + body.extend_from_slice(nonce_tpm); + MockResponse::Canned(response(TPM_ST::NO_SESSIONS, 0, &body)) + } + + #[test] + fn a_session_the_client_refuses_to_build_is_flushed() { + // TPM2_StartAuthSession has returned, so the TPM has allocated and loaded a session. + // Only then does this client decide it will not build a `Session` from it: parameter + // encryption was asked for on a session with no secret key material to key it with. + // The handle is in the response and nowhere else, and a TPM typically has room for about + // three loaded sessions, so dropping it here costs a slot until the next TPM reset. + // + // This is not a hypothetical path: `examples/tpm_samples.rs` provokes exactly this + // refusal on every run to demonstrate it, and then loads two more sessions. + let (mut tpm, log) = tpm_with(vec![ + start_auth_session_response(SESSION_HANDLE, &[0xBB; 32]), + flush_context_response(), + ]); + + let err = tpm + .start_auth_session_full( + TPM_SE::HMAC, + TPM_ALG_ID::SHA256, + TPMA_SESSION::continueSession | TPMA_SESSION::decrypt, + TPMT_SYM_DEF::new(TPM_ALG_ID::AES, 128, TPM_ALG_ID::CFB), + ) + .expect_err("an unsalted, unbound session cannot carry parameter encryption"); + assert!( + format!("{}", err).contains("no secret key material"), + "unexpected error: {}", + err + ); + + let commands = log.lock().unwrap(); + assert_eq!( + commands.len(), + 2, + "the session the TPM loaded must be flushed, not abandoned" + ); + assert_flush_of(&commands[1], SESSION_HANDLE); + } + + #[test] + fn a_flush_on_the_error_path_does_not_displace_the_error_that_caused_it() { + // The flush is best effort and issued for its side effect on the TPM. Here the device + // has no response left for it, so `FlushContext` fails -- and the caller must still be + // told why the session was refused, not why the cleanup was. + let (mut tpm, log) = tpm_with(vec![start_auth_session_response( + SESSION_HANDLE, + &[0xBB; 32], + )]); + + let err = tpm + .start_auth_session_full( + TPM_SE::HMAC, + TPM_ALG_ID::SHA256, + TPMA_SESSION::continueSession | TPMA_SESSION::encrypt, + TPMT_SYM_DEF::new(TPM_ALG_ID::AES, 128, TPM_ALG_ID::CFB), + ) + .expect_err("the refusal stands whatever the cleanup does"); + assert!( + format!("{}", err).contains("no secret key material"), + "unexpected error: {}", + err + ); + assert_eq!( + log.lock().unwrap().len(), + 2, + "the flush should still have been attempted" + ); + } + + // --------------------------------------------------------------------------------------- + // Session salt: sized by the salt key, not by the session. + // --------------------------------------------------------------------------------------- + + /// A software stand-in for an RSA salt key: the private half, so the test can decrypt what + /// the client encrypts, and a public area whose `nameAlg` the caller chooses. + fn salt_key(name_alg: TPM_ALG_ID) -> (RsaPrivateKey, TrustedPublic) { + let private_key = RsaPrivateKey::new(&mut OsRng, 2048).unwrap(); + let parameters = TPMS_RSA_PARMS::new( + &TPMT_SYM_DEF_OBJECT::new(TPM_ALG_ID::AES, 128, TPM_ALG_ID::CFB), + &Some(TPMU_ASYM_SCHEME::null(TPMS_NULL_ASYM_SCHEME::default())), + 2048, + 65537, + ); + let public = TPMT_PUBLIC { + nameAlg: name_alg, + parameters: Some(TPMU_PUBLIC_PARMS::rsaDetail(parameters)), + unique: Some(TPMU_PUBLIC_ID::rsa(TPM2B_PUBLIC_KEY_RSA { + buffer: private_key.n().to_bytes_be(), + })), + ..Default::default() + }; + let trusted = TrustedPublic::assume_trusted(public, &SOFTWARE_PROVIDER).unwrap(); + (private_key, trusted) + } + + /// The `encryptedSalt` parameter of a logged `TPM2_StartAuthSession`: + /// `tag ‖ commandSize ‖ commandCode ‖ tpmKey ‖ bind ‖ nonceCaller ‖ encryptedSalt ‖ ...` + fn encrypted_salt_of(cmd: &[u8]) -> Vec { + let mut p = 2 + 4 + 4 + 4 + 4; + let nonce_len = be16(cmd, p) as usize; + p += 2 + nonce_len; + let salt_len = be16(cmd, p) as usize; + p += 2; + cmd[p..p + salt_len].to_vec() + } + + #[test] + fn the_session_salt_is_sized_by_the_salt_keys_name_alg_not_by_the_session_hash() { + // The TPM recovers the salt with OAEP under the salt *key's* nameAlg and then requires + // what it recovered to be exactly that hash's digest size (TPM 2.0 Part 4, + // `CryptSecretDecrypt`, which answers TPM_RC_VALUE on `encryptedSalt` otherwise). Sizing + // the salt by the session hash instead is right only while the two happen to agree; a + // SHA-1 salt key with a SHA-256 session sends 32 bytes where the TPM demands 20, and + // every salted session against that key fails outright. + // + // The client cannot see the TPM's side of that check, so this test does what the TPM + // does: decrypt the salt with the key's own private half and measure it. + let (private_key, trusted) = salt_key(TPM_ALG_ID::SHA1); + + let (mut tpm, log) = tpm_with(vec![start_auth_session_response( + SESSION_HANDLE, + &[0xBB; 32], + )]); + tpm.start_salted_auth_session( + &TPM_HANDLE::new(0x81000001), + &trusted, + TPM_SE::HMAC, + TPM_ALG_ID::SHA256, + TPMA_SESSION::continueSession, + TPMT_SYM_DEF::default(), + ) + .expect("a salted session over the mock device"); + + let cmd = log.lock().unwrap()[0].clone(); + let salt = private_key + .decrypt( + Oaep::new_with_label::("SECRET\0"), + &encrypted_salt_of(&cmd), + ) + .expect("the salt is encrypted under the salt key's own nameAlg"); + + assert_eq!( + salt.len(), + Crypto::digest_size_checked(TPM_ALG_ID::SHA1).unwrap(), + "the salt must be the digest size of the salt key's nameAlg (SHA-1, 20 bytes), not \ + of the session hash (SHA-256, 32 bytes)" + ); + assert_ne!( + salt.len(), + Crypto::digest_size_checked(TPM_ALG_ID::SHA256).unwrap(), + "sizing the salt by the session hash is the regression this pins" + ); + } +} + +/// Round trips against the machine's own TPM, one per session category. +/// +/// **These require hardware and are not CI coverage.** They are `#[ignore]`d and only run when +/// asked for by name, for example +/// `cargo test --locked hardware -- --ignored --test-threads=1`. +/// They use the local TBS device, create and flush transient objects under the owner hierarchy, +/// and will fail on a TPM whose owner hierarchy has a non-empty authValue. +/// +/// Their purpose is the one thing a mock cannot serve: confirming that the command and response +/// authorization rules in this module agree with a real TPM's, for every session category those +/// rules distinguish between. +#[cfg(all(test, target_os = "windows", feature = "software-crypto"))] +mod hardware_tests { + use super::*; + use crate::crypto::software_provider::SOFTWARE_PROVIDER; + use crate::device::TpmTbsDevice; + use crate::policy::{PolicyAuthValue, PolicyPassword, PolicyPcr, PolicyTree}; + use crate::tpm_type_extensions::TrustedPublic; + use crate::tpm_types::*; + + const OBJ_AUTH: &[u8] = b"object-auth"; + + fn open_tpm() -> Tpm2 { + let mut tpm = Tpm2::with_software_crypto(Box::new(TpmTbsDevice::new())); + tpm.connect().expect("no local TPM available"); + tpm + } + + /// A keyed-hash primary under the owner hierarchy carrying `policy`, with `userWithAuth` so + /// that the authValue paths are exercised too. + fn make_primary(tpm: &mut Tpm2, policy: &[u8]) -> Result { + let attrs = TPMA_OBJECT::sign + | TPMA_OBJECT::fixedParent + | TPMA_OBJECT::fixedTPM + | TPMA_OBJECT::userWithAuth; + let parameters = TPMU_PUBLIC_PARMS::keyedHashDetail(TPMS_KEYEDHASH_PARMS::new(&Some( + TPMU_SCHEME_KEYEDHASH::hmac(TPMS_SCHEME_HMAC { + hashAlg: TPM_ALG_ID::SHA256, + }), + ))); + let unique = TPMU_PUBLIC_ID::keyedHash(TPM2B_DIGEST_KEYEDHASH::default()); + let templ = TPMT_PUBLIC::new( + TPM_ALG_ID::SHA256, + attrs, + &policy.to_vec(), + &Some(parameters), + &Some(unique), + ); + let sens = TPMS_SENSITIVE_CREATE::new(&OBJ_AUTH.to_vec(), &vec![5, 4, 3, 2, 1, 0]); + let resp = tpm.CreatePrimary( + &TPM_HANDLE::new(TPM_RH::OWNER.get_value()), + &sens, + &templ, + &Default::default(), + &Default::default(), + )?; + let mut handle = resp.handle; + handle.set_auth(OBJ_AUTH); + Ok(handle) + } + + /// An RSA storage primary, used where a salt key is needed. + fn make_storage_primary(tpm: &mut Tpm2) -> Result { + let attrs = TPMA_OBJECT::decrypt + | TPMA_OBJECT::restricted + | TPMA_OBJECT::fixedParent + | TPMA_OBJECT::fixedTPM + | TPMA_OBJECT::sensitiveDataOrigin + | TPMA_OBJECT::userWithAuth; + let parameters = TPMU_PUBLIC_PARMS::rsaDetail(TPMS_RSA_PARMS::new( + &TPMT_SYM_DEF_OBJECT::new(TPM_ALG_ID::AES, 128, TPM_ALG_ID::CFB), + // A restricted decryption key must carry the NULL asymmetric scheme; an RSASSA + // scheme here is rejected by the TPM. + &Some(TPMU_ASYM_SCHEME::null(TPMS_NULL_ASYM_SCHEME::default())), + 2048, + 65537, + )); + let unique = TPMU_PUBLIC_ID::rsa(TPM2B_PUBLIC_KEY_RSA::default()); + let templ = TPMT_PUBLIC::new( + TPM_ALG_ID::SHA256, + attrs, + &Vec::new(), + &Some(parameters), + &Some(unique), + ); + let resp = tpm.CreatePrimary( + &TPM_HANDLE::new(TPM_RH::OWNER.get_value()), + &TPMS_SENSITIVE_CREATE::new(&Vec::new(), &Vec::new()), + &templ, + &Default::default(), + &Default::default(), + )?; + Ok(resp.handle) + } + + /// The exchange every case below runs: one authorized command, so that both the command and + /// the response authorization for this session category are exercised end to end. + fn authorized_round_trip(tpm: &mut Tpm2, handle: &TPM_HANDLE, session: Session) { + let out = tpm + .with_session(session) + .HMAC(handle, &vec![1, 2, 3, 4], TPM_ALG_ID::SHA256) + .expect("authorized command should succeed and its response should verify"); + assert_eq!(out.len(), 32); + } + + #[test] + #[ignore = "requires a local TPM"] + fn hardware_pwap_session_round_trip() { + let mut tpm = open_tpm(); + let handle = make_primary(&mut tpm, &[]).unwrap(); + authorized_round_trip(&mut tpm, &handle, Session::pw(Some(OBJ_AUTH.to_vec()))); + tpm.FlushContext(&handle).unwrap(); + } + + #[test] + #[ignore = "requires a local TPM"] + fn hardware_salted_hmac_session_round_trip() { + let mut tpm = open_tpm(); + let handle = make_primary(&mut tpm, &[]).unwrap(); + let salt_key = make_storage_primary(&mut tpm).unwrap(); + + // The salt key is one this process just created, so `assume_trusted` is the honest + // constructor: there is no channel between us and it for anyone to be in the middle of. + let public = tpm.ReadPublic(&salt_key).unwrap().outPublic; + let trusted = TrustedPublic::assume_trusted(public, &SOFTWARE_PROVIDER).unwrap(); + + let session = tpm + .start_salted_auth_session( + &salt_key, + &trusted, + TPM_SE::HMAC, + TPM_ALG_ID::SHA256, + TPMA_SESSION::continueSession, + TPMT_SYM_DEF::default(), + ) + .unwrap(); + assert!(session.has_secret_key_material()); + let sess_handle = session.sess_in.sessionHandle.clone(); + authorized_round_trip(&mut tpm, &handle, session); + + tpm.FlushContext(&sess_handle).unwrap(); + tpm.FlushContext(&salt_key).unwrap(); + tpm.FlushContext(&handle).unwrap(); + } + + #[test] + #[ignore = "requires a local TPM"] + fn hardware_bound_hmac_session_round_trip() { + let mut tpm = open_tpm(); + let handle = make_primary(&mut tpm, &[]).unwrap(); + + let session = tpm + .start_auth_session_ex( + None, + &handle, + TPM_SE::HMAC, + TPM_ALG_ID::SHA256, + TPMA_SESSION::continueSession, + TPMT_SYM_DEF::default(), + ) + .unwrap(); + assert!( + session.has_secret_key_material(), + "binding to an entity with a non-empty authValue does give the session a secret" + ); + let sess_handle = session.sess_in.sessionHandle.clone(); + authorized_round_trip(&mut tpm, &handle, session); + + tpm.FlushContext(&sess_handle).unwrap(); + tpm.FlushContext(&handle).unwrap(); + } + + #[test] + #[ignore = "requires a local TPM"] + fn hardware_policy_auth_value_session_round_trip() { + let mut tpm = open_tpm(); + let tree = PolicyTree::new().add(PolicyAuthValue::new()); + let digest = tree + .get_policy_digest(&SOFTWARE_PROVIDER, TPM_ALG_ID::SHA256) + .unwrap(); + + let handle = make_primary(&mut tpm, &digest).unwrap(); + let session = tpm + .start_auth_session(TPM_SE::POLICY, TPM_ALG_ID::SHA256) + .unwrap(); + let sess_handle = session.sess_in.sessionHandle.clone(); + let session = tree.execute(&mut tpm, session).unwrap(); + assert!(session.expects_response_auth()); + authorized_round_trip(&mut tpm, &handle, session); + + tpm.FlushContext(&sess_handle).unwrap(); + tpm.FlushContext(&handle).unwrap(); + } + + #[test] + #[ignore = "requires a local TPM"] + fn hardware_policy_password_session_round_trip() { + let mut tpm = open_tpm(); + let tree = PolicyTree::new().add(PolicyPassword::new()); + let digest = tree + .get_policy_digest(&SOFTWARE_PROVIDER, TPM_ALG_ID::SHA256) + .unwrap(); + + let handle = make_primary(&mut tpm, &digest).unwrap(); + let session = tpm + .start_auth_session(TPM_SE::POLICY, TPM_ALG_ID::SHA256) + .unwrap(); + let sess_handle = session.sess_in.sessionHandle.clone(); + let session = tree.execute(&mut tpm, session).unwrap(); + // The one category that must NOT expect a response authorization. + assert!(!session.expects_response_auth()); + authorized_round_trip(&mut tpm, &handle, session); + + tpm.FlushContext(&sess_handle).unwrap(); + tpm.FlushContext(&handle).unwrap(); + } + + #[test] + #[ignore = "requires a local TPM"] + fn hardware_policy_pcr_session_round_trip() { + let mut tpm = open_tpm(); + // `pcrSelect` is a bitmap and must be at least PCR_SELECT_MIN (3) bytes; a one-byte, + // all-zero selection both undersizes the field and names no PCR at all. + let selection = TPMS_PCR_SELECTION::new_from_pcr_u32(TPM_ALG_ID::SHA256, 0).unwrap(); + let read = tpm.PCR_Read(&vec![selection.clone()]).unwrap(); + + let tree = PolicyTree::new().add(PolicyPcr::new(read.pcrValues.clone(), vec![selection])); + let digest = tree + .get_policy_digest(&SOFTWARE_PROVIDER, TPM_ALG_ID::SHA256) + .unwrap(); + + let handle = make_primary(&mut tpm, &digest).unwrap(); + let session = tpm + .start_auth_session(TPM_SE::POLICY, TPM_ALG_ID::SHA256) + .unwrap(); + let sess_handle = session.sess_in.sessionHandle.clone(); + let session = tree.execute(&mut tpm, session).unwrap(); + // A policy session with neither PolicyAuthValue nor PolicyPassword: the TPM still + // authenticates the response, and this client must check it. This is the category the + // old rule skipped. + assert!(session.expects_response_auth()); + authorized_round_trip(&mut tpm, &handle, session); + + tpm.FlushContext(&sess_handle).unwrap(); + tpm.FlushContext(&handle).unwrap(); + } +} diff --git a/TSS.Rust/src/tpm_structure.rs b/TSS.Rust/src/tpm_structure.rs index 5321dab3..a601667a 100644 --- a/TSS.Rust/src/tpm_structure.rs +++ b/TSS.Rust/src/tpm_structure.rs @@ -230,3 +230,96 @@ mod tests { Ok(()) } } + +/// Pins the marshaling contract for a structure whose union field carries no value. +/// +/// The generator emits an early `return Ok(())` for a structure whose union selector is its +/// first marshaled field, so an absent union used to serialize to an empty buffer instead of +/// being reported. That is a deliberate exception for `TPMT_SENSITIVE` only: `TPM2_LoadExternal` +/// loads a public area alone by sending a zero-size `inPrivate`. Every other structure must +/// report `TpmError::InvalidUnion` rather than emit a silently truncated encoding. +#[cfg(test)] +mod absent_union_marshaling { + use super::*; + + /// Serializing a default-constructed `$t` must fail with `InvalidUnion`. + macro_rules! assert_invalid_union { + ($t:ty) => { + match <$t>::default().toBytes() { + Err(TpmError::InvalidUnion) => {} + other => panic!( + "{} with an absent union marshaled as {:?}", + stringify!($t), + other + ), + } + }; + } + + #[test] + fn default_sensitive_is_the_one_exception_and_marshals_to_nothing() { + assert_eq!( + TPMT_SENSITIVE::default().toBytes().unwrap(), + Vec::::new() + ); + } + + /// Every other structure whose union selector is its first marshaled field. + #[test] + fn an_absent_leading_union_is_rejected() { + assert_invalid_union!(TPMS_CAPABILITY_DATA); + assert_invalid_union!(TPMT_KEYEDHASH_SCHEME); + assert_invalid_union!(TPMT_SIG_SCHEME); + assert_invalid_union!(TPMT_KDF_SCHEME); + assert_invalid_union!(TPMT_ASYM_SCHEME); + assert_invalid_union!(TPMT_RSA_SCHEME); + assert_invalid_union!(TPMT_RSA_DECRYPT); + assert_invalid_union!(TPMT_ECC_SCHEME); + assert_invalid_union!(TPMT_SIGNATURE); + assert_invalid_union!(TPMS_KEYEDHASH_PARMS); + assert_invalid_union!(TPMT_PUBLIC_PARMS); + assert_invalid_union!(TPMT_PUBLIC); + assert_invalid_union!(SignResponse); + assert_invalid_union!(TPM2_TestParms_REQUEST); + } + + /// A union behind other fields never reached the early return, and is unaffected. + #[test] + fn an_absent_trailing_union_is_still_rejected() { + assert_invalid_union!(TPMS_ATTEST); + } + + /// The exception is load bearing: a public-key-only `TPM2_LoadExternal` puts a zero-size + /// `inPrivate` sized object on the wire ahead of the public area. + #[test] + fn public_only_load_external_marshals_a_zero_size_in_private() -> Result<(), TpmError> { + let in_public = TPMT_PUBLIC { + nameAlg: TPM_ALG_ID::SHA256, + objectAttributes: TPMA_OBJECT(TPMA_OBJECT::sign.0 | TPMA_OBJECT::userWithAuth.0), + authPolicy: vec![], + parameters: Some(TPMU_PUBLIC_PARMS::rsaDetail(TPMS_RSA_PARMS { + symmetric: TPMT_SYM_DEF_OBJECT::default(), + scheme: Some(TPMU_ASYM_SCHEME::null(TPMS_NULL_ASYM_SCHEME::default())), + keyBits: 2048, + exponent: 0, + })), + unique: Some(TPMU_PUBLIC_ID::rsa(TPM2B_PUBLIC_KEY_RSA { + buffer: vec![0xA5; 256], + })), + }; + + let request = TPM2_LoadExternal_REQUEST::new( + &TPMT_SENSITIVE::default(), + &in_public, + &TPM_HANDLE::new(TPM_RH::NULL.get_value()), + ); + let bytes = request.toBytes()?; + + assert_eq!(&bytes[..2], &[0u8, 0u8], "inPrivate must be a zero-size object"); + + let public_size = u16::from_be_bytes([bytes[2], bytes[3]]) as usize; + assert_eq!(public_size, in_public.toBytes()?.len()); + assert_eq!(bytes.len(), 2 + 2 + public_size + 4); + Ok(()) + } +} diff --git a/TSS.Rust/src/tpm_type_extensions.rs b/TSS.Rust/src/tpm_type_extensions.rs index 2f6bacb5..f0dbae1e 100644 --- a/TSS.Rust/src/tpm_type_extensions.rs +++ b/TSS.Rust/src/tpm_type_extensions.rs @@ -5,6 +5,7 @@ use crate::tpm_buffer::*; use crate::tpm_structure::TpmEnum; use crate::tpm_types::CertifyResponse; use crate::tpm_types::*; +use subtle::ConstantTimeEq; use zeroize::Zeroize; /// Activation data returned from create_activation @@ -14,6 +15,281 @@ pub struct ActivationData { pub secret: Vec, // Encrypted seed (ENCRYPTED_SECRET) } +/// A [`TPMT_PUBLIC`] the caller has decided to trust, paired with its locally derived Name. +/// +/// # What this type does and does not mean +/// +/// `TrustedPublic` records a **caller-asserted** trust decision and nothing more. It exists so +/// that the decision is made once, in one greppable place, instead of being implied by whatever +/// public area happened to be in scope at the call site. +/// +/// It is **not** a channel-authentication mechanism: nothing here authenticates the transport +/// the public area travelled over, and constructing one does not make a subsequent exchange +/// with the TPM authenticated. +/// +/// It is **not** proof of TPM residency: nothing here shows that the private half of this key +/// is held by a TPM, or by *the* TPM you are talking to. A public area is just bytes, and the +/// Name is a digest over those same bytes, so an adversary who chooses the public area also +/// chooses its Name. +/// +/// What it is worth depends entirely on where the expected Name came from: +/// +/// * [`TrustedPublic::from_pinned_name`] is meaningful when the expected Name was obtained out +/// of band — burned into an image, shipped in a signed manifest, recorded at enrolment time +/// on a channel you trusted then. It rejects any public area that does not hash to that Name. +/// * [`TrustedPublic::assume_trusted`] asserts trust with no evidence at all. It is the right +/// call for a locally generated key you just created yourself, and the wrong call for +/// anything that arrived over a channel an adversary can reach. +#[derive(Clone, Debug)] +pub struct TrustedPublic { + public: TPMT_PUBLIC, + name: Vec, +} + +impl TrustedPublic { + /// Accept `public` only if it hashes to `expected_name`. + /// + /// The Name is recomputed locally with [`TPMT_PUBLIC::get_name`] and compared; a mismatch is + /// an error. The strength of the result is exactly the strength of `expected_name`'s + /// provenance — see the type-level documentation. + pub fn from_pinned_name( + public: TPMT_PUBLIC, + expected_name: &[u8], + crypto: &CryptoProvider, + ) -> Result { + if expected_name.is_empty() { + return Err(TpmError::InvalidParameter); + } + public.verify_name(expected_name, crypto)?; + let name = public.get_name(crypto)?; + Ok(Self { public, name }) + } + + /// Accept `public` on the caller's say-so, with nothing checked. + /// + /// Deliberately loud, and deliberately easy to grep for. Reach for this only when the public + /// area cannot have been chosen by an adversary — a key this process just created, or one + /// read back over a channel that is already authenticated by other means. If you cannot + /// name the reason, use [`TrustedPublic::from_pinned_name`] instead. + pub fn assume_trusted(public: TPMT_PUBLIC, crypto: &CryptoProvider) -> Result { + let name = public.get_name(crypto)?; + Ok(Self { public, name }) + } + + /// Accept `public` on the strength of a credential a TPM could only have recovered by + /// holding the named object. + /// + /// This is the `TPM2_MakeCredential` / `TPM2_ActivateCredential` exchange: a credential of + /// the caller's choosing is encrypted to a storage key's public area — an endorsement key, + /// normally — naming the object evidence is wanted for, and the TPM returns the credential + /// only if it holds both that storage key and an object with that Name. + /// + /// `activated_name` is the Name given to [`TPMT_PUBLIC::create_activation`], and + /// `recovered_credential` is what `TPM2_ActivateCredential` returned. Two things are + /// checked: that `public` really is the public area of the object the credential was bound + /// to, and that the credential came back intact. The first catches the easy mistake of + /// naming one object and then trusting another's public area. + /// + /// What the result is worth rests on two things this function cannot see and the caller must + /// get right: + /// + /// * **the storage key's own provenance.** Credential activation moves trust from the + /// storage key to the named object; it does not create any. If the endorsement key's + /// public area was itself taken on faith, so is everything derived here. Chain it to a + /// manufacturer's EK certificate. + /// * **the credential's unpredictability.** Anyone who can guess it can answer without a + /// TPM, so use bytes freshly generated at random for this one exchange. + pub fn from_activated_credential( + public: TPMT_PUBLIC, + activated_name: &[u8], + credential: &[u8], + recovered_credential: &[u8], + crypto: &CryptoProvider, + ) -> Result { + if credential.is_empty() { + return Err(TpmError::InvalidParameter); + } + + // Compared in constant time: the caller supplies the credential, and the TPM's answer + // arrives from wherever the TPM is. Neither should be able to be recovered a byte at a + // time by an adversary who can submit answers and watch how long the rejection takes. + if !bool::from(credential.ct_eq(recovered_credential)) { + return Err(TpmError::VerificationFailed( + "Activation did not recover the credential it was made from".to_string(), + )); + } + + Self::from_pinned_name(public, activated_name, crypto) + } + + /// The public area. + pub fn public(&self) -> &TPMT_PUBLIC { + &self.public + } + + /// The Name derived from the public area, `nameAlg || H_nameAlg(publicArea)`. + pub fn name(&self) -> &[u8] { + &self.name + } + + /// Check a `TPM2_Certify` attestation this key signed over `certified_key`. + /// + /// # The signing key's provenance is a precondition, not a result + /// + /// The caller is responsible for establishing out of band that this signing key is the key + /// it means, **before** calling this function. The two usual ways are credential activation + /// against an endorsement key whose certificate chains to a manufacturer root — see + /// [`TrustedPublic::from_activated_credential`] — and validating an attestation key + /// certificate issued by a CA the caller already trusts, pinning the Name it carries with + /// [`TrustedPublic::from_pinned_name`]. + /// + /// Nothing here substitutes for that. Every value this function inspects reaches it from + /// the same untrusted source: the attestation, the signature, and the signing key's own + /// `objectAttributes` all travel together, so an adversary who fabricates a public area and + /// an attestation to match satisfies all of these checks at once. This function does not + /// authenticate a channel, does not defeat an adversary sitting on one, and does not show + /// that the private half of the signing key lives in a TPM — let alone in the TPM you + /// believe you are talking to. + /// + /// What it does establish, *given* that provenance: the key you already decided to trust + /// signed this attestation, the attestation is bound to `nonce`, and it names + /// `certified_key`. A zero-length `nonce` is accepted and carries no freshness — supply + /// bytes you generated at random for this exchange if replay is a concern. + /// + /// # What is checked + /// + /// * the signing key's attributes are fit for attestation (defense in depth — see + /// [`TrustedPublic::check_attestation_key_attributes`]); + /// * `magic` is `TPM_GENERATED_VALUE`; + /// * `extraData` is `nonce`; + /// * the attested body is a `certify`, and the Name it carries is `certified_key`'s; + /// * the signature's hash algorithm is the one the signing key's scheme names; + /// * the signature verifies over the marshalled attestation. + /// + /// Every failure is an `Err`: [`TpmError::VerificationFailed`] when a check did not pass and + /// [`TpmError::NotSupported`] when the signature uses an algorithm this crate cannot verify. + /// There is no success value to drop, so no caller can mistake a failed check for a pass. + pub fn validate_certify( + &self, + crypto: &CryptoProvider, + certified_key: &TPMT_PUBLIC, + nonce: &[u8], + certify_response: &CertifyResponse, + ) -> Result<(), TpmError> { + self.check_attestation_key_attributes()?; + + let attest = &certify_response.certifyInfo; + + // Everything from here to the algorithm dispatch below is deliberately hoisted above it. + // These are the checks that give an attestation its meaning, and they are defined on the + // attestation alone, so no signature algorithm has any business reaching a success path + // without them. An earlier version dispatched first and delegated the non-RSASSA case to + // the signature verifier with an empty digest, which skipped all of them; it was not + // exploitable only because that verifier happened to reject the same cases for its own + // reasons. Keep the order: structure first, then cryptography. + if attest.magic != TPM_GENERATED::VALUE { + return Err(TpmError::VerificationFailed(format!( + "Certify: magic is 0x{:X}, not TPM_GENERATED_VALUE", + attest.magic.0 + ))); + } + + if attest.extraData != nonce { + return Err(TpmError::VerificationFailed( + "Certify: extraData does not carry the nonce supplied".to_string(), + )); + } + + let Some(TPMU_ATTEST::certify(certify_info)) = &attest.attested else { + return Err(TpmError::VerificationFailed( + "Certify: the attested body is not a TPMS_CERTIFY_INFO".to_string(), + )); + }; + + if certify_info.name != certified_key.get_name(crypto)? { + return Err(TpmError::VerificationFailed( + "Certify: the attestation names a different object than the key supplied" + .to_string(), + )); + } + + let Some(TPMU_SIGNATURE::rsassa(signature)) = &certify_response.signature else { + return Err(TpmError::NotSupported( + "Certify: only RSASSA signatures can be validated".to_string(), + )); + }; + + if self.public.get_signing_hash_alg()? != signature.hash { + return Err(TpmError::VerificationFailed( + "Certify: the signature's hash algorithm is not the one the key's scheme names" + .to_string(), + )); + } + + let signed_blob = { + let mut buffer = TpmBuffer::new(None); + attest.toTpm(&mut buffer)?; + buffer.trim().to_vec() + }; + let signed_blob_hash = Crypto::hash(crypto, signature.hash, &signed_blob)?; + + if !Crypto::validate_signature( + crypto, + &self.public, + signed_blob_hash, + &certify_response.signature, + )? { + return Err(TpmError::VerificationFailed( + "Certify: the signature over the attestation is invalid".to_string(), + )); + } + + Ok(()) + } + + /// Reject a signing key whose attributes make an attestation it signs worthless. + /// + /// **Defense in depth, and nothing more.** `objectAttributes` sits in the same public area + /// as everything else the caller was handed, so an adversary who fabricates a public area + /// simply sets these bits. Reading them proves nothing about provenance and cannot stand in + /// for establishing it. These checks are meaningful only once the key's provenance has been + /// settled out of band, and what they then catch is an honest mistake: a key that genuinely + /// is the one that was pinned, but created from a template unfit for attestation. + /// + /// * `restricted` is the load-bearing one, because it is what gives the + /// `magic == TPM_GENERATED_VALUE` check any content. A TPM will not produce the hash + /// validation ticket that `TPM2_Sign` demands of a restricted key when the data hashed + /// begins with `TPM_GENERATED_VALUE` (TPM 2.0 Part 3, `TPM2_Hash` and + /// `TPM2_SequenceComplete`), so a restricted key signs no externally supplied structure + /// that could be mistaken for an attestation. An **unrestricted** key signs anything put + /// in front of it, hand-written `TPMS_ATTEST` included, and the magic check becomes a + /// check that the attacker remembered a constant. + /// * `sign` because a key without it is not a signing key at all. + /// * `fixedTPM` and `fixedParent` are what a TPM sets on a key that cannot be duplicated out + /// of its hierarchy. Requiring them rejects a key whose private half may lawfully have + /// been copied elsewhere — which would make an attestation say nothing about *which* + /// TPM produced it. Like the rest, this is the public area's own claim about itself. + pub fn check_attestation_key_attributes(&self) -> Result<(), TpmError> { + let attributes = self.public.objectAttributes; + + for (required, name) in [ + (TPMA_OBJECT::restricted, "restricted"), + (TPMA_OBJECT::sign, "sign"), + (TPMA_OBJECT::fixedTPM, "fixedTPM"), + (TPMA_OBJECT::fixedParent, "fixedParent"), + ] { + if attributes.0 & required.0 == 0 { + return Err(TpmError::VerificationFailed(format!( + "Certify: the signing key does not have {} set, so it is unfit to attest", + name + ))); + } + } + + Ok(()) + } +} + impl TPMS_RSA_PARMS { /// The public exponent as big-endian bytes with no leading zeros. /// @@ -51,6 +327,26 @@ impl TPMT_PUBLIC { Ok(pub_hash) } + /// Recompute this public area's Name and check it against `expected`. + /// + /// The Name of a TPM object is `nameAlg || H_nameAlg(publicArea)`, so it is a value the + /// caller can derive locally from the public area alone. Verifying it proves only that the + /// public area in hand is the one the expected Name commits to. It proves nothing about + /// where that public area came from, and nothing about the channel it arrived over. + /// + /// A mismatch is [`TpmError::VerificationFailed`], the variant every other check on + /// attacker-reachable data in this API uses, so a caller can tell an untrusted public area + /// from an operational failure without reading the message. + pub fn verify_name(&self, expected: &[u8], crypto: &CryptoProvider) -> Result<(), TpmError> { + let actual = self.get_name(crypto)?; + if actual != expected { + return Err(TpmError::VerificationFailed( + "TPMT_PUBLIC Name does not match the expected Name".to_string(), + )); + } + Ok(()) + } + pub fn get_signing_hash_alg(&self) -> Result { let rsa_params = if let Some(TPMU_PUBLIC_PARMS::rsaDetail(rsa_params)) = &self.parameters { rsa_params @@ -71,58 +367,6 @@ impl TPMT_PUBLIC { Ok(scheme.hashAlg) } - pub fn validate_certify( - &self, - crypto: &CryptoProvider, - certified_key: &TPMT_PUBLIC, - nonce: &[u8], - certify_response: &CertifyResponse, - ) -> Result { - let key_hash_alg = self.get_signing_hash_alg()?; - let signature_hash_alg = if let Some(TPMU_SIGNATURE::rsassa(signature)) = &certify_response.signature { - signature.hash - } else { - return Crypto::validate_signature( - crypto, - self, - Vec::new(), - &certify_response.signature, - ); - }; - if key_hash_alg != signature_hash_alg { - return Ok(false); - } - - let attest = &certify_response.certifyInfo; - - if (attest.extraData != nonce) { - return Ok(false); - } - - if (attest.magic != TPM_GENERATED::VALUE) { - return Ok(false); - } - - if let Some(TPMU_ATTEST::certify(quote_info)) = &attest.attested { - if (quote_info.name != certified_key.get_name(crypto)?) { - return Ok(false); - } - } else { - return Ok(false); - } - - // And finally, check the signature - let signed_blob = { - let mut buffer = TpmBuffer::new(None); - certify_response.certifyInfo.toTpm(&mut buffer)?; - buffer.trim().to_vec() - }; - - let signed_blob_hash = Crypto::hash(crypto, signature_hash_alg, &signed_blob)?; - - Crypto::validate_signature(crypto, self, signed_blob_hash, &certify_response.signature) - } - /// Implements the TPM2_MakeCredential command functionality: /// 1. Establish a seed and the secret that conveys it to the TPM /// 2. Derive symmetric key via KDFa @@ -153,7 +397,9 @@ impl TPMT_PUBLIC { || sym_def.keyBits != 128 || sym_def.mode != TPM_ALG_ID::CFB { - return Err(TpmError::NotSupported("Unsupported wrapping scheme".to_string())); + return Err(TpmError::NotSupported( + "Unsupported wrapping scheme".to_string(), + )); } // The seed is the same size as the nameAlg digest, per TPM 2.0 Part 1 "Credential @@ -179,13 +425,13 @@ impl TPMT_PUBLIC { credential_with_size.extend_from_slice(&(credential.len() as u16).to_be_bytes()); credential_with_size.extend_from_slice(credential); - // 3. Encrypt the credential + // 3. Encrypt the credential let enc_credential = Crypto::cfb_xcrypt( crypto, true, &sym_key, &[0u8; 16], // Zero IV - &credential_with_size + &credential_with_size, )?; // 4. Generate the integrity HMAC key @@ -203,13 +449,8 @@ impl TPMT_PUBLIC { let mut to_hmac = Vec::new(); to_hmac.extend_from_slice(&enc_credential); to_hmac.extend_from_slice(activated_name); - - let integrity_hmac = Crypto::hmac( - crypto, - self.nameAlg, - &hmac_key, - &to_hmac - )?; + + let integrity_hmac = Crypto::hmac(crypto, self.nameAlg, &hmac_key, &to_hmac)?; // Cleanup sensitive data seed.zeroize(); @@ -293,24 +534,25 @@ impl TPMT_PUBLIC { } // Performs RSA encryption of the given data using the public key - pub fn encrypt( - &self, - crypto: &CryptoProvider, - data: &[u8], - ) -> Result, TpmError> { + pub fn encrypt(&self, crypto: &CryptoProvider, data: &[u8]) -> Result, TpmError> { // Verify we have an RSA key with correct parameters let rsa_params = if let Some(TPMU_PUBLIC_PARMS::rsaDetail(params)) = &self.parameters { params } else { - return Err(TpmError::NotSupported("Only RSA encryption supported".to_string())); + return Err(TpmError::NotSupported( + "Only RSA encryption supported".to_string(), + )); }; // Check symmetric definition let sym_def = &rsa_params.symmetric; - if sym_def.algorithm != TPM_ALG_ID::AES - || sym_def.keyBits != 128 - || sym_def.mode != TPM_ALG_ID::CFB { - return Err(TpmError::NotSupported("Unsupported wrapping scheme".to_string())); + if sym_def.algorithm != TPM_ALG_ID::AES + || sym_def.keyBits != 128 + || sym_def.mode != TPM_ALG_ID::CFB + { + return Err(TpmError::NotSupported( + "Unsupported wrapping scheme".to_string(), + )); } // Get RSA public key components @@ -341,13 +583,17 @@ impl TPMT_PUBLIC { let rsa_params = if let Some(TPMU_PUBLIC_PARMS::rsaDetail(params)) = &self.parameters { params } else { - return Err(TpmError::NotSupported("Only RSA keys can encrypt session salt".to_string())); + return Err(TpmError::NotSupported( + "Only RSA keys can encrypt session salt".to_string(), + )); }; let rsa_pub_n = if let Some(TPMU_PUBLIC_ID::rsa(unique)) = &self.unique { &unique.buffer } else { - return Err(TpmError::NotSupported("Only RSA keys can encrypt session salt".to_string())); + return Err(TpmError::NotSupported( + "Only RSA keys can encrypt session salt".to_string(), + )); }; Crypto::rsa_oaep_encrypt( @@ -362,40 +608,269 @@ impl TPMT_PUBLIC { } impl TPMS_PCR_SELECTION { + /// The smallest `pcrSelect` a valid selection carries, whatever it names. + /// + /// `PCR_SELECT_MIN` in the TPM 2.0 specification: three bytes, enough for the 24 PCRs a + /// PC Client platform defines. A shorter selection is not a valid `TPMS_PCR_SELECTION`, so + /// every selection built here is at least this long even when it names PCR 0. + pub const MIN_PCR_SELECT_BYTES: usize = 3; + + /// The longest `pcrSelect` this structure can carry on the wire. + /// + /// `TPMS_PCR_SELECTION` marshals `pcrSelect` with a **one-byte** size prefix — see + /// `buf.writeSizedByteBuf(&self.pcrSelect, 1)` in the generated `tpm_types.rs` — so a longer + /// selection cannot be expressed. `TpmBuffer::writeSizedByteBuf` fails the marshal rather + /// than truncating the length, so nothing is silently mis-sent, but a selection that cannot + /// be marshalled is of no use to anyone and there is no reason to build one. + pub const MAX_PCR_SELECT_BYTES: usize = u8::MAX as usize; + + /// The largest PCR index any `TPMS_PCR_SELECTION` can name: 2039. + /// + /// It follows from [`Self::MAX_PCR_SELECT_BYTES`]: the last representable bit is bit 7 of + /// byte 254. Real TPMs implement far fewer PCRs — 24 on a PC Client platform — so this is a + /// bound on what the wire format can express, not a promise that any TPM has that many. + pub const MAX_PCR_INDEX: u32 = (Self::MAX_PCR_SELECT_BYTES as u32) * 8 - 1; + + /// The `pcrSelect` byte holding `pcr`'s bit, or an error if no selection can hold it. + /// + /// Checked **before** anything is allocated. Sizing the array from an unchecked `pcr` lets + /// a caller that took the index from a configuration file or off the network ask for + /// `u32::MAX / 8 + 1` bytes — half a gigabyte — and be met with an allocation failure abort + /// rather than an error it can handle. + fn select_byte_index(pcr: u32) -> Result { + if pcr > Self::MAX_PCR_INDEX { + return Err(TpmError::InvalidArraySize(format!( + "PCR {} needs a pcrSelect of {} bytes, but TPMS_PCR_SELECTION marshals \ + pcrSelect behind a one-byte size prefix, so it holds at most {} bytes and \ + PCR {} is the largest index it can name", + pcr, + pcr as usize / 8 + 1, + Self::MAX_PCR_SELECT_BYTES, + Self::MAX_PCR_INDEX + ))); + } + Ok(pcr as usize / 8) + } + /// Get a PCR-selection array naming exactly one PCR in one bank - pub fn get_selection_array(hash_alg: TPM_ALG_ID, pcr: u32) -> Vec { - vec![TPMS_PCR_SELECTION::new_from_pcr_u32(hash_alg, pcr)] + /// + /// Errors when `pcr` is above [`Self::MAX_PCR_INDEX`] — see [`Self::new_from_pcr_u32`]. + pub fn get_selection_array(hash_alg: TPM_ALG_ID, pcr: u32) -> Result, TpmError> { + Ok(vec![TPMS_PCR_SELECTION::new_from_pcr_u32(hash_alg, pcr)?]) } /// Create a TPMS_PCR_SELECTION naming a single-PCR - pub fn new_from_pcr_u32(hash_alg: TPM_ALG_ID, pcr: u32) -> Self { - let mut size = 3; + /// + /// `pcr` above [`Self::MAX_PCR_INDEX`] is an error: the selection it would need is longer + /// than the wire format can express, so building it would allocate a large buffer for a + /// value that could never be sent. + pub fn new_from_pcr_u32(hash_alg: TPM_ALG_ID, pcr: u32) -> Result { + let byte_index = Self::select_byte_index(pcr)?; + + // `byte_index` is already the byte holding `pcr`'s bit, so the array must grow whenever + // that index does not fit in the minimum size. Dividing it by 8 again here compared the + // wrong quantity and left the size at 3 for every PCR up to 191, so selecting PCR 24 + // (the first PCR outside the standard 0-23 range) indexed past the end of the vector. + let size = std::cmp::max(Self::MIN_PCR_SELECT_BYTES, byte_index + 1); + + let mut pcr_select = vec![0u8; size]; + pcr_select[byte_index] = 1 << (pcr % 8); + + Ok(TPMS_PCR_SELECTION::new(hash_alg, &pcr_select)) + } - let pcr_bytes = pcr / 8; - if ((pcr_bytes / 8) + 1) > size { - size = pcr_bytes + 1; + /// Create a TPMS_PCR_SELECTION for a set of PCRs in a single bank + /// + /// Any PCR above [`Self::MAX_PCR_INDEX`] is an error, on the same grounds as + /// [`Self::new_from_pcr_u32`]. Every index is checked before the array is allocated, so a + /// single out-of-range entry cannot drive the allocation. + pub fn new_from_pcrs_vec(hash_alg: TPM_ALG_ID, pcrs: &[u32]) -> Result { + let mut size = Self::MIN_PCR_SELECT_BYTES; + for pcr in pcrs { + size = std::cmp::max(size, Self::select_byte_index(*pcr)? + 1); } - let mut pcr_select = vec![0; size as usize]; - pcr_select[pcr_bytes as usize] = 1 << (pcr % 8); + let mut pcr_select = vec![0u8; size]; + for pcr in pcrs { + pcr_select[*pcr as usize / 8] |= 1 << (*pcr % 8); + } - TPMS_PCR_SELECTION::new(hash_alg, &pcr_select) + Ok(TPMS_PCR_SELECTION::new(hash_alg, &pcr_select)) } +} - /// Create a TPMS_PCR_SELECTION for a set of PCRs in a single bank - pub fn new_from_pcrs_vec(hash_alg: TPM_ALG_ID, pcrs: &[u32]) -> Self { - let mut pcr_max = *pcrs.iter().max().unwrap_or(&0); +#[cfg(test)] +mod pcr_selection_tests { + use super::*; - if (pcr_max < 23) { - pcr_max = 23; + #[test] + fn pcr_selection_is_unchanged_for_the_standard_pcr_range() -> Result<(), TpmError> { + // PCRs 0-23 are the standard TPM range and must keep producing the historical 3-byte + // wire format: it is part of every existing PCR policy, so any change here would + // silently break policy digests computed against the old layout. + for pcr in 0..24u32 { + let selection = TPMS_PCR_SELECTION::new_from_pcr_u32(TPM_ALG_ID::SHA256, pcr)?; + assert_eq!(selection.pcrSelect.len(), 3); + + let mut expected = vec![0u8; 3]; + expected[(pcr / 8) as usize] = 1 << (pcr % 8); + assert_eq!(selection.pcrSelect, expected); + + // The same range through the vector-taking constructor, which shares the bound + // check and must not have picked up a different size from it. + let from_vec = TPMS_PCR_SELECTION::new_from_pcrs_vec(TPM_ALG_ID::SHA256, &[pcr])?; + assert_eq!(from_vec.pcrSelect, expected); } - let mut pcr_select = vec![0; (pcr_max / 8 + 1) as usize]; - for pcr in pcrs { - pcr_select[*pcr as usize / 8] |= 1 << (*pcr % 8); + Ok(()) + } + + #[test] + fn pcr_selection_handles_a_pcr_beyond_the_first_three_bytes() -> Result<(), TpmError> { + // PCR 24 is the first PCR outside the standard 0-23 range and previously panicked + // because the growth check divided the byte index by 8 a second time. + let selection = TPMS_PCR_SELECTION::new_from_pcr_u32(TPM_ALG_ID::SHA256, 24)?; + + assert_eq!(selection.pcrSelect.len(), 4); + assert_eq!(selection.pcrSelect, vec![0, 0, 0, 1]); + + Ok(()) + } + + #[test] + fn pcr_selection_handles_a_large_pcr_value() -> Result<(), TpmError> { + let selection = TPMS_PCR_SELECTION::new_from_pcr_u32(TPM_ALG_ID::SHA256, 200)?; + + assert_eq!(selection.pcrSelect.len(), 26); + assert_eq!(selection.pcrSelect[25], 1); + assert!(selection.pcrSelect[..25].iter().all(|&b| b == 0)); + + Ok(()) + } + + #[test] + fn pcr_selection_sets_the_correct_bit() -> Result<(), TpmError> { + let selection = TPMS_PCR_SELECTION::new_from_pcr_u32(TPM_ALG_ID::SHA256, 19)?; + + // PCR 19 is bit 3 (0b0000_1000) of byte 2 (19 / 8 == 2, 19 % 8 == 3). + assert_eq!(selection.pcrSelect, vec![0, 0, 0b0000_1000]); + + Ok(()) + } + + /// The largest PCR the wire format can name still builds, and still marshals. + /// + /// The second half is what grounds `MAX_PCR_INDEX` in something other than a comment: the + /// size prefix is one byte, so 255 bytes is the most that can be written, and the marshalled + /// form is checked to begin with that length. Widening the bound by one PCR makes + /// `select_byte_index` accept an index needing 256 bytes, which `writeSizedByteBuf` refuses + /// -- see the test below. + #[test] + fn pcr_selection_accepts_the_largest_representable_pcr() -> Result<(), TpmError> { + let selection = TPMS_PCR_SELECTION::new_from_pcr_u32( + TPM_ALG_ID::SHA256, + TPMS_PCR_SELECTION::MAX_PCR_INDEX, + )?; + + assert_eq!( + selection.pcrSelect.len(), + TPMS_PCR_SELECTION::MAX_PCR_SELECT_BYTES + ); + assert_eq!(selection.pcrSelect[254], 0b1000_0000); + assert!(selection.pcrSelect[..254].iter().all(|&b| b == 0)); + + // `toBytes` fails the marshal if the buffer went out of bounds, which is how + // `writeSizedByteBuf` reports a payload too long for its size prefix. + let marshalled = selection.toBytes()?; + + // hash (2 bytes) || size (1 byte) || pcrSelect + assert_eq!(marshalled[2], 255); + assert_eq!(marshalled.len(), 2 + 1 + 255); + + Ok(()) + } + + /// A `pcrSelect` one byte longer than the bound allows cannot be marshalled at all. + /// + /// This is the fact `MAX_PCR_SELECT_BYTES` is derived from, checked against the generated + /// marshaller rather than assumed. If the generator ever moved `TPMS_PCR_SELECTION` to a + /// wider size prefix this test would fail, which is the signal to widen the bound. + #[test] + fn a_pcr_select_over_the_bound_does_not_marshal() { + let oversized = TPMS_PCR_SELECTION::new( + TPM_ALG_ID::SHA256, + &vec![0u8; TPMS_PCR_SELECTION::MAX_PCR_SELECT_BYTES + 1], + ); + + let mut buffer = TpmBuffer::new(None); + let _ = oversized.toTpm(&mut buffer); + assert!( + !buffer.isOk(), + "a 256-byte pcrSelect does not fit behind a one-byte size prefix" + ); + assert!( + oversized.toBytes().is_err(), + "and the failure is reported to a caller that marshals the whole structure" + ); + } + + /// An out-of-range PCR is rejected before anything is allocated. + /// + /// Reverting the bound check turns this into a request for `u32::MAX / 8 + 1` bytes -- half + /// a gigabyte -- for a value that could never be sent. The test then fails on the `Ok` that + /// comes back; when this was checked by hand, the run also stopped making progress under + /// the memory it had asked for, which is the outcome the bound exists to prevent. + #[test] + fn pcr_selection_rejects_a_pcr_no_selection_can_name() { + for pcr in [ + TPMS_PCR_SELECTION::MAX_PCR_INDEX + 1, + u32::MAX / 2, + u32::MAX, + ] { + let error = TPMS_PCR_SELECTION::new_from_pcr_u32(TPM_ALG_ID::SHA256, pcr) + .expect_err("a PCR the wire format cannot name must not be allocated for"); + assert!( + matches!(error, TpmError::InvalidArraySize(_)), + "unexpected error for PCR {pcr}: {error}" + ); + + assert!( + TPMS_PCR_SELECTION::get_selection_array(TPM_ALG_ID::SHA256, pcr).is_err(), + "get_selection_array must carry the bound its element constructor applies" + ); } + } + + /// The same bound on the vector-taking constructor, including when the out-of-range index is + /// not the only one and not the first. + /// + /// Reverting `new_from_pcrs_vec` to sizing from `max(pcrs)` without a check reintroduces the + /// same unbounded allocation, and this fails. + #[test] + fn pcr_selection_from_a_vec_rejects_a_pcr_no_selection_can_name() { + let error = TPMS_PCR_SELECTION::new_from_pcrs_vec( + TPM_ALG_ID::SHA256, + &[0, 7, u32::MAX, TPMS_PCR_SELECTION::MAX_PCR_INDEX], + ) + .expect_err("one out-of-range PCR is enough to reject the whole selection"); + assert!( + matches!(error, TpmError::InvalidArraySize(_)), + "unexpected error: {error}" + ); - TPMS_PCR_SELECTION::new(hash_alg, &pcr_select) + // The largest representable index is accepted in the same position, so the rejection + // above is the bound and not the shape of the input. + let selection = TPMS_PCR_SELECTION::new_from_pcrs_vec( + TPM_ALG_ID::SHA256, + &[0, 7, TPMS_PCR_SELECTION::MAX_PCR_INDEX], + ) + .expect("the largest representable PCR is in range"); + assert_eq!( + selection.pcrSelect.len(), + TPMS_PCR_SELECTION::MAX_PCR_SELECT_BYTES + ); + assert_eq!(selection.pcrSelect[0], 0b1000_0001); + assert_eq!(selection.pcrSelect[254], 0b1000_0000); } } @@ -441,73 +916,422 @@ impl TPM_HANDLE { return Err(TpmError::GenericError(format!("Setting an invalid name of an entity with the name defined by the handle value, handle type: {}", handle_type))); } - Ok(()) + Ok(()) + } + + /// Get the TPM name of this handle + pub fn get_name(&self) -> Result, TpmError> { + let handle_type = self.get_type(); + + // Per spec: handles of these types have their handle value as their name + if handle_type == TPM_HT::PCR + || handle_type == TPM_HT::HMAC_SESSION + || handle_type == TPM_HT::POLICY_SESSION + || handle_type == TPM_HT::PERMANENT + { + let mut name = Vec::with_capacity(4); + name.extend_from_slice(&self.handle.to_be_bytes()); + return Ok(name); + } + + if handle_type == TPM_HT::NV_INDEX + || handle_type == TPM_HT::TRANSIENT + || handle_type == TPM_HT::PERSISTENT + { + if (self.name.is_empty()) { + return Err(TpmError::GenericError(format!( + "Name is not set for handle, handle type: {}", + handle_type + ))); + } + return Ok(self.name.clone()); + } + + Err(TpmError::GenericError(format!( + "Unknown handle type, handle type: {}", + handle_type + ))) + } +} + +impl std::fmt::Display for TPM_HANDLE { + /// Get a string representation of this handle + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}:0x{:x}", self.get_type(), self.handle) + } +} + +/// Wipes the private prime `TSS_KEY::privatePart` holds, so that a key that has gone out of scope +/// is not left in freed heap. +/// +/// # Why this lives here +/// +/// `TSS_KEY` is generated by TssCodeGen (`TSS.Rust/src/tpm_types.rs`) and generated files must not +/// be hand-edited, but `Drop` may be implemented anywhere in the defining crate, so the wipe can +/// be added from here. Every clone is wiped by this same implementation, exactly as for +/// [`RsaKeyParts`]. +/// +/// The printing half of the problem is closed too, by the `std::fmt::Debug` implementation +/// immediately below: the generator no longer derives `Debug` over this type, so `{:?}` renders +/// the prime as a byte count and nothing more. +/// +/// One visible consequence, the same one `RsaKeyParts` already has: a type with a `Drop` cannot +/// have its fields moved out, so `TSS_KEY { publicPart, ..Default::default() }` no longer +/// compiles. Name both fields instead. The error is a compile error, not a surprise at runtime. +impl Drop for TSS_KEY { + fn drop(&mut self) { + self.privatePart.zeroize(); + } +} + +/// Renders the public half of the key in full and the private prime not at all. +/// +/// A derived `Debug` would print the RSA factor into any log line or error path that formats a +/// key, which is why `TSS_KEY` is listed in `CGenRust.StructsWithHandWrittenDebug` and the +/// generator emits no derive for it. The byte count is disclosed deliberately: it is already +/// implied by `publicPart.parameters.keyBits`, and without it the rendering says nothing about +/// whether a key was populated at all. +impl std::fmt::Debug for TSS_KEY { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("TSS_KEY") + .field("publicPart", &self.publicPart) + .field( + "privatePart", + &format_args!("<{} bytes withheld>", self.privatePart.len()), + ) + .finish() + } +} + +/// Renders what identifies a handle and none of what authorizes it. +/// +/// `auth_value` is the caller's authorization value in the clear, and `TPM_HANDLE` is formatted +/// wherever a command is traced or an error names the object it failed on, so a derived `Debug` +/// would put that secret into ordinary log output. The handle and the Name are both public — the +/// Name is a digest over a public area — and are printed in full, so the rendering still says +/// which object this is. +/// +/// Note what this does *not* do: unlike [`TSS_KEY`], `TPM_HANDLE` has no `Drop` that zeroizes +/// `auth_value`. A handle is constructed, copied and cloned on nearly every code path in the +/// crate, so a `Drop` would both cost more than it buys and, by blocking field moves, break a +/// large amount of existing construction. The auth value is therefore no longer *printable*, but +/// it is still left in freed heap when a handle is dropped. +impl std::fmt::Debug for TPM_HANDLE { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("TPM_HANDLE") + .field("handle", &format_args!("0x{:08x}", self.handle)) + .field( + "auth_value", + &format_args!("<{} bytes withheld>", self.auth_value.len()), + ) + .field("name", &self.name) + .finish() + } +} + +/// Renders the sensitive area's type-independent structure and none of its secrets. +/// +/// `authValue` is an authorization secret, `seedValue` is the protection seed a parent uses to +/// derive its children's protection keys, and `sensitive` is the private key itself. None of the +/// three has a non-secret use, so all three are withheld. The union selector is printed, because +/// which *kind* of key this is is public and is the one thing a reader needs to orient. +impl std::fmt::Debug for TPMT_SENSITIVE { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let sensitive_kind = match &self.sensitive { + Some(s) => format!("{:?}", s.GetUnionSelector()), + None => "none".to_string(), + }; + f.debug_struct("TPMT_SENSITIVE") + .field( + "authValue", + &format_args!("<{} bytes withheld>", self.authValue.len()), + ) + .field( + "seedValue", + &format_args!("<{} bytes withheld>", self.seedValue.len()), + ) + .field("sensitive", &format_args!("<{sensitive_kind} withheld>")) + .finish() + } +} + +/// Renders neither the authorization value nor the data to be sealed. +/// +/// Both fields of this structure are secrets the caller is handing to the TPM: `userAuth` becomes +/// the created object's authorization value, and `data` is the key or sealed blob itself. +impl std::fmt::Debug for TPMS_SENSITIVE_CREATE { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("TPMS_SENSITIVE_CREATE") + .field( + "userAuth", + &format_args!("<{} bytes withheld>", self.userAuth.len()), + ) + .field( + "data", + &format_args!("<{} bytes withheld>", self.data.len()), + ) + .finish() + } +} + +/// Redacting `Debug` for the five `TPMU_SENSITIVE_COMPOSITE` members. +/// +/// Each of these is a single buffer holding one form of private key material, and each is used +/// nowhere in the generated binding except as a member of that union, so there is no public value +/// this can hide. They are listed in `CGenRust.StructsWithHandWrittenDebug`, so the generator +/// emits no derived `Debug` and the assertion at the end of `tpm_types.rs` requires these. +macro_rules! debug_withholds_buffer { + ($($ty:ident),+ $(,)?) => { + $( + impl std::fmt::Debug for $ty { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct(stringify!($ty)) + .field( + "buffer", + &format_args!("<{} bytes withheld>", self.buffer.len()), + ) + .finish() + } + } + )+ + }; +} + +debug_withholds_buffer!( + TPM2B_PRIVATE_KEY_RSA, + TPM2B_ECC_PARAMETER, + TPM2B_SENSITIVE_DATA, + TPM2B_SYM_KEY, + TPM2B_PRIVATE_VENDOR_SPECIFIC, +); + +/// Not gated on `software-crypto`: none of this needs a crypto backend, and the redaction is +/// exactly as load bearing in a `--no-default-features` build. +#[cfg(test)] +mod secret_redaction_tests { + use super::*; + + /// Bytes chosen so that neither their decimal nor their hexadecimal rendering is a substring + /// of anything the redacted `Debug` legitimately prints. + const SECRET: [u8; 6] = [0xA7, 0xB3, 0xC9, 0xD1, 0xE5, 0xF2]; + + fn assert_withholds_secret(rendered: &str, secret: &[u8]) { + for byte in secret { + assert!( + !rendered.contains(&byte.to_string()), + "debug rendering {rendered} leaks byte {byte} in decimal" + ); + assert!( + !rendered.to_lowercase().contains(&format!("{byte:02x}")), + "debug rendering {rendered} leaks byte {byte} in hex" + ); + } + assert!( + !rendered.contains(&format!("{:?}", secret)), + "debug rendering {rendered} leaks the secret verbatim" + ); + } + + #[test] + fn tss_key_debug_withholds_the_private_prime() { + let key = TSS_KEY { + publicPart: TPMT_PUBLIC { + nameAlg: TPM_ALG_ID::SHA256, + unique: Some(TPMU_PUBLIC_ID::rsa(TPM2B_PUBLIC_KEY_RSA { + buffer: vec![0x11, 0x22], + })), + ..Default::default() + }, + privatePart: SECRET.to_vec(), + }; + + let rendered = format!("{:?}", key); + + assert_withholds_secret(&rendered, &SECRET); + + // The public half stays legible, which is the point of hand writing the rendering rather + // than dropping `Debug` altogether. + assert!( + rendered.contains(&format!("{:?}", TPM_ALG_ID::SHA256)), + "{rendered}" + ); + assert!(rendered.contains("[17, 34]"), "{rendered}"); + assert!( + rendered.contains("privatePart: <6 bytes withheld>"), + "{rendered}" + ); + } + + #[test] + fn tpm_handle_debug_withholds_the_auth_value() { + let mut handle = TPM_HANDLE::new(0x81000001); + handle.auth_value = SECRET.to_vec(); + handle.name = vec![0x11, 0x22]; + + let rendered = format!("{:?}", handle); + + assert_withholds_secret(&rendered, &SECRET); + + // The handle and the Name are both public, and are what makes a traced handle + // identifiable at all. + assert!(rendered.contains("0x81000001"), "{rendered}"); + assert!(rendered.contains("[17, 34]"), "{rendered}"); + assert!( + rendered.contains("auth_value: <6 bytes withheld>"), + "{rendered}" + ); + } + + #[test] + fn sensitive_area_debug_withholds_every_secret_it_carries() { + let sensitive = TPMT_SENSITIVE { + authValue: SECRET.to_vec(), + seedValue: SECRET.to_vec(), + sensitive: Some(TPMU_SENSITIVE_COMPOSITE::rsa(TPM2B_PRIVATE_KEY_RSA { + buffer: SECRET.to_vec(), + })), + }; + + let rendered = format!("{:?}", sensitive); + + assert_withholds_secret(&rendered, &SECRET); + + // Which kind of key this is is public, and is the one thing a reader needs to orient. + assert!( + rendered.contains(&format!("{:?}", TPM_ALG_ID::RSA)), + "{rendered}" + ); + } + + #[test] + fn sensitive_composite_members_debug_withholds_their_buffers() { + let rendered = format!( + "{:?} {:?} {:?} {:?} {:?}", + TPM2B_PRIVATE_KEY_RSA { + buffer: SECRET.to_vec() + }, + TPM2B_ECC_PARAMETER { + buffer: SECRET.to_vec() + }, + TPM2B_SENSITIVE_DATA { + buffer: SECRET.to_vec() + }, + TPM2B_SYM_KEY { + buffer: SECRET.to_vec() + }, + TPM2B_PRIVATE_VENDOR_SPECIFIC { + buffer: SECRET.to_vec() + }, + ); + + assert_withholds_secret(&rendered, &SECRET); + assert_eq!( + rendered.matches("<6 bytes withheld>").count(), + 5, + "{rendered}" + ); } - /// Get the TPM name of this handle - pub fn get_name(&self) -> Result, TpmError> { - let handle_type = self.get_type(); + #[test] + fn sensitive_create_debug_withholds_the_auth_and_the_data() { + let create = TPMS_SENSITIVE_CREATE::new(&SECRET.to_vec(), &SECRET.to_vec()); - // Per spec: handles of these types have their handle value as their name - if handle_type == TPM_HT::PCR - || handle_type == TPM_HT::HMAC_SESSION - || handle_type == TPM_HT::POLICY_SESSION - || handle_type == TPM_HT::PERMANENT - { - let mut name = Vec::with_capacity(4); - name.extend_from_slice(&self.handle.to_be_bytes()); - return Ok(name); - } + let rendered = format!("{:?}", create); - if handle_type == TPM_HT::NV_INDEX - || handle_type == TPM_HT::TRANSIENT - || handle_type == TPM_HT::PERSISTENT - { - if (self.name.is_empty()) { - return Err(TpmError::GenericError(format!( - "Name is not set for handle, handle type: {}", - handle_type - ))); - } - return Ok(self.name.clone()); - } + assert_withholds_secret(&rendered, &SECRET); + assert!( + rendered.contains("userAuth: <6 bytes withheld>"), + "{rendered}" + ); + assert!(rendered.contains("data: <6 bytes withheld>"), "{rendered}"); + } - Err(TpmError::GenericError(format!( - "Unknown handle type, handle type: {}", - handle_type - ))) + /// Pins that the zeroizing destructor is still present. + /// + /// A `T: Drop` bound is satisfied only by a type with an explicit `impl Drop`, so this fails + /// the moment the implementation above is deleted. It does not, and cannot, observe the wipe + /// itself: reading the buffer after a real drop would be a use after free, and `Drop::drop` + /// cannot be called directly. + #[test] + fn tss_key_still_has_its_zeroizing_drop() { + // `drop_bounds` warns because a `T: Drop` bound is almost never what a caller wants. + // Here it is exactly what is wanted: the bound is satisfied only by a type carrying an + // explicit `impl Drop`, which is the property under test. + #[allow(drop_bounds)] + fn assert_explicit_drop() {} + assert_explicit_drop::(); } -} -impl std::fmt::Display for TPM_HANDLE { - /// Get a string representation of this handle - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}:0x{:x}", self.get_type(), self.handle) + #[test] + fn withholding_debug_left_clone_and_default_alone() { + let key = TSS_KEY { + publicPart: TPMT_PUBLIC::default(), + privatePart: SECRET.to_vec(), + }; + assert_eq!(key.clone().privatePart, SECRET.to_vec()); + assert!(TSS_KEY::default().privatePart.is_empty()); + + let mut handle = TPM_HANDLE::new(0x81000001); + handle.auth_value = SECRET.to_vec(); + assert_eq!(handle.clone().auth_value, SECRET.to_vec()); + assert_eq!(handle.clone().handle, 0x81000001); + assert_eq!(TPM_HANDLE::default().handle, u32::from(TPM_RH::NULL)); } } impl TSS_KEY { /// Generate an RSA key pair in software. /// Populates publicPart.unique with the modulus and privatePart with the first prime (p). + /// + /// The prime moves out of the [`RsaKeyParts`] the provider returned and into `privatePart`, + /// which is wiped on drop by the [`Drop`] implementation above and withheld from `{:?}` by + /// the [`std::fmt::Debug`] implementation above. + /// + /// Calling this twice on the same key is safe for the prime it replaces: the store goes + /// through [`TSS_KEY::set_private_part`], which wipes the old one before the allocation + /// holding it is freed. pub fn create_key(&mut self, crypto: &CryptoProvider) -> Result<(), TpmError> { let (key_bits, exponent) = if let Some(TPMU_PUBLIC_PARMS::rsaDetail(ref params)) = self.publicPart.parameters { (params.keyBits as usize, params.exponent_bytes()) } else { - return Err(TpmError::GenericError("Only RSA key creation is supported".to_string())); + return Err(TpmError::GenericError( + "Only RSA key creation is supported".to_string(), + )); }; - let key = Crypto::rsa_generate_keypair(crypto, key_bits, &exponent)?; + let mut key = Crypto::rsa_generate_keypair(crypto, key_bits, &exponent)?; + + // `RsaKeyParts` wipes its prime when dropped, so its fields cannot be moved out. Taking + // them leaves nothing behind for the wipe to do, which is what is wanted here: the + // material is moving into this key rather than being copied out of it. - // Store modulus (n) in publicPart.unique - self.publicPart.unique = Some(TPMU_PUBLIC_ID::rsa(TPM2B_PUBLIC_KEY_RSA { buffer: key.modulus })); + // Store modulus (n) in publicPart.unique. No wipe is needed for what this replaces: the + // modulus is the public half of the key and is published in the Name of every object + // derived from it. + self.publicPart.unique = Some(TPMU_PUBLIC_ID::rsa(TPM2B_PUBLIC_KEY_RSA { + buffer: std::mem::take(&mut key.modulus), + })); - // Store first prime (p) as privatePart - self.privatePart = key.prime; + // Store first prime (p) as privatePart. + self.set_private_part(std::mem::take(&mut key.prime)); Ok(()) } + /// Store `prime` as the private half of this key, wiping the prime it replaces. + /// + /// Plain assignment would not do: it drops the previous `Vec`, and `Vec`'s own `Drop` only + /// frees, it does not zeroize. The [`Drop`] implementation above runs only when the whole key + /// goes out of scope, so calling [`TSS_KEY::create_key`] twice on the same key would leave + /// the first prime sitting in freed heap for whatever allocates next. + /// + /// Every write to `privatePart` in this crate goes through here. + pub fn set_private_part(&mut self, prime: Vec) { + self.privatePart.zeroize(); + self.privatePart = prime; + } + /// Sign a digest using the software key (RSASSA-PKCS1-v1_5). /// `digest` should be the hash of the data to sign. /// Returns a TPMT_SIGNATURE with RSASSA scheme. @@ -517,16 +1341,21 @@ impl TSS_KEY { digest: &[u8], hash_alg: TPM_ALG_ID, ) -> Result { - let rsa_params = if let Some(TPMU_PUBLIC_PARMS::rsaDetail(ref params)) = self.publicPart.parameters { - params - } else { - return Err(TpmError::GenericError("Only RSA signing is supported".to_string())); - }; + let rsa_params = + if let Some(TPMU_PUBLIC_PARMS::rsaDetail(ref params)) = self.publicPart.parameters { + params + } else { + return Err(TpmError::GenericError( + "Only RSA signing is supported".to_string(), + )); + }; let n_bytes = if let Some(TPMU_PUBLIC_ID::rsa(ref pub_key)) = self.publicPart.unique { pub_key.buffer.clone() } else { - return Err(TpmError::GenericError("No public key available".to_string())); + return Err(TpmError::GenericError( + "No public key available".to_string(), + )); }; // Reconstruct RSA private key from modulus + prime p @@ -547,6 +1376,161 @@ impl TSS_KEY { } } +/// Observes that overwriting `TSS_KEY::privatePart` wipes the prime it replaces. +/// +/// The claim is about memory that has been freed, and freed memory cannot be read afterwards +/// without reaching into it. It can be read at the *moment* of freeing, though: a `GlobalAlloc` +/// is handed a still-valid pointer to the block, so the wrapper below inspects it there and +/// records what it found before delegating to the system allocator. +/// +/// Two things keep that read sound. Exactly one block is ever inspected — the one whose address +/// was armed, on this thread, while it was still owned by a live `Vec`, so no other allocation +/// can be sitting at that address — and only the bytes that `Vec` had initialized are read, +/// never its spare capacity. +/// +/// A watched block that is *resized* rather than dropped escapes the check, because `realloc` is +/// forwarded to the system allocator untouched. That fails safe: the verdict stays `NOT_FREED` +/// and the assertions below reject it. +#[cfg(test)] +mod private_part_wipe_tests { + use super::*; + use std::alloc::{GlobalAlloc, Layout, System}; + use std::cell::Cell; + + /// The watched block was not released while it was being watched, so nothing was observed. + const NOT_FREED: u8 = 0; + /// It was released holding nothing but zeros. + const FREED_WIPED: u8 = 1; + /// It was released with its contents still in it. + const FREED_INTACT: u8 = 2; + + thread_local! { + /// Address of the block to inspect when it is released, or 0 for "not watching". + static WATCHED_PTR: Cell = const { Cell::new(0) }; + /// How many bytes of that block were initialized. Only these are read. + static WATCHED_LEN: Cell = const { Cell::new(0) }; + static VERDICT: Cell = const { Cell::new(NOT_FREED) }; + } + + struct WatchingAllocator; + + unsafe impl GlobalAlloc for WatchingAllocator { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + System.alloc(layout) + } + + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { + System.alloc_zeroed(layout) + } + + unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { + System.realloc(ptr, layout, new_size) + } + + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { + // `try_with` because thread-local storage may already have been torn down when a + // thread's last allocations are released. The cells are `const`-initialized, so + // reading them never allocates and this cannot re-enter the allocator. + let watched = WATCHED_PTR.try_with(|w| w.get()).unwrap_or(0); + if watched != 0 && watched == ptr as usize { + let len = WATCHED_LEN.try_with(|w| w.get()).unwrap_or(0); + let initialized = std::slice::from_raw_parts(ptr, len.min(layout.size())); + let verdict = if initialized.iter().all(|&byte| byte == 0) { + FREED_WIPED + } else { + FREED_INTACT + }; + let _ = WATCHED_PTR.try_with(|w| w.set(0)); + let _ = VERDICT.try_with(|v| v.set(verdict)); + } + System.dealloc(ptr, layout) + } + } + + #[global_allocator] + static ALLOCATOR: WatchingAllocator = WatchingAllocator; + + /// Start watching the block `secret` currently owns. + fn watch(secret: &[u8]) { + VERDICT.with(|v| v.set(NOT_FREED)); + WATCHED_LEN.with(|w| w.set(secret.len())); + WATCHED_PTR.with(|w| w.set(secret.as_ptr() as usize)); + } + + /// Stop watching, and report what the allocator saw. + fn verdict() -> u8 { + WATCHED_PTR.with(|w| w.set(0)); + VERDICT.with(|v| v.get()) + } + + fn assert_wiped(verdict: u8) { + assert_ne!( + verdict, NOT_FREED, + "the watched block was never released, so this test observed nothing at all" + ); + assert_eq!( + verdict, FREED_WIPED, + "the block holding the replaced prime was released with the prime still in it" + ); + } + + /// Deleting the `zeroize` in [`TSS_KEY::set_private_part`] fails this: the block is then + /// released still holding `0xA7`, and the verdict is `FREED_INTACT`. + #[test] + fn overwriting_the_private_part_wipes_the_prime_it_replaces() { + let mut key = TSS_KEY { + publicPart: TPMT_PUBLIC::default(), + privatePart: vec![0xA7u8; 64], + }; + + watch(&key.privatePart); + key.set_private_part(vec![0x11; 64]); + + assert_wiped(verdict()); + assert_eq!(key.privatePart, vec![0x11; 64]); + } + + /// The same property for [`TSS_KEY::create_key`], which is where the defect was reported. + /// + /// The test above would stay green if `create_key` went back to assigning to the field + /// directly, so this one pins that the store still goes through the wiping path. 1024 bits + /// because two keys are generated and the modulus size is irrelevant to what is observed. + #[test] + #[cfg(feature = "software-crypto")] + fn a_second_create_key_wipes_the_prime_the_first_left() -> Result<(), TpmError> { + use crate::crypto::software_provider::SOFTWARE_PROVIDER; + + let mut key = TSS_KEY { + publicPart: TPMT_PUBLIC { + nameAlg: TPM_ALG_ID::SHA256, + parameters: Some(TPMU_PUBLIC_PARMS::rsaDetail(TPMS_RSA_PARMS::new( + &TPMT_SYM_DEF_OBJECT::new(TPM_ALG_ID::AES, 128, TPM_ALG_ID::CFB), + &Some(TPMU_ASYM_SCHEME::null(TPMS_NULL_ASYM_SCHEME::default())), + 1024, + 65537, + ))), + ..Default::default() + }, + privatePart: Vec::new(), + }; + + key.create_key(&SOFTWARE_PROVIDER)?; + let first_prime = key.privatePart.clone(); + assert!(!first_prime.is_empty(), "the first key produced no prime"); + + watch(&key.privatePart); + key.create_key(&SOFTWARE_PROVIDER)?; + + assert_wiped(verdict()); + assert_ne!( + key.privatePart, first_prime, + "the second call must have produced a different key for this to mean anything" + ); + + Ok(()) + } +} + // The activation round trip is checked against a software endorsement key built with the `rsa` // crate, so these tests only apply when the software provider is compiled in. #[cfg(all(test, feature = "software-crypto"))] @@ -619,7 +1603,15 @@ mod tests { ))); } - let sym_key = Crypto::kdfa(&SOFTWARE_PROVIDER, name_alg, seed, "STORAGE", activated_name, &[], 128)?; + let sym_key = Crypto::kdfa( + &SOFTWARE_PROVIDER, + name_alg, + seed, + "STORAGE", + activated_name, + &[], + 128, + )?; let hmac_key = Crypto::kdfa( &SOFTWARE_PROVIDER, name_alg, @@ -807,7 +1799,10 @@ mod tests { TpmError::GenericError("The ephemeral point is not on the curve".to_string()) })?; - let z = diffie_hellman(private_key.to_nonzero_scalar(), ephemeral_public.as_affine()); + let z = diffie_hellman( + private_key.to_nonzero_scalar(), + ephemeral_public.as_affine(), + ); // The TPM is the responder, yet it still names the originator's point as partyU. Deriving // with the roles reversed would produce a different seed in silence, which is why this @@ -869,7 +1864,11 @@ mod tests { let seed = ecc_recover_seed::(&private_key, name_alg, &activation.secret)?; let recovered = activate_credential(&seed, name_alg, &activated_name, &activation)?; - assert_eq!(recovered, credential, "curve {:?}, nameAlg {:?}", curve, name_alg); + assert_eq!( + recovered, credential, + "curve {:?}, nameAlg {:?}", + curve, name_alg + ); Ok(()) } @@ -1079,4 +2078,417 @@ mod tests { Ok(()) } + + /// The attributes a TPM gives a key created to sign attestations. + const ATTESTATION_ATTRIBUTES: TPMA_OBJECT = TPMA_OBJECT( + TPMA_OBJECT::restricted.0 + | TPMA_OBJECT::sign.0 + | TPMA_OBJECT::fixedTPM.0 + | TPMA_OBJECT::fixedParent.0 + | TPMA_OBJECT::sensitiveDataOrigin.0 + | TPMA_OBJECT::userWithAuth.0, + ); + + /// The public area of an RSASSA-SHA256 signing key, with `attributes` and `modulus`. + /// + /// Nothing but the genuine-certification test needs the modulus to be a real one: every + /// other check `validate_certify` makes is defined on the attestation or on the attributes, + /// so filler bytes keep those tests off the key generator. + fn signing_key_public(attributes: TPMA_OBJECT, modulus: Vec) -> TPMT_PUBLIC { + TPMT_PUBLIC { + nameAlg: TPM_ALG_ID::SHA256, + objectAttributes: attributes, + parameters: Some(TPMU_PUBLIC_PARMS::rsaDetail(TPMS_RSA_PARMS::new( + &TPMT_SYM_DEF_OBJECT::default(), + &Some(TPMU_ASYM_SCHEME::rsassa(TPMS_SIG_SCHEME_RSASSA { + hashAlg: TPM_ALG_ID::SHA256, + })), + 2048, + 65537, + ))), + unique: Some(TPMU_PUBLIC_ID::rsa(TPM2B_PUBLIC_KEY_RSA { + buffer: modulus, + })), + ..Default::default() + } + } + + /// An attestation key whose private half this test can actually sign with. + fn attestation_key() -> Result { + let mut key = TSS_KEY { + publicPart: signing_key_public(ATTESTATION_ATTRIBUTES, Vec::new()), + privatePart: Vec::new(), + }; + key.create_key(&SOFTWARE_PROVIDER)?; + Ok(key) + } + + /// The public area of the object being certified. Its contents are immaterial: only its Name + /// is compared, and that is derived from whatever is here. + fn certified_key_public() -> TPMT_PUBLIC { + signing_key_public( + TPMA_OBJECT::sign | TPMA_OBJECT::fixedParent, + vec![0x11; 256], + ) + } + + /// A well formed `TPMS_ATTEST` of a certify, as a TPM would produce it. + fn certify_attestation( + certified_key: &TPMT_PUBLIC, + nonce: &[u8], + ) -> Result { + Ok(TPMS_ATTEST { + magic: TPM_GENERATED::VALUE, + qualifiedSigner: vec![0x0a; 34], + extraData: nonce.to_vec(), + clockInfo: TPMS_CLOCK_INFO::new(1234, 5, 6, 1), + firmwareVersion: 0x2024_0101, + attested: Some(TPMU_ATTEST::certify(TPMS_CERTIFY_INFO { + name: certified_key.get_name(&SOFTWARE_PROVIDER)?, + qualifiedName: vec![0x0b; 34], + })), + }) + } + + /// Sign an attestation the way a TPM signs one, with RSASSA over its marshalled form, under + /// `hash_alg`. + /// + /// The hash is a parameter because one test needs a signature that genuinely verifies under + /// an algorithm the key's *scheme* does not name — a garbage signature would be rejected by + /// `validate_signature` with the same error variant, and would pass whether or not the check + /// under test exists. + fn sign_attestation_with( + key: &TSS_KEY, + attest: &TPMS_ATTEST, + hash_alg: TPM_ALG_ID, + ) -> Result { + let mut buffer = TpmBuffer::new(None); + attest.toTpm(&mut buffer)?; + let digest = Crypto::hash(&SOFTWARE_PROVIDER, hash_alg, buffer.trim())?; + let signature = key.sign(&SOFTWARE_PROVIDER, &digest, hash_alg)?; + + Ok(CertifyResponse { + certifyInfo: attest.clone(), + signature: signature.signature, + }) + } + + /// Sign an attestation the way a TPM signs one, with RSASSA over its marshalled form. + fn sign_attestation(key: &TSS_KEY, attest: &TPMS_ATTEST) -> Result { + sign_attestation_with(key, attest, TPM_ALG_ID::SHA256) + } + + /// A signature in an algorithm this crate cannot verify. + /// + /// Pairing one with an otherwise flawed attestation is what shows that the checks on the + /// attestation run before the signature algorithm is dispatched on: if any of them could be + /// reached only through the RSASSA arm, these tests would report `NotSupported` instead. + fn unverifiable_signature() -> Option { + Some(TPMU_SIGNATURE::ecdsa(TPMS_SIGNATURE_ECDSA { + hash: TPM_ALG_ID::SHA256, + signatureR: vec![0x03; 32], + signatureS: vec![0x04; 32], + })) + } + + /// The signing key as `validate_certify` wants it. These tests build the public area + /// themselves, so there is no channel to distrust and nothing to pin against. + fn trusted(public: TPMT_PUBLIC) -> Result { + TrustedPublic::assume_trusted(public, &SOFTWARE_PROVIDER) + } + + fn assert_verification_failed(error: TpmError) { + assert!( + matches!(error, TpmError::VerificationFailed(_)), + "expected a verification failure, got {error}" + ); + } + + #[test] + fn validate_certify_accepts_a_genuine_certification() -> Result<(), TpmError> { + let key = attestation_key()?; + let certified_key = certified_key_public(); + let nonce = vec![9, 8, 7, 6, 5]; + let response = sign_attestation(&key, &certify_attestation(&certified_key, &nonce)?)?; + + trusted(key.publicPart.clone())?.validate_certify( + &SOFTWARE_PROVIDER, + &certified_key, + &nonce, + &response, + )?; + + Ok(()) + } + + #[test] + fn validate_certify_rejects_a_signature_over_something_else() -> Result<(), TpmError> { + let key = attestation_key()?; + let certified_key = certified_key_public(); + let nonce = vec![9, 8, 7, 6, 5]; + let mut response = sign_attestation(&key, &certify_attestation(&certified_key, &nonce)?)?; + + // A field the checks above the signature do not look at, so only the signature can catch + // it: the attestation now differs from the one that was signed. + response.certifyInfo.firmwareVersion += 1; + + let error = trusted(key.publicPart.clone())? + .validate_certify(&SOFTWARE_PROVIDER, &certified_key, &nonce, &response) + .expect_err("a signature over a different attestation must not verify"); + assert_verification_failed(error); + + Ok(()) + } + + #[test] + fn validate_certify_rejects_an_unrestricted_signing_key() -> Result<(), TpmError> { + // Everything else about this attestation is genuine, so each attribute is the only + // reason left for the rejection. + let key = attestation_key()?; + let certified_key = certified_key_public(); + let nonce = vec![4, 4, 2]; + let response = sign_attestation(&key, &certify_attestation(&certified_key, &nonce)?)?; + + for missing in [ + TPMA_OBJECT::restricted, + TPMA_OBJECT::sign, + TPMA_OBJECT::fixedTPM, + TPMA_OBJECT::fixedParent, + ] { + let mut public = key.publicPart.clone(); + public.objectAttributes = TPMA_OBJECT(public.objectAttributes.0 & !missing.0); + + let error = trusted(public)? + .validate_certify(&SOFTWARE_PROVIDER, &certified_key, &nonce, &response) + .expect_err("a signing key unfit to attest must be rejected"); + assert_verification_failed(error); + } + + Ok(()) + } + + #[test] + fn validate_certify_rejects_a_non_rsassa_signature() -> Result<(), TpmError> { + let signing_key = signing_key_public(ATTESTATION_ATTRIBUTES, vec![0xcd; 256]); + let certified_key = certified_key_public(); + let nonce = vec![1, 2, 3]; + + // Nothing else is wrong with this attestation: the only thing standing between it and a + // success is the signature algorithm. + let response = CertifyResponse { + certifyInfo: certify_attestation(&certified_key, &nonce)?, + signature: unverifiable_signature(), + }; + + let error = trusted(signing_key)? + .validate_certify(&SOFTWARE_PROVIDER, &certified_key, &nonce, &response) + .expect_err("a signature this crate cannot verify must not reach a success path"); + assert!( + matches!(error, TpmError::NotSupported(_)), + "expected NotSupported, got {error}" + ); + + Ok(()) + } + + #[test] + fn validate_certify_rejects_a_forged_magic_value() -> Result<(), TpmError> { + let signing_key = signing_key_public(ATTESTATION_ATTRIBUTES, vec![0xcd; 256]); + let certified_key = certified_key_public(); + let nonce = vec![1, 2, 3]; + + let mut attest = certify_attestation(&certified_key, &nonce)?; + attest.magic = TPM_GENERATED(0); + + let response = CertifyResponse { + certifyInfo: attest, + signature: unverifiable_signature(), + }; + + let error = trusted(signing_key)? + .validate_certify(&SOFTWARE_PROVIDER, &certified_key, &nonce, &response) + .expect_err("an attestation without TPM_GENERATED_VALUE must be rejected"); + assert_verification_failed(error); + + Ok(()) + } + + #[test] + fn validate_certify_rejects_a_mismatched_nonce() -> Result<(), TpmError> { + let signing_key = signing_key_public(ATTESTATION_ATTRIBUTES, vec![0xcd; 256]); + let certified_key = certified_key_public(); + + let response = CertifyResponse { + certifyInfo: certify_attestation(&certified_key, &[1, 2, 3])?, + signature: unverifiable_signature(), + }; + + let error = trusted(signing_key)? + .validate_certify(&SOFTWARE_PROVIDER, &certified_key, &[1, 2, 4], &response) + .expect_err("an attestation carrying another nonce must be rejected"); + assert_verification_failed(error); + + Ok(()) + } + + #[test] + fn validate_certify_rejects_a_mismatched_certified_key_name() -> Result<(), TpmError> { + let signing_key = signing_key_public(ATTESTATION_ATTRIBUTES, vec![0xcd; 256]); + let certified_key = certified_key_public(); + let nonce = vec![1, 2, 3]; + + let response = CertifyResponse { + certifyInfo: certify_attestation(&certified_key, &nonce)?, + signature: unverifiable_signature(), + }; + + let another_key = signing_key_public(TPMA_OBJECT::sign, vec![0x22; 256]); + + let error = trusted(signing_key)? + .validate_certify(&SOFTWARE_PROVIDER, &another_key, &nonce, &response) + .expect_err("an attestation naming another object must be rejected"); + assert_verification_failed(error); + + Ok(()) + } + + #[test] + fn validate_certify_rejects_an_attestation_that_is_not_a_certify() -> Result<(), TpmError> { + let signing_key = signing_key_public(ATTESTATION_ATTRIBUTES, vec![0xcd; 256]); + let certified_key = certified_key_public(); + let nonce = vec![1, 2, 3]; + + let mut attest = certify_attestation(&certified_key, &nonce)?; + attest.attested = Some(TPMU_ATTEST::quote(TPMS_QUOTE_INFO { + pcrSelect: Vec::new(), + pcrDigest: vec![0x05; 32], + })); + + let response = CertifyResponse { + certifyInfo: attest, + signature: unverifiable_signature(), + }; + + let error = trusted(signing_key)? + .validate_certify(&SOFTWARE_PROVIDER, &certified_key, &nonce, &response) + .expect_err("an attestation of another kind must be rejected"); + assert_verification_failed(error); + + Ok(()) + } + + #[test] + fn validate_certify_rejects_a_signature_hash_the_key_scheme_does_not_name( + ) -> Result<(), TpmError> { + let key = attestation_key()?; + let certified_key = certified_key_public(); + let nonce = vec![1, 2, 3]; + let attest = certify_attestation(&certified_key, &nonce)?; + + // The key's scheme is RSASSA-SHA256, so a SHA-1 signature is not one it makes — but this + // one is otherwise impeccable: made with this very key, over this very attestation, and + // it verifies. Feeding a garbage signature here instead would prove nothing, because + // `validate_signature` rejects garbage with the same `VerificationFailed` variant and the + // test would pass with the scheme check deleted. + let response = sign_attestation_with(&key, &attest, TPM_ALG_ID::SHA1)?; + + // Stated as an assertion rather than left as a claim in a comment: without the check + // under test, this flows through to `validate_signature` and `validate_certify` returns + // `Ok(())`. + let signed_blob = { + let mut buffer = TpmBuffer::new(None); + attest.toTpm(&mut buffer)?; + buffer.trim().to_vec() + }; + assert!( + Crypto::validate_signature( + &SOFTWARE_PROVIDER, + &key.publicPart, + Crypto::hash(&SOFTWARE_PROVIDER, TPM_ALG_ID::SHA1, &signed_blob)?, + &response.signature, + )?, + "the SHA-1 signature must be genuine, or this test passes for the wrong reason" + ); + + let error = trusted(key.publicPart.clone())? + .validate_certify(&SOFTWARE_PROVIDER, &certified_key, &nonce, &response) + .expect_err("a signature hash the key's scheme does not name must be rejected"); + assert_verification_failed(error); + + Ok(()) + } + + #[test] + fn from_activated_credential_rejects_what_the_activation_did_not_prove() -> Result<(), TpmError> + { + let public = certified_key_public(); + let name = public.get_name(&SOFTWARE_PROVIDER)?; + let credential = vec![0x5a; 20]; + + // The credential the TPM returned is the one that was made for this Name. + let trusted = TrustedPublic::from_activated_credential( + public.clone(), + &name, + &credential, + &credential, + &SOFTWARE_PROVIDER, + )?; + assert_eq!(trusted.name(), name.as_slice()); + + // A TPM that could not recover the credential proves nothing. + assert_verification_failed( + TrustedPublic::from_activated_credential( + public.clone(), + &name, + &credential, + &[0x5b; 20], + &SOFTWARE_PROVIDER, + ) + .expect_err("a credential that did not come back is not evidence of anything"), + ); + + // Naming one object and then trusting another's public area proves nothing either. + // This one arrives through `verify_name`, and it is a rejection of an untrusted public + // area exactly as the credential comparison above is, so it reports the same variant. + let another_key = signing_key_public(TPMA_OBJECT::sign, vec![0x22; 256]); + assert_verification_failed( + TrustedPublic::from_activated_credential( + another_key, + &name, + &credential, + &credential, + &SOFTWARE_PROVIDER, + ) + .expect_err("the activation named a different object than the public area supplied"), + ); + + Ok(()) + } + + /// Pins the variant a Name mismatch reports, which is what lets a caller tell an untrusted + /// public area from an operational failure without matching on the message. + /// + /// Reverting `verify_name` to `GenericError` fails this test and the + /// `from_activated_credential` case above. + #[test] + fn a_name_mismatch_is_a_verification_failure() -> Result<(), TpmError> { + let public = certified_key_public(); + let name = public.get_name(&SOFTWARE_PROVIDER)?; + + public.verify_name(&name, &SOFTWARE_PROVIDER)?; + + let other_name = + signing_key_public(TPMA_OBJECT::sign, vec![0x22; 256]).get_name(&SOFTWARE_PROVIDER)?; + assert_verification_failed( + public + .verify_name(&other_name, &SOFTWARE_PROVIDER) + .expect_err("a public area that does not hash to the expected Name is untrusted"), + ); + assert_verification_failed( + TrustedPublic::from_pinned_name(public, &other_name, &SOFTWARE_PROVIDER) + .expect_err("from_pinned_name rejects on the same grounds"), + ); + + Ok(()) + } } diff --git a/TSS.Rust/src/tpm_types.rs b/TSS.Rust/src/tpm_types.rs index 2798edf1..c48ef8e1 100644 --- a/TSS.Rust/src/tpm_types.rs +++ b/TSS.Rust/src/tpm_types.rs @@ -7541,7 +7541,11 @@ impl TpmMarshaller for TPMU_SENSITIVE_COMPOSITE { } /// Handle of a loaded TPM key or other object [TSS] -#[derive(Debug, Clone, Derivative)] +/// +/// Holds secret material, so `Debug` is deliberately not derived here. The redacting +/// implementation is hand-written in `src/tpm_type_extensions.rs`; omitting it is a compile +/// error, enforced by the assertion at the end of this file. +#[derive(Clone, Derivative)] #[derivative(Default)] pub struct TPM_HANDLE { /// Handle value @@ -9616,9 +9620,8 @@ impl TpmStructure for TPMS_CAPABILITY_DATA { // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields - if (self.data.is_none()) { return Ok(()) }; - buf.writeInt(self.data.as_ref().unwrap().GetUnionSelector().into()); - self.data.as_ref().unwrap().toTpm(buf)?; + buf.writeInt(self.data.as_ref().ok_or(TpmError::InvalidUnion)?.GetUnionSelector().into()); + self.data.as_ref().ok_or(TpmError::InvalidUnion)?.toTpm(buf)?; Ok(()) } @@ -9626,7 +9629,7 @@ impl TpmStructure for TPMS_CAPABILITY_DATA { // Deserialize fields let r#capability: TPM_CAP = TPM_CAP(buf.readInt() as u32); self.data = TPMU_CAPABILITIES::create(r#capability)?; - self.data.as_mut().unwrap().initFromTpm(buf)?; + self.data.as_mut().ok_or(TpmError::InvalidUnion)?.initFromTpm(buf)?; Ok(()) } @@ -10347,12 +10350,12 @@ impl TpmStructure for TPMS_ATTEST { fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields buf.writeInt(self.magic.into()); - buf.writeShort(self.attested.as_ref().unwrap().GetUnionSelector().into()); + buf.writeShort(self.attested.as_ref().ok_or(TpmError::InvalidUnion)?.GetUnionSelector().into()); buf.writeSizedByteBuf(&self.qualifiedSigner, 2); buf.writeSizedByteBuf(&self.extraData, 2); self.clockInfo.toTpm(buf)?; buf.writeInt64(self.firmwareVersion as u64); - self.attested.as_ref().unwrap().toTpm(buf)?; + self.attested.as_ref().ok_or(TpmError::InvalidUnion)?.toTpm(buf)?; Ok(()) } @@ -10365,7 +10368,7 @@ impl TpmStructure for TPMS_ATTEST { self.clockInfo.initFromTpm(buf)?; self.firmwareVersion = buf.readInt64() as u64; self.attested = TPMU_ATTEST::create(r#type)?; - self.attested.as_mut().unwrap().initFromTpm(buf)?; + self.attested.as_mut().ok_or(TpmError::InvalidUnion)?.initFromTpm(buf)?; Ok(()) } @@ -10996,7 +10999,11 @@ impl TpmMarshaller for TPMT_SYM_DEF_OBJECT { } /// This structure is used to hold a symmetric key in the sensitive area of an asymmetric object. -#[derive(Debug, Clone, Derivative)] +/// +/// Holds secret material, so `Debug` is deliberately not derived here. The redacting +/// implementation is hand-written in `src/tpm_type_extensions.rs`; omitting it is a compile +/// error, enforced by the assertion at the end of this file. +#[derive(Clone, Derivative)] #[derivative(Default)] pub struct TPM2B_SYM_KEY { /// The key @@ -11263,7 +11270,11 @@ impl TpmMarshaller for TPM2B_DERIVE { } /// This buffer wraps the TPMU_SENSITIVE_CREATE structure. -#[derive(Debug, Clone, Derivative)] +/// +/// Holds secret material, so `Debug` is deliberately not derived here. The redacting +/// implementation is hand-written in `src/tpm_type_extensions.rs`; omitting it is a compile +/// error, enforced by the assertion at the end of this file. +#[derive(Clone, Derivative)] #[derivative(Default)] pub struct TPM2B_SENSITIVE_DATA { /// Symmetric data for a created object or the label and context for a derived object @@ -11317,7 +11328,11 @@ impl TpmMarshaller for TPM2B_SENSITIVE_DATA { /// This structure defines the values to be placed in the sensitive area of a created /// object. This structure is only used within a TPM2B_SENSITIVE_CREATE structure. -#[derive(Debug, Clone, Derivative)] +/// +/// Holds secret material, so `Debug` is deliberately not derived here. The redacting +/// implementation is hand-written in `src/tpm_type_extensions.rs`; omitting it is a compile +/// error, enforced by the assertion at the end of this file. +#[derive(Clone, Derivative)] #[derivative(Default)] pub struct TPMS_SENSITIVE_CREATE { /// The USER auth secret value @@ -11715,9 +11730,8 @@ impl TpmStructure for TPMT_KEYEDHASH_SCHEME { // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields - if (self.details.is_none()) { return Ok(()) }; - buf.writeShort(self.details.as_ref().unwrap().GetUnionSelector().into()); - self.details.as_ref().unwrap().toTpm(buf)?; + buf.writeShort(self.details.as_ref().ok_or(TpmError::InvalidUnion)?.GetUnionSelector().into()); + self.details.as_ref().ok_or(TpmError::InvalidUnion)?.toTpm(buf)?; Ok(()) } @@ -11725,7 +11739,7 @@ impl TpmStructure for TPMT_KEYEDHASH_SCHEME { // Deserialize fields let r#scheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); self.details = TPMU_SCHEME_KEYEDHASH::create(r#scheme)?; - self.details.as_mut().unwrap().initFromTpm(buf)?; + self.details.as_mut().ok_or(TpmError::InvalidUnion)?.initFromTpm(buf)?; Ok(()) } @@ -12091,9 +12105,8 @@ impl TpmStructure for TPMT_SIG_SCHEME { // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields - if (self.details.is_none()) { return Ok(()) }; - buf.writeShort(self.details.as_ref().unwrap().GetUnionSelector().into()); - self.details.as_ref().unwrap().toTpm(buf)?; + buf.writeShort(self.details.as_ref().ok_or(TpmError::InvalidUnion)?.GetUnionSelector().into()); + self.details.as_ref().ok_or(TpmError::InvalidUnion)?.toTpm(buf)?; Ok(()) } @@ -12101,7 +12114,7 @@ impl TpmStructure for TPMT_SIG_SCHEME { // Deserialize fields let r#scheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); self.details = TPMU_SIG_SCHEME::create(r#scheme)?; - self.details.as_mut().unwrap().initFromTpm(buf)?; + self.details.as_mut().ok_or(TpmError::InvalidUnion)?.initFromTpm(buf)?; Ok(()) } @@ -12544,9 +12557,8 @@ impl TpmStructure for TPMT_KDF_SCHEME { // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields - if (self.details.is_none()) { return Ok(()) }; - buf.writeShort(self.details.as_ref().unwrap().GetUnionSelector().into()); - self.details.as_ref().unwrap().toTpm(buf)?; + buf.writeShort(self.details.as_ref().ok_or(TpmError::InvalidUnion)?.GetUnionSelector().into()); + self.details.as_ref().ok_or(TpmError::InvalidUnion)?.toTpm(buf)?; Ok(()) } @@ -12554,7 +12566,7 @@ impl TpmStructure for TPMT_KDF_SCHEME { // Deserialize fields let r#scheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); self.details = TPMU_KDF_SCHEME::create(r#scheme)?; - self.details.as_mut().unwrap().initFromTpm(buf)?; + self.details.as_mut().ok_or(TpmError::InvalidUnion)?.initFromTpm(buf)?; Ok(()) } @@ -12646,9 +12658,8 @@ impl TpmStructure for TPMT_ASYM_SCHEME { // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields - if (self.details.is_none()) { return Ok(()) }; - buf.writeShort(self.details.as_ref().unwrap().GetUnionSelector().into()); - self.details.as_ref().unwrap().toTpm(buf)?; + buf.writeShort(self.details.as_ref().ok_or(TpmError::InvalidUnion)?.GetUnionSelector().into()); + self.details.as_ref().ok_or(TpmError::InvalidUnion)?.toTpm(buf)?; Ok(()) } @@ -12656,7 +12667,7 @@ impl TpmStructure for TPMT_ASYM_SCHEME { // Deserialize fields let r#scheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); self.details = TPMU_ASYM_SCHEME::create(r#scheme)?; - self.details.as_mut().unwrap().initFromTpm(buf)?; + self.details.as_mut().ok_or(TpmError::InvalidUnion)?.initFromTpm(buf)?; Ok(()) } @@ -12706,9 +12717,8 @@ impl TpmStructure for TPMT_RSA_SCHEME { // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields - if (self.details.is_none()) { return Ok(()) }; - buf.writeShort(self.details.as_ref().unwrap().GetUnionSelector().into()); - self.details.as_ref().unwrap().toTpm(buf)?; + buf.writeShort(self.details.as_ref().ok_or(TpmError::InvalidUnion)?.GetUnionSelector().into()); + self.details.as_ref().ok_or(TpmError::InvalidUnion)?.toTpm(buf)?; Ok(()) } @@ -12716,7 +12726,7 @@ impl TpmStructure for TPMT_RSA_SCHEME { // Deserialize fields let r#scheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); self.details = TPMU_ASYM_SCHEME::create(r#scheme)?; - self.details.as_mut().unwrap().initFromTpm(buf)?; + self.details.as_mut().ok_or(TpmError::InvalidUnion)?.initFromTpm(buf)?; Ok(()) } @@ -12766,9 +12776,8 @@ impl TpmStructure for TPMT_RSA_DECRYPT { // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields - if (self.details.is_none()) { return Ok(()) }; - buf.writeShort(self.details.as_ref().unwrap().GetUnionSelector().into()); - self.details.as_ref().unwrap().toTpm(buf)?; + buf.writeShort(self.details.as_ref().ok_or(TpmError::InvalidUnion)?.GetUnionSelector().into()); + self.details.as_ref().ok_or(TpmError::InvalidUnion)?.toTpm(buf)?; Ok(()) } @@ -12776,7 +12785,7 @@ impl TpmStructure for TPMT_RSA_DECRYPT { // Deserialize fields let r#scheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); self.details = TPMU_ASYM_SCHEME::create(r#scheme)?; - self.details.as_mut().unwrap().initFromTpm(buf)?; + self.details.as_mut().ok_or(TpmError::InvalidUnion)?.initFromTpm(buf)?; Ok(()) } @@ -12849,7 +12858,11 @@ impl TpmMarshaller for TPM2B_PUBLIC_KEY_RSA { } /// This sized buffer holds the largest RSA prime number supported by the TPM. -#[derive(Debug, Clone, Derivative)] +/// +/// Holds secret material, so `Debug` is deliberately not derived here. The redacting +/// implementation is hand-written in `src/tpm_type_extensions.rs`; omitting it is a compile +/// error, enforced by the assertion at the end of this file. +#[derive(Clone, Derivative)] #[derivative(Default)] pub struct TPM2B_PRIVATE_KEY_RSA { pub buffer: Vec, @@ -12901,7 +12914,11 @@ impl TpmMarshaller for TPM2B_PRIVATE_KEY_RSA { } /// This sized buffer holds the largest ECC parameter (coordinate) supported by the TPM. -#[derive(Debug, Clone, Derivative)] +/// +/// Holds secret material, so `Debug` is deliberately not derived here. The redacting +/// implementation is hand-written in `src/tpm_type_extensions.rs`; omitting it is a compile +/// error, enforced by the assertion at the end of this file. +#[derive(Clone, Derivative)] #[derivative(Default)] pub struct TPM2B_ECC_PARAMETER { /// The parameter data @@ -13095,9 +13112,8 @@ impl TpmStructure for TPMT_ECC_SCHEME { // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields - if (self.details.is_none()) { return Ok(()) }; - buf.writeShort(self.details.as_ref().unwrap().GetUnionSelector().into()); - self.details.as_ref().unwrap().toTpm(buf)?; + buf.writeShort(self.details.as_ref().ok_or(TpmError::InvalidUnion)?.GetUnionSelector().into()); + self.details.as_ref().ok_or(TpmError::InvalidUnion)?.toTpm(buf)?; Ok(()) } @@ -13105,7 +13121,7 @@ impl TpmStructure for TPMT_ECC_SCHEME { // Deserialize fields let r#scheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); self.details = TPMU_ASYM_SCHEME::create(r#scheme)?; - self.details.as_mut().unwrap().initFromTpm(buf)?; + self.details.as_mut().ok_or(TpmError::InvalidUnion)?.initFromTpm(buf)?; Ok(()) } @@ -13213,10 +13229,10 @@ impl TpmStructure for TPMS_ALGORITHM_DETAIL_ECC { // Serialize fields buf.writeShort(self.curveID.into()); buf.writeShort(self.keySize as u16); - buf.writeShort(self.kdf.as_ref().unwrap().GetUnionSelector().into()); - self.kdf.as_ref().unwrap().toTpm(buf)?; - buf.writeShort(self.sign.as_ref().unwrap().GetUnionSelector().into()); - self.sign.as_ref().unwrap().toTpm(buf)?; + buf.writeShort(self.kdf.as_ref().ok_or(TpmError::InvalidUnion)?.GetUnionSelector().into()); + self.kdf.as_ref().ok_or(TpmError::InvalidUnion)?.toTpm(buf)?; + buf.writeShort(self.sign.as_ref().ok_or(TpmError::InvalidUnion)?.GetUnionSelector().into()); + self.sign.as_ref().ok_or(TpmError::InvalidUnion)?.toTpm(buf)?; buf.writeSizedByteBuf(&self.p, 2); buf.writeSizedByteBuf(&self.a, 2); buf.writeSizedByteBuf(&self.b, 2); @@ -13233,10 +13249,10 @@ impl TpmStructure for TPMS_ALGORITHM_DETAIL_ECC { self.keySize = buf.readShort() as u16; let r#kdfScheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); self.kdf = TPMU_KDF_SCHEME::create(r#kdfScheme)?; - self.kdf.as_mut().unwrap().initFromTpm(buf)?; + self.kdf.as_mut().ok_or(TpmError::InvalidUnion)?.initFromTpm(buf)?; let r#signScheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); self.sign = TPMU_ASYM_SCHEME::create(r#signScheme)?; - self.sign.as_mut().unwrap().initFromTpm(buf)?; + self.sign.as_mut().ok_or(TpmError::InvalidUnion)?.initFromTpm(buf)?; self.p = buf.readSizedByteBuf(2); self.a = buf.readSizedByteBuf(2); self.b = buf.readSizedByteBuf(2); @@ -13767,9 +13783,8 @@ impl TpmStructure for TPMT_SIGNATURE { // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields - if (self.signature.is_none()) { return Ok(()) }; - buf.writeShort(self.signature.as_ref().unwrap().GetUnionSelector().into()); - self.signature.as_ref().unwrap().toTpm(buf)?; + buf.writeShort(self.signature.as_ref().ok_or(TpmError::InvalidUnion)?.GetUnionSelector().into()); + self.signature.as_ref().ok_or(TpmError::InvalidUnion)?.toTpm(buf)?; Ok(()) } @@ -13777,7 +13792,7 @@ impl TpmStructure for TPMT_SIGNATURE { // Deserialize fields let r#sigAlg: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); self.signature = TPMU_SIGNATURE::create(r#sigAlg)?; - self.signature.as_mut().unwrap().initFromTpm(buf)?; + self.signature.as_mut().ok_or(TpmError::InvalidUnion)?.initFromTpm(buf)?; Ok(()) } @@ -13880,9 +13895,8 @@ impl TpmStructure for TPMS_KEYEDHASH_PARMS { // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields - if (self.scheme.is_none()) { return Ok(()) }; - buf.writeShort(self.scheme.as_ref().unwrap().GetUnionSelector().into()); - self.scheme.as_ref().unwrap().toTpm(buf)?; + buf.writeShort(self.scheme.as_ref().ok_or(TpmError::InvalidUnion)?.GetUnionSelector().into()); + self.scheme.as_ref().ok_or(TpmError::InvalidUnion)?.toTpm(buf)?; Ok(()) } @@ -13890,7 +13904,7 @@ impl TpmStructure for TPMS_KEYEDHASH_PARMS { // Deserialize fields let r#schemeScheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); self.scheme = TPMU_SCHEME_KEYEDHASH::create(r#schemeScheme)?; - self.scheme.as_mut().unwrap().initFromTpm(buf)?; + self.scheme.as_mut().ok_or(TpmError::InvalidUnion)?.initFromTpm(buf)?; Ok(()) } @@ -13956,8 +13970,8 @@ impl TpmStructure for TPMS_ASYM_PARMS { fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields self.symmetric.toTpm(buf)?; - buf.writeShort(self.scheme.as_ref().unwrap().GetUnionSelector().into()); - self.scheme.as_ref().unwrap().toTpm(buf)?; + buf.writeShort(self.scheme.as_ref().ok_or(TpmError::InvalidUnion)?.GetUnionSelector().into()); + self.scheme.as_ref().ok_or(TpmError::InvalidUnion)?.toTpm(buf)?; Ok(()) } @@ -13966,7 +13980,7 @@ impl TpmStructure for TPMS_ASYM_PARMS { self.symmetric.initFromTpm(buf)?; let r#schemeScheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); self.scheme = TPMU_ASYM_SCHEME::create(r#schemeScheme)?; - self.scheme.as_mut().unwrap().initFromTpm(buf)?; + self.scheme.as_mut().ok_or(TpmError::InvalidUnion)?.initFromTpm(buf)?; Ok(()) } @@ -14049,8 +14063,8 @@ impl TpmStructure for TPMS_RSA_PARMS { fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields self.symmetric.toTpm(buf)?; - buf.writeShort(self.scheme.as_ref().unwrap().GetUnionSelector().into()); - self.scheme.as_ref().unwrap().toTpm(buf)?; + buf.writeShort(self.scheme.as_ref().ok_or(TpmError::InvalidUnion)?.GetUnionSelector().into()); + self.scheme.as_ref().ok_or(TpmError::InvalidUnion)?.toTpm(buf)?; buf.writeShort(self.keyBits as u16); buf.writeInt(self.exponent as u32); Ok(()) @@ -14061,7 +14075,7 @@ impl TpmStructure for TPMS_RSA_PARMS { self.symmetric.initFromTpm(buf)?; let r#schemeScheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); self.scheme = TPMU_ASYM_SCHEME::create(r#schemeScheme)?; - self.scheme.as_mut().unwrap().initFromTpm(buf)?; + self.scheme.as_mut().ok_or(TpmError::InvalidUnion)?.initFromTpm(buf)?; self.keyBits = buf.readShort() as u16; self.exponent = buf.readInt() as u32; Ok(()) @@ -14147,11 +14161,11 @@ impl TpmStructure for TPMS_ECC_PARMS { fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields self.symmetric.toTpm(buf)?; - buf.writeShort(self.scheme.as_ref().unwrap().GetUnionSelector().into()); - self.scheme.as_ref().unwrap().toTpm(buf)?; + buf.writeShort(self.scheme.as_ref().ok_or(TpmError::InvalidUnion)?.GetUnionSelector().into()); + self.scheme.as_ref().ok_or(TpmError::InvalidUnion)?.toTpm(buf)?; buf.writeShort(self.curveID.into()); - buf.writeShort(self.kdf.as_ref().unwrap().GetUnionSelector().into()); - self.kdf.as_ref().unwrap().toTpm(buf)?; + buf.writeShort(self.kdf.as_ref().ok_or(TpmError::InvalidUnion)?.GetUnionSelector().into()); + self.kdf.as_ref().ok_or(TpmError::InvalidUnion)?.toTpm(buf)?; Ok(()) } @@ -14160,11 +14174,11 @@ impl TpmStructure for TPMS_ECC_PARMS { self.symmetric.initFromTpm(buf)?; let r#schemeScheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); self.scheme = TPMU_ASYM_SCHEME::create(r#schemeScheme)?; - self.scheme.as_mut().unwrap().initFromTpm(buf)?; + self.scheme.as_mut().ok_or(TpmError::InvalidUnion)?.initFromTpm(buf)?; self.curveID = TPM_ECC_CURVE(buf.readShort() as u16); let r#kdfScheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); self.kdf = TPMU_KDF_SCHEME::create(r#kdfScheme)?; - self.kdf.as_mut().unwrap().initFromTpm(buf)?; + self.kdf.as_mut().ok_or(TpmError::InvalidUnion)?.initFromTpm(buf)?; Ok(()) } @@ -14213,9 +14227,8 @@ impl TpmStructure for TPMT_PUBLIC_PARMS { // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields - if (self.parameters.is_none()) { return Ok(()) }; - buf.writeShort(self.parameters.as_ref().unwrap().GetUnionSelector().into()); - self.parameters.as_ref().unwrap().toTpm(buf)?; + buf.writeShort(self.parameters.as_ref().ok_or(TpmError::InvalidUnion)?.GetUnionSelector().into()); + self.parameters.as_ref().ok_or(TpmError::InvalidUnion)?.toTpm(buf)?; Ok(()) } @@ -14223,7 +14236,7 @@ impl TpmStructure for TPMT_PUBLIC_PARMS { // Deserialize fields let r#type: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); self.parameters = TPMU_PUBLIC_PARMS::create(r#type)?; - self.parameters.as_mut().unwrap().initFromTpm(buf)?; + self.parameters.as_mut().ok_or(TpmError::InvalidUnion)?.initFromTpm(buf)?; Ok(()) } @@ -14300,13 +14313,12 @@ impl TpmStructure for TPMT_PUBLIC { // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields - if (self.parameters.is_none()) { return Ok(()) }; - buf.writeShort(self.parameters.as_ref().unwrap().GetUnionSelector().into()); + buf.writeShort(self.parameters.as_ref().ok_or(TpmError::InvalidUnion)?.GetUnionSelector().into()); buf.writeShort(self.nameAlg.into()); buf.writeInt(self.objectAttributes.into()); buf.writeSizedByteBuf(&self.authPolicy, 2); - self.parameters.as_ref().unwrap().toTpm(buf)?; - self.unique.as_ref().unwrap().toTpm(buf)?; + self.parameters.as_ref().ok_or(TpmError::InvalidUnion)?.toTpm(buf)?; + self.unique.as_ref().ok_or(TpmError::InvalidUnion)?.toTpm(buf)?; Ok(()) } @@ -14317,9 +14329,9 @@ impl TpmStructure for TPMT_PUBLIC { self.objectAttributes = TPMA_OBJECT(buf.readInt() as u32); self.authPolicy = buf.readSizedByteBuf(2); self.parameters = TPMU_PUBLIC_PARMS::create(r#type)?; - self.parameters.as_mut().unwrap().initFromTpm(buf)?; + self.parameters.as_mut().ok_or(TpmError::InvalidUnion)?.initFromTpm(buf)?; self.unique = TPMU_PUBLIC_ID::create(r#type)?; - self.unique.as_mut().unwrap().initFromTpm(buf)?; + self.unique.as_mut().ok_or(TpmError::InvalidUnion)?.initFromTpm(buf)?; Ok(()) } @@ -14447,7 +14459,11 @@ impl TpmMarshaller for TPM2B_TEMPLATE { /// values will be computed so that computations using the private key will not need to /// start with just one prime factor. This structure can be used to store the results of /// such vendor-specific calculations. -#[derive(Debug, Clone, Derivative)] +/// +/// Holds secret material, so `Debug` is deliberately not derived here. The redacting +/// implementation is hand-written in `src/tpm_type_extensions.rs`; omitting it is a compile +/// error, enforced by the assertion at the end of this file. +#[derive(Clone, Derivative)] #[derivative(Default)] pub struct TPM2B_PRIVATE_VENDOR_SPECIFIC { pub buffer: Vec, @@ -14500,7 +14516,11 @@ impl TpmMarshaller for TPM2B_PRIVATE_VENDOR_SPECIFIC { /// AuthValue shall not be larger than the size of the digest produced by the nameAlg of /// the object. seedValue shall be the size of the digest produced by the nameAlg of the object. -#[derive(Debug, Clone, Derivative)] +/// +/// Holds secret material, so `Debug` is deliberately not derived here. The redacting +/// implementation is hand-written in `src/tpm_type_extensions.rs`; omitting it is a compile +/// error, enforced by the assertion at the end of this file. +#[derive(Clone, Derivative)] #[derivative(Default)] pub struct TPMT_SENSITIVE { /// Identifier for the sensitive area @@ -14541,10 +14561,10 @@ impl TpmStructure for TPMT_SENSITIVE { fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields if (self.sensitive.is_none()) { return Ok(()) }; - buf.writeShort(self.sensitive.as_ref().unwrap().GetUnionSelector().into()); + buf.writeShort(self.sensitive.as_ref().ok_or(TpmError::InvalidUnion)?.GetUnionSelector().into()); buf.writeSizedByteBuf(&self.authValue, 2); buf.writeSizedByteBuf(&self.seedValue, 2); - self.sensitive.as_ref().unwrap().toTpm(buf)?; + self.sensitive.as_ref().ok_or(TpmError::InvalidUnion)?.toTpm(buf)?; Ok(()) } @@ -14554,7 +14574,7 @@ impl TpmStructure for TPMT_SENSITIVE { self.authValue = buf.readSizedByteBuf(2); self.seedValue = buf.readSizedByteBuf(2); self.sensitive = TPMU_SENSITIVE_COMPOSITE::create(r#sensitiveType)?; - self.sensitive.as_mut().unwrap().initFromTpm(buf)?; + self.sensitive.as_mut().ok_or(TpmError::InvalidUnion)?.initFromTpm(buf)?; Ok(()) } @@ -17969,8 +17989,8 @@ impl TpmStructure for TPM2_RSA_Encrypt_REQUEST { fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields buf.writeSizedByteBuf(&self.message, 2); - buf.writeShort(self.inScheme.as_ref().unwrap().GetUnionSelector().into()); - self.inScheme.as_ref().unwrap().toTpm(buf)?; + buf.writeShort(self.inScheme.as_ref().ok_or(TpmError::InvalidUnion)?.GetUnionSelector().into()); + self.inScheme.as_ref().ok_or(TpmError::InvalidUnion)?.toTpm(buf)?; buf.writeSizedByteBuf(&self.label, 2); Ok(()) } @@ -17980,7 +18000,7 @@ impl TpmStructure for TPM2_RSA_Encrypt_REQUEST { self.message = buf.readSizedByteBuf(2); let r#inSchemeScheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); self.inScheme = TPMU_ASYM_SCHEME::create(r#inSchemeScheme)?; - self.inScheme.as_mut().unwrap().initFromTpm(buf)?; + self.inScheme.as_mut().ok_or(TpmError::InvalidUnion)?.initFromTpm(buf)?; self.label = buf.readSizedByteBuf(2); Ok(()) } @@ -18119,8 +18139,8 @@ impl TpmStructure for TPM2_RSA_Decrypt_REQUEST { fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields buf.writeSizedByteBuf(&self.cipherText, 2); - buf.writeShort(self.inScheme.as_ref().unwrap().GetUnionSelector().into()); - self.inScheme.as_ref().unwrap().toTpm(buf)?; + buf.writeShort(self.inScheme.as_ref().ok_or(TpmError::InvalidUnion)?.GetUnionSelector().into()); + self.inScheme.as_ref().ok_or(TpmError::InvalidUnion)?.toTpm(buf)?; buf.writeSizedByteBuf(&self.label, 2); Ok(()) } @@ -18130,7 +18150,7 @@ impl TpmStructure for TPM2_RSA_Decrypt_REQUEST { self.cipherText = buf.readSizedByteBuf(2); let r#inSchemeScheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); self.inScheme = TPMU_ASYM_SCHEME::create(r#inSchemeScheme)?; - self.inScheme.as_mut().unwrap().initFromTpm(buf)?; + self.inScheme.as_mut().ok_or(TpmError::InvalidUnion)?.initFromTpm(buf)?; self.label = buf.readSizedByteBuf(2); Ok(()) } @@ -18775,8 +18795,8 @@ impl TpmStructure for TPM2_ECC_Encrypt_REQUEST { fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields buf.writeSizedByteBuf(&self.plainText, 2); - buf.writeShort(self.inScheme.as_ref().unwrap().GetUnionSelector().into()); - self.inScheme.as_ref().unwrap().toTpm(buf)?; + buf.writeShort(self.inScheme.as_ref().ok_or(TpmError::InvalidUnion)?.GetUnionSelector().into()); + self.inScheme.as_ref().ok_or(TpmError::InvalidUnion)?.toTpm(buf)?; Ok(()) } @@ -18785,7 +18805,7 @@ impl TpmStructure for TPM2_ECC_Encrypt_REQUEST { self.plainText = buf.readSizedByteBuf(2); let r#inSchemeScheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); self.inScheme = TPMU_KDF_SCHEME::create(r#inSchemeScheme)?; - self.inScheme.as_mut().unwrap().initFromTpm(buf)?; + self.inScheme.as_mut().ok_or(TpmError::InvalidUnion)?.initFromTpm(buf)?; Ok(()) } @@ -18933,8 +18953,8 @@ impl TpmStructure for TPM2_ECC_Decrypt_REQUEST { buf.writeSizedObj(&self.C1)?; buf.writeSizedByteBuf(&self.C2, 2); buf.writeSizedByteBuf(&self.C3, 2); - buf.writeShort(self.inScheme.as_ref().unwrap().GetUnionSelector().into()); - self.inScheme.as_ref().unwrap().toTpm(buf)?; + buf.writeShort(self.inScheme.as_ref().ok_or(TpmError::InvalidUnion)?.GetUnionSelector().into()); + self.inScheme.as_ref().ok_or(TpmError::InvalidUnion)?.toTpm(buf)?; Ok(()) } @@ -18945,7 +18965,7 @@ impl TpmStructure for TPM2_ECC_Decrypt_REQUEST { self.C3 = buf.readSizedByteBuf(2); let r#inSchemeScheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); self.inScheme = TPMU_KDF_SCHEME::create(r#inSchemeScheme)?; - self.inScheme.as_mut().unwrap().initFromTpm(buf)?; + self.inScheme.as_mut().ok_or(TpmError::InvalidUnion)?.initFromTpm(buf)?; Ok(()) } @@ -20700,8 +20720,8 @@ impl TpmStructure for TPM2_Certify_REQUEST { fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields buf.writeSizedByteBuf(&self.qualifyingData, 2); - buf.writeShort(self.inScheme.as_ref().unwrap().GetUnionSelector().into()); - self.inScheme.as_ref().unwrap().toTpm(buf)?; + buf.writeShort(self.inScheme.as_ref().ok_or(TpmError::InvalidUnion)?.GetUnionSelector().into()); + self.inScheme.as_ref().ok_or(TpmError::InvalidUnion)?.toTpm(buf)?; Ok(()) } @@ -20710,7 +20730,7 @@ impl TpmStructure for TPM2_Certify_REQUEST { self.qualifyingData = buf.readSizedByteBuf(2); let r#inSchemeScheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); self.inScheme = TPMU_SIG_SCHEME::create(r#inSchemeScheme)?; - self.inScheme.as_mut().unwrap().initFromTpm(buf)?; + self.inScheme.as_mut().ok_or(TpmError::InvalidUnion)?.initFromTpm(buf)?; Ok(()) } @@ -20769,8 +20789,8 @@ impl TpmStructure for CertifyResponse { fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields buf.writeSizedObj(&self.certifyInfo)?; - buf.writeShort(self.signature.as_ref().unwrap().GetUnionSelector().into()); - self.signature.as_ref().unwrap().toTpm(buf)?; + buf.writeShort(self.signature.as_ref().ok_or(TpmError::InvalidUnion)?.GetUnionSelector().into()); + self.signature.as_ref().ok_or(TpmError::InvalidUnion)?.toTpm(buf)?; Ok(()) } @@ -20779,7 +20799,7 @@ impl TpmStructure for CertifyResponse { buf.readSizedObj(&mut self.certifyInfo)?; let r#signatureSigAlg: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); self.signature = TPMU_SIGNATURE::create(r#signatureSigAlg)?; - self.signature.as_mut().unwrap().initFromTpm(buf)?; + self.signature.as_mut().ok_or(TpmError::InvalidUnion)?.initFromTpm(buf)?; Ok(()) } @@ -20875,8 +20895,8 @@ impl TpmStructure for TPM2_CertifyCreation_REQUEST { // Serialize fields buf.writeSizedByteBuf(&self.qualifyingData, 2); buf.writeSizedByteBuf(&self.creationHash, 2); - buf.writeShort(self.inScheme.as_ref().unwrap().GetUnionSelector().into()); - self.inScheme.as_ref().unwrap().toTpm(buf)?; + buf.writeShort(self.inScheme.as_ref().ok_or(TpmError::InvalidUnion)?.GetUnionSelector().into()); + self.inScheme.as_ref().ok_or(TpmError::InvalidUnion)?.toTpm(buf)?; self.creationTicket.toTpm(buf)?; Ok(()) } @@ -20887,7 +20907,7 @@ impl TpmStructure for TPM2_CertifyCreation_REQUEST { self.creationHash = buf.readSizedByteBuf(2); let r#inSchemeScheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); self.inScheme = TPMU_SIG_SCHEME::create(r#inSchemeScheme)?; - self.inScheme.as_mut().unwrap().initFromTpm(buf)?; + self.inScheme.as_mut().ok_or(TpmError::InvalidUnion)?.initFromTpm(buf)?; self.creationTicket.initFromTpm(buf)?; Ok(()) } @@ -20946,8 +20966,8 @@ impl TpmStructure for CertifyCreationResponse { fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields buf.writeSizedObj(&self.certifyInfo)?; - buf.writeShort(self.signature.as_ref().unwrap().GetUnionSelector().into()); - self.signature.as_ref().unwrap().toTpm(buf)?; + buf.writeShort(self.signature.as_ref().ok_or(TpmError::InvalidUnion)?.GetUnionSelector().into()); + self.signature.as_ref().ok_or(TpmError::InvalidUnion)?.toTpm(buf)?; Ok(()) } @@ -20956,7 +20976,7 @@ impl TpmStructure for CertifyCreationResponse { buf.readSizedObj(&mut self.certifyInfo)?; let r#signatureSigAlg: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); self.signature = TPMU_SIGNATURE::create(r#signatureSigAlg)?; - self.signature.as_mut().unwrap().initFromTpm(buf)?; + self.signature.as_mut().ok_or(TpmError::InvalidUnion)?.initFromTpm(buf)?; Ok(()) } @@ -21036,8 +21056,8 @@ impl TpmStructure for TPM2_Quote_REQUEST { fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields buf.writeSizedByteBuf(&self.qualifyingData, 2); - buf.writeShort(self.inScheme.as_ref().unwrap().GetUnionSelector().into()); - self.inScheme.as_ref().unwrap().toTpm(buf)?; + buf.writeShort(self.inScheme.as_ref().ok_or(TpmError::InvalidUnion)?.GetUnionSelector().into()); + self.inScheme.as_ref().ok_or(TpmError::InvalidUnion)?.toTpm(buf)?; buf.writeObjArr(self.PCRselect.as_ref())?; Ok(()) } @@ -21047,7 +21067,7 @@ impl TpmStructure for TPM2_Quote_REQUEST { self.qualifyingData = buf.readSizedByteBuf(2); let r#inSchemeScheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); self.inScheme = TPMU_SIG_SCHEME::create(r#inSchemeScheme)?; - self.inScheme.as_mut().unwrap().initFromTpm(buf)?; + self.inScheme.as_mut().ok_or(TpmError::InvalidUnion)?.initFromTpm(buf)?; buf.readObjArr(self.PCRselect.as_mut())?; Ok(()) } @@ -21103,8 +21123,8 @@ impl TpmStructure for QuoteResponse { fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields buf.writeSizedObj(&self.quoted)?; - buf.writeShort(self.signature.as_ref().unwrap().GetUnionSelector().into()); - self.signature.as_ref().unwrap().toTpm(buf)?; + buf.writeShort(self.signature.as_ref().ok_or(TpmError::InvalidUnion)?.GetUnionSelector().into()); + self.signature.as_ref().ok_or(TpmError::InvalidUnion)?.toTpm(buf)?; Ok(()) } @@ -21113,7 +21133,7 @@ impl TpmStructure for QuoteResponse { buf.readSizedObj(&mut self.quoted)?; let r#signatureSigAlg: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); self.signature = TPMU_SIGNATURE::create(r#signatureSigAlg)?; - self.signature.as_mut().unwrap().initFromTpm(buf)?; + self.signature.as_mut().ok_or(TpmError::InvalidUnion)?.initFromTpm(buf)?; Ok(()) } @@ -21203,8 +21223,8 @@ impl TpmStructure for TPM2_GetSessionAuditDigest_REQUEST { fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields buf.writeSizedByteBuf(&self.qualifyingData, 2); - buf.writeShort(self.inScheme.as_ref().unwrap().GetUnionSelector().into()); - self.inScheme.as_ref().unwrap().toTpm(buf)?; + buf.writeShort(self.inScheme.as_ref().ok_or(TpmError::InvalidUnion)?.GetUnionSelector().into()); + self.inScheme.as_ref().ok_or(TpmError::InvalidUnion)?.toTpm(buf)?; Ok(()) } @@ -21213,7 +21233,7 @@ impl TpmStructure for TPM2_GetSessionAuditDigest_REQUEST { self.qualifyingData = buf.readSizedByteBuf(2); let r#inSchemeScheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); self.inScheme = TPMU_SIG_SCHEME::create(r#inSchemeScheme)?; - self.inScheme.as_mut().unwrap().initFromTpm(buf)?; + self.inScheme.as_mut().ok_or(TpmError::InvalidUnion)?.initFromTpm(buf)?; Ok(()) } @@ -21268,8 +21288,8 @@ impl TpmStructure for GetSessionAuditDigestResponse { fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields buf.writeSizedObj(&self.auditInfo)?; - buf.writeShort(self.signature.as_ref().unwrap().GetUnionSelector().into()); - self.signature.as_ref().unwrap().toTpm(buf)?; + buf.writeShort(self.signature.as_ref().ok_or(TpmError::InvalidUnion)?.GetUnionSelector().into()); + self.signature.as_ref().ok_or(TpmError::InvalidUnion)?.toTpm(buf)?; Ok(()) } @@ -21278,7 +21298,7 @@ impl TpmStructure for GetSessionAuditDigestResponse { buf.readSizedObj(&mut self.auditInfo)?; let r#signatureSigAlg: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); self.signature = TPMU_SIGNATURE::create(r#signatureSigAlg)?; - self.signature.as_mut().unwrap().initFromTpm(buf)?; + self.signature.as_mut().ok_or(TpmError::InvalidUnion)?.initFromTpm(buf)?; Ok(()) } @@ -21363,8 +21383,8 @@ impl TpmStructure for TPM2_GetCommandAuditDigest_REQUEST { fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields buf.writeSizedByteBuf(&self.qualifyingData, 2); - buf.writeShort(self.inScheme.as_ref().unwrap().GetUnionSelector().into()); - self.inScheme.as_ref().unwrap().toTpm(buf)?; + buf.writeShort(self.inScheme.as_ref().ok_or(TpmError::InvalidUnion)?.GetUnionSelector().into()); + self.inScheme.as_ref().ok_or(TpmError::InvalidUnion)?.toTpm(buf)?; Ok(()) } @@ -21373,7 +21393,7 @@ impl TpmStructure for TPM2_GetCommandAuditDigest_REQUEST { self.qualifyingData = buf.readSizedByteBuf(2); let r#inSchemeScheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); self.inScheme = TPMU_SIG_SCHEME::create(r#inSchemeScheme)?; - self.inScheme.as_mut().unwrap().initFromTpm(buf)?; + self.inScheme.as_mut().ok_or(TpmError::InvalidUnion)?.initFromTpm(buf)?; Ok(()) } @@ -21430,8 +21450,8 @@ impl TpmStructure for GetCommandAuditDigestResponse { fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields buf.writeSizedObj(&self.auditInfo)?; - buf.writeShort(self.signature.as_ref().unwrap().GetUnionSelector().into()); - self.signature.as_ref().unwrap().toTpm(buf)?; + buf.writeShort(self.signature.as_ref().ok_or(TpmError::InvalidUnion)?.GetUnionSelector().into()); + self.signature.as_ref().ok_or(TpmError::InvalidUnion)?.toTpm(buf)?; Ok(()) } @@ -21440,7 +21460,7 @@ impl TpmStructure for GetCommandAuditDigestResponse { buf.readSizedObj(&mut self.auditInfo)?; let r#signatureSigAlg: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); self.signature = TPMU_SIGNATURE::create(r#signatureSigAlg)?; - self.signature.as_mut().unwrap().initFromTpm(buf)?; + self.signature.as_mut().ok_or(TpmError::InvalidUnion)?.initFromTpm(buf)?; Ok(()) } @@ -21523,8 +21543,8 @@ impl TpmStructure for TPM2_GetTime_REQUEST { fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields buf.writeSizedByteBuf(&self.qualifyingData, 2); - buf.writeShort(self.inScheme.as_ref().unwrap().GetUnionSelector().into()); - self.inScheme.as_ref().unwrap().toTpm(buf)?; + buf.writeShort(self.inScheme.as_ref().ok_or(TpmError::InvalidUnion)?.GetUnionSelector().into()); + self.inScheme.as_ref().ok_or(TpmError::InvalidUnion)?.toTpm(buf)?; Ok(()) } @@ -21533,7 +21553,7 @@ impl TpmStructure for TPM2_GetTime_REQUEST { self.qualifyingData = buf.readSizedByteBuf(2); let r#inSchemeScheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); self.inScheme = TPMU_SIG_SCHEME::create(r#inSchemeScheme)?; - self.inScheme.as_mut().unwrap().initFromTpm(buf)?; + self.inScheme.as_mut().ok_or(TpmError::InvalidUnion)?.initFromTpm(buf)?; Ok(()) } @@ -21588,8 +21608,8 @@ impl TpmStructure for GetTimeResponse { fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields buf.writeSizedObj(&self.timeInfo)?; - buf.writeShort(self.signature.as_ref().unwrap().GetUnionSelector().into()); - self.signature.as_ref().unwrap().toTpm(buf)?; + buf.writeShort(self.signature.as_ref().ok_or(TpmError::InvalidUnion)?.GetUnionSelector().into()); + self.signature.as_ref().ok_or(TpmError::InvalidUnion)?.toTpm(buf)?; Ok(()) } @@ -21598,7 +21618,7 @@ impl TpmStructure for GetTimeResponse { buf.readSizedObj(&mut self.timeInfo)?; let r#signatureSigAlg: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); self.signature = TPMU_SIGNATURE::create(r#signatureSigAlg)?; - self.signature.as_mut().unwrap().initFromTpm(buf)?; + self.signature.as_mut().ok_or(TpmError::InvalidUnion)?.initFromTpm(buf)?; Ok(()) } @@ -21691,8 +21711,8 @@ impl TpmStructure for TPM2_CertifyX509_REQUEST { fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields buf.writeSizedByteBuf(&self.reserved, 2); - buf.writeShort(self.inScheme.as_ref().unwrap().GetUnionSelector().into()); - self.inScheme.as_ref().unwrap().toTpm(buf)?; + buf.writeShort(self.inScheme.as_ref().ok_or(TpmError::InvalidUnion)?.GetUnionSelector().into()); + self.inScheme.as_ref().ok_or(TpmError::InvalidUnion)?.toTpm(buf)?; buf.writeSizedByteBuf(&self.partialCertificate, 2); Ok(()) } @@ -21702,7 +21722,7 @@ impl TpmStructure for TPM2_CertifyX509_REQUEST { self.reserved = buf.readSizedByteBuf(2); let r#inSchemeScheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); self.inScheme = TPMU_SIG_SCHEME::create(r#inSchemeScheme)?; - self.inScheme.as_mut().unwrap().initFromTpm(buf)?; + self.inScheme.as_mut().ok_or(TpmError::InvalidUnion)?.initFromTpm(buf)?; self.partialCertificate = buf.readSizedByteBuf(2); Ok(()) } @@ -21768,8 +21788,8 @@ impl TpmStructure for CertifyX509Response { // Serialize fields buf.writeSizedByteBuf(&self.addedToCertificate, 2); buf.writeSizedByteBuf(&self.tbsDigest, 2); - buf.writeShort(self.signature.as_ref().unwrap().GetUnionSelector().into()); - self.signature.as_ref().unwrap().toTpm(buf)?; + buf.writeShort(self.signature.as_ref().ok_or(TpmError::InvalidUnion)?.GetUnionSelector().into()); + self.signature.as_ref().ok_or(TpmError::InvalidUnion)?.toTpm(buf)?; Ok(()) } @@ -21779,7 +21799,7 @@ impl TpmStructure for CertifyX509Response { self.tbsDigest = buf.readSizedByteBuf(2); let r#signatureSigAlg: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); self.signature = TPMU_SIGNATURE::create(r#signatureSigAlg)?; - self.signature.as_mut().unwrap().initFromTpm(buf)?; + self.signature.as_mut().ok_or(TpmError::InvalidUnion)?.initFromTpm(buf)?; Ok(()) } @@ -22129,8 +22149,8 @@ impl TpmStructure for TPM2_VerifySignature_REQUEST { fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields buf.writeSizedByteBuf(&self.digest, 2); - buf.writeShort(self.signature.as_ref().unwrap().GetUnionSelector().into()); - self.signature.as_ref().unwrap().toTpm(buf)?; + buf.writeShort(self.signature.as_ref().ok_or(TpmError::InvalidUnion)?.GetUnionSelector().into()); + self.signature.as_ref().ok_or(TpmError::InvalidUnion)?.toTpm(buf)?; Ok(()) } @@ -22139,7 +22159,7 @@ impl TpmStructure for TPM2_VerifySignature_REQUEST { self.digest = buf.readSizedByteBuf(2); let r#signatureSigAlg: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); self.signature = TPMU_SIGNATURE::create(r#signatureSigAlg)?; - self.signature.as_mut().unwrap().initFromTpm(buf)?; + self.signature.as_mut().ok_or(TpmError::InvalidUnion)?.initFromTpm(buf)?; Ok(()) } @@ -22273,8 +22293,8 @@ impl TpmStructure for TPM2_Sign_REQUEST { fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields buf.writeSizedByteBuf(&self.digest, 2); - buf.writeShort(self.inScheme.as_ref().unwrap().GetUnionSelector().into()); - self.inScheme.as_ref().unwrap().toTpm(buf)?; + buf.writeShort(self.inScheme.as_ref().ok_or(TpmError::InvalidUnion)?.GetUnionSelector().into()); + self.inScheme.as_ref().ok_or(TpmError::InvalidUnion)?.toTpm(buf)?; self.validation.toTpm(buf)?; Ok(()) } @@ -22284,7 +22304,7 @@ impl TpmStructure for TPM2_Sign_REQUEST { self.digest = buf.readSizedByteBuf(2); let r#inSchemeScheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); self.inScheme = TPMU_SIG_SCHEME::create(r#inSchemeScheme)?; - self.inScheme.as_mut().unwrap().initFromTpm(buf)?; + self.inScheme.as_mut().ok_or(TpmError::InvalidUnion)?.initFromTpm(buf)?; self.validation.initFromTpm(buf)?; Ok(()) } @@ -22337,9 +22357,8 @@ impl TpmStructure for SignResponse { // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields - if (self.signature.is_none()) { return Ok(()) }; - buf.writeShort(self.signature.as_ref().unwrap().GetUnionSelector().into()); - self.signature.as_ref().unwrap().toTpm(buf)?; + buf.writeShort(self.signature.as_ref().ok_or(TpmError::InvalidUnion)?.GetUnionSelector().into()); + self.signature.as_ref().ok_or(TpmError::InvalidUnion)?.toTpm(buf)?; Ok(()) } @@ -22347,7 +22366,7 @@ impl TpmStructure for SignResponse { // Deserialize fields let r#signatureSigAlg: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); self.signature = TPMU_SIGNATURE::create(r#signatureSigAlg)?; - self.signature.as_mut().unwrap().initFromTpm(buf)?; + self.signature.as_mut().ok_or(TpmError::InvalidUnion)?.initFromTpm(buf)?; Ok(()) } @@ -23214,8 +23233,8 @@ impl TpmStructure for TPM2_PolicySigned_REQUEST { buf.writeSizedByteBuf(&self.cpHashA, 2); buf.writeSizedByteBuf(&self.policyRef, 2); buf.writeInt(self.expiration as u32); - buf.writeShort(self.auth.as_ref().unwrap().GetUnionSelector().into()); - self.auth.as_ref().unwrap().toTpm(buf)?; + buf.writeShort(self.auth.as_ref().ok_or(TpmError::InvalidUnion)?.GetUnionSelector().into()); + self.auth.as_ref().ok_or(TpmError::InvalidUnion)?.toTpm(buf)?; Ok(()) } @@ -23227,7 +23246,7 @@ impl TpmStructure for TPM2_PolicySigned_REQUEST { self.expiration = buf.readInt() as i32; let r#authSigAlg: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); self.auth = TPMU_SIGNATURE::create(r#authSigAlg)?; - self.auth.as_mut().unwrap().initFromTpm(buf)?; + self.auth.as_mut().ok_or(TpmError::InvalidUnion)?.initFromTpm(buf)?; Ok(()) } @@ -25921,8 +25940,8 @@ impl TpmStructure for TPM2_FieldUpgradeStart_REQUEST { fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields buf.writeSizedByteBuf(&self.fuDigest, 2); - buf.writeShort(self.manifestSignature.as_ref().unwrap().GetUnionSelector().into()); - self.manifestSignature.as_ref().unwrap().toTpm(buf)?; + buf.writeShort(self.manifestSignature.as_ref().ok_or(TpmError::InvalidUnion)?.GetUnionSelector().into()); + self.manifestSignature.as_ref().ok_or(TpmError::InvalidUnion)?.toTpm(buf)?; Ok(()) } @@ -25931,7 +25950,7 @@ impl TpmStructure for TPM2_FieldUpgradeStart_REQUEST { self.fuDigest = buf.readSizedByteBuf(2); let r#manifestSignatureSigAlg: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); self.manifestSignature = TPMU_SIGNATURE::create(r#manifestSignatureSigAlg)?; - self.manifestSignature.as_mut().unwrap().initFromTpm(buf)?; + self.manifestSignature.as_mut().ok_or(TpmError::InvalidUnion)?.initFromTpm(buf)?; Ok(()) } @@ -26910,8 +26929,8 @@ impl TpmStructure for GetCapabilityResponse { fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields buf.writeByte(self.moreData as u8); - buf.writeInt(self.capabilityData.as_ref().unwrap().GetUnionSelector().into()); - self.capabilityData.as_ref().unwrap().toTpm(buf)?; + buf.writeInt(self.capabilityData.as_ref().ok_or(TpmError::InvalidUnion)?.GetUnionSelector().into()); + self.capabilityData.as_ref().ok_or(TpmError::InvalidUnion)?.toTpm(buf)?; Ok(()) } @@ -26920,7 +26939,7 @@ impl TpmStructure for GetCapabilityResponse { self.moreData = buf.readByte() as u8; let r#capabilityDataCapability: TPM_CAP = TPM_CAP(buf.readInt() as u32); self.capabilityData = TPMU_CAPABILITIES::create(r#capabilityDataCapability)?; - self.capabilityData.as_mut().unwrap().initFromTpm(buf)?; + self.capabilityData.as_mut().ok_or(TpmError::InvalidUnion)?.initFromTpm(buf)?; Ok(()) } @@ -26980,9 +26999,8 @@ impl TpmStructure for TPM2_TestParms_REQUEST { // Implement serialization/deserialization fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields - if (self.parameters.is_none()) { return Ok(()) }; - buf.writeShort(self.parameters.as_ref().unwrap().GetUnionSelector().into()); - self.parameters.as_ref().unwrap().toTpm(buf)?; + buf.writeShort(self.parameters.as_ref().ok_or(TpmError::InvalidUnion)?.GetUnionSelector().into()); + self.parameters.as_ref().ok_or(TpmError::InvalidUnion)?.toTpm(buf)?; Ok(()) } @@ -26990,7 +27008,7 @@ impl TpmStructure for TPM2_TestParms_REQUEST { // Deserialize fields let r#parametersType: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); self.parameters = TPMU_PUBLIC_PARMS::create(r#parametersType)?; - self.parameters.as_mut().unwrap().initFromTpm(buf)?; + self.parameters.as_mut().ok_or(TpmError::InvalidUnion)?.initFromTpm(buf)?; Ok(()) } @@ -28150,8 +28168,8 @@ impl TpmStructure for TPM2_NV_Certify_REQUEST { fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields buf.writeSizedByteBuf(&self.qualifyingData, 2); - buf.writeShort(self.inScheme.as_ref().unwrap().GetUnionSelector().into()); - self.inScheme.as_ref().unwrap().toTpm(buf)?; + buf.writeShort(self.inScheme.as_ref().ok_or(TpmError::InvalidUnion)?.GetUnionSelector().into()); + self.inScheme.as_ref().ok_or(TpmError::InvalidUnion)?.toTpm(buf)?; buf.writeShort(self.size as u16); buf.writeShort(self.offset as u16); Ok(()) @@ -28162,7 +28180,7 @@ impl TpmStructure for TPM2_NV_Certify_REQUEST { self.qualifyingData = buf.readSizedByteBuf(2); let r#inSchemeScheme: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); self.inScheme = TPMU_SIG_SCHEME::create(r#inSchemeScheme)?; - self.inScheme.as_mut().unwrap().initFromTpm(buf)?; + self.inScheme.as_mut().ok_or(TpmError::InvalidUnion)?.initFromTpm(buf)?; self.size = buf.readShort() as u16; self.offset = buf.readShort() as u16; Ok(()) @@ -28220,8 +28238,8 @@ impl TpmStructure for NV_CertifyResponse { fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> { // Serialize fields buf.writeSizedObj(&self.certifyInfo)?; - buf.writeShort(self.signature.as_ref().unwrap().GetUnionSelector().into()); - self.signature.as_ref().unwrap().toTpm(buf)?; + buf.writeShort(self.signature.as_ref().ok_or(TpmError::InvalidUnion)?.GetUnionSelector().into()); + self.signature.as_ref().ok_or(TpmError::InvalidUnion)?.toTpm(buf)?; Ok(()) } @@ -28230,7 +28248,7 @@ impl TpmStructure for NV_CertifyResponse { buf.readSizedObj(&mut self.certifyInfo)?; let r#signatureSigAlg: TPM_ALG_ID = TPM_ALG_ID(buf.readShort() as u16); self.signature = TPMU_SIGNATURE::create(r#signatureSigAlg)?; - self.signature.as_mut().unwrap().initFromTpm(buf)?; + self.signature.as_mut().ok_or(TpmError::InvalidUnion)?.initFromTpm(buf)?; Ok(()) } @@ -29185,7 +29203,11 @@ impl TpmMarshaller for CommandHeader { } /// Contains the public and private part of a TPM key -#[derive(Debug, Clone, Derivative)] +/// +/// Holds secret material, so `Debug` is deliberately not derived here. The redacting +/// implementation is hand-written in `src/tpm_type_extensions.rs`; omitting it is a compile +/// error, enforced by the assertion at the end of this file. +#[derive(Clone, Derivative)] #[derivative(Default)] pub struct TSS_KEY { /// Public part of key @@ -31154,3 +31176,20 @@ lazy_static::lazy_static! { } +/// Compile-time requirement that each type listed in CGenRust.StructsWithHandWrittenDebug +/// has the redacting Debug that was withheld from its derive list. If you added a type to +/// that list, implement Debug for it in src/tpm_type_extensions.rs; until you do, this +/// fails to build and names the type. +const _: fn() = || { + fn assert_debug() {} + assert_debug::(); + assert_debug::(); + assert_debug::(); + assert_debug::(); + assert_debug::(); + assert_debug::(); + assert_debug::(); + assert_debug::(); + assert_debug::(); +}; + diff --git a/TssCodeGen/src/CGenRust.cs b/TssCodeGen/src/CGenRust.cs index ec9e777a..ea6d83c8 100644 --- a/TssCodeGen/src/CGenRust.cs +++ b/TssCodeGen/src/CGenRust.cs @@ -23,6 +23,48 @@ internal class CGenRust : CodeGenBase ("deserialize", "(&mut self, buffer: &mut TpmBuffer)"), }; + // Structs that deliberately do NOT get a derived Debug, because at least one of their + // fields holds secret material that must never reach a log line or an error message. + // For each name here the generator omits Debug from the derive list and emits a + // compile-time assertion that the type implements Debug anyway; the redacting + // implementation is hand-written in TSS.Rust/src/tpm_type_extensions.rs. + // + // The decision lives in this list rather than being inferred from the AST for two + // reasons. Whether a field is secret is a judgement about how the TPM uses it, which the + // specification tables do not record. And TPM_HANDLE's secret field (auth_value) is + // injected from src/tpm_extensions.rs.snips, so the generator never sees it at all. + // Keeping the redaction hand-written also keeps the security-sensitive judgement in code + // a Rust reviewer reads, rather than in a code emitter they do not. + // + // Entries 3 and 4 are the two structures that carry a sensitive area in the clear; + // entries 5..9 are the five TPMU_SENSITIVE_COMPOSITE members. Each of those five is used + // nowhere else in the generated binding, so redacting them cannot hide a public value. + // TPM2B_ECC_PARAMETER in particular reaches Rust only as the sensitive composite's ECC + // member, because the type extractor flattens TPMS_ECC_POINT's public coordinates to + // plain byte vectors. + // + // Deliberately NOT listed, because redacting them would cost more honesty than it buys: + // TPM2B_AUTH - a type alias for TPM2B_DIGEST, so redacting it would + // redact every public digest (PCR values, Names, policies). + // TPM2B_PRIVATE, + // TPM2B_ENCRYPTED_SECRET, + // TPM2B_ID_OBJECT - TPM-encrypted blobs, meant to be stored and moved in the + // clear; they are not plaintext secrets. + // TPMS_ECC_POINT - public curve coordinates. + // TPM2B_SENSITIVE - holds only a TPMT_SENSITIVE, which redacts itself, so the + // derived Debug here already prints nothing secret. + static readonly string[] StructsWithHandWrittenDebug = new string[] { + "TSS_KEY", // privatePart: an RSA prime + "TPM_HANDLE", // auth_value: the caller's authorization value + "TPMT_SENSITIVE", // authValue, seedValue and the sensitive composite + "TPMS_SENSITIVE_CREATE", // userAuth and the data to be sealed + "TPM2B_PRIVATE_KEY_RSA", // an RSA prime + "TPM2B_ECC_PARAMETER", // an ECC private scalar + "TPM2B_SENSITIVE_DATA", // sealed data or a keyedhash key + "TPM2B_SYM_KEY", // a symmetric key + "TPM2B_PRIVATE_VENDOR_SPECIFIC" // vendor-specific private key parts + }; + // Maps enum type to a map of enumerator names to values Dictionary> EnumMap; @@ -124,6 +166,32 @@ void GenerateTpmTypesRs() // Generate the enum maps GenEnumMap(); + + GenHandWrittenDebugAssertions(); + } + + /// + /// Emits a compile-time requirement that every struct the generator withheld + /// #[derive(Debug)] from has a hand-written Debug somewhere in the crate. + /// + /// Without this, forgetting the implementation would only be caught if something happened + /// to format the type, so a secret-bearing type nobody prints yet would silently have no + /// Debug at all and the next caller to add a `{:?}` would get a confusing error far from + /// the cause. The closure body below is type-checked even though it is never run, so a + /// missing implementation is a hard build failure naming the offending type. + /// + void GenHandWrittenDebugAssertions() + { + WriteComment("Compile-time requirement that each type listed in CGenRust.StructsWithHandWrittenDebug " + + "has the redacting Debug that was withheld from its derive list. If you added a type to " + + "that list, implement Debug for it in src/tpm_type_extensions.rs; until you do, this fails " + + "to build and names the type."); + TabIn("const _: fn() = || {"); + Write("fn assert_debug() {}"); + foreach (var typeName in StructsWithHandWrittenDebug) + Write($"assert_debug::<{typeName}>();"); + TabOut("};"); + Write(""); } /// @@ -452,7 +520,18 @@ void GenStructDecl(TpmStruct s) } WriteComment(s); - Write($"#[derive(Debug, Clone, Derivative)]"); + if (StructsWithHandWrittenDebug.Contains(structName)) + { + Write("///"); + Write("/// Holds secret material, so `Debug` is deliberately not derived here. The redacting"); + Write("/// implementation is hand-written in `src/tpm_type_extensions.rs`; omitting it is a compile"); + Write("/// error, enforced by the assertion at the end of this file."); + Write($"#[derive(Clone, Derivative)]"); + } + else + { + Write($"#[derive(Debug, Clone, Derivative)]"); + } Write("#[derivative(Default)]"); Write($"pub struct {structName} {{"); TabIn(); @@ -875,7 +954,7 @@ void GenStructMarshalingImpl(TpmStruct s) // To TPM implementation TabIn("fn serialize(&self, buf: &mut TpmBuffer) -> Result<(), TpmError> {"); Write("// Serialize fields"); - var toTpmOps = GetFieldsMarshalOpsRecursive(s, GetToTpmFieldsMarshalOps); + var toTpmOps = GetFieldsMarshalOpsRecursive(s, fields => GetToTpmFieldsMarshalOps(fields, s.SpecName)); foreach (var op in toTpmOps) { diff --git a/TssCodeGen/src/CodeGenBase.cs b/TssCodeGen/src/CodeGenBase.cs index fcc873d9..c4227941 100644 --- a/TssCodeGen/src/CodeGenBase.cs +++ b/TssCodeGen/src/CodeGenBase.cs @@ -31,6 +31,14 @@ public abstract class CodeGenBase public static readonly string[] ForceJustOneReturnParm = new string[] { "Load", "LoadExternal" }; + /// Spec names of the structures a default-constructed instance of which must marshal + /// as an empty (zero size) object instead of reporting the absent union field as an error. + /// Only TPMT_SENSITIVE relies on this: TPM2_LoadExternal takes an empty inPrivate + /// sized object when only the public part of a key is loaded. Currently honored by the Rust + /// generator only; the other target languages apply the convention to every structure whose + /// union selector is its first marshaled field. + public static readonly string[] EmptyMarshalingStructs = new string[] { "TPMT_SENSITIVE" }; + protected CodeGenBase(string rootDir, string snipsFileName = null) { @@ -104,7 +112,9 @@ public static List GetBifieldElements(TpmBitfield bf) return elements; } - public static List GetToTpmFieldsMarshalOps(StructField[] fields) + /// Spec name of the structure being marshaled. Only supplied by + /// the Rust generator, which limits the empty-object convention to EmptyMarshalingStructs. + public static List GetToTpmFieldsMarshalOps(StructField[] fields, string structSpecName = null) { var marshalOps = new List(); string fieldNamePrefix = TargetLang.Rust ? "&" : ""; @@ -159,9 +169,11 @@ public static List GetToTpmFieldsMarshalOps(StructField[] fields) break; case MarshalType.UnionSelector: - // A trick to allow using default-constructed TPMT_SENSITIVE as an empty (non-marshaling) object + // A trick to allow using default-constructed TPMT_SENSITIVE as an empty (non-marshaling) object. + // Rust restricts it to EmptyMarshalingStructs, so that any other absent union is reported. string unionField = ThisMember + f.RelatedUnion.Name; - if (f == fields.First()) + if (f == fields.First() && + (!TargetLang.Rust || EmptyMarshalingStructs.Contains(structSpecName))) { string earlyReturn = TargetLang.Rust ? " { return Ok(()) }" : " return"; marshalOps.Add(TargetLang.IfNull(unionField) + earlyReturn); diff --git a/TssCodeGen/src/TargetLang.cs b/TssCodeGen/src/TargetLang.cs index c1ac4819..23b66679 100644 --- a/TssCodeGen/src/TargetLang.cs +++ b/TssCodeGen/src/TargetLang.cs @@ -105,7 +105,9 @@ public static IEnumerable GetElementaryTypes() public static string ClassMember => (Cpp || Rust) ? "::" : "."; public static string AsReference(bool isConst) => Rust ? (isConst ? ".as_ref()" : ".as_mut()") : ""; - public static string UnionMember(bool isConst) => Rust ? AsReference(isConst) + ".unwrap()." : Member; + // In Rust a union field is an Option<>, and an absent value must be reported as an error + // rather than panicking. All the marshaling methods return Result<(), TpmError>. + public static string UnionMember(bool isConst) => Rust ? AsReference(isConst) + ".ok_or(TpmError::InvalidUnion)?." : Member; public static string Member => Cpp ? "->" : "."; public static string Null => _null; public static string Neg => Py ? "not " : "!"; From bb7cc9ba31eec98d753377ab455bebcd1a343097 Mon Sep 17 00:00:00 2001 From: Roee Kasher Date: Sun, 16 Aug 2026 14:12:53 +0300 Subject: [PATCH 13/13] Generate Default implementations instead of deriving them (#11) derivative is unmaintained (RUSTSEC-2024-0388). It is a proc macro, so it contributes no code to the built artifact and this is supply-chain hygiene rather than a vulnerability, but the only thing the crate used it for was a Default with per-field values, and the generator can emit that itself. smart-default and educe were the obvious replacements and both were rejected: smart-default was last published in 2023 and is a future advisory waiting to happen, and educe would trade one proc macro dependency for another. The sibling repository this code is developed alongside hand-writes every Default impl and derives none, so emitting the implementation is also the local convention. A struct whose fields all start at Default::default() now derives Default as before. The rest get an emitted impl. Fields a .snips block injects are part of the struct and so have to be initialized too, which the generator could not see; CodeGenBase now exposes the snippet lines for that. TPM_HANDLE is the only type affected today, and its two injected fields would otherwise have made the emitted impl fail to compile. The 214 fields that carried an explicit default keep the same expression, except 162 that said TPM_HANDLE::default() for a TPM_HANDLE-typed field and now say Default::default(), which resolves to the same value because TPM_HANDLE's own default is unchanged at TPM_RH::NULL. Regeneration is idempotent and no other language's output moves. --- TSS.Rust/Cargo.lock | 29 +- TSS.Rust/Cargo.toml | 1 - TSS.Rust/README.md | 1 - TSS.Rust/src/tpm_types.rs | 1692 ++++++++++++++++----------------- TssCodeGen/src/CGenRust.cs | 137 ++- TssCodeGen/src/CodeGenBase.cs | 8 + 6 files changed, 939 insertions(+), 929 deletions(-) diff --git a/TSS.Rust/Cargo.lock b/TSS.Rust/Cargo.lock index e95a4a3b..1d082ccf 100644 --- a/TSS.Rust/Cargo.lock +++ b/TSS.Rust/Cargo.lock @@ -119,17 +119,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "derivative" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "digest" version = "0.10.7" @@ -529,17 +518,6 @@ version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - [[package]] name = "syn" version = "2.0.100" @@ -557,7 +535,6 @@ version = "0.1.0" dependencies = [ "aes", "cipher", - "derivative", "elliptic-curve", "hmac", "lazy_static", @@ -651,7 +628,7 @@ checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn", ] [[package]] @@ -662,7 +639,7 @@ checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn", ] [[package]] @@ -716,7 +693,7 @@ checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn", ] [[package]] diff --git a/TSS.Rust/Cargo.toml b/TSS.Rust/Cargo.toml index eb3890a4..fc1e5dda 100644 --- a/TSS.Rust/Cargo.toml +++ b/TSS.Rust/Cargo.toml @@ -42,7 +42,6 @@ software-crypto = [ cng-crypto = [] [dependencies] -derivative = "2.2.0" lazy_static = "1.5.0" # Constant-time comparison of authorization HMAC tags. subtle = "2.6" diff --git a/TSS.Rust/README.md b/TSS.Rust/README.md index 7f32f938..b1a04636 100644 --- a/TSS.Rust/README.md +++ b/TSS.Rust/README.md @@ -54,7 +54,6 @@ TSS.Rust follows the same architecture as other TSS.MSR implementations: Key Rust crates used: * `rsa`, `sha1`, `sha2`, `hmac` - Cryptographic operations * `aes`, `cfb-mode` - Symmetric encryption for parameter encryption -* `derivative` - Custom `Default` implementations for generated types * `windows` - Windows TBS API access ## See Also diff --git a/TSS.Rust/src/tpm_types.rs b/TSS.Rust/src/tpm_types.rs index c48ef8e1..4fa937ef 100644 --- a/TSS.Rust/src/tpm_types.rs +++ b/TSS.Rust/src/tpm_types.rs @@ -45,7 +45,6 @@ use crate::tpm_structure::*; use std::collections::HashMap; use std::fmt; use std::fmt::Debug; -use derivative::Derivative; // <> // ------------------------------------------------------------------------------------------------ @@ -7545,11 +7544,9 @@ impl TpmMarshaller for TPMU_SENSITIVE_COMPOSITE { /// Holds secret material, so `Debug` is deliberately not derived here. The redacting /// implementation is hand-written in `src/tpm_type_extensions.rs`; omitting it is a compile /// error, enforced by the assertion at the end of this file. -#[derive(Clone, Derivative)] -#[derivative(Default)] +#[derive(Clone)] pub struct TPM_HANDLE { /// Handle value - #[derivative(Default(value="TPM_RH::NULL.into()"))] pub handle: u32, /// The authorization value associated with this handle @@ -7559,6 +7556,16 @@ pub struct TPM_HANDLE { pub name: Vec, } +impl Default for TPM_HANDLE { + fn default() -> Self { + Self { + handle: TPM_RH::NULL.into(), + auth_value: Default::default(), + name: Default::default(), + } + } +} + impl TPM_HANDLE { /// Creates a new instance with the specified values pub fn new( @@ -7605,8 +7612,7 @@ impl TpmMarshaller for TPM_HANDLE { /// An empty union element does not contain any data to marshal. /// This data structure can be used in place of any other union /// initialized with its own empty element. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMS_NULL_UNION { } @@ -7646,8 +7652,7 @@ impl TpmMarshaller for TPMS_NULL_UNION { /// This structure is used as a placeholder. In some cases, a union will have a selector /// value with no data to unmarshal when that type is selected. Rather than leave the /// entry empty, TPMS_EMPTY may be selected. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMS_EMPTY { } @@ -7685,17 +7690,24 @@ impl TpmMarshaller for TPMS_EMPTY { } /// This structure is a return value for a TPM2_GetCapability() that reads the installed algorithms. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone)] pub struct TPMS_ALGORITHM_DESCRIPTION { /// An algorithm - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub alg: TPM_ALG_ID, /// The attributes of the algorithm pub attributes: TPMA_ALGORITHM, } +impl Default for TPMS_ALGORITHM_DESCRIPTION { + fn default() -> Self { + Self { + alg: TPM_ALG_ID::NULL, + attributes: Default::default(), + } + } +} + impl TPMS_ALGORITHM_DESCRIPTION { /// Creates a new instance with the specified values pub fn new( @@ -7745,20 +7757,27 @@ impl TpmMarshaller for TPMS_ALGORITHM_DESCRIPTION { /// Table 80 shows the basic hash-agile structure used in this specification. To handle /// hash agility, this structure uses the hashAlg parameter to indicate the algorithm used /// to compute the digest and, by implication, the size of the digest. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone)] pub struct TPMT_HA { /// Selector of the hash contained in the digest that implies the size of the digest /// NOTE The leading + on the type indicates that this structure should pass an indication /// to the unmarshaling function for TPMI_ALG_HASH so that TPM_ALG_NULL will be allowed if /// a use of a TPMT_HA allows TPM_ALG_NULL. - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub hashAlg: TPM_ALG_ID, /// Hash value pub digest: Vec, } +impl Default for TPMT_HA { + fn default() -> Self { + Self { + hashAlg: TPM_ALG_ID::NULL, + digest: Default::default(), + } + } +} + impl TPMT_HA { /// Creates a new instance with the specified values pub fn new( @@ -7810,8 +7829,7 @@ impl TpmMarshaller for TPMT_HA { /// This structure is used for a sized buffer that cannot be larger than the largest /// digest produced by any hash algorithm implemented on the TPM. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2B_DIGEST { /// The buffer area that can be no larger than a digest pub buffer: Vec, @@ -7864,8 +7882,7 @@ impl TpmMarshaller for TPM2B_DIGEST { /// This structure is used for a data buffer that is required to be no larger than the /// size of the Name of an object. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2B_DATA { pub buffer: Vec, } @@ -7929,8 +7946,7 @@ pub type TPM2B_AUTH = TPM2B_DIGEST; pub type TPM2B_OPERAND = TPM2B_DIGEST; /// This type is a sized buffer that can hold event data. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2B_EVENT { /// The operand pub buffer: Vec, @@ -7980,8 +7996,7 @@ impl TpmMarshaller for TPM2B_EVENT { /// This type is a sized buffer that can hold a maximally sized buffer for commands that /// use a large data buffer such as TPM2_Hash(), TPM2_SequenceUpdate(), or TPM2_FieldUpgradeData(). -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2B_MAX_BUFFER { /// The operand pub buffer: Vec, @@ -8031,8 +8046,7 @@ impl TpmMarshaller for TPM2B_MAX_BUFFER { /// This type is a sized buffer that can hold a maximally sized buffer for NV data /// commands such as TPM2_NV_Read(), TPM2_NV_Write(), and TPM2_NV_Certify(). -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2B_MAX_NV_BUFFER { /// The operand /// NOTE MAX_NV_BUFFER_SIZE is TPM-dependent @@ -8083,8 +8097,7 @@ impl TpmMarshaller for TPM2B_MAX_NV_BUFFER { /// This TPM-dependent structure is used to provide the timeout value for an /// authorization. The size shall be 8 or less. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2B_TIMEOUT { /// The timeout value pub buffer: Vec, @@ -8135,8 +8148,7 @@ impl TpmMarshaller for TPM2B_TIMEOUT { /// This structure is used for passing an initial value for a symmetric block cipher to or /// from the TPM. The size is set to be the largest block size of any implemented /// symmetric cipher implemented on the TPM. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2B_IV { /// The IV value pub buffer: Vec, @@ -8185,8 +8197,7 @@ impl TpmMarshaller for TPM2B_IV { } /// This buffer holds a Name for any entity type. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2B_NAME { /// The Name structure pub name: Vec, @@ -8235,8 +8246,7 @@ impl TpmMarshaller for TPM2B_NAME { } /// This structure provides a standard method of specifying a list of PCR. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMS_PCR_SELECT { /// The bit map of selected PCR pub pcrSelect: Vec, @@ -8285,17 +8295,24 @@ impl TpmMarshaller for TPMS_PCR_SELECT { } /// Table 94 Definition of TPMS_PCR_SELECTION Structure -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone)] pub struct TPMS_PCR_SELECTION { /// The hash algorithm associated with the selection - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub hash: TPM_ALG_ID, /// The bit map of selected PCR pub pcrSelect: Vec, } +impl Default for TPMS_PCR_SELECTION { + fn default() -> Self { + Self { + hash: TPM_ALG_ID::NULL, + pcrSelect: Default::default(), + } + } +} + impl TPMS_PCR_SELECTION { /// Creates a new instance with the specified values pub fn new( @@ -8344,11 +8361,9 @@ impl TpmMarshaller for TPMS_PCR_SELECTION { /// This ticket is produced by TPM2_Create() or TPM2_CreatePrimary(). It is used to bind /// the creation data to the object to which it applies. The ticket is computed by -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMT_TK_CREATION { /// The hierarchy containing name - #[derivative(Default(value="TPM_HANDLE::default()"))] pub hierarchy: TPM_HANDLE, /// This shall be the HMAC produced using a proof value of hierarchy. @@ -8406,11 +8421,9 @@ impl TpmMarshaller for TPMT_TK_CREATION { /// This ticket is produced by TPM2_VerifySignature(). This formulation is used for /// multiple ticket uses. The ticket provides evidence that the TPM has validated that a /// digest was signed by a key with the Name of keyName. The ticket is computed by -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMT_TK_VERIFIED { /// The hierarchy containing keyName - #[derivative(Default(value="TPM_HANDLE::default()"))] pub hierarchy: TPM_HANDLE, /// This shall be the HMAC produced using a proof value of hierarchy. @@ -8468,14 +8481,12 @@ impl TpmMarshaller for TPMT_TK_VERIFIED { /// This ticket is produced by TPM2_PolicySigned() and TPM2_PolicySecret() when the /// authorization has an expiration time. If nonceTPM was provided in the policy command, /// the ticket is computed by -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMT_TK_AUTH { /// Ticket structure tag pub tag: TPM_ST, /// The hierarchy of the object used to produce the ticket - #[derivative(Default(value="TPM_HANDLE::default()"))] pub hierarchy: TPM_HANDLE, /// This shall be the HMAC produced using a proof value of hierarchy. @@ -8534,11 +8545,9 @@ impl TpmMarshaller for TPMT_TK_AUTH { /// This ticket is produced by TPM2_SequenceComplete() or TPM2_Hash() when the message /// that was digested did not start with TPM_GENERATED_VALUE. The ticket is computed by -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMT_TK_HASHCHECK { /// The hierarchy - #[derivative(Default(value="TPM_HANDLE::default()"))] pub hierarchy: TPM_HANDLE, /// This shall be the HMAC produced using a proof value of hierarchy. @@ -8595,17 +8604,24 @@ impl TpmMarshaller for TPMT_TK_HASHCHECK { /// This structure is used to report the properties of an algorithm identifier. It is /// returned in response to a TPM2_GetCapability() with capability = TPM_CAP_ALG. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone)] pub struct TPMS_ALG_PROPERTY { /// An algorithm identifier - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub alg: TPM_ALG_ID, /// The attributes of the algorithm pub algProperties: TPMA_ALGORITHM, } +impl Default for TPMS_ALG_PROPERTY { + fn default() -> Self { + Self { + alg: TPM_ALG_ID::NULL, + algProperties: Default::default(), + } + } +} + impl TPMS_ALG_PROPERTY { /// Creates a new instance with the specified values pub fn new( @@ -8654,8 +8670,7 @@ impl TpmMarshaller for TPMS_ALG_PROPERTY { /// This structure is used to report the properties that are UINT32 values. It is returned /// in response to a TPM2_GetCapability(). -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMS_TAGGED_PROPERTY { /// A property identifier pub property: TPM_PT, @@ -8711,8 +8726,7 @@ impl TpmMarshaller for TPMS_TAGGED_PROPERTY { } /// This structure is used in TPM2_GetCapability() to return the attributes of the PCR. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMS_TAGGED_PCR_SELECT { /// The property identifier pub tag: TPM_PT_PCR, @@ -8769,11 +8783,9 @@ impl TpmMarshaller for TPMS_TAGGED_PCR_SELECT { /// This structure is used in TPM2_GetCapability() to return the policy associated with a /// permanent handle. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMS_TAGGED_POLICY { /// A permanent handle - #[derivative(Default(value="TPM_HANDLE::default()"))] pub handle: TPM_HANDLE, /// The policy algorithm and hash @@ -8827,11 +8839,9 @@ impl TpmMarshaller for TPMS_TAGGED_POLICY { } /// This structure is used in TPM2_GetCapability() to return the ACT data. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMS_ACT_DATA { /// A permanent handle - #[derivative(Default(value="TPM_HANDLE::default()"))] pub handle: TPM_HANDLE, /// The current timeout of the ACT @@ -8893,8 +8903,7 @@ impl TpmMarshaller for TPMS_ACT_DATA { /// A list of command codes may be input to the TPM or returned by the TPM depending on /// the command. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPML_CC { /// A list of command codes /// The maximum only applies to a command code list in a command. The response size is @@ -8948,8 +8957,7 @@ impl TpmMarshaller for TPML_CC { } /// This list is only used in TPM2_GetCapability(capability = TPM_CAP_COMMANDS). -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPML_CCA { /// A list of command codes attributes pub commandAttributes: Vec, @@ -9001,8 +9009,7 @@ impl TpmMarshaller for TPML_CCA { } /// This list is returned by TPM2_IncrementalSelfTest(). -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPML_ALG { /// A list of algorithm IDs /// The maximum only applies to an algorithm list in a command. The response size is @@ -9054,8 +9061,7 @@ impl TpmMarshaller for TPML_ALG { /// This structure is used when the TPM returns a list of loaded handles when the /// capability in TPM2_GetCapability() is TPM_CAP_HANDLE. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPML_HANDLE { /// An array of handles pub handle: Vec, @@ -9108,8 +9114,7 @@ impl TpmMarshaller for TPML_HANDLE { /// This list is used to convey a list of digest values. This type is used in /// TPM2_PolicyOR() and in TPM2_PCR_Read(). -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPML_DIGEST { /// A list of digests /// For TPM2_PolicyOR(), all digests will have been computed using the digest of the @@ -9162,8 +9167,7 @@ impl TpmMarshaller for TPML_DIGEST { /// This list is used to convey a list of digest values. This type is returned by /// TPM2_PCR_Event() and TPM2_EventSequenceComplete() and is an input for TPM2_PCR_Extend(). -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPML_DIGEST_VALUES { /// A list of tagged digests pub digests: Vec, @@ -9213,8 +9217,7 @@ impl TpmMarshaller for TPML_DIGEST_VALUES { /// This list is used to indicate the PCR that are included in a selection when more than /// one PCR value may be selected. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPML_PCR_SELECTION { /// List of selections pub pcrSelections: Vec, @@ -9267,8 +9270,7 @@ impl TpmMarshaller for TPML_PCR_SELECTION { /// This list is used to report on a list of algorithm attributes. It is returned in a /// TPM2_GetCapability(). -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPML_ALG_PROPERTY { /// List of properties pub algProperties: Vec, @@ -9321,8 +9323,7 @@ impl TpmMarshaller for TPML_ALG_PROPERTY { /// This list is used to report on a list of properties that are TPMS_TAGGED_PROPERTY /// values. It is returned by a TPM2_GetCapability(). -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPML_TAGGED_TPM_PROPERTY { /// An array of tagged properties pub tpmProperty: Vec, @@ -9375,8 +9376,7 @@ impl TpmMarshaller for TPML_TAGGED_TPM_PROPERTY { /// This list is used to report on a list of properties that are TPMS_PCR_SELECT values. /// It is returned by a TPM2_GetCapability(). -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPML_TAGGED_PCR_PROPERTY { /// A tagged PCR selection pub pcrProperty: Vec, @@ -9429,8 +9429,7 @@ impl TpmMarshaller for TPML_TAGGED_PCR_PROPERTY { /// This list is used to report the ECC curve ID values supported by the TPM. It is /// returned by a TPM2_GetCapability(). -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPML_ECC_CURVE { /// Array of ECC curve identifiers pub eccCurves: Vec, @@ -9484,8 +9483,7 @@ impl TpmMarshaller for TPML_ECC_CURVE { /// This list is used to report the authorization policy values for permanent handles. /// This is list may be generated by TPM2_GetCapabiltiy(). A permanent handle that cannot /// have a policy is not included in the list. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPML_TAGGED_POLICY { /// Array of tagged policies pub policies: Vec, @@ -9538,8 +9536,7 @@ impl TpmMarshaller for TPML_TAGGED_POLICY { /// This list is used to report the timeout and state for the ACT. This list may be /// generated by TPM2_GetCapabilty(). Only implemented ACT are present in the list -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPML_ACT_DATA { /// Array of ACT data pub actData: Vec, @@ -9591,8 +9588,7 @@ impl TpmMarshaller for TPML_ACT_DATA { } /// This data area is returned in response to a TPM2_GetCapability(). -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMS_CAPABILITY_DATA { /// The capability @@ -9649,8 +9645,7 @@ impl TpmMarshaller for TPMS_CAPABILITY_DATA { } /// This structure is used in each of the attestation commands. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMS_CLOCK_INFO { /// Time value in milliseconds that advances while the TPM is powered /// NOTE The interpretation of the time-origin (clock=0) is out of the scope of this @@ -9727,8 +9722,7 @@ impl TpmMarshaller for TPMS_CLOCK_INFO { } /// This structure is used in, e.g., the TPM2_GetTime() attestation and TPM2_ReadClock(). -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMS_TIME_INFO { /// Time in milliseconds since the TIme circuit was last reset /// This structure element is used to report on the TPM's Time value. @@ -9785,8 +9779,7 @@ impl TpmMarshaller for TPMS_TIME_INFO { } /// This structure is used when the TPM performs TPM2_GetTime. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMS_TIME_ATTEST_INFO { /// The Time, Clock, resetCount, restartCount, and Safe indicator pub time: TPMS_TIME_INFO, @@ -9845,8 +9838,7 @@ impl TpmMarshaller for TPMS_TIME_ATTEST_INFO { } /// This is the attested data for TPM2_Certify(). -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMS_CERTIFY_INFO { /// Name of the certified object pub name: Vec, @@ -9905,8 +9897,7 @@ impl TpmMarshaller for TPMS_CERTIFY_INFO { } /// This is the attested data for TPM2_Quote(). -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMS_QUOTE_INFO { /// Information on algID, PCR selected and digest pub pcrSelect: Vec, @@ -9965,14 +9956,12 @@ impl TpmMarshaller for TPMS_QUOTE_INFO { } /// This is the attested data for TPM2_GetCommandAuditDigest(). -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone)] pub struct TPMS_COMMAND_AUDIT_INFO { /// The monotonic audit counter pub auditCounter: u64, /// Hash algorithm used for the command audit - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub digestAlg: TPM_ALG_ID, /// The current value of the audit digest @@ -9982,6 +9971,17 @@ pub struct TPMS_COMMAND_AUDIT_INFO { pub commandDigest: Vec, } +impl Default for TPMS_COMMAND_AUDIT_INFO { + fn default() -> Self { + Self { + auditCounter: Default::default(), + digestAlg: TPM_ALG_ID::NULL, + auditDigest: Default::default(), + commandDigest: Default::default(), + } + } +} + impl TPMS_COMMAND_AUDIT_INFO { /// Creates a new instance with the specified values pub fn new( @@ -10040,8 +10040,7 @@ impl TpmMarshaller for TPMS_COMMAND_AUDIT_INFO { } /// This is the attested data for TPM2_GetSessionAuditDigest(). -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMS_SESSION_AUDIT_INFO { /// Current exclusive status of the session /// TRUE if all of the commands recorded in the sessionDigest were executed without any @@ -10102,8 +10101,7 @@ impl TpmMarshaller for TPMS_SESSION_AUDIT_INFO { } /// This is the attested data for TPM2_CertifyCreation(). -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMS_CREATION_INFO { /// Name of the object pub objectName: Vec, @@ -10163,8 +10161,7 @@ impl TpmMarshaller for TPMS_CREATION_INFO { /// This structure contains the Name and contents of the selected NV Index that is /// certified by TPM2_NV_Certify(). -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMS_NV_CERTIFY_INFO { /// Name of the NV Index pub indexName: Vec, @@ -10231,8 +10228,7 @@ impl TpmMarshaller for TPMS_NV_CERTIFY_INFO { /// This structure contains the Name and hash of the contents of the selected NV Index /// that is certified by TPM2_NV_Certify(). The data is hashed using hash of the signing scheme. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMS_NV_DIGEST_CERTIFY_INFO { /// Name of the NV Index pub indexName: Vec, @@ -10292,8 +10288,7 @@ impl TpmMarshaller for TPMS_NV_DIGEST_CERTIFY_INFO { /// This structure is used on each TPM-generated signed structure. The signature is over /// this structure. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMS_ATTEST { /// The indication that this structure was created by a TPM (always TPM_GENERATED_VALUE) pub magic: TPM_GENERATED, @@ -10389,8 +10384,7 @@ impl TpmMarshaller for TPMS_ATTEST { /// This sized buffer to contain the signed structure. The attestationData is the signed /// portion of the structure. The size parameter is not signed. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2B_ATTEST { /// The signed structure pub attestationData: TPMS_ATTEST, @@ -10439,11 +10433,9 @@ impl TpmMarshaller for TPM2B_ATTEST { } /// This is the format used for each of the authorizations in the session area of a command. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMS_AUTH_COMMAND { /// The session handle - #[derivative(Default(value="TPM_HANDLE::default()"))] pub sessionHandle: TPM_HANDLE, /// The session nonce, may be the Empty Buffer @@ -10513,8 +10505,7 @@ impl TpmMarshaller for TPMS_AUTH_COMMAND { /// This is the format for each of the authorizations in the session area of the response. /// If the TPM returns TPM_RC_SUCCESS, then the session area of the response contains the /// same number of authorizations as the command and the authorizations are in the same order. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMS_AUTH_RESPONSE { /// The session nonce, may be the Empty Buffer pub nonce: Vec, @@ -10578,8 +10569,7 @@ impl TpmMarshaller for TPMS_AUTH_RESPONSE { /// Custom data structure representing an empty element (i.e. the one with /// no data to marshal) for selector algorithm TPM_ALG_TDES for the union TPMU_SYM_DETAILS -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMS_TDES_SYM_DETAILS { } @@ -10618,8 +10608,7 @@ impl TpmMarshaller for TPMS_TDES_SYM_DETAILS { /// Custom data structure representing an empty element (i.e. the one with /// no data to marshal) for selector algorithm TPM_ALG_AES for the union TPMU_SYM_DETAILS -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMS_AES_SYM_DETAILS { } @@ -10658,8 +10647,7 @@ impl TpmMarshaller for TPMS_AES_SYM_DETAILS { /// Custom data structure representing an empty element (i.e. the one with /// no data to marshal) for selector algorithm TPM_ALG_SM4 for the union TPMU_SYM_DETAILS -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMS_SM4_SYM_DETAILS { } @@ -10698,8 +10686,7 @@ impl TpmMarshaller for TPMS_SM4_SYM_DETAILS { /// Custom data structure representing an empty element (i.e. the one with /// no data to marshal) for selector algorithm TPM_ALG_CAMELLIA for the union TPMU_SYM_DETAILS -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMS_CAMELLIA_SYM_DETAILS { } @@ -10738,8 +10725,7 @@ impl TpmMarshaller for TPMS_CAMELLIA_SYM_DETAILS { /// Custom data structure representing an empty element (i.e. the one with /// no data to marshal) for selector algorithm TPM_ALG_ANY for the union TPMU_SYM_DETAILS -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMS_ANY_SYM_DETAILS { } @@ -10778,8 +10764,7 @@ impl TpmMarshaller for TPMS_ANY_SYM_DETAILS { /// Custom data structure representing an empty element (i.e. the one with /// no data to marshal) for selector algorithm TPM_ALG_XOR for the union TPMU_SYM_DETAILS -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMS_XOR_SYM_DETAILS { } @@ -10818,8 +10803,7 @@ impl TpmMarshaller for TPMS_XOR_SYM_DETAILS { /// Custom data structure representing an empty element (i.e. the one with /// no data to marshal) for selector algorithm TPM_ALG_NULL for the union TPMU_SYM_DETAILS -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMS_NULL_SYM_DETAILS { } @@ -10858,21 +10842,28 @@ impl TpmMarshaller for TPMS_NULL_SYM_DETAILS { /// The TPMT_SYM_DEF structure is used to select an algorithm to be used for parameter /// encryption in those cases when different symmetric algorithms may be selected. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone)] pub struct TPMT_SYM_DEF { /// Indicates a symmetric algorithm - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub algorithm: TPM_ALG_ID, /// A supported key size pub keyBits: u16, /// The mode for the key - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub mode: TPM_ALG_ID, } +impl Default for TPMT_SYM_DEF { + fn default() -> Self { + Self { + algorithm: TPM_ALG_ID::NULL, + keyBits: Default::default(), + mode: TPM_ALG_ID::NULL, + } + } +} + impl TPMT_SYM_DEF { /// Creates a new instance with the specified values pub fn new( @@ -10928,13 +10919,11 @@ impl TpmMarshaller for TPMT_SYM_DEF { /// This structure is used when different symmetric block cipher (not XOR) algorithms may /// be selected. If the Object can be an ordinary parent (not a derivation parent), this /// must be the first field in the Object's parameter (see 12.2.3.7) field. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone)] pub struct TPMT_SYM_DEF_OBJECT { /// Selects a symmetric block cipher /// When used in the parameter area of a parent object, this shall be a supported block /// cipher and not TPM_ALG_NULL - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub algorithm: TPM_ALG_ID, /// The key size @@ -10942,10 +10931,19 @@ pub struct TPMT_SYM_DEF_OBJECT { /// Default mode /// When used in the parameter area of a parent object, this shall be TPM_ALG_CFB. - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub mode: TPM_ALG_ID, } +impl Default for TPMT_SYM_DEF_OBJECT { + fn default() -> Self { + Self { + algorithm: TPM_ALG_ID::NULL, + keyBits: Default::default(), + mode: TPM_ALG_ID::NULL, + } + } +} + impl TPMT_SYM_DEF_OBJECT { /// Creates a new instance with the specified values pub fn new( @@ -11003,8 +11001,7 @@ impl TpmMarshaller for TPMT_SYM_DEF_OBJECT { /// Holds secret material, so `Debug` is deliberately not derived here. The redacting /// implementation is hand-written in `src/tpm_type_extensions.rs`; omitting it is a compile /// error, enforced by the assertion at the end of this file. -#[derive(Clone, Derivative)] -#[derivative(Default)] +#[derive(Clone, Default)] pub struct TPM2B_SYM_KEY { /// The key pub buffer: Vec, @@ -11056,8 +11053,7 @@ impl TpmMarshaller for TPM2B_SYM_KEY { } /// This structure contains the parameters for a symmetric block cipher object. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMS_SYMCIPHER_PARMS { /// A symmetric block cipher pub sym: TPMT_SYM_DEF_OBJECT, @@ -11111,8 +11107,7 @@ impl TpmMarshaller for TPMS_SYMCIPHER_PARMS { /// This buffer holds a label or context value. For interoperability and backwards /// compatibility, LABEL_MAX_BUFFER is the minimum of the largest digest on the device and /// the largest ECC parameter (MAX_ECC_KEY_BYTES) but no more than 32 bytes. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2B_LABEL { /// Symmetric data for a created object or the label and context for a derived object pub buffer: Vec, @@ -11163,8 +11158,7 @@ impl TpmMarshaller for TPM2B_LABEL { /// This structure contains the label and context fields for a derived object. These /// values are used in the derivation KDF. The values in the unique field of inPublic area /// template take precedence over the values in the inSensitive parameter. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMS_DERIVE { pub label: Vec, pub context: Vec, @@ -11220,8 +11214,7 @@ impl TpmMarshaller for TPMS_DERIVE { } /// Table 147 Definition of TPM2B_DERIVE Structure -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2B_DERIVE { /// Symmetric data for a created object or the label and context for a derived object pub buffer: TPMS_DERIVE, @@ -11274,8 +11267,7 @@ impl TpmMarshaller for TPM2B_DERIVE { /// Holds secret material, so `Debug` is deliberately not derived here. The redacting /// implementation is hand-written in `src/tpm_type_extensions.rs`; omitting it is a compile /// error, enforced by the assertion at the end of this file. -#[derive(Clone, Derivative)] -#[derivative(Default)] +#[derive(Clone, Default)] pub struct TPM2B_SENSITIVE_DATA { /// Symmetric data for a created object or the label and context for a derived object pub buffer: Vec, @@ -11332,8 +11324,7 @@ impl TpmMarshaller for TPM2B_SENSITIVE_DATA { /// Holds secret material, so `Debug` is deliberately not derived here. The redacting /// implementation is hand-written in `src/tpm_type_extensions.rs`; omitting it is a compile /// error, enforced by the assertion at the end of this file. -#[derive(Clone, Derivative)] -#[derivative(Default)] +#[derive(Clone, Default)] pub struct TPMS_SENSITIVE_CREATE { /// The USER auth secret value pub userAuth: Vec, @@ -11391,8 +11382,7 @@ impl TpmMarshaller for TPMS_SENSITIVE_CREATE { /// This structure contains the sensitive creation data in a sized buffer. This structure /// is defined so that both the userAuth and data values of the TPMS_SENSITIVE_CREATE may /// be passed as a single parameter for parameter encryption purposes. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2B_SENSITIVE_CREATE { /// Data to be sealed or a symmetric key value. pub sensitive: TPMS_SENSITIVE_CREATE, @@ -11442,14 +11432,20 @@ impl TpmMarshaller for TPM2B_SENSITIVE_CREATE { /// This structure is the scheme data for schemes that only require a hash to complete /// their definition. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone)] pub struct TPMS_SCHEME_HASH { /// The hash algorithm used to digest the message - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub hashAlg: TPM_ALG_ID, } +impl Default for TPMS_SCHEME_HASH { + fn default() -> Self { + Self { + hashAlg: TPM_ALG_ID::NULL, + } + } +} + impl TPMS_SCHEME_HASH { /// Creates a new instance with the specified values pub fn new( @@ -11496,17 +11492,24 @@ impl TpmMarshaller for TPMS_SCHEME_HASH { } /// This definition is for split signing schemes that require a commit count. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone)] pub struct TPMS_SCHEME_ECDAA { /// The hash algorithm used to digest the message - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub hashAlg: TPM_ALG_ID, /// The counter value that is used between TPM2_Commit() and the sign operation pub count: u16, } +impl Default for TPMS_SCHEME_ECDAA { + fn default() -> Self { + Self { + hashAlg: TPM_ALG_ID::NULL, + count: Default::default(), + } + } +} + impl TPMS_SCHEME_ECDAA { /// Creates a new instance with the specified values pub fn new( @@ -11557,14 +11560,20 @@ impl TpmMarshaller for TPMS_SCHEME_ECDAA { } /// Table 155 Definition of Types for HMAC_SIG_SCHEME -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone)] pub struct TPMS_SCHEME_HMAC { /// The hash algorithm used to digest the message - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub hashAlg: TPM_ALG_ID, } +impl Default for TPMS_SCHEME_HMAC { + fn default() -> Self { + Self { + hashAlg: TPM_ALG_ID::NULL, + } + } +} + impl TPMS_SCHEME_HMAC { fn GetUnionSelector() -> TPM_ALG_ID { TPM_ALG_ID::HMAC @@ -11601,18 +11610,24 @@ impl TpmMarshaller for TPMS_SCHEME_HMAC { } /// This structure is for the XOR encryption scheme. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone)] pub struct TPMS_SCHEME_XOR { /// The hash algorithm used to digest the message - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub hashAlg: TPM_ALG_ID, /// The key derivation function - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub kdf: TPM_ALG_ID, } +impl Default for TPMS_SCHEME_XOR { + fn default() -> Self { + Self { + hashAlg: TPM_ALG_ID::NULL, + kdf: TPM_ALG_ID::NULL, + } + } +} + impl TPMS_SCHEME_XOR { /// Creates a new instance with the specified values pub fn new( @@ -11664,8 +11679,7 @@ impl TpmMarshaller for TPMS_SCHEME_XOR { /// Custom data structure representing an empty element (i.e. the one with /// no data to marshal) for selector algorithm TPM_ALG_NULL for the union TPMU_SCHEME_KEYEDHASH -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMS_NULL_SCHEME_KEYEDHASH { } @@ -11703,8 +11717,7 @@ impl TpmMarshaller for TPMS_NULL_SCHEME_KEYEDHASH { } /// This structure is used for a hash signing object. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMT_KEYEDHASH_SCHEME { /// Selects the scheme @@ -11759,14 +11772,20 @@ impl TpmMarshaller for TPMT_KEYEDHASH_SCHEME { } /// These are the RSA schemes that only need a hash algorithm as a scheme parameter. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone)] pub struct TPMS_SIG_SCHEME_RSASSA { /// The hash algorithm used to digest the message - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub hashAlg: TPM_ALG_ID, } +impl Default for TPMS_SIG_SCHEME_RSASSA { + fn default() -> Self { + Self { + hashAlg: TPM_ALG_ID::NULL, + } + } +} + impl TPMS_SIG_SCHEME_RSASSA { fn GetUnionSelector() -> TPM_ALG_ID { TPM_ALG_ID::RSASSA @@ -11803,14 +11822,20 @@ impl TpmMarshaller for TPMS_SIG_SCHEME_RSASSA { } /// These are the RSA schemes that only need a hash algorithm as a scheme parameter. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone)] pub struct TPMS_SIG_SCHEME_RSAPSS { /// The hash algorithm used to digest the message - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub hashAlg: TPM_ALG_ID, } +impl Default for TPMS_SIG_SCHEME_RSAPSS { + fn default() -> Self { + Self { + hashAlg: TPM_ALG_ID::NULL, + } + } +} + impl TPMS_SIG_SCHEME_RSAPSS { fn GetUnionSelector() -> TPM_ALG_ID { TPM_ALG_ID::RSAPSS @@ -11849,14 +11874,20 @@ impl TpmMarshaller for TPMS_SIG_SCHEME_RSAPSS { /// Most of the ECC signature schemes only require a hash algorithm to complete the /// definition and can be typed as TPMS_SCHEME_HASH. Anonymous algorithms also require a /// count value so they are typed to be TPMS_SCHEME_ECDAA. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone)] pub struct TPMS_SIG_SCHEME_ECDSA { /// The hash algorithm used to digest the message - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub hashAlg: TPM_ALG_ID, } +impl Default for TPMS_SIG_SCHEME_ECDSA { + fn default() -> Self { + Self { + hashAlg: TPM_ALG_ID::NULL, + } + } +} + impl TPMS_SIG_SCHEME_ECDSA { fn GetUnionSelector() -> TPM_ALG_ID { TPM_ALG_ID::ECDSA @@ -11895,14 +11926,20 @@ impl TpmMarshaller for TPMS_SIG_SCHEME_ECDSA { /// Most of the ECC signature schemes only require a hash algorithm to complete the /// definition and can be typed as TPMS_SCHEME_HASH. Anonymous algorithms also require a /// count value so they are typed to be TPMS_SCHEME_ECDAA. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone)] pub struct TPMS_SIG_SCHEME_SM2 { /// The hash algorithm used to digest the message - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub hashAlg: TPM_ALG_ID, } +impl Default for TPMS_SIG_SCHEME_SM2 { + fn default() -> Self { + Self { + hashAlg: TPM_ALG_ID::NULL, + } + } +} + impl TPMS_SIG_SCHEME_SM2 { fn GetUnionSelector() -> TPM_ALG_ID { TPM_ALG_ID::SM2 @@ -11941,14 +11978,20 @@ impl TpmMarshaller for TPMS_SIG_SCHEME_SM2 { /// Most of the ECC signature schemes only require a hash algorithm to complete the /// definition and can be typed as TPMS_SCHEME_HASH. Anonymous algorithms also require a /// count value so they are typed to be TPMS_SCHEME_ECDAA. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone)] pub struct TPMS_SIG_SCHEME_ECSCHNORR { /// The hash algorithm used to digest the message - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub hashAlg: TPM_ALG_ID, } +impl Default for TPMS_SIG_SCHEME_ECSCHNORR { + fn default() -> Self { + Self { + hashAlg: TPM_ALG_ID::NULL, + } + } +} + impl TPMS_SIG_SCHEME_ECSCHNORR { fn GetUnionSelector() -> TPM_ALG_ID { TPM_ALG_ID::ECSCHNORR @@ -11987,17 +12030,24 @@ impl TpmMarshaller for TPMS_SIG_SCHEME_ECSCHNORR { /// Most of the ECC signature schemes only require a hash algorithm to complete the /// definition and can be typed as TPMS_SCHEME_HASH. Anonymous algorithms also require a /// count value so they are typed to be TPMS_SCHEME_ECDAA. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone)] pub struct TPMS_SIG_SCHEME_ECDAA { /// The hash algorithm used to digest the message - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub hashAlg: TPM_ALG_ID, /// The counter value that is used between TPM2_Commit() and the sign operation pub count: u16, } +impl Default for TPMS_SIG_SCHEME_ECDAA { + fn default() -> Self { + Self { + hashAlg: TPM_ALG_ID::NULL, + count: Default::default(), + } + } +} + impl TPMS_SIG_SCHEME_ECDAA { fn GetUnionSelector() -> TPM_ALG_ID { TPM_ALG_ID::ECDAA @@ -12037,8 +12087,7 @@ impl TpmMarshaller for TPMS_SIG_SCHEME_ECDAA { /// Custom data structure representing an empty element (i.e. the one with /// no data to marshal) for selector algorithm TPM_ALG_NULL for the union TPMU_SIG_SCHEME -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMS_NULL_SIG_SCHEME { } @@ -12076,8 +12125,7 @@ impl TpmMarshaller for TPMS_NULL_SIG_SCHEME { } /// Table 162 Definition of TPMT_SIG_SCHEME Structure -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMT_SIG_SCHEME { /// Scheme selector @@ -12134,14 +12182,20 @@ impl TpmMarshaller for TPMT_SIG_SCHEME { } /// These are the RSA encryption schemes that only need a hash algorithm as a controlling parameter. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone)] pub struct TPMS_ENC_SCHEME_OAEP { /// The hash algorithm used to digest the message - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub hashAlg: TPM_ALG_ID, } +impl Default for TPMS_ENC_SCHEME_OAEP { + fn default() -> Self { + Self { + hashAlg: TPM_ALG_ID::NULL, + } + } +} + impl TPMS_ENC_SCHEME_OAEP { fn GetUnionSelector() -> TPM_ALG_ID { TPM_ALG_ID::OAEP @@ -12178,8 +12232,7 @@ impl TpmMarshaller for TPMS_ENC_SCHEME_OAEP { } /// These are the RSA encryption schemes that only need a hash algorithm as a controlling parameter. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMS_ENC_SCHEME_RSAES { } @@ -12217,14 +12270,20 @@ impl TpmMarshaller for TPMS_ENC_SCHEME_RSAES { } /// These are the ECC schemes that only need a hash algorithm as a controlling parameter. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone)] pub struct TPMS_KEY_SCHEME_ECDH { /// The hash algorithm used to digest the message - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub hashAlg: TPM_ALG_ID, } +impl Default for TPMS_KEY_SCHEME_ECDH { + fn default() -> Self { + Self { + hashAlg: TPM_ALG_ID::NULL, + } + } +} + impl TPMS_KEY_SCHEME_ECDH { fn GetUnionSelector() -> TPM_ALG_ID { TPM_ALG_ID::ECDH @@ -12261,14 +12320,20 @@ impl TpmMarshaller for TPMS_KEY_SCHEME_ECDH { } /// These are the ECC schemes that only need a hash algorithm as a controlling parameter. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone)] pub struct TPMS_KEY_SCHEME_ECMQV { /// The hash algorithm used to digest the message - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub hashAlg: TPM_ALG_ID, } +impl Default for TPMS_KEY_SCHEME_ECMQV { + fn default() -> Self { + Self { + hashAlg: TPM_ALG_ID::NULL, + } + } +} + impl TPMS_KEY_SCHEME_ECMQV { fn GetUnionSelector() -> TPM_ALG_ID { TPM_ALG_ID::ECMQV @@ -12307,14 +12372,20 @@ impl TpmMarshaller for TPMS_KEY_SCHEME_ECMQV { /// These structures are used to define the key derivation for symmetric secret sharing /// using asymmetric methods. A secret sharing scheme is required in any asymmetric key /// with the decrypt attribute SET. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone)] pub struct TPMS_KDF_SCHEME_MGF1 { /// The hash algorithm used to digest the message - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub hashAlg: TPM_ALG_ID, } +impl Default for TPMS_KDF_SCHEME_MGF1 { + fn default() -> Self { + Self { + hashAlg: TPM_ALG_ID::NULL, + } + } +} + impl TPMS_KDF_SCHEME_MGF1 { fn GetUnionSelector() -> TPM_ALG_ID { TPM_ALG_ID::MGF1 @@ -12353,14 +12424,20 @@ impl TpmMarshaller for TPMS_KDF_SCHEME_MGF1 { /// These structures are used to define the key derivation for symmetric secret sharing /// using asymmetric methods. A secret sharing scheme is required in any asymmetric key /// with the decrypt attribute SET. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone)] pub struct TPMS_KDF_SCHEME_KDF1_SP800_56A { /// The hash algorithm used to digest the message - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub hashAlg: TPM_ALG_ID, } +impl Default for TPMS_KDF_SCHEME_KDF1_SP800_56A { + fn default() -> Self { + Self { + hashAlg: TPM_ALG_ID::NULL, + } + } +} + impl TPMS_KDF_SCHEME_KDF1_SP800_56A { fn GetUnionSelector() -> TPM_ALG_ID { TPM_ALG_ID::KDF1_SP800_56A @@ -12399,14 +12476,20 @@ impl TpmMarshaller for TPMS_KDF_SCHEME_KDF1_SP800_56A { /// These structures are used to define the key derivation for symmetric secret sharing /// using asymmetric methods. A secret sharing scheme is required in any asymmetric key /// with the decrypt attribute SET. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone)] pub struct TPMS_KDF_SCHEME_KDF2 { /// The hash algorithm used to digest the message - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub hashAlg: TPM_ALG_ID, } +impl Default for TPMS_KDF_SCHEME_KDF2 { + fn default() -> Self { + Self { + hashAlg: TPM_ALG_ID::NULL, + } + } +} + impl TPMS_KDF_SCHEME_KDF2 { fn GetUnionSelector() -> TPM_ALG_ID { TPM_ALG_ID::KDF2 @@ -12445,14 +12528,20 @@ impl TpmMarshaller for TPMS_KDF_SCHEME_KDF2 { /// These structures are used to define the key derivation for symmetric secret sharing /// using asymmetric methods. A secret sharing scheme is required in any asymmetric key /// with the decrypt attribute SET. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone)] pub struct TPMS_KDF_SCHEME_KDF1_SP800_108 { /// The hash algorithm used to digest the message - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub hashAlg: TPM_ALG_ID, } +impl Default for TPMS_KDF_SCHEME_KDF1_SP800_108 { + fn default() -> Self { + Self { + hashAlg: TPM_ALG_ID::NULL, + } + } +} + impl TPMS_KDF_SCHEME_KDF1_SP800_108 { fn GetUnionSelector() -> TPM_ALG_ID { TPM_ALG_ID::KDF1_SP800_108 @@ -12490,8 +12579,7 @@ impl TpmMarshaller for TPMS_KDF_SCHEME_KDF1_SP800_108 { /// Custom data structure representing an empty element (i.e. the one with /// no data to marshal) for selector algorithm TPM_ALG_NULL for the union TPMU_KDF_SCHEME -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMS_NULL_KDF_SCHEME { } @@ -12529,8 +12617,7 @@ impl TpmMarshaller for TPMS_NULL_KDF_SCHEME { } /// Table 167 Definition of TPMT_KDF_SCHEME Structure -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMT_KDF_SCHEME { /// Scheme selector @@ -12587,8 +12674,7 @@ impl TpmMarshaller for TPMT_KDF_SCHEME { /// Custom data structure representing an empty element (i.e. the one with /// no data to marshal) for selector algorithm TPM_ALG_NULL for the union TPMU_ASYM_SCHEME -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMS_NULL_ASYM_SCHEME { } @@ -12628,8 +12714,7 @@ impl TpmMarshaller for TPMS_NULL_ASYM_SCHEME { /// This structure is defined to allow overlay of all of the schemes for any asymmetric /// object. This structure is not sent on the interface. It is defined so that common /// functions may operate on any similar scheme structure. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMT_ASYM_SCHEME { /// Scheme selector @@ -12687,8 +12772,7 @@ impl TpmMarshaller for TPMT_ASYM_SCHEME { } /// Table 172 Definition of {RSA} TPMT_RSA_SCHEME Structure -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMT_RSA_SCHEME { /// Scheme selector @@ -12746,8 +12830,7 @@ impl TpmMarshaller for TPMT_RSA_SCHEME { } /// Table 174 Definition of {RSA} TPMT_RSA_DECRYPT Structure -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMT_RSA_DECRYPT { /// Scheme selector @@ -12805,8 +12888,7 @@ impl TpmMarshaller for TPMT_RSA_DECRYPT { } /// This sized buffer holds the largest RSA public key supported by the TPM. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2B_PUBLIC_KEY_RSA { /// Value pub buffer: Vec, @@ -12862,8 +12944,7 @@ impl TpmMarshaller for TPM2B_PUBLIC_KEY_RSA { /// Holds secret material, so `Debug` is deliberately not derived here. The redacting /// implementation is hand-written in `src/tpm_type_extensions.rs`; omitting it is a compile /// error, enforced by the assertion at the end of this file. -#[derive(Clone, Derivative)] -#[derivative(Default)] +#[derive(Clone, Default)] pub struct TPM2B_PRIVATE_KEY_RSA { pub buffer: Vec, } @@ -12918,8 +12999,7 @@ impl TpmMarshaller for TPM2B_PRIVATE_KEY_RSA { /// Holds secret material, so `Debug` is deliberately not derived here. The redacting /// implementation is hand-written in `src/tpm_type_extensions.rs`; omitting it is a compile /// error, enforced by the assertion at the end of this file. -#[derive(Clone, Derivative)] -#[derivative(Default)] +#[derive(Clone, Default)] pub struct TPM2B_ECC_PARAMETER { /// The parameter data pub buffer: Vec, @@ -12971,8 +13051,7 @@ impl TpmMarshaller for TPM2B_ECC_PARAMETER { } /// This structure holds two ECC coordinates that, together, make up an ECC point. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMS_ECC_POINT { /// X coordinate pub x: Vec, @@ -13032,8 +13111,7 @@ impl TpmMarshaller for TPMS_ECC_POINT { /// This structure is defined to allow a point to be a single sized parameter so that it /// may be encrypted. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2B_ECC_POINT { /// Coordinates pub point: TPMS_ECC_POINT, @@ -13082,8 +13160,7 @@ impl TpmMarshaller for TPM2B_ECC_POINT { } /// Table 183 Definition of (TPMT_SIG_SCHEME) {ECC} TPMT_ECC_SCHEME Structure -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMT_ECC_SCHEME { /// Scheme selector @@ -13142,8 +13219,7 @@ impl TpmMarshaller for TPMT_ECC_SCHEME { /// This structure is used to report on the curve parameters of an ECC curve. It is /// returned by TPM2_ECC_Parameters(). -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMS_ALGORITHM_DETAIL_ECC { /// Identifier for the curve pub curveID: TPM_ECC_CURVE, @@ -13279,18 +13355,25 @@ impl TpmMarshaller for TPMS_ALGORITHM_DETAIL_ECC { } /// Table 185 Definition of {RSA} TPMS_SIGNATURE_RSA Structure -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone)] pub struct TPMS_SIGNATURE_RSA { /// The hash algorithm used to digest the message /// TPM_ALG_NULL is not allowed. - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub hash: TPM_ALG_ID, /// The signature is the size of a public key. pub sig: Vec, } +impl Default for TPMS_SIGNATURE_RSA { + fn default() -> Self { + Self { + hash: TPM_ALG_ID::NULL, + sig: Default::default(), + } + } +} + impl TPMS_SIGNATURE_RSA { /// Creates a new instance with the specified values pub fn new( @@ -13341,18 +13424,25 @@ impl TpmMarshaller for TPMS_SIGNATURE_RSA { } /// Table 185 Definition of {RSA} TPMS_SIGNATURE_RSA Structure -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone)] pub struct TPMS_SIGNATURE_RSASSA { /// The hash algorithm used to digest the message /// TPM_ALG_NULL is not allowed. - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub hash: TPM_ALG_ID, /// The signature is the size of a public key. pub sig: Vec, } +impl Default for TPMS_SIGNATURE_RSASSA { + fn default() -> Self { + Self { + hash: TPM_ALG_ID::NULL, + sig: Default::default(), + } + } +} + impl TPMS_SIGNATURE_RSASSA { fn GetUnionSelector() -> TPM_ALG_ID { TPM_ALG_ID::RSASSA @@ -13391,18 +13481,25 @@ impl TpmMarshaller for TPMS_SIGNATURE_RSASSA { } /// Table 185 Definition of {RSA} TPMS_SIGNATURE_RSA Structure -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone)] pub struct TPMS_SIGNATURE_RSAPSS { /// The hash algorithm used to digest the message /// TPM_ALG_NULL is not allowed. - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub hash: TPM_ALG_ID, /// The signature is the size of a public key. pub sig: Vec, } +impl Default for TPMS_SIGNATURE_RSAPSS { + fn default() -> Self { + Self { + hash: TPM_ALG_ID::NULL, + sig: Default::default(), + } + } +} + impl TPMS_SIGNATURE_RSAPSS { fn GetUnionSelector() -> TPM_ALG_ID { TPM_ALG_ID::RSAPSS @@ -13441,17 +13538,25 @@ impl TpmMarshaller for TPMS_SIGNATURE_RSAPSS { } /// Table 187 Definition of {ECC} TPMS_SIGNATURE_ECC Structure -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone)] pub struct TPMS_SIGNATURE_ECC { /// The hash algorithm used in the signature process /// TPM_ALG_NULL is not allowed. - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub hash: TPM_ALG_ID, pub signatureR: Vec, pub signatureS: Vec, } +impl Default for TPMS_SIGNATURE_ECC { + fn default() -> Self { + Self { + hash: TPM_ALG_ID::NULL, + signatureR: Default::default(), + signatureS: Default::default(), + } + } +} + impl TPMS_SIGNATURE_ECC { /// Creates a new instance with the specified values pub fn new( @@ -13506,17 +13611,25 @@ impl TpmMarshaller for TPMS_SIGNATURE_ECC { } /// Table 187 Definition of {ECC} TPMS_SIGNATURE_ECC Structure -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone)] pub struct TPMS_SIGNATURE_ECDSA { /// The hash algorithm used in the signature process /// TPM_ALG_NULL is not allowed. - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub hash: TPM_ALG_ID, pub signatureR: Vec, pub signatureS: Vec, } +impl Default for TPMS_SIGNATURE_ECDSA { + fn default() -> Self { + Self { + hash: TPM_ALG_ID::NULL, + signatureR: Default::default(), + signatureS: Default::default(), + } + } +} + impl TPMS_SIGNATURE_ECDSA { fn GetUnionSelector() -> TPM_ALG_ID { TPM_ALG_ID::ECDSA @@ -13557,17 +13670,25 @@ impl TpmMarshaller for TPMS_SIGNATURE_ECDSA { } /// Table 187 Definition of {ECC} TPMS_SIGNATURE_ECC Structure -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone)] pub struct TPMS_SIGNATURE_ECDAA { /// The hash algorithm used in the signature process /// TPM_ALG_NULL is not allowed. - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub hash: TPM_ALG_ID, pub signatureR: Vec, pub signatureS: Vec, } +impl Default for TPMS_SIGNATURE_ECDAA { + fn default() -> Self { + Self { + hash: TPM_ALG_ID::NULL, + signatureR: Default::default(), + signatureS: Default::default(), + } + } +} + impl TPMS_SIGNATURE_ECDAA { fn GetUnionSelector() -> TPM_ALG_ID { TPM_ALG_ID::ECDAA @@ -13608,17 +13729,25 @@ impl TpmMarshaller for TPMS_SIGNATURE_ECDAA { } /// Table 187 Definition of {ECC} TPMS_SIGNATURE_ECC Structure -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone)] pub struct TPMS_SIGNATURE_SM2 { /// The hash algorithm used in the signature process /// TPM_ALG_NULL is not allowed. - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub hash: TPM_ALG_ID, pub signatureR: Vec, pub signatureS: Vec, } +impl Default for TPMS_SIGNATURE_SM2 { + fn default() -> Self { + Self { + hash: TPM_ALG_ID::NULL, + signatureR: Default::default(), + signatureS: Default::default(), + } + } +} + impl TPMS_SIGNATURE_SM2 { fn GetUnionSelector() -> TPM_ALG_ID { TPM_ALG_ID::SM2 @@ -13659,17 +13788,25 @@ impl TpmMarshaller for TPMS_SIGNATURE_SM2 { } /// Table 187 Definition of {ECC} TPMS_SIGNATURE_ECC Structure -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone)] pub struct TPMS_SIGNATURE_ECSCHNORR { /// The hash algorithm used in the signature process /// TPM_ALG_NULL is not allowed. - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub hash: TPM_ALG_ID, pub signatureR: Vec, pub signatureS: Vec, } +impl Default for TPMS_SIGNATURE_ECSCHNORR { + fn default() -> Self { + Self { + hash: TPM_ALG_ID::NULL, + signatureR: Default::default(), + signatureS: Default::default(), + } + } +} + impl TPMS_SIGNATURE_ECSCHNORR { fn GetUnionSelector() -> TPM_ALG_ID { TPM_ALG_ID::ECSCHNORR @@ -13711,8 +13848,7 @@ impl TpmMarshaller for TPMS_SIGNATURE_ECSCHNORR { /// Custom data structure representing an empty element (i.e. the one with /// no data to marshal) for selector algorithm TPM_ALG_NULL for the union TPMU_SIGNATURE -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMS_NULL_SIGNATURE { } @@ -13754,8 +13890,7 @@ impl TpmMarshaller for TPMS_NULL_SIGNATURE { /// signature. This structure is output from commands such as the attestation commands and /// TPM2_Sign, and is an input to commands such as TPM2_VerifySignature(), /// TPM2_PolicySigned(), and TPM2_FieldUpgradeStart(). -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMT_SIGNATURE { /// Selector of the algorithm used to construct the signature @@ -13812,8 +13947,7 @@ impl TpmMarshaller for TPMT_SIGNATURE { } /// Table 192 Definition of TPM2B_ENCRYPTED_SECRET Structure -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2B_ENCRYPTED_SECRET { /// Secret pub secret: Vec, @@ -13863,8 +13997,7 @@ impl TpmMarshaller for TPM2B_ENCRYPTED_SECRET { /// This structure describes the parameters that would appear in the public area of a /// KEYEDHASH object. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMS_KEYEDHASH_PARMS { /// Selects the scheme @@ -13926,8 +14059,7 @@ impl TpmMarshaller for TPMS_KEYEDHASH_PARMS { /// This structure contains the common public area parameters for an asymmetric key. The /// first two parameters of the parameter definition structures of an asymmetric key shall /// have the same two first components. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMS_ASYM_PARMS { /// The companion symmetric algorithm for a restricted decryption key and shall be set to /// a supported symmetric algorithm @@ -14004,8 +14136,7 @@ impl TpmMarshaller for TPMS_ASYM_PARMS { /// default of 216 + 1. Support for other values is optional. Use of other exponents in /// duplicated keys is not recommended because the resulting keys would not be /// interoperable with other TPMs. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMS_RSA_PARMS { /// For a restricted decryption key, shall be set to a supported symmetric algorithm, key /// size, and mode. @@ -14097,8 +14228,7 @@ impl TpmMarshaller for TPMS_RSA_PARMS { } /// This structure contains the parameters for prime modulus ECC. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMS_ECC_PARMS { /// For a restricted decryption key, shall be set to a supported symmetric algorithm, key /// size. and mode. @@ -14199,8 +14329,7 @@ impl TpmMarshaller for TPMS_ECC_PARMS { /// This structure is used in TPM2_TestParms() to validate that a set of algorithm /// parameters is supported by the TPM. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMT_PUBLIC_PARMS { /// The algorithm to be tested @@ -14257,15 +14386,13 @@ impl TpmMarshaller for TPMT_PUBLIC_PARMS { /// Table 201 defines the public area structure. The Name of the object is nameAlg /// concatenated with the digest of this structure using nameAlg. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone)] pub struct TPMT_PUBLIC { /// Algorithm associated with this object /// Algorithm used for computing the Name of the object /// NOTE The "+" indicates that the instance of a TPMT_PUBLIC may have a "+" to indicate /// that the nameAlg may be TPM_ALG_NULL. - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub nameAlg: TPM_ALG_ID, /// Attributes that, along with type, determine the manipulations of this object @@ -14288,6 +14415,18 @@ pub struct TPMT_PUBLIC { pub unique: Option, } +impl Default for TPMT_PUBLIC { + fn default() -> Self { + Self { + nameAlg: TPM_ALG_ID::NULL, + objectAttributes: Default::default(), + authPolicy: Default::default(), + parameters: Default::default(), + unique: Default::default(), + } + } +} + impl TPMT_PUBLIC { /// Creates a new instance with the specified values pub fn new( @@ -14352,8 +14491,7 @@ impl TpmMarshaller for TPMT_PUBLIC { /// This sized buffer is used to embed a TPMT_PUBLIC in a load command and in any response /// that returns a public area. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2B_PUBLIC { /// The public area /// NOTE The + indicates that the caller may specify that use of TPM_ALG_NULL is allowed @@ -14404,8 +14542,7 @@ impl TpmMarshaller for TPM2B_PUBLIC { } /// This sized buffer is used to embed a TPMT_TEMPLATE for TPM2_CreateLoaded(). -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2B_TEMPLATE { /// The public area pub buffer: Vec, @@ -14463,8 +14600,7 @@ impl TpmMarshaller for TPM2B_TEMPLATE { /// Holds secret material, so `Debug` is deliberately not derived here. The redacting /// implementation is hand-written in `src/tpm_type_extensions.rs`; omitting it is a compile /// error, enforced by the assertion at the end of this file. -#[derive(Clone, Derivative)] -#[derivative(Default)] +#[derive(Clone, Default)] pub struct TPM2B_PRIVATE_VENDOR_SPECIFIC { pub buffer: Vec, } @@ -14520,8 +14656,7 @@ impl TpmMarshaller for TPM2B_PRIVATE_VENDOR_SPECIFIC { /// Holds secret material, so `Debug` is deliberately not derived here. The redacting /// implementation is hand-written in `src/tpm_type_extensions.rs`; omitting it is a compile /// error, enforced by the assertion at the end of this file. -#[derive(Clone, Derivative)] -#[derivative(Default)] +#[derive(Clone, Default)] pub struct TPMT_SENSITIVE { /// Identifier for the sensitive area /// This shall be the same as the type parameter of the associated public area. @@ -14595,8 +14730,7 @@ impl TpmMarshaller for TPMT_SENSITIVE { /// The TPM2B_SENSITIVE structure is used as a parameter in TPM2_LoadExternal(). It is an /// unencrypted sensitive area but it may be encrypted using parameter encryption. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2B_SENSITIVE { /// An unencrypted sensitive area pub sensitiveArea: TPMT_SENSITIVE, @@ -14646,8 +14780,7 @@ impl TpmMarshaller for TPM2B_SENSITIVE { /// This structure is defined to size the contents of a TPM2B_PRIVATE. This structure is /// not directly marshaled or unmarshaled. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct _PRIVATE { pub integrityOuter: Vec, @@ -14710,8 +14843,7 @@ impl TpmMarshaller for _PRIVATE { /// The TPM2B_PRIVATE structure is used as a parameter in multiple commands that create, /// load, and modify the sensitive area of an object. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2B_PRIVATE { /// An encrypted private area pub buffer: Vec, @@ -14760,8 +14892,7 @@ impl TpmMarshaller for TPM2B_PRIVATE { } /// This structure is used for sizing the TPM2B_ID_OBJECT. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMS_ID_OBJECT { /// HMAC using the nameAlg of the storage key on the target TPM pub integrityHMAC: Vec, @@ -14822,8 +14953,7 @@ impl TpmMarshaller for TPMS_ID_OBJECT { /// This structure is an output from TPM2_MakeCredential() and is an input to /// TPM2_ActivateCredential(). -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2B_ID_OBJECT { /// An encrypted credential area pub credential: TPMS_ID_OBJECT, @@ -14874,8 +15004,7 @@ impl TpmMarshaller for TPM2B_ID_OBJECT { /// This is the data that can be written to and read from a TPM_NT_PIN_PASS or /// TPM_NT_PIN_FAIL non-volatile index. pinCount is the most significant octets. pinLimit /// is the least significant octets. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMS_NV_PIN_COUNTER_PARAMETERS { /// This counter shows the current number of successful authValue authorization attempts /// to access a TPM_NT_PIN_PASS index or the current number of unsuccessful authValue @@ -14934,16 +15063,13 @@ impl TpmMarshaller for TPMS_NV_PIN_COUNTER_PARAMETERS { } /// This structure describes an NV Index. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone)] pub struct TPMS_NV_PUBLIC { /// The handle of the data area - #[derivative(Default(value="TPM_HANDLE::default()"))] pub nvIndex: TPM_HANDLE, /// Hash algorithm used to compute the name of the Index and used for the authPolicy. For /// an extend index, the hash algorithm used for the extend. - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub nameAlg: TPM_ALG_ID, /// The Index attributes @@ -14959,6 +15085,18 @@ pub struct TPMS_NV_PUBLIC { pub dataSize: u16, } +impl Default for TPMS_NV_PUBLIC { + fn default() -> Self { + Self { + nvIndex: Default::default(), + nameAlg: TPM_ALG_ID::NULL, + attributes: Default::default(), + authPolicy: Default::default(), + dataSize: Default::default(), + } + } +} + impl TPMS_NV_PUBLIC { /// Creates a new instance with the specified values pub fn new( @@ -15018,8 +15156,7 @@ impl TpmMarshaller for TPMS_NV_PUBLIC { } /// This structure is used when a TPMS_NV_PUBLIC is sent on the TPM interface. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2B_NV_PUBLIC { /// The public area pub nvPublic: TPMS_NV_PUBLIC, @@ -15069,8 +15206,7 @@ impl TpmMarshaller for TPM2B_NV_PUBLIC { /// This structure holds the object or session context data. When saved, the full /// structure is encrypted. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2B_CONTEXT_SENSITIVE { /// The sensitive data pub buffer: Vec, @@ -15119,8 +15255,7 @@ impl TpmMarshaller for TPM2B_CONTEXT_SENSITIVE { } /// This structure holds the integrity value and the encrypted data for a context. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMS_CONTEXT_DATA { /// The integrity value pub integrity: Vec, @@ -15176,8 +15311,7 @@ impl TpmMarshaller for TPMS_CONTEXT_DATA { } /// This structure is used in a TPMS_CONTEXT. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2B_CONTEXT_DATA { pub buffer: TPMS_CONTEXT_DATA, } @@ -15227,8 +15361,7 @@ impl TpmMarshaller for TPM2B_CONTEXT_DATA { /// This structure is used in TPM2_ContextLoad() and TPM2_ContextSave(). If the values of /// the TPMS_CONTEXT structure in TPM2_ContextLoad() are not the same as the values when /// the context was saved (TPM2_ContextSave()), then the TPM shall not load the context. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMS_CONTEXT { /// The sequence number of the context /// NOTE Transient object contexts and session contexts used different counters. @@ -15236,11 +15369,9 @@ pub struct TPMS_CONTEXT { /// A handle indicating if the context is a session, object, or sequence object (see Table /// 222 Context Handle Values - #[derivative(Default(value="TPM_HANDLE::default()"))] pub savedHandle: TPM_HANDLE, /// The hierarchy of the context - #[derivative(Default(value="TPM_HANDLE::default()"))] pub hierarchy: TPM_HANDLE, /// The context data and integrity HMAC @@ -15306,8 +15437,7 @@ impl TpmMarshaller for TPMS_CONTEXT { /// digest of selected PCR. These values represent the environment in which the object was /// created. Creation data allows a relying party to determine if an object was created /// when some appropriate protections were present. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone)] pub struct TPMS_CREATION_DATA { /// List indicating the PCR included in pcrDigest pub pcrSelect: Vec, @@ -15321,7 +15451,6 @@ pub struct TPMS_CREATION_DATA { pub locality: TPMA_LOCALITY, /// NameAlg of the parent - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub parentNameAlg: TPM_ALG_ID, /// Name of the parent at time of creation @@ -15338,6 +15467,20 @@ pub struct TPMS_CREATION_DATA { pub outsideInfo: Vec, } +impl Default for TPMS_CREATION_DATA { + fn default() -> Self { + Self { + pcrSelect: Default::default(), + pcrDigest: Default::default(), + locality: Default::default(), + parentNameAlg: TPM_ALG_ID::NULL, + parentName: Default::default(), + parentQualifiedName: Default::default(), + outsideInfo: Default::default(), + } + } +} + impl TPMS_CREATION_DATA { /// Creates a new instance with the specified values pub fn new( @@ -15406,8 +15549,7 @@ impl TpmMarshaller for TPMS_CREATION_DATA { /// This structure is created by TPM2_Create() and TPM2_CreatePrimary(). It is never /// entered into the TPM and never has a size of zero. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2B_CREATION_DATA { pub creationData: TPMS_CREATION_DATA, } @@ -15456,8 +15598,7 @@ impl TpmMarshaller for TPM2B_CREATION_DATA { /// TPMS_AC_OUTPUT is used to return information about an AC. The tag structure parameter /// indicates the type of the data value. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPMS_AC_OUTPUT { /// Tag indicating the contents of data pub tag: TPM_AT, @@ -15513,8 +15654,7 @@ impl TpmMarshaller for TPMS_AC_OUTPUT { } /// This list is only used in TPM2_AC_GetCapability(). -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPML_AC_CAPABILITIES { /// A list of AC values pub acCapabilities: Vec, @@ -15568,8 +15708,7 @@ impl TpmMarshaller for TPML_AC_CAPABILITIES { /// completed successfully. If a TPM requires TPM2_Startup() and another command is /// received, or if the TPM receives TPM2_Startup() when it is not required, the TPM shall /// return TPM_RC_INITIALIZE. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_Startup_REQUEST { /// TPM_SU_CLEAR or TPM_SU_STATE pub startupType: TPM_SU, @@ -15630,8 +15769,7 @@ impl ReqStructure for TPM2_Startup_REQUEST { /// This command is used to prepare the TPM for a power cycle. The shutdownType parameter /// indicates how the subsequent TPM2_Startup() will be processed. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_Shutdown_REQUEST { /// TPM_SU_CLEAR or TPM_SU_STATE pub shutdownType: TPM_SU, @@ -15693,8 +15831,7 @@ impl ReqStructure for TPM2_Shutdown_REQUEST { /// This command causes the TPM to perform a test of its capabilities. If the fullTest is /// YES, the TPM will test all functions. If fullTest = NO, the TPM will only test those /// functions that have not previously been tested. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_SelfTest_REQUEST { /// YES if full test to be performed /// NO if only test of untested functions required @@ -15755,8 +15892,7 @@ impl ReqStructure for TPM2_SelfTest_REQUEST { } /// This command causes the TPM to perform a test of the selected algorithms. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_IncrementalSelfTest_REQUEST { /// List of algorithms that should be tested pub toTest: Vec, @@ -15817,8 +15953,7 @@ impl ReqStructure for TPM2_IncrementalSelfTest_REQUEST { } /// This command causes the TPM to perform a test of the selected algorithms. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct IncrementalSelfTestResponse { /// List of algorithms that need testing pub toDoList: Vec, @@ -15870,8 +16005,7 @@ impl RespStructure for IncrementalSelfTestResponse { /// This command returns manufacturer-specific information regarding the results of a /// self-test and an indication of the test status. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_GetTestResult_REQUEST { } @@ -15918,8 +16052,7 @@ impl ReqStructure for TPM2_GetTestResult_REQUEST { /// This command returns manufacturer-specific information regarding the results of a /// self-test and an indication of the test status. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct GetTestResultResponse { /// Test result data /// contains manufacturer-specific information @@ -15976,19 +16109,16 @@ impl RespStructure for GetTestResultResponse { /// This command is used to start an authorization session using alternative methods of /// establishing the session key (sessionKey). The session key is then used to derive /// values used for authorization and for encrypting parameters. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone)] pub struct TPM2_StartAuthSession_REQUEST { /// Handle of a loaded decrypt key used to encrypt salt /// may be TPM_RH_NULL /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub tpmKey: TPM_HANDLE, /// Entity providing the authValue /// may be TPM_RH_NULL /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub bind: TPM_HANDLE, /// Initial nonceCaller, sets nonceTPM size for the session @@ -16008,10 +16138,23 @@ pub struct TPM2_StartAuthSession_REQUEST { /// Hash algorithm to use for the session /// Shall be a hash algorithm supported by the TPM and not TPM_ALG_NULL - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub authHash: TPM_ALG_ID, } +impl Default for TPM2_StartAuthSession_REQUEST { + fn default() -> Self { + Self { + tpmKey: Default::default(), + bind: Default::default(), + nonceCaller: Default::default(), + encryptedSalt: Default::default(), + sessionType: Default::default(), + symmetric: Default::default(), + authHash: TPM_ALG_ID::NULL, + } + } +} + impl TPM2_StartAuthSession_REQUEST { /// Creates a new instance with the specified values pub fn new( @@ -16089,11 +16232,9 @@ impl ReqStructure for TPM2_StartAuthSession_REQUEST { /// This command is used to start an authorization session using alternative methods of /// establishing the session key (sessionKey). The session key is then used to derive /// values used for authorization and for encrypting parameters. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct StartAuthSessionResponse { /// Handle for the newly created session - #[derivative(Default(value="TPM_HANDLE::default()"))] pub handle: TPM_HANDLE, /// The initial nonce from the TPM, used in the computation of the sessionKey @@ -16150,11 +16291,9 @@ impl RespStructure for StartAuthSessionResponse { /// TPM2_PolicyPCR() was executed. Restarting the session allows the authorizations to be /// replayed because the session restarts with the same nonceTPM. If the PCR are valid for /// the policy, the policy may then succeed. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_PolicyRestart_REQUEST { /// The handle for the policy session - #[derivative(Default(value="TPM_HANDLE::default()"))] pub sessionHandle: TPM_HANDLE, } @@ -16216,13 +16355,11 @@ impl ReqStructure for TPM2_PolicyRestart_REQUEST { /// responsibility of the caller. The object will need to be loaded (TPM2_Load()) before /// it may be used. The only difference between the inPublic TPMT_PUBLIC template and the /// outPublic TPMT_PUBLIC object is in the unique field. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_Create_REQUEST { /// Handle of parent for new object /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub parentHandle: TPM_HANDLE, /// The sensitive data @@ -16314,8 +16451,7 @@ impl ReqStructure for TPM2_Create_REQUEST { /// responsibility of the caller. The object will need to be loaded (TPM2_Load()) before /// it may be used. The only difference between the inPublic TPMT_PUBLIC template and the /// outPublic TPMT_PUBLIC object is in the unique field. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct CreateResponse { /// The private portion of the object pub outPrivate: TPM2B_PRIVATE, @@ -16388,13 +16524,11 @@ impl RespStructure for CreateResponse { /// This command is used to load objects into the TPM. This command is used when both a /// TPM2B_PUBLIC and TPM2B_PRIVATE are to be loaded. If only a TPM2B_PUBLIC is to be /// loaded, the TPM2_LoadExternal command is used. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_Load_REQUEST { /// TPM handle of parent key; shall not be a reserved handle /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub parentHandle: TPM_HANDLE, /// The private portion of the object @@ -16466,11 +16600,9 @@ impl ReqStructure for TPM2_Load_REQUEST { /// This command is used to load objects into the TPM. This command is used when both a /// TPM2B_PUBLIC and TPM2B_PRIVATE are to be loaded. If only a TPM2B_PUBLIC is to be /// loaded, the TPM2_LoadExternal command is used. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct LoadResponse { /// Handle of type TPM_HT_TRANSIENT for the loaded object - #[derivative(Default(value="TPM_HANDLE::default()"))] pub handle: TPM_HANDLE, /// Name of the loaded object @@ -16525,8 +16657,7 @@ impl RespStructure for LoadResponse { /// This command is used to load an object that is not a Protected Object into the TPM. /// The command allows loading of a public area or both a public and sensitive area. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_LoadExternal_REQUEST { /// The sensitive portion of the object (optional) pub inPrivate: TPMT_SENSITIVE, @@ -16535,7 +16666,6 @@ pub struct TPM2_LoadExternal_REQUEST { pub inPublic: TPMT_PUBLIC, /// Hierarchy with which the object area is associated - #[derivative(Default(value="TPM_HANDLE::default()"))] pub hierarchy: TPM_HANDLE, } @@ -16603,11 +16733,9 @@ impl ReqStructure for TPM2_LoadExternal_REQUEST { /// This command is used to load an object that is not a Protected Object into the TPM. /// The command allows loading of a public area or both a public and sensitive area. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct LoadExternalResponse { /// Handle of type TPM_HT_TRANSIENT for the loaded object - #[derivative(Default(value="TPM_HANDLE::default()"))] pub handle: TPM_HANDLE, /// Name of the loaded object @@ -16661,12 +16789,10 @@ impl RespStructure for LoadExternalResponse { } /// This command allows access to the public area of a loaded object. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_ReadPublic_REQUEST { /// TPM handle of an object /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub objectHandle: TPM_HANDLE, } @@ -16722,8 +16848,7 @@ impl ReqStructure for TPM2_ReadPublic_REQUEST { } /// This command allows access to the public area of a loaded object. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct ReadPublicResponse { /// Structure containing the public area of an object pub outPublic: TPMT_PUBLIC, @@ -16787,19 +16912,16 @@ impl RespStructure for ReadPublicResponse { /// This command enables the association of a credential with an object in a way that /// ensures that the TPM has validated the parameters of the credentialed object. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_ActivateCredential_REQUEST { /// Handle of the object associated with certificate in credentialBlob /// Auth Index: 1 /// Auth Role: ADMIN - #[derivative(Default(value="TPM_HANDLE::default()"))] pub activateHandle: TPM_HANDLE, /// Loaded key used to decrypt the TPMS_SENSITIVE in credentialBlob /// Auth Index: 2 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub keyHandle: TPM_HANDLE, /// The credential @@ -16873,8 +16995,7 @@ impl ReqStructure for TPM2_ActivateCredential_REQUEST { /// This command enables the association of a credential with an object in a way that /// ensures that the TPM has validated the parameters of the credentialed object. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct ActivateCredentialResponse { /// The decrypted certificate information /// the data should be no larger than the size of the digest of the nameAlg associated @@ -16928,12 +17049,10 @@ impl RespStructure for ActivateCredentialResponse { /// This command allows the TPM to perform the actions required of a Certificate Authority /// (CA) in creating a TPM2B_ID_OBJECT containing an activation credential. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_MakeCredential_REQUEST { /// Loaded public area, used to encrypt the sensitive area containing the credential key /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub handle: TPM_HANDLE, /// The credential information @@ -17005,8 +17124,7 @@ impl ReqStructure for TPM2_MakeCredential_REQUEST { /// This command allows the TPM to perform the actions required of a Certificate Authority /// (CA) in creating a TPM2B_ID_OBJECT containing an activation credential. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct MakeCredentialResponse { /// The credential pub credentialBlob: TPMS_ID_OBJECT, @@ -17062,13 +17180,11 @@ impl RespStructure for MakeCredentialResponse { } /// This command returns the data in a loaded Sealed Data Object. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_Unseal_REQUEST { /// Handle of a loaded data object /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub itemHandle: TPM_HANDLE, } @@ -17124,8 +17240,7 @@ impl ReqStructure for TPM2_Unseal_REQUEST { } /// This command returns the data in a loaded Sealed Data Object. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct UnsealResponse { /// Unsealed data /// Size of outData is limited to be no more than 128 octets. @@ -17177,18 +17292,15 @@ impl RespStructure for UnsealResponse { } /// This command is used to change the authorization secret for a TPM-resident object. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_ObjectChangeAuth_REQUEST { /// Handle of the object /// Auth Index: 1 /// Auth Role: ADMIN - #[derivative(Default(value="TPM_HANDLE::default()"))] pub objectHandle: TPM_HANDLE, /// Handle of the parent /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub parentHandle: TPM_HANDLE, /// New authorization value @@ -17254,8 +17366,7 @@ impl ReqStructure for TPM2_ObjectChangeAuth_REQUEST { } /// This command is used to change the authorization secret for a TPM-resident object. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct ObjectChangeAuthResponse { /// Private area containing the new authorization value pub outPrivate: TPM2B_PRIVATE, @@ -17309,14 +17420,12 @@ impl RespStructure for ObjectChangeAuthResponse { /// parentHandle. If parentHandle references a Primary Seed, then a Primary Object is /// created; if parentHandle references a Storage Parent, then an Ordinary Object is /// created; and if parentHandle references a Derivation Parent, then a Derived Object is generated. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_CreateLoaded_REQUEST { /// Handle of a transient storage key, a persistent storage key, TPM_RH_ENDORSEMENT, /// TPM_RH_OWNER, TPM_RH_PLATFORM+{PP}, or TPM_RH_NULL /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub parentHandle: TPM_HANDLE, /// The sensitive data, see TPM 2.0 Part 1 Sensitive Values @@ -17391,11 +17500,9 @@ impl ReqStructure for TPM2_CreateLoaded_REQUEST { /// parentHandle. If parentHandle references a Primary Seed, then a Primary Object is /// created; if parentHandle references a Storage Parent, then an Ordinary Object is /// created; and if parentHandle references a Derivation Parent, then a Derived Object is generated. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct CreateLoadedResponse { /// Handle of type TPM_HT_TRANSIENT for created object - #[derivative(Default(value="TPM_HANDLE::default()"))] pub handle: TPM_HANDLE, /// The sensitive area of the object (optional) @@ -17460,18 +17567,15 @@ impl RespStructure for CreateLoadedResponse { /// This command duplicates a loaded object so that it may be used in a different /// hierarchy. The new parent key for the duplicate may be on the same or different TPM or /// TPM_RH_NULL. Only the public area of newParentHandle is required to be loaded. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_Duplicate_REQUEST { /// Loaded object to duplicate /// Auth Index: 1 /// Auth Role: DUP - #[derivative(Default(value="TPM_HANDLE::default()"))] pub objectHandle: TPM_HANDLE, /// Shall reference the public area of an asymmetric key /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub newParentHandle: TPM_HANDLE, /// Optional symmetric encryption key @@ -17549,8 +17653,7 @@ impl ReqStructure for TPM2_Duplicate_REQUEST { /// This command duplicates a loaded object so that it may be used in a different /// hierarchy. The new parent key for the duplicate may be on the same or different TPM or /// TPM_RH_NULL. Only the public area of newParentHandle is required to be loaded. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct DuplicateResponse { /// If the caller provided an encryption key or if symmetricAlg was TPM_ALG_NULL, then /// this will be the Empty Buffer; otherwise, it shall contain the TPM-generated, @@ -17618,18 +17721,15 @@ impl RespStructure for DuplicateResponse { /// A new protection seed value is generated according to the methods appropriate for /// newParent and the blob is re-encrypted and a new integrity value is computed. The /// re-encrypted blob is returned in outDuplicate and the symmetric key returned in outSymKey. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_Rewrap_REQUEST { /// Parent of object /// Auth Index: 1 /// Auth Role: User - #[derivative(Default(value="TPM_HANDLE::default()"))] pub oldParent: TPM_HANDLE, /// New parent of the object /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub newParent: TPM_HANDLE, /// An object encrypted using symmetric key derived from inSymSeed @@ -17714,8 +17814,7 @@ impl ReqStructure for TPM2_Rewrap_REQUEST { /// A new protection seed value is generated according to the methods appropriate for /// newParent and the blob is re-encrypted and a new integrity value is computed. The /// re-encrypted blob is returned in outDuplicate and the symmetric key returned in outSymKey. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct RewrapResponse { /// An object encrypted using symmetric key derived from outSymSeed pub outDuplicate: TPM2B_PRIVATE, @@ -17773,13 +17872,11 @@ impl RespStructure for RewrapResponse { /// a Storage Key. After encryption, the object may be loaded and used in the new /// hierarchy. The imported object (duplicate) may be singly encrypted, multiply /// encrypted, or unencrypted. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_Import_REQUEST { /// The handle of the new parent for the object /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub parentHandle: TPM_HANDLE, /// The optional symmetric encryption key used as the inner wrapper for duplicate @@ -17882,8 +17979,7 @@ impl ReqStructure for TPM2_Import_REQUEST { /// a Storage Key. After encryption, the object may be loaded and used in the new /// hierarchy. The imported object (duplicate) may be singly encrypted, multiply /// encrypted, or unencrypted. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct ImportResponse { /// The sensitive area encrypted with the symmetric key of parentHandle pub outPrivate: TPM2B_PRIVATE, @@ -17936,12 +18032,10 @@ impl RespStructure for ImportResponse { /// IETF RFC 8017. If the scheme of keyHandle is TPM_ALG_NULL, then the caller may use /// inScheme to specify the padding scheme. If scheme of keyHandle is not TPM_ALG_NULL, /// then inScheme shall either be TPM_ALG_NULL or be the same as scheme (TPM_RC_SCHEME). -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_RSA_Encrypt_REQUEST { /// Reference to public portion of RSA key to use for encryption /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub keyHandle: TPM_HANDLE, /// Message to be encrypted @@ -18036,8 +18130,7 @@ impl ReqStructure for TPM2_RSA_Encrypt_REQUEST { /// IETF RFC 8017. If the scheme of keyHandle is TPM_ALG_NULL, then the caller may use /// inScheme to specify the padding scheme. If scheme of keyHandle is not TPM_ALG_NULL, /// then inScheme shall either be TPM_ALG_NULL or be the same as scheme (TPM_RC_SCHEME). -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct RSA_EncryptResponse { /// Encrypted output pub outData: Vec, @@ -18089,13 +18182,11 @@ impl RespStructure for RSA_EncryptResponse { /// This command performs RSA decryption using the indicated padding scheme according to /// IETF RFC 8017 ((PKCS#1). -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_RSA_Decrypt_REQUEST { /// RSA key to use for decryption /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub keyHandle: TPM_HANDLE, /// Cipher text to be decrypted @@ -18184,8 +18275,7 @@ impl ReqStructure for TPM2_RSA_Decrypt_REQUEST { /// This command performs RSA decryption using the indicated padding scheme according to /// IETF RFC 8017 ((PKCS#1). -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct RSA_DecryptResponse { /// Decrypted output pub message: Vec, @@ -18238,12 +18328,10 @@ impl RespStructure for RSA_DecryptResponse { /// This command uses the TPM to generate an ephemeral key pair (de, Qe where Qe [de]G). /// It uses the private ephemeral key and a loaded public key (QS) to compute the shared /// secret value (P [hde]QS). -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_ECDH_KeyGen_REQUEST { /// Handle of a loaded ECC key public area. /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub keyHandle: TPM_HANDLE, } @@ -18301,8 +18389,7 @@ impl ReqStructure for TPM2_ECDH_KeyGen_REQUEST { /// This command uses the TPM to generate an ephemeral key pair (de, Qe where Qe [de]G). /// It uses the private ephemeral key and a loaded public key (QS) to compute the shared /// secret value (P [hde]QS). -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct ECDH_KeyGenResponse { /// Results of P h[de]Qs pub zPoint: TPMS_ECC_POINT, @@ -18361,13 +18448,11 @@ impl RespStructure for ECDH_KeyGenResponse { /// private key (ds). It will perform the multiplication of the provided inPoint (QB) with /// the private key (ds) and return the coordinates of the resultant point (Z = (xZ , yZ) /// [hds]QB; where h is the cofactor of the curve). -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_ECDH_ZGen_REQUEST { /// Handle of a loaded ECC key /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub keyHandle: TPM_HANDLE, /// A public key @@ -18434,8 +18519,7 @@ impl ReqStructure for TPM2_ECDH_ZGen_REQUEST { /// private key (ds). It will perform the multiplication of the provided inPoint (QB) with /// the private key (ds) and return the coordinates of the resultant point (Z = (xZ , yZ) /// [hds]QB; where h is the cofactor of the curve). -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct ECDH_ZGenResponse { /// X and Y coordinates of the product of the multiplication Z = (xZ , yZ) [hdS]QB pub outPoint: TPMS_ECC_POINT, @@ -18486,8 +18570,7 @@ impl RespStructure for ECDH_ZGenResponse { } /// This command returns the parameters of an ECC curve identified by its TCG-assigned curveID. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_ECC_Parameters_REQUEST { /// Parameter set selector pub curveID: TPM_ECC_CURVE, @@ -18547,8 +18630,7 @@ impl ReqStructure for TPM2_ECC_Parameters_REQUEST { } /// This command returns the parameters of an ECC curve identified by its TCG-assigned curveID. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct ECC_ParametersResponse { /// ECC parameters for the selected curve pub parameters: TPMS_ALGORITHM_DETAIL_ECC, @@ -18601,14 +18683,12 @@ impl RespStructure for ECC_ParametersResponse { /// combination with TPM2_EC_Ephemeral(). TPM2_EC_Ephemeral() generates an ephemeral key /// and returns the public point of that ephemeral key along with a numeric value that /// allows the TPM to regenerate the associated private key. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone)] pub struct TPM2_ZGen_2Phase_REQUEST { /// Handle of an unrestricted decryption key ECC /// The private key referenced by this handle is used as dS,A /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub keyA: TPM_HANDLE, /// Other partys static public key (Qs,B = (Xs,B, Ys,B)) @@ -18618,13 +18698,24 @@ pub struct TPM2_ZGen_2Phase_REQUEST { pub inQeB: TPMS_ECC_POINT, /// The key exchange scheme - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub inScheme: TPM_ALG_ID, /// Value returned by TPM2_EC_Ephemeral() pub counter: u16, } +impl Default for TPM2_ZGen_2Phase_REQUEST { + fn default() -> Self { + Self { + keyA: Default::default(), + inQsB: Default::default(), + inQeB: Default::default(), + inScheme: TPM_ALG_ID::NULL, + counter: Default::default(), + } + } +} + impl TPM2_ZGen_2Phase_REQUEST { /// Creates a new instance with the specified values pub fn new( @@ -18697,8 +18788,7 @@ impl ReqStructure for TPM2_ZGen_2Phase_REQUEST { /// combination with TPM2_EC_Ephemeral(). TPM2_EC_Ephemeral() generates an ephemeral key /// and returns the public point of that ephemeral key along with a numeric value that /// allows the TPM to regenerate the associated private key. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct ZGen_2PhaseResponse { /// X and Y coordinates of the computed value (scheme dependent) pub outZ1: TPMS_ECC_POINT, @@ -18754,12 +18844,10 @@ impl RespStructure for ZGen_2PhaseResponse { } /// This command performs ECC encryption as described in Part 1, Annex D. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_ECC_Encrypt_REQUEST { /// Reference to public portion of ECC key to use for encryption /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub keyHandle: TPM_HANDLE, /// Plaintext to be encrypted @@ -18837,8 +18925,7 @@ impl ReqStructure for TPM2_ECC_Encrypt_REQUEST { } /// This command performs ECC encryption as described in Part 1, Annex D. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct ECC_EncryptResponse { /// The public ephemeral key used for ECDH pub C1: TPMS_ECC_POINT, @@ -18899,13 +18986,11 @@ impl RespStructure for ECC_EncryptResponse { } /// This command performs ECC decryption. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_ECC_Decrypt_REQUEST { /// ECC key to use for decryption /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub keyHandle: TPM_HANDLE, /// The public ephemeral key used for ECDH @@ -18997,8 +19082,7 @@ impl ReqStructure for TPM2_ECC_Decrypt_REQUEST { } /// This command performs ECC decryption. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct ECC_DecryptResponse { /// Decrypted output pub plainText: Vec, @@ -19050,13 +19134,11 @@ impl RespStructure for ECC_DecryptResponse { /// NOTE 1 This command is deprecated, and TPM2_EncryptDecrypt2() is preferred. This /// should be reflected in platform-specific specifications. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone)] pub struct TPM2_EncryptDecrypt_REQUEST { /// The symmetric key used for the operation /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub keyHandle: TPM_HANDLE, /// If YES, then the operation is decryption; if NO, the operation is encryption @@ -19064,7 +19146,6 @@ pub struct TPM2_EncryptDecrypt_REQUEST { /// Symmetric encryption/decryption mode /// this field shall match the default mode of the key or be TPM_ALG_NULL. - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub mode: TPM_ALG_ID, /// An initial value as required by the algorithm @@ -19074,6 +19155,18 @@ pub struct TPM2_EncryptDecrypt_REQUEST { pub inData: Vec, } +impl Default for TPM2_EncryptDecrypt_REQUEST { + fn default() -> Self { + Self { + keyHandle: Default::default(), + decrypt: Default::default(), + mode: TPM_ALG_ID::NULL, + ivIn: Default::default(), + inData: Default::default(), + } + } +} + impl TPM2_EncryptDecrypt_REQUEST { /// Creates a new instance with the specified values pub fn new( @@ -19143,8 +19236,7 @@ impl ReqStructure for TPM2_EncryptDecrypt_REQUEST { /// NOTE 1 This command is deprecated, and TPM2_EncryptDecrypt2() is preferred. This /// should be reflected in platform-specific specifications. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct EncryptDecryptResponse { /// Encrypted or decrypted output pub outData: Vec, @@ -19201,13 +19293,11 @@ impl RespStructure for EncryptDecryptResponse { /// This command is identical to TPM2_EncryptDecrypt(), except that the inData parameter /// is the first parameter. This permits inData to be parameter encrypted. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone)] pub struct TPM2_EncryptDecrypt2_REQUEST { /// The symmetric key used for the operation /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub keyHandle: TPM_HANDLE, /// The data to be encrypted/decrypted @@ -19218,13 +19308,24 @@ pub struct TPM2_EncryptDecrypt2_REQUEST { /// Symmetric mode /// this field shall match the default mode of the key or be TPM_ALG_NULL. - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub mode: TPM_ALG_ID, /// An initial value as required by the algorithm pub ivIn: Vec, } +impl Default for TPM2_EncryptDecrypt2_REQUEST { + fn default() -> Self { + Self { + keyHandle: Default::default(), + inData: Default::default(), + decrypt: Default::default(), + mode: TPM_ALG_ID::NULL, + ivIn: Default::default(), + } + } +} + impl TPM2_EncryptDecrypt2_REQUEST { /// Creates a new instance with the specified values pub fn new( @@ -19295,8 +19396,7 @@ impl ReqStructure for TPM2_EncryptDecrypt2_REQUEST { /// This command is identical to TPM2_EncryptDecrypt(), except that the inData parameter /// is the first parameter. This permits inData to be parameter encrypted. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct EncryptDecrypt2Response { /// Encrypted or decrypted output pub outData: Vec, @@ -19352,21 +19452,28 @@ impl RespStructure for EncryptDecrypt2Response { } /// This command performs a hash operation on a data buffer and returns the results. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone)] pub struct TPM2_Hash_REQUEST { /// Data to be hashed pub data: Vec, /// Algorithm for the hash being computed shall not be TPM_ALG_NULL - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub hashAlg: TPM_ALG_ID, /// Hierarchy to use for the ticket (TPM_RH_NULL allowed) - #[derivative(Default(value="TPM_HANDLE::default()"))] pub hierarchy: TPM_HANDLE, } +impl Default for TPM2_Hash_REQUEST { + fn default() -> Self { + Self { + data: Default::default(), + hashAlg: TPM_ALG_ID::NULL, + hierarchy: Default::default(), + } + } +} + impl TPM2_Hash_REQUEST { /// Creates a new instance with the specified values pub fn new( @@ -19430,8 +19537,7 @@ impl ReqStructure for TPM2_Hash_REQUEST { } /// This command performs a hash operation on a data buffer and returns the results. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct HashResponse { /// Results pub outHash: Vec, @@ -19489,23 +19595,30 @@ impl RespStructure for HashResponse { } /// This command performs an HMAC on the supplied data using the indicated hash algorithm. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone)] pub struct TPM2_HMAC_REQUEST { /// Handle for the symmetric signing key providing the HMAC key /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub handle: TPM_HANDLE, /// HMAC data pub buffer: Vec, /// Algorithm to use for HMAC - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub hashAlg: TPM_ALG_ID, } +impl Default for TPM2_HMAC_REQUEST { + fn default() -> Self { + Self { + handle: Default::default(), + buffer: Default::default(), + hashAlg: TPM_ALG_ID::NULL, + } + } +} + impl TPM2_HMAC_REQUEST { /// Creates a new instance with the specified values pub fn new( @@ -19567,8 +19680,7 @@ impl ReqStructure for TPM2_HMAC_REQUEST { } /// This command performs an HMAC on the supplied data using the indicated hash algorithm. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct HMACResponse { /// The returned HMAC in a sized buffer pub outHMAC: Vec, @@ -19620,23 +19732,30 @@ impl RespStructure for HMACResponse { /// This command performs an HMAC or a block cipher MAC on the supplied data using the /// indicated algorithm. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone)] pub struct TPM2_MAC_REQUEST { /// Handle for the symmetric signing key providing the MAC key /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub handle: TPM_HANDLE, /// MAC data pub buffer: Vec, /// Algorithm to use for MAC - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub inScheme: TPM_ALG_ID, } +impl Default for TPM2_MAC_REQUEST { + fn default() -> Self { + Self { + handle: Default::default(), + buffer: Default::default(), + inScheme: TPM_ALG_ID::NULL, + } + } +} + impl TPM2_MAC_REQUEST { /// Creates a new instance with the specified values pub fn new( @@ -19699,8 +19818,7 @@ impl ReqStructure for TPM2_MAC_REQUEST { /// This command performs an HMAC or a block cipher MAC on the supplied data using the /// indicated algorithm. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct MACResponse { /// The returned MAC in a sized buffer pub outMAC: Vec, @@ -19751,8 +19869,7 @@ impl RespStructure for MACResponse { } /// This command returns the next bytesRequested octets from the random number generator (RNG). -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_GetRandom_REQUEST { /// Number of octets to return pub bytesRequested: u16, @@ -19812,8 +19929,7 @@ impl ReqStructure for TPM2_GetRandom_REQUEST { } /// This command returns the next bytesRequested octets from the random number generator (RNG). -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct GetRandomResponse { /// The random octets pub randomBytes: Vec, @@ -19864,8 +19980,7 @@ impl RespStructure for GetRandomResponse { } /// This command is used to add "additional information" to the RNG state. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_StirRandom_REQUEST { /// Additional information pub inData: Vec, @@ -19928,23 +20043,30 @@ impl ReqStructure for TPM2_StirRandom_REQUEST { /// This command starts an HMAC sequence. The TPM will create and initialize an HMAC /// sequence structure, assign a handle to the sequence, and set the authValue of the /// sequence object to the value in auth. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone)] pub struct TPM2_HMAC_Start_REQUEST { /// Handle of an HMAC key /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub handle: TPM_HANDLE, /// Authorization value for subsequent use of the sequence pub auth: Vec, /// The hash algorithm to use for the HMAC - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub hashAlg: TPM_ALG_ID, } +impl Default for TPM2_HMAC_Start_REQUEST { + fn default() -> Self { + Self { + handle: Default::default(), + auth: Default::default(), + hashAlg: TPM_ALG_ID::NULL, + } + } +} + impl TPM2_HMAC_Start_REQUEST { /// Creates a new instance with the specified values pub fn new( @@ -20008,11 +20130,9 @@ impl ReqStructure for TPM2_HMAC_Start_REQUEST { /// This command starts an HMAC sequence. The TPM will create and initialize an HMAC /// sequence structure, assign a handle to the sequence, and set the authValue of the /// sequence object to the value in auth. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct HMAC_StartResponse { /// A handle to reference the sequence - #[derivative(Default(value="TPM_HANDLE::default()"))] pub handle: TPM_HANDLE, } @@ -20060,23 +20180,30 @@ impl RespStructure for HMAC_StartResponse { /// This command starts a MAC sequence. The TPM will create and initialize a MAC sequence /// structure, assign a handle to the sequence, and set the authValue of the sequence /// object to the value in auth. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone)] pub struct TPM2_MAC_Start_REQUEST { /// Handle of a MAC key /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub handle: TPM_HANDLE, /// Authorization value for subsequent use of the sequence pub auth: Vec, /// The algorithm to use for the MAC - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub inScheme: TPM_ALG_ID, } +impl Default for TPM2_MAC_Start_REQUEST { + fn default() -> Self { + Self { + handle: Default::default(), + auth: Default::default(), + inScheme: TPM_ALG_ID::NULL, + } + } +} + impl TPM2_MAC_Start_REQUEST { /// Creates a new instance with the specified values pub fn new( @@ -20140,11 +20267,9 @@ impl ReqStructure for TPM2_MAC_Start_REQUEST { /// This command starts a MAC sequence. The TPM will create and initialize a MAC sequence /// structure, assign a handle to the sequence, and set the authValue of the sequence /// object to the value in auth. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct MAC_StartResponse { /// A handle to reference the sequence - #[derivative(Default(value="TPM_HANDLE::default()"))] pub handle: TPM_HANDLE, } @@ -20193,18 +20318,25 @@ impl RespStructure for MAC_StartResponse { /// then a hash sequence is started. If hashAlg is TPM_ALG_NULL, then an Event Sequence is /// started. If hashAlg is neither an implemented algorithm nor TPM_ALG_NULL, then the TPM /// shall return TPM_RC_HASH. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone)] pub struct TPM2_HashSequenceStart_REQUEST { /// Authorization value for subsequent use of the sequence pub auth: Vec, /// The hash algorithm to use for the hash sequence /// An Event Sequence starts if this is TPM_ALG_NULL. - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub hashAlg: TPM_ALG_ID, } +impl Default for TPM2_HashSequenceStart_REQUEST { + fn default() -> Self { + Self { + auth: Default::default(), + hashAlg: TPM_ALG_ID::NULL, + } + } +} + impl TPM2_HashSequenceStart_REQUEST { /// Creates a new instance with the specified values pub fn new( @@ -20267,11 +20399,9 @@ impl ReqStructure for TPM2_HashSequenceStart_REQUEST { /// then a hash sequence is started. If hashAlg is TPM_ALG_NULL, then an Event Sequence is /// started. If hashAlg is neither an implemented algorithm nor TPM_ALG_NULL, then the TPM /// shall return TPM_RC_HASH. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct HashSequenceStartResponse { /// A handle to reference the sequence - #[derivative(Default(value="TPM_HANDLE::default()"))] pub handle: TPM_HANDLE, } @@ -20318,13 +20448,11 @@ impl RespStructure for HashSequenceStartResponse { /// This command is used to add data to a hash or HMAC sequence. The amount of data in /// buffer may be any size up to the limits of the TPM. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_SequenceUpdate_REQUEST { /// Handle for the sequence object /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub sequenceHandle: TPM_HANDLE, /// Data to be added to hash @@ -20389,20 +20517,17 @@ impl ReqStructure for TPM2_SequenceUpdate_REQUEST { /// This command adds the last part of data, if any, to a hash/HMAC sequence and returns /// the result. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_SequenceComplete_REQUEST { /// Authorization for the sequence /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub sequenceHandle: TPM_HANDLE, /// Data to be added to the hash/HMAC pub buffer: Vec, /// Hierarchy of the ticket for a hash - #[derivative(Default(value="TPM_HANDLE::default()"))] pub hierarchy: TPM_HANDLE, } @@ -20468,8 +20593,7 @@ impl ReqStructure for TPM2_SequenceComplete_REQUEST { /// This command adds the last part of data, if any, to a hash/HMAC sequence and returns /// the result. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct SequenceCompleteResponse { /// The returned HMAC or digest in a sized buffer pub result: Vec, @@ -20531,19 +20655,16 @@ impl RespStructure for SequenceCompleteResponse { /// returned digest list is processed in the same manner as the digest list input /// parameter to TPM2_PCR_Extend(). That is, if a bank contains a PCR associated with /// pcrHandle, it is extended with the associated digest value from the list. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_EventSequenceComplete_REQUEST { /// PCR to be extended with the Event data /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub pcrHandle: TPM_HANDLE, /// Authorization for the sequence /// Auth Index: 2 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub sequenceHandle: TPM_HANDLE, /// Data to be added to the Event @@ -20613,8 +20734,7 @@ impl ReqStructure for TPM2_EventSequenceComplete_REQUEST { /// returned digest list is processed in the same manner as the digest list input /// parameter to TPM2_PCR_Extend(). That is, if a bank contains a PCR associated with /// pcrHandle, it is extended with the associated digest value from the list. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct EventSequenceCompleteResponse { /// List of digests computed for the PCR pub results: Vec, @@ -20669,19 +20789,16 @@ impl RespStructure for EventSequenceCompleteResponse { /// area with a given Name is self-consistent and associated with a valid sensitive area. /// If a relying party has a public area that has the same Name as a Name certified with /// this command, then the values in that public area are correct. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_Certify_REQUEST { /// Handle of the object to be certified /// Auth Index: 1 /// Auth Role: ADMIN - #[derivative(Default(value="TPM_HANDLE::default()"))] pub objectHandle: TPM_HANDLE, /// Handle of the key used to sign the attestation structure /// Auth Index: 2 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub signHandle: TPM_HANDLE, /// User provided qualifying data @@ -20766,8 +20883,7 @@ impl ReqStructure for TPM2_Certify_REQUEST { /// area with a given Name is self-consistent and associated with a valid sensitive area. /// If a relying party has a public area that has the same Name as a Name certified with /// this command, then the values in that public area are correct. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct CertifyResponse { /// The structure that was signed pub certifyInfo: TPMS_ATTEST, @@ -20834,18 +20950,15 @@ impl RespStructure for CertifyResponse { /// The TPM will validate that the ticket was produced by the TPM and that the ticket /// validates the association between a loaded public area and the provided hash of the /// creation data (creationHash). -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_CertifyCreation_REQUEST { /// Handle of the key that will sign the attestation block /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub signHandle: TPM_HANDLE, /// The object associated with the creation data /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub objectHandle: TPM_HANDLE, /// User-provided qualifying data @@ -20943,8 +21056,7 @@ impl ReqStructure for TPM2_CertifyCreation_REQUEST { /// The TPM will validate that the ticket was produced by the TPM and that the ticket /// validates the association between a loaded public area and the provided hash of the /// creation data (creationHash). -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct CertifyCreationResponse { /// The structure that was signed pub certifyInfo: TPMS_ATTEST, @@ -21008,13 +21120,11 @@ impl RespStructure for CertifyCreationResponse { } /// This command is used to quote PCR values. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_Quote_REQUEST { /// Handle of key that will perform signature /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub signHandle: TPM_HANDLE, /// Data supplied by the caller @@ -21100,8 +21210,7 @@ impl ReqStructure for TPM2_Quote_REQUEST { } /// This command is used to quote PCR values. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct QuoteResponse { /// The quoted information pub quoted: TPMS_ATTEST, @@ -21165,24 +21274,20 @@ impl RespStructure for QuoteResponse { } /// This command returns a digital signature of the audit session digest. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_GetSessionAuditDigest_REQUEST { /// Handle of the privacy administrator (TPM_RH_ENDORSEMENT) /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub privacyAdminHandle: TPM_HANDLE, /// Handle of the signing key /// Auth Index: 2 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub signHandle: TPM_HANDLE, /// Handle of the audit session /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub sessionHandle: TPM_HANDLE, /// User-provided qualifying data may be zero-length @@ -21265,8 +21370,7 @@ impl ReqStructure for TPM2_GetSessionAuditDigest_REQUEST { } /// This command returns a digital signature of the audit session digest. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct GetSessionAuditDigestResponse { /// The audit information that was signed pub auditInfo: TPMS_ATTEST, @@ -21332,19 +21436,16 @@ impl RespStructure for GetSessionAuditDigestResponse { /// This command returns the current value of the command audit digest, a digest of the /// commands being audited, and the audit hash algorithm. These values are placed in an /// attestation structure and signed with the key referenced by signHandle. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_GetCommandAuditDigest_REQUEST { /// Handle of the privacy administrator (TPM_RH_ENDORSEMENT) /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub privacyHandle: TPM_HANDLE, /// The handle of the signing key /// Auth Index: 2 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub signHandle: TPM_HANDLE, /// Other data to associate with this audit digest @@ -21427,8 +21528,7 @@ impl ReqStructure for TPM2_GetCommandAuditDigest_REQUEST { /// This command returns the current value of the command audit digest, a digest of the /// commands being audited, and the audit hash algorithm. These values are placed in an /// attestation structure and signed with the key referenced by signHandle. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct GetCommandAuditDigestResponse { /// The auditInfo that was signed pub auditInfo: TPMS_ATTEST, @@ -21492,19 +21592,16 @@ impl RespStructure for GetCommandAuditDigestResponse { } /// This command returns the current values of Time and Clock. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_GetTime_REQUEST { /// Handle of the privacy administrator (TPM_RH_ENDORSEMENT) /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub privacyAdminHandle: TPM_HANDLE, /// The keyHandle identifier of a loaded key that can perform digital signatures /// Auth Index: 2 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub signHandle: TPM_HANDLE, /// Data to tick stamp @@ -21585,8 +21682,7 @@ impl ReqStructure for TPM2_GetTime_REQUEST { } /// This command returns the current values of Time and Clock. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct GetTimeResponse { /// Standard TPM-generated attestation block pub timeInfo: TPMS_ATTEST, @@ -21655,19 +21751,16 @@ impl RespStructure for GetTimeResponse { /// information, TPM2_CertifyX509 encodes the attestation information in a DER-encoded /// X.509 certificate that is compliant with RFC5280 Internet X.509 Public Key /// Infrastructure Certificate and Certificate Revocation List (CRL) Profile. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_CertifyX509_REQUEST { /// Handle of the object to be certified /// Auth Index: 1 /// Auth Role: ADMIN - #[derivative(Default(value="TPM_HANDLE::default()"))] pub objectHandle: TPM_HANDLE, /// Handle of the key used to sign the attestation structure /// Auth Index: 2 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub signHandle: TPM_HANDLE, /// Shall be an Empty Buffer @@ -21760,8 +21853,7 @@ impl ReqStructure for TPM2_CertifyX509_REQUEST { /// information, TPM2_CertifyX509 encodes the attestation information in a DER-encoded /// X.509 certificate that is compliant with RFC5280 Internet X.509 Public Key /// Infrastructure Certificate and Certificate Revocation List (CRL) Profile. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct CertifyX509Response { /// A DER encoded SEQUENCE containing the DER encoded fields added to partialCertificate /// to make it a complete RFC5280 TBSCertificate. @@ -21834,13 +21926,11 @@ impl RespStructure for CertifyX509Response { /// will perform the point multiplications on the provided points and return intermediate /// signing values. The signHandle parameter shall refer to an ECC key and the signing /// scheme must be anonymous (TPM_RC_SCHEME). -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_Commit_REQUEST { /// Handle of the key that will be used in the signing operation /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub signHandle: TPM_HANDLE, /// A point (M) on the curve used by signHandle @@ -21921,8 +22011,7 @@ impl ReqStructure for TPM2_Commit_REQUEST { /// will perform the point multiplications on the provided points and return intermediate /// signing values. The signHandle parameter shall refer to an ECC key and the signing /// scheme must be anonymous (TPM_RC_SCHEME). -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct CommitResponse { /// ECC point K [ds](x2, y2) pub K: TPMS_ECC_POINT, @@ -21988,8 +22077,7 @@ impl RespStructure for CommitResponse { } /// TPM2_EC_Ephemeral() creates an ephemeral key for use in a two-phase key exchange protocol. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_EC_Ephemeral_REQUEST { /// The curve for the computed ephemeral point pub curveID: TPM_ECC_CURVE, @@ -22049,8 +22137,7 @@ impl ReqStructure for TPM2_EC_Ephemeral_REQUEST { } /// TPM2_EC_Ephemeral() creates an ephemeral key for use in a two-phase key exchange protocol. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct EC_EphemeralResponse { /// Ephemeral public key Q [r]G pub Q: TPMS_ECC_POINT, @@ -22107,12 +22194,10 @@ impl RespStructure for EC_EphemeralResponse { /// This command uses loaded keys to validate a signature on a message with the message /// digest passed to the TPM. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_VerifySignature_REQUEST { /// Handle of public key that will be used in the validation /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub keyHandle: TPM_HANDLE, /// Digest of the signed message @@ -22192,8 +22277,7 @@ impl ReqStructure for TPM2_VerifySignature_REQUEST { /// This command uses loaded keys to validate a signature on a message with the message /// digest passed to the TPM. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct VerifySignatureResponse { pub validation: TPMT_TK_VERIFIED, } @@ -22243,13 +22327,11 @@ impl RespStructure for VerifySignatureResponse { /// This command causes the TPM to sign an externally provided hash with the specified /// symmetric or asymmetric signing key. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_Sign_REQUEST { /// Handle of key that will perform signing /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub keyHandle: TPM_HANDLE, /// Digest to be signed @@ -22338,8 +22420,7 @@ impl ReqStructure for TPM2_Sign_REQUEST { /// This command causes the TPM to sign an externally provided hash with the specified /// symmetric or asymmetric signing key. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct SignResponse { /// Selector of the algorithm used to construct the signature @@ -22399,17 +22480,14 @@ impl RespStructure for SignResponse { /// This command may be used by the Privacy Administrator or platform to change the audit /// status of a command or to set the hash algorithm used for the audit digest, but not /// both at the same time. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone)] pub struct TPM2_SetCommandCodeAuditStatus_REQUEST { /// TPM_RH_OWNER or TPM_RH_PLATFORM+{PP} /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub auth: TPM_HANDLE, /// Hash algorithm for the audit digest; if TPM_ALG_NULL, then the hash is not changed - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub auditAlg: TPM_ALG_ID, /// List of commands that will be added to those that will be audited @@ -22419,6 +22497,17 @@ pub struct TPM2_SetCommandCodeAuditStatus_REQUEST { pub clearList: Vec, } +impl Default for TPM2_SetCommandCodeAuditStatus_REQUEST { + fn default() -> Self { + Self { + auth: Default::default(), + auditAlg: TPM_ALG_ID::NULL, + setList: Default::default(), + clearList: Default::default(), + } + } +} + impl TPM2_SetCommandCodeAuditStatus_REQUEST { /// Creates a new instance with the specified values pub fn new( @@ -22486,13 +22575,11 @@ impl ReqStructure for TPM2_SetCommandCodeAuditStatus_REQUEST { /// contains one or more tagged digest values identified by an algorithm ID. For each /// digest, the PCR associated with pcrHandle is Extended into the bank identified by the /// tag (hashAlg). -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_PCR_Extend_REQUEST { /// Handle of the PCR /// Auth Handle: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub pcrHandle: TPM_HANDLE, /// List of tagged digest values to be extended @@ -22556,13 +22643,11 @@ impl ReqStructure for TPM2_PCR_Extend_REQUEST { } /// This command is used to cause an update to the indicated PCR. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_PCR_Event_REQUEST { /// Handle of the PCR /// Auth Handle: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub pcrHandle: TPM_HANDLE, /// Event data in sized buffer @@ -22626,8 +22711,7 @@ impl ReqStructure for TPM2_PCR_Event_REQUEST { } /// This command is used to cause an update to the indicated PCR. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct PCR_EventResponse { pub digests: Vec, } @@ -22677,8 +22761,7 @@ impl RespStructure for PCR_EventResponse { } /// This command returns the values of all PCR specified in pcrSelectionIn. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_PCR_Read_REQUEST { /// The selection of PCR to read pub pcrSelectionIn: Vec, @@ -22739,8 +22822,7 @@ impl ReqStructure for TPM2_PCR_Read_REQUEST { } /// This command returns the values of all PCR specified in pcrSelectionIn. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct PCR_ReadResponse { /// The current value of the PCR update counter pub pcrUpdateCounter: u32, @@ -22801,13 +22883,11 @@ impl RespStructure for PCR_ReadResponse { /// This command is used to set the desired PCR allocation of PCR and algorithms. This /// command requires Platform Authorization. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_PCR_Allocate_REQUEST { /// TPM_RH_PLATFORM+{PP} /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub authHandle: TPM_HANDLE, /// The requested allocation @@ -22872,8 +22952,7 @@ impl ReqStructure for TPM2_PCR_Allocate_REQUEST { /// This command is used to set the desired PCR allocation of PCR and algorithms. This /// command requires Platform Authorization. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct PCR_AllocateResponse { /// YES if the allocation succeeded pub allocationSuccess: u8, @@ -22939,27 +23018,34 @@ impl RespStructure for PCR_AllocateResponse { /// This command is used to associate a policy with a PCR or group of PCR. The policy /// determines the conditions under which a PCR may be extended or reset. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone)] pub struct TPM2_PCR_SetAuthPolicy_REQUEST { /// TPM_RH_PLATFORM+{PP} /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub authHandle: TPM_HANDLE, /// The desired authPolicy pub authPolicy: Vec, /// The hash algorithm of the policy - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub hashAlg: TPM_ALG_ID, /// The PCR for which the policy is to be set - #[derivative(Default(value="TPM_HANDLE::default()"))] pub pcrNum: TPM_HANDLE, } +impl Default for TPM2_PCR_SetAuthPolicy_REQUEST { + fn default() -> Self { + Self { + authHandle: Default::default(), + authPolicy: Default::default(), + hashAlg: TPM_ALG_ID::NULL, + pcrNum: Default::default(), + } + } +} + impl TPM2_PCR_SetAuthPolicy_REQUEST { /// Creates a new instance with the specified values pub fn new( @@ -23025,13 +23111,11 @@ impl ReqStructure for TPM2_PCR_SetAuthPolicy_REQUEST { } /// This command changes the authValue of a PCR or group of PCR. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_PCR_SetAuthValue_REQUEST { /// Handle for a PCR that may have an authorization value set /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub pcrHandle: TPM_HANDLE, /// The desired authorization value @@ -23097,13 +23181,11 @@ impl ReqStructure for TPM2_PCR_SetAuthValue_REQUEST { /// If the attribute of a PCR allows the PCR to be reset and proper authorization is /// provided, then this command may be used to set the PCR in all banks to zero. The /// attributes of the PCR may restrict the locality that can perform the reset operation. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_PCR_Reset_REQUEST { /// The PCR to reset /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub pcrHandle: TPM_HANDLE, } @@ -23160,17 +23242,14 @@ impl ReqStructure for TPM2_PCR_Reset_REQUEST { /// This command includes a signed authorization in a policy. The command ties the policy /// to a signing key by including the Name of the signing key in the policyDigest -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_PolicySigned_REQUEST { /// Handle for a key that will validate the signature /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub authObject: TPM_HANDLE, /// Handle for the policy session being extended /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub policySession: TPM_HANDLE, /// The policy nonce for the session @@ -23279,8 +23358,7 @@ impl ReqStructure for TPM2_PolicySigned_REQUEST { /// This command includes a signed authorization in a policy. The command ties the policy /// to a signing key by including the Name of the signing key in the policyDigest -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct PolicySignedResponse { /// Implementation-specific time value, used to indicate to the TPM when the ticket expires /// NOTE If policyTicket is a NULL Ticket, then this shall be the Empty Buffer. @@ -23341,18 +23419,15 @@ impl RespStructure for PolicySignedResponse { /// knowledge of the secret value using an authorization session using the authValue /// associated with authHandle. A password session, an HMAC session, or a policy session /// containing TPM2_PolicyAuthValue() or TPM2_PolicyPassword() will satisfy this requirement. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_PolicySecret_REQUEST { /// Handle for an entity providing the authorization /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub authHandle: TPM_HANDLE, /// Handle for the policy session being extended /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub policySession: TPM_HANDLE, /// The policy nonce for the session @@ -23448,8 +23523,7 @@ impl ReqStructure for TPM2_PolicySecret_REQUEST { /// knowledge of the secret value using an authorization session using the authValue /// associated with authHandle. A password session, an HMAC session, or a policy session /// containing TPM2_PolicyAuthValue() or TPM2_PolicyPassword() will satisfy this requirement. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct PolicySecretResponse { /// Implementation-specific time value used to indicate to the TPM when the ticket expires pub timeout: Vec, @@ -23508,12 +23582,10 @@ impl RespStructure for PolicySecretResponse { /// This command is similar to TPM2_PolicySigned() except that it takes a ticket instead /// of a signed authorization. The ticket represents a validated authorization that had an /// expiration time associated with it. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_PolicyTicket_REQUEST { /// Handle for the policy session being extended /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub policySession: TPM_HANDLE, /// Time when authorization will expire @@ -23611,12 +23683,10 @@ impl ReqStructure for TPM2_PolicyTicket_REQUEST { /// all of the options. If a policy may be satisfied by different sets of conditions, the /// TPM need only evaluate one set that satisfies the policy. This command will indicate /// that one of the required sets of conditions has been satisfied. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_PolicyOR_REQUEST { /// Handle for the policy session being extended /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub policySession: TPM_HANDLE, /// The list of hashes to check for a match @@ -23683,12 +23753,10 @@ impl ReqStructure for TPM2_PolicyOR_REQUEST { /// command together with TPM2_PolicyOR() allows one group of authorizations to occur when /// PCR are in one state and a different set of authorizations when the PCR are in a /// different state. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_PolicyPCR_REQUEST { /// Handle for the policy session being extended /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub policySession: TPM_HANDLE, /// Expected digest value of the selected PCR using the hash algorithm of the session; may @@ -23760,12 +23828,10 @@ impl ReqStructure for TPM2_PolicyPCR_REQUEST { } /// This command indicates that the authorization will be limited to a specific locality. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_PolicyLocality_REQUEST { /// Handle for the policy session being extended /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub policySession: TPM_HANDLE, /// The allowed localities for the policy @@ -23830,23 +23896,19 @@ impl ReqStructure for TPM2_PolicyLocality_REQUEST { /// This command is used to cause conditional gating of a policy based on the contents of /// an NV Index. It is an immediate assertion. The NV index is validated during the /// TPM2_PolicyNV() command, not when the session is used for authorization. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_PolicyNV_REQUEST { /// Handle indicating the source of the authorization value /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub authHandle: TPM_HANDLE, /// The NV Index of the area to read /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub nvIndex: TPM_HANDLE, /// Handle for the policy session being extended /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub policySession: TPM_HANDLE, /// The second operand @@ -23929,12 +23991,10 @@ impl ReqStructure for TPM2_PolicyNV_REQUEST { /// This command is used to cause conditional gating of a policy based on the contents of /// the TPMS_TIME_INFO structure. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_PolicyCounterTimer_REQUEST { /// Handle for the policy session being extended /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub policySession: TPM_HANDLE, /// The second operand @@ -24012,12 +24072,10 @@ impl ReqStructure for TPM2_PolicyCounterTimer_REQUEST { } /// This command indicates that the authorization will be limited to a specific command code. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_PolicyCommandCode_REQUEST { /// Handle for the policy session being extended /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub policySession: TPM_HANDLE, /// The allowed commandCode @@ -24081,12 +24139,10 @@ impl ReqStructure for TPM2_PolicyCommandCode_REQUEST { /// This command indicates that physical presence will need to be asserted at the time the /// authorization is performed. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_PolicyPhysicalPresence_REQUEST { /// Handle for the policy session being extended /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub policySession: TPM_HANDLE, } @@ -24142,12 +24198,10 @@ impl ReqStructure for TPM2_PolicyPhysicalPresence_REQUEST { } /// This command is used to allow a policy to be bound to a specific command and command parameters. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_PolicyCpHash_REQUEST { /// Handle for the policy session being extended /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub policySession: TPM_HANDLE, /// The cpHash added to the policy @@ -24213,12 +24267,10 @@ impl ReqStructure for TPM2_PolicyCpHash_REQUEST { /// This command allows a policy to be bound to a specific set of TPM entities without /// being bound to the parameters of the command. This is most useful for commands such as /// TPM2_Duplicate() and for TPM2_PCR_Event() when the referenced PCR requires a policy. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_PolicyNameHash_REQUEST { /// Handle for the policy session being extended /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub policySession: TPM_HANDLE, /// The digest to be added to the policy @@ -24283,12 +24335,10 @@ impl ReqStructure for TPM2_PolicyNameHash_REQUEST { /// This command allows qualification of duplication to allow duplication to a selected /// new parent. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_PolicyDuplicationSelect_REQUEST { /// Handle for the policy session being extended /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub policySession: TPM_HANDLE, /// The Name of the object to be duplicated @@ -24368,12 +24418,10 @@ impl ReqStructure for TPM2_PolicyDuplicationSelect_REQUEST { /// This command allows policies to change. If a policy were static, then it would be /// difficult to add users to a policy. This command lets a policy authority sign a new /// policy so that it may be used in an existing policy. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_PolicyAuthorize_REQUEST { /// Handle for the policy session being extended /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub policySession: TPM_HANDLE, /// Digest of the policy being approved @@ -24458,12 +24506,10 @@ impl ReqStructure for TPM2_PolicyAuthorize_REQUEST { } /// This command allows a policy to be bound to the authorization value of the authorized entity. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_PolicyAuthValue_REQUEST { /// Handle for the policy session being extended /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub policySession: TPM_HANDLE, } @@ -24519,12 +24565,10 @@ impl ReqStructure for TPM2_PolicyAuthValue_REQUEST { } /// This command allows a policy to be bound to the authorization value of the authorized object. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_PolicyPassword_REQUEST { /// Handle for the policy session being extended /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub policySession: TPM_HANDLE, } @@ -24581,12 +24625,10 @@ impl ReqStructure for TPM2_PolicyPassword_REQUEST { /// This command returns the current policyDigest of the session. This command allows the /// TPM to be used to perform the actions required to pre-compute the authPolicy for an object. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_PolicyGetDigest_REQUEST { /// Handle for the policy session /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub policySession: TPM_HANDLE, } @@ -24643,8 +24685,7 @@ impl ReqStructure for TPM2_PolicyGetDigest_REQUEST { /// This command returns the current policyDigest of the session. This command allows the /// TPM to be used to perform the actions required to pre-compute the authPolicy for an object. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct PolicyGetDigestResponse { /// The current value of the policySessionpolicyDigest pub policyDigest: Vec, @@ -24697,12 +24738,10 @@ impl RespStructure for PolicyGetDigestResponse { /// This command allows a policy to be bound to the TPMA_NV_WRITTEN attributes. This is a /// deferred assertion. Values are stored in the policy session context and checked when /// the policy is used for authorization. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_PolicyNvWritten_REQUEST { /// Handle for the policy session being extended /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub policySession: TPM_HANDLE, /// YES if NV Index is required to have been written @@ -24768,12 +24807,10 @@ impl ReqStructure for TPM2_PolicyNvWritten_REQUEST { /// This command allows a policy to be bound to a specific creation template. This is most /// useful for an object creation command such as TPM2_Create(), TPM2_CreatePrimary(), or /// TPM2_CreateLoaded(). -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_PolicyTemplate_REQUEST { /// Handle for the policy session being extended /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub policySession: TPM_HANDLE, /// The digest to be added to the policy @@ -24840,23 +24877,19 @@ impl ReqStructure for TPM2_PolicyTemplate_REQUEST { /// TPM2_PolicyAuthorize(), the authorization ticket never expires, so the authorization /// may not be withdrawn. With this command, the approved policy is kept in an NV Index /// location so that the policy may be changed as needed to render the old policy unusable. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_PolicyAuthorizeNV_REQUEST { /// Handle indicating the source of the authorization value /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub authHandle: TPM_HANDLE, /// The NV Index of the area to read /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub nvIndex: TPM_HANDLE, /// Handle for the policy session being extended /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub policySession: TPM_HANDLE, } @@ -24920,13 +24953,11 @@ impl ReqStructure for TPM2_PolicyAuthorizeNV_REQUEST { /// the object to be created. The size of the unique field shall not be checked for /// consistency with the other object parameters. The command will create and load a /// Primary Object. The sensitive area is not returned. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_CreatePrimary_REQUEST { /// TPM_RH_ENDORSEMENT, TPM_RH_OWNER, TPM_RH_PLATFORM+{PP}, or TPM_RH_NULL /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub primaryHandle: TPM_HANDLE, /// The sensitive data, see TPM 2.0 Part 1 Sensitive Values @@ -25016,11 +25047,9 @@ impl ReqStructure for TPM2_CreatePrimary_REQUEST { /// the object to be created. The size of the unique field shall not be checked for /// consistency with the other object parameters. The command will create and load a /// Primary Object. The sensitive area is not returned. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct CreatePrimaryResponse { /// Handle of type TPM_HT_TRANSIENT for created Primary Object - #[derivative(Default(value="TPM_HANDLE::default()"))] pub handle: TPM_HANDLE, /// The public portion of the created object @@ -25097,18 +25126,15 @@ impl RespStructure for CreatePrimaryResponse { /// This command enables and disables use of a hierarchy and its associated NV storage. /// The command allows phEnable, phEnableNV, shEnable, and ehEnable to be changed when the /// proper authorization is provided. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_HierarchyControl_REQUEST { /// TPM_RH_ENDORSEMENT, TPM_RH_OWNER or TPM_RH_PLATFORM+{PP} /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub authHandle: TPM_HANDLE, /// The enable being modified /// TPM_RH_ENDORSEMENT, TPM_RH_OWNER, TPM_RH_PLATFORM, or TPM_RH_PLATFORM_NV - #[derivative(Default(value="TPM_HANDLE::default()"))] pub enable: TPM_HANDLE, /// YES if the enable should be SET, NO if the enable should be CLEAR @@ -25179,13 +25205,11 @@ impl ReqStructure for TPM2_HierarchyControl_REQUEST { /// (ownerPolicy), and the endorsement hierarchy (endorsementPolicy). On TPMs implementing /// Authenticated Countdown Timers (ACT), this command may also be used to set the /// authorization policy for an ACT. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone)] pub struct TPM2_SetPrimaryPolicy_REQUEST { /// TPM_RH_LOCKOUT, TPM_RH_ENDORSEMENT, TPM_RH_OWNER, TPMI_RH_ACT or TPM_RH_PLATFORM+{PP} /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub authHandle: TPM_HANDLE, /// An authorization policy digest; may be the Empty Buffer @@ -25194,10 +25218,19 @@ pub struct TPM2_SetPrimaryPolicy_REQUEST { /// The hash algorithm to use for the policy /// If the authPolicy is an Empty Buffer, then this field shall be TPM_ALG_NULL. - #[derivative(Default(value="TPM_ALG_ID::NULL"))] pub hashAlg: TPM_ALG_ID, } +impl Default for TPM2_SetPrimaryPolicy_REQUEST { + fn default() -> Self { + Self { + authHandle: Default::default(), + authPolicy: Default::default(), + hashAlg: TPM_ALG_ID::NULL, + } + } +} + impl TPM2_SetPrimaryPolicy_REQUEST { /// Creates a new instance with the specified values pub fn new( @@ -25260,13 +25293,11 @@ impl ReqStructure for TPM2_SetPrimaryPolicy_REQUEST { /// This replaces the current platform primary seed (PPS) with a value from the RNG and /// sets platformPolicy to the default initialization value (the Empty Buffer). -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_ChangePPS_REQUEST { /// TPM_RH_PLATFORM+{PP} /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub authHandle: TPM_HANDLE, } @@ -25327,13 +25358,11 @@ impl ReqStructure for TPM2_ChangePPS_REQUEST { /// Buffer. It will flush any resident objects (transient or persistent) in the /// Endorsement hierarchy and not allow objects in the hierarchy associated with the /// previous EPS to be loaded. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_ChangeEPS_REQUEST { /// TPM_RH_PLATFORM+{PP} /// Auth Handle: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub authHandle: TPM_HANDLE, } @@ -25389,13 +25418,11 @@ impl ReqStructure for TPM2_ChangeEPS_REQUEST { } /// This command removes all TPM context associated with a specific Owner. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_Clear_REQUEST { /// TPM_RH_LOCKOUT or TPM_RH_PLATFORM+{PP} /// Auth Handle: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub authHandle: TPM_HANDLE, } @@ -25451,13 +25478,11 @@ impl ReqStructure for TPM2_Clear_REQUEST { } /// TPM2_ClearControl() disables and enables the execution of TPM2_Clear(). -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_ClearControl_REQUEST { /// TPM_RH_LOCKOUT or TPM_RH_PLATFORM+{PP} /// Auth Handle: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub auth: TPM_HANDLE, /// YES if the disableOwnerClear flag is to be SET, NO if the flag is to be CLEAR. @@ -25521,13 +25546,11 @@ impl ReqStructure for TPM2_ClearControl_REQUEST { /// This command allows the authorization secret for a hierarchy or lockout to be changed /// using the current authorization value as the command authorization. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_HierarchyChangeAuth_REQUEST { /// TPM_RH_LOCKOUT, TPM_RH_ENDORSEMENT, TPM_RH_OWNER or TPM_RH_PLATFORM+{PP} /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub authHandle: TPM_HANDLE, /// New authorization value @@ -25593,13 +25616,11 @@ impl ReqStructure for TPM2_HierarchyChangeAuth_REQUEST { /// This command cancels the effect of a TPM lockout due to a number of successive /// authorization failures. If this command is properly authorized, the lockout counter is /// set to zero. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_DictionaryAttackLockReset_REQUEST { /// TPM_RH_LOCKOUT /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub lockHandle: TPM_HANDLE, } @@ -25655,13 +25676,11 @@ impl ReqStructure for TPM2_DictionaryAttackLockReset_REQUEST { } /// This command changes the lockout parameters. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_DictionaryAttackParameters_REQUEST { /// TPM_RH_LOCKOUT /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub lockHandle: TPM_HANDLE, /// Count of authorization failures before the lockout is imposed @@ -25741,13 +25760,11 @@ impl ReqStructure for TPM2_DictionaryAttackParameters_REQUEST { /// This command is used to determine which commands require assertion of Physical /// Presence (PP) in addition to platformAuth/platformPolicy. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_PP_Commands_REQUEST { /// TPM_RH_PLATFORM+PP /// Auth Index: 1 /// Auth Role: USER + Physical Presence - #[derivative(Default(value="TPM_HANDLE::default()"))] pub auth: TPM_HANDLE, /// List of commands to be added to those that will require that Physical Presence be asserted @@ -25819,13 +25836,11 @@ impl ReqStructure for TPM2_PP_Commands_REQUEST { /// This command allows the platform to change the set of algorithms that are used by the /// TPM. The algorithmSet setting is a vendor-dependent value. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_SetAlgorithmSet_REQUEST { /// TPM_RH_PLATFORM /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub authHandle: TPM_HANDLE, /// A TPM vendor-dependent value indicating the algorithm set selection @@ -25889,19 +25904,16 @@ impl ReqStructure for TPM2_SetAlgorithmSet_REQUEST { /// This command uses platformPolicy and a TPM Vendor Authorization Key to authorize a /// Field Upgrade Manifest. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_FieldUpgradeStart_REQUEST { /// TPM_RH_PLATFORM+{PP} /// Auth Index:1 /// Auth Role: ADMIN - #[derivative(Default(value="TPM_HANDLE::default()"))] pub authorization: TPM_HANDLE, /// Handle of a public area that contains the TPM Vendor Authorization Key that will be /// used to validate manifestSignature /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub keyHandle: TPM_HANDLE, /// Digest of the first block in the field upgrade sequence @@ -25985,8 +25997,7 @@ impl ReqStructure for TPM2_FieldUpgradeStart_REQUEST { /// exact format of fuData is vendor-specific. This command is only possible following a /// successful TPM2_FieldUpgradeStart(). If the TPM has not received a properly authorized /// TPM2_FieldUpgradeStart(), then the TPM shall return TPM_RC_FIELDUPGRADE. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_FieldUpgradeData_REQUEST { /// Field upgrade image data pub fuData: Vec, @@ -26050,8 +26061,7 @@ impl ReqStructure for TPM2_FieldUpgradeData_REQUEST { /// exact format of fuData is vendor-specific. This command is only possible following a /// successful TPM2_FieldUpgradeStart(). If the TPM has not received a properly authorized /// TPM2_FieldUpgradeStart(), then the TPM shall return TPM_RC_FIELDUPGRADE. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct FieldUpgradeDataResponse { /// Tagged digest of the next block /// TPM_ALG_NULL if field update is complete @@ -26107,8 +26117,7 @@ impl RespStructure for FieldUpgradeDataResponse { } /// This command is used to read a copy of the current firmware installed in the TPM. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_FirmwareRead_REQUEST { /// The number of previous calls to this command in this sequence /// set to 0 on the first call @@ -26169,8 +26178,7 @@ impl ReqStructure for TPM2_FirmwareRead_REQUEST { } /// This command is used to read a copy of the current firmware installed in the TPM. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct FirmwareReadResponse { /// Field upgrade image data pub fuData: Vec, @@ -26222,12 +26230,10 @@ impl RespStructure for FirmwareReadResponse { /// This command saves a session context, object context, or sequence object context /// outside the TPM. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_ContextSave_REQUEST { /// Handle of the resource to save /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub saveHandle: TPM_HANDLE, } @@ -26284,8 +26290,7 @@ impl ReqStructure for TPM2_ContextSave_REQUEST { /// This command saves a session context, object context, or sequence object context /// outside the TPM. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct ContextSaveResponse { pub context: TPMS_CONTEXT, } @@ -26334,8 +26339,7 @@ impl RespStructure for ContextSaveResponse { } /// This command is used to reload a context that has been saved by TPM2_ContextSave(). -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_ContextLoad_REQUEST { /// The context blob pub context: TPMS_CONTEXT, @@ -26395,11 +26399,9 @@ impl ReqStructure for TPM2_ContextLoad_REQUEST { } /// This command is used to reload a context that has been saved by TPM2_ContextSave(). -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct ContextLoadResponse { /// The handle assigned to the resource after it has been successfully loaded - #[derivative(Default(value="TPM_HANDLE::default()"))] pub handle: TPM_HANDLE, } @@ -26446,12 +26448,10 @@ impl RespStructure for ContextLoadResponse { /// This command causes all context associated with a loaded object, sequence object, or /// session to be removed from TPM memory. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_FlushContext_REQUEST { /// The handle of the item to flush /// NOTE This is a use of a handle as a parameter. - #[derivative(Default(value="TPM_HANDLE::default()"))] pub flushHandle: TPM_HANDLE, } @@ -26510,25 +26510,21 @@ impl ReqStructure for TPM2_FlushContext_REQUEST { /// This command allows certain Transient Objects to be made persistent or a persistent /// object to be evicted. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_EvictControl_REQUEST { /// TPM_RH_OWNER or TPM_RH_PLATFORM+{PP} /// Auth Handle: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub auth: TPM_HANDLE, /// The handle of a loaded object /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub objectHandle: TPM_HANDLE, /// If objectHandle is a transient object handle, then this is the persistent handle for /// the object /// if objectHandle is a persistent object handle, then it shall be the same value as /// persistentHandle - #[derivative(Default(value="TPM_HANDLE::default()"))] pub persistentHandle: TPM_HANDLE, } @@ -26591,8 +26587,7 @@ impl ReqStructure for TPM2_EvictControl_REQUEST { /// This command reads the current TPMS_TIME_INFO structure that contains the current /// setting of Time, Clock, resetCount, and restartCount. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_ReadClock_REQUEST { } @@ -26639,8 +26634,7 @@ impl ReqStructure for TPM2_ReadClock_REQUEST { /// This command reads the current TPMS_TIME_INFO structure that contains the current /// setting of Time, Clock, resetCount, and restartCount. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct ReadClockResponse { pub currentTime: TPMS_TIME_INFO, } @@ -26692,13 +26686,11 @@ impl RespStructure for ReadClockResponse { /// newTime is less than the current value of Clock or if the new time is greater than /// FFFF00000000000016. If both of these checks succeed, Clock is set to newTime. If /// either of these checks fails, the TPM shall return TPM_RC_VALUE and make no change to Clock. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_ClockSet_REQUEST { /// TPM_RH_OWNER or TPM_RH_PLATFORM+{PP} /// Auth Handle: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub auth: TPM_HANDLE, /// New Clock setting in milliseconds @@ -26762,13 +26754,11 @@ impl ReqStructure for TPM2_ClockSet_REQUEST { /// This command adjusts the rate of advance of Clock and Time to provide a better /// approximation to real time. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_ClockRateAdjust_REQUEST { /// TPM_RH_OWNER or TPM_RH_PLATFORM+{PP} /// Auth Handle: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub auth: TPM_HANDLE, /// Adjustment to current Clock update rate @@ -26831,8 +26821,7 @@ impl ReqStructure for TPM2_ClockRateAdjust_REQUEST { } /// This command returns various information regarding the TPM and its current state. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_GetCapability_REQUEST { /// Group selection; determines the format of the response pub capability: TPM_CAP, @@ -26906,8 +26895,7 @@ impl ReqStructure for TPM2_GetCapability_REQUEST { } /// This command returns various information regarding the TPM and its current state. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct GetCapabilityResponse { /// Flag to indicate if there are more values of this type pub moreData: u8, @@ -26971,8 +26959,7 @@ impl RespStructure for GetCapabilityResponse { /// This command is used to check to see if specific combinations of algorithm parameters /// are supported. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_TestParms_REQUEST { /// The algorithm to be tested @@ -27041,13 +27028,11 @@ impl ReqStructure for TPM2_TestParms_REQUEST { /// This command defines the attributes of an NV Index and causes the TPM to reserve space /// to hold the data associated with the NV Index. If a definition already exists at the /// NV Index, the TPM will return TPM_RC_NV_DEFINED. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_NV_DefineSpace_REQUEST { /// TPM_RH_OWNER or TPM_RH_PLATFORM+{PP} /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub authHandle: TPM_HANDLE, /// The authorization value @@ -27118,18 +27103,15 @@ impl ReqStructure for TPM2_NV_DefineSpace_REQUEST { } /// This command removes an Index from the TPM. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_NV_UndefineSpace_REQUEST { /// TPM_RH_OWNER or TPM_RH_PLATFORM+{PP} /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub authHandle: TPM_HANDLE, /// The NV Index to remove from NV space /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub nvIndex: TPM_HANDLE, } @@ -27188,19 +27170,16 @@ impl ReqStructure for TPM2_NV_UndefineSpace_REQUEST { /// This command allows removal of a platform-created NV Index that has /// TPMA_NV_POLICY_DELETE SET. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_NV_UndefineSpaceSpecial_REQUEST { /// Index to be deleted /// Auth Index: 1 /// Auth Role: ADMIN - #[derivative(Default(value="TPM_HANDLE::default()"))] pub nvIndex: TPM_HANDLE, /// TPM_RH_PLATFORM + {PP} /// Auth Index: 2 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub platform: TPM_HANDLE, } @@ -27259,12 +27238,10 @@ impl ReqStructure for TPM2_NV_UndefineSpaceSpecial_REQUEST { /// This command is used to read the public area and Name of an NV Index. The public area /// of an Index is not privacy-sensitive and no authorization is required to read this data. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_NV_ReadPublic_REQUEST { /// The NV Index /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub nvIndex: TPM_HANDLE, } @@ -27321,8 +27298,7 @@ impl ReqStructure for TPM2_NV_ReadPublic_REQUEST { /// This command is used to read the public area and Name of an NV Index. The public area /// of an Index is not privacy-sensitive and no authorization is required to read this data. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct NV_ReadPublicResponse { /// The public area of the NV Index pub nvPublic: TPMS_NV_PUBLIC, @@ -27379,18 +27355,15 @@ impl RespStructure for NV_ReadPublicResponse { /// This command writes a value to an area in NV memory that was previously defined by /// TPM2_NV_DefineSpace(). -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_NV_Write_REQUEST { /// Handle indicating the source of the authorization value /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub authHandle: TPM_HANDLE, /// The NV Index of the area to write /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub nvIndex: TPM_HANDLE, /// The data to write @@ -27464,18 +27437,15 @@ impl ReqStructure for TPM2_NV_Write_REQUEST { /// This command is used to increment the value in an NV Index that has the TPM_NT_COUNTER /// attribute. The data value of the NV Index is incremented by one. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_NV_Increment_REQUEST { /// Handle indicating the source of the authorization value /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub authHandle: TPM_HANDLE, /// The NV Index to increment /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub nvIndex: TPM_HANDLE, } @@ -27534,18 +27504,15 @@ impl ReqStructure for TPM2_NV_Increment_REQUEST { /// This command extends a value to an area in NV memory that was previously defined by /// TPM2_NV_DefineSpace. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_NV_Extend_REQUEST { /// Handle indicating the source of the authorization value /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub authHandle: TPM_HANDLE, /// The NV Index to extend /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub nvIndex: TPM_HANDLE, /// The data to extend @@ -27613,18 +27580,15 @@ impl ReqStructure for TPM2_NV_Extend_REQUEST { /// This command is used to SET bits in an NV Index that was created as a bit field. Any /// number of bits from 0 to 64 may be SET. The contents of bits are ORed with the current /// contents of the NV Index. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_NV_SetBits_REQUEST { /// Handle indicating the source of the authorization value /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub authHandle: TPM_HANDLE, /// NV Index of the area in which the bit is to be set /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub nvIndex: TPM_HANDLE, /// The data to OR with the current contents @@ -27690,18 +27654,15 @@ impl ReqStructure for TPM2_NV_SetBits_REQUEST { /// If the TPMA_NV_WRITEDEFINE or TPMA_NV_WRITE_STCLEAR attributes of an NV location are /// SET, then this command may be used to inhibit further writes of the NV Index. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_NV_WriteLock_REQUEST { /// Handle indicating the source of the authorization value /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub authHandle: TPM_HANDLE, /// The NV Index of the area to lock /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub nvIndex: TPM_HANDLE, } @@ -27760,13 +27721,11 @@ impl ReqStructure for TPM2_NV_WriteLock_REQUEST { /// The command will SET TPMA_NV_WRITELOCKED for all indexes that have their /// TPMA_NV_GLOBALLOCK attribute SET. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_NV_GlobalWriteLock_REQUEST { /// TPM_RH_OWNER or TPM_RH_PLATFORM+{PP} /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub authHandle: TPM_HANDLE, } @@ -27822,18 +27781,15 @@ impl ReqStructure for TPM2_NV_GlobalWriteLock_REQUEST { } /// This command reads a value from an area in NV memory previously defined by TPM2_NV_DefineSpace(). -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_NV_Read_REQUEST { /// The handle indicating the source of the authorization value /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub authHandle: TPM_HANDLE, /// The NV Index to be read /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub nvIndex: TPM_HANDLE, /// Number of octets to read @@ -27906,8 +27862,7 @@ impl ReqStructure for TPM2_NV_Read_REQUEST { } /// This command reads a value from an area in NV memory previously defined by TPM2_NV_DefineSpace(). -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct NV_ReadResponse { /// The data read pub data: Vec, @@ -27959,18 +27914,15 @@ impl RespStructure for NV_ReadResponse { /// If TPMA_NV_READ_STCLEAR is SET in an Index, then this command may be used to prevent /// further reads of the NV Index until the next TPM2_Startup (TPM_SU_CLEAR). -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_NV_ReadLock_REQUEST { /// The handle indicating the source of the authorization value /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub authHandle: TPM_HANDLE, /// The NV Index to be locked /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub nvIndex: TPM_HANDLE, } @@ -28028,13 +27980,11 @@ impl ReqStructure for TPM2_NV_ReadLock_REQUEST { } /// This command allows the authorization secret for an NV Index to be changed. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_NV_ChangeAuth_REQUEST { /// Handle of the entity /// Auth Index: 1 /// Auth Role: ADMIN - #[derivative(Default(value="TPM_HANDLE::default()"))] pub nvIndex: TPM_HANDLE, /// New authorization value @@ -28099,24 +28049,20 @@ impl ReqStructure for TPM2_NV_ChangeAuth_REQUEST { /// The purpose of this command is to certify the contents of an NV Index or portion of an /// NV Index. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_NV_Certify_REQUEST { /// Handle of the key used to sign the attestation structure /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub signHandle: TPM_HANDLE, /// Handle indicating the source of the authorization value for the NV Index /// Auth Index: 2 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub authHandle: TPM_HANDLE, /// Index for the area to be certified /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub nvIndex: TPM_HANDLE, /// User-provided qualifying data @@ -28215,8 +28161,7 @@ impl ReqStructure for TPM2_NV_Certify_REQUEST { /// The purpose of this command is to certify the contents of an NV Index or portion of an /// NV Index. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct NV_CertifyResponse { /// The structure that was signed pub certifyInfo: TPMS_ATTEST, @@ -28281,12 +28226,10 @@ impl RespStructure for NV_CertifyResponse { /// The purpose of this command is to obtain information about an Attached Component /// referenced by an AC handle. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_AC_GetCapability_REQUEST { /// Handle indicating the Attached Component /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub ac: TPM_HANDLE, /// Starting info type @@ -28357,8 +28300,7 @@ impl ReqStructure for TPM2_AC_GetCapability_REQUEST { /// The purpose of this command is to obtain information about an Attached Component /// referenced by an AC handle. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct AC_GetCapabilityResponse { /// Flag to indicate whether there are more values pub moreData: u8, @@ -28414,24 +28356,20 @@ impl RespStructure for AC_GetCapabilityResponse { /// The purpose of this command is to send (copy) a loaded object from the TPM to an /// Attached Component. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_AC_Send_REQUEST { /// Handle of the object being sent to ac /// Auth Index: 1 /// Auth Role: DUP - #[derivative(Default(value="TPM_HANDLE::default()"))] pub sendObject: TPM_HANDLE, /// The handle indicating the source of the authorization value /// Auth Index: 2 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub authHandle: TPM_HANDLE, /// Handle indicating the Attached Component to which the object will be sent /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub ac: TPM_HANDLE, /// Optional non sensitive information related to the object @@ -28500,8 +28438,7 @@ impl ReqStructure for TPM2_AC_Send_REQUEST { /// The purpose of this command is to send (copy) a loaded object from the TPM to an /// Attached Component. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct AC_SendResponse { /// May include AC specific data or information about an error. pub acDataOut: TPMS_AC_OUTPUT, @@ -28554,12 +28491,10 @@ impl RespStructure for AC_SendResponse { /// Component (AC). Qualification includes selection of the receiving AC and the method of /// authentication for the AC, and, in certain circumstances, the Object to be sent may be /// specified. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_Policy_AC_SendSelect_REQUEST { /// Handle for the policy session being extended /// Auth Index: None - #[derivative(Default(value="TPM_HANDLE::default()"))] pub policySession: TPM_HANDLE, /// The Name of the Object to be sent @@ -28645,13 +28580,11 @@ impl ReqStructure for TPM2_Policy_AC_SendSelect_REQUEST { /// This command is used to set the time remaining before an Authenticated Countdown Timer /// (ACT) expires. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_ACT_SetTimeout_REQUEST { /// Handle of the selected ACT /// Auth Index: 1 /// Auth Role: USER - #[derivative(Default(value="TPM_HANDLE::default()"))] pub actHandle: TPM_HANDLE, /// The start timeout value for the ACT in seconds @@ -28714,8 +28647,7 @@ impl ReqStructure for TPM2_ACT_SetTimeout_REQUEST { } /// This is a placeholder to allow testing of the dispatch code. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2_Vendor_TCG_Test_REQUEST { /// Dummy data pub inputData: Vec, @@ -28776,8 +28708,7 @@ impl ReqStructure for TPM2_Vendor_TCG_Test_REQUEST { } /// This is a placeholder to allow testing of the dispatch code. -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct Vendor_TCG_TestResponse { /// Dummy data pub outputData: Vec, @@ -28882,8 +28813,7 @@ pub type TPMS_SCHEME_KDF1_SP800_108 = TPMS_KDF_SCHEME_KDF1_SP800_108; /// Contains the public and the plaintext-sensitive and/or encrypted private part of a TPM /// key (or other object) -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TssObject { /// Public part of key pub Public: TPMT_PUBLIC, @@ -28946,8 +28876,7 @@ impl TpmMarshaller for TssObject { } /// Contains a PCR index and associated hash(pcr-value) [TSS] -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct PcrValue { /// PCR Index pub index: u32, @@ -29003,11 +28932,9 @@ impl TpmMarshaller for PcrValue { } /// Structure representing a session block in a command buffer [TSS] -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct SessionIn { /// Session handle - #[derivative(Default(value="TPM_HANDLE::default()"))] pub handle: TPM_HANDLE, /// Caller nonce @@ -29075,8 +29002,7 @@ impl TpmMarshaller for SessionIn { } /// Structure representing a session block in a response buffer [TSS] -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct SessionOut { /// TPM nonce pub nonceTpm: Vec, @@ -29139,8 +29065,7 @@ impl TpmMarshaller for SessionOut { } /// Command header [TSS] -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct CommandHeader { /// Command tag (sessions, or no sessions) pub Tag: TPM_ST, @@ -29207,8 +29132,7 @@ impl TpmMarshaller for CommandHeader { /// Holds secret material, so `Debug` is deliberately not derived here. The redacting /// implementation is hand-written in `src/tpm_type_extensions.rs`; omitting it is a compile /// error, enforced by the assertion at the end of this file. -#[derive(Clone, Derivative)] -#[derivative(Default)] +#[derive(Clone, Default)] pub struct TSS_KEY { /// Public part of key pub publicPart: TPMT_PUBLIC, @@ -29264,8 +29188,7 @@ impl TpmMarshaller for TSS_KEY { } /// Auto-derived from TPM2B_DIGEST to provide unique GetUnionSelector() implementation -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2B_DIGEST_SYMCIPHER { /// The buffer area that can be no larger than a digest pub buffer: Vec, @@ -29307,8 +29230,7 @@ impl TpmMarshaller for TPM2B_DIGEST_SYMCIPHER { } /// Auto-derived from TPM2B_DIGEST -#[derive(Debug, Clone, Derivative)] -#[derivative(Default)] +#[derive(Debug, Clone, Default)] pub struct TPM2B_DIGEST_KEYEDHASH { /// The buffer area that can be no larger than a digest pub buffer: Vec, diff --git a/TssCodeGen/src/CGenRust.cs b/TssCodeGen/src/CGenRust.cs index ea6d83c8..55c115a5 100644 --- a/TssCodeGen/src/CGenRust.cs +++ b/TssCodeGen/src/CGenRust.cs @@ -519,6 +519,16 @@ void GenStructDecl(TpmStruct s) return; } + // The members are collected before anything is written, because whether Default can be + // derived is decided in the derive list, above the members that decide it. + var members = CollectMembers(s); + var initializers = DefaultInitializers(members); + + // A struct all of whose members start out as Default::default() just derives Default. + // The rest get the hand-emitted implementation below. + bool deriveDefault = !initializers.Any(i => i.InitVal != null); + string defaultDerive = deriveDefault ? ", Default" : ""; + WriteComment(s); if (StructsWithHandWrittenDebug.Contains(structName)) { @@ -526,21 +536,23 @@ void GenStructDecl(TpmStruct s) Write("/// Holds secret material, so `Debug` is deliberately not derived here. The redacting"); Write("/// implementation is hand-written in `src/tpm_type_extensions.rs`; omitting it is a compile"); Write("/// error, enforced by the assertion at the end of this file."); - Write($"#[derive(Clone, Derivative)]"); + Write($"#[derive(Clone{defaultDerive})]"); } else { - Write($"#[derive(Debug, Clone, Derivative)]"); + Write($"#[derive(Debug, Clone{defaultDerive})]"); } - Write("#[derivative(Default)]"); Write($"pub struct {structName} {{"); TabIn(); - GenFields(s); + GenFields(members); TabOut("}"); Write(""); + if (!deriveDefault) + GenDefaultImpl(structName, initializers); + // Implement struct methods TabIn($"impl {structName} {{"); @@ -611,35 +623,128 @@ void GenConstructorFieldsDecl(TpmStruct s) { } // Generates the struct's fields, supporting "derived" structs by containing the same fields - void GenFields(TpmStruct s) { + void GenFields(List members) { + foreach (var m in members) + { + if (m.SnipType != null) + { + InsertSnip(m.SnipType); + continue; + } + + WriteComment(m.Field); + if (m.IsUnionSelector) + { + // Selectors are handled through methods in Rust + continue; + } + + Write($"pub {ToRustName(m.Field.Name)}: {TransType(m.Field)},"); + } + } + + // One item of a generated struct's body: either an AST field (possibly a union selector, + // for which only the comment is emitted), or the point at which a snips block is inserted. + // The struct declaration and its Default implementation are both driven off this one list, + // so the two cannot drift apart. + class StructMember + { + internal StructField Field; + internal bool IsUnionSelector; + // The expression this member's default value is; null means Default::default() + internal string InitVal; + internal string SnipType; + } + + // Collects the struct's members, supporting "derived" structs by containing the same fields + static List CollectMembers(TpmStruct s) + { + var members = new List(); + CollectMembers(s, members); + return members; + } + + static void CollectMembers(TpmStruct s, List members) + { var fieldsToInit = s.NonDefaultInitFields.Select(f => f.Name).ToHashSet(); if (s.DerivedFrom != null) { - GenFields(s.DerivedFrom); + CollectMembers(s.DerivedFrom, members); } - // Fields foreach (var f in s.NonSizeFields) { if (f.MarshalType == MarshalType.ConstantValue) // No member field for a constant tag continue; - WriteComment(f); - if (f.MarshalType == MarshalType.UnionSelector) + bool isUnionSelector = f.MarshalType == MarshalType.UnionSelector; + members.Add(new StructMember { + Field = f, + IsUnionSelector = isUnionSelector, + InitVal = !isUnionSelector && fieldsToInit.Contains(f.Name) + ? CustomInitVal(f) : null + }); + } + + members.Add(new StructMember { SnipType = s.Name }); + } + + // The field's initial value if it differs from the field type's own default, else null. + // + // The AST asks for a TPM_HANDLE field to start out as TPM_HANDLE::default(), which is what + // Default::default() produces for it anyway. Reporting no value for such a field lets its + // struct derive Default instead of spelling out an implementation that says nothing. + static string CustomInitVal(StructField f) + { + string initVal = f.GetInitVal(); + return initVal == $"{TransType(f)}::default()" ? null : initVal; + } + + // Matches a field declaration in a snips block. Such fields are absent from the AST, but + // present in the generated struct, so its Default implementation has to initialize them. + static readonly Regex SnipFieldRegex = new Regex(@"^\s*pub\s+(?[A-Za-z_]\w*)\s*:"); + + // The name and default value expression of every field the generated struct declares, + // in declaration order. + List<(string Name, string InitVal)> DefaultInitializers(List members) + { + var initializers = new List<(string, string)>(); + foreach (var m in members) + { + if (m.SnipType != null) { - // Selectors are handled through methods in Rust - continue; + foreach (var line in GetSnip(m.SnipType)) + { + var match = SnipFieldRegex.Match(line); + if (match.Success) + initializers.Add((match.Groups["name"].Value, null)); + } } - - if (fieldsToInit.Contains(f.Name)) + else if (!m.IsUnionSelector) { - Write($"#[derivative(Default(value=\"{f.GetInitVal()}\"))]"); + initializers.Add((ToRustName(m.Field.Name), m.InitVal)); } - Write($"pub {ToRustName(f.Name)}: {TransType(f)},"); } + return initializers; + } - InsertSnip(s.Name); + // Emits the Default implementation of a struct at least one of whose fields does not start + // out as Default::default(). Every field is listed, not just those with a value of their + // own, so that a field added later cannot silently acquire a default nobody chose for it: + // it either appears here or the struct expression does not compile. + void GenDefaultImpl(string structName, List<(string Name, string InitVal)> initializers) + { + TabIn($"impl Default for {structName} {{"); + TabIn("fn default() -> Self {"); + TabIn("Self {"); + + foreach (var (name, initVal) in initializers) + Write($"{name}: {initVal ?? "Default::default()"},"); + + TabOut("}", false); + TabOut("}", false); + TabOut("}"); } void GenTpmStructureImplementation(TpmStruct s) diff --git a/TssCodeGen/src/CodeGenBase.cs b/TssCodeGen/src/CodeGenBase.cs index c4227941..e8df8d4e 100644 --- a/TssCodeGen/src/CodeGenBase.cs +++ b/TssCodeGen/src/CodeGenBase.cs @@ -325,6 +325,14 @@ internal void LoadSnips(string snipsPath) AddSnip(curType, snipLines); } + /// The snippet lines inserted into the given type's definition, or an empty + /// sequence if the type has no snippet. + /// A generator needs to look at these when the code it emits elsewhere must + /// account for what the snippet declares. The Rust generator does: a struct's Default + /// implementation has to initialize the fields the snippet injects, too. + protected IEnumerable GetSnip(string typeName) + => Snips.TryGetValue(typeName, out var snip) ? snip : Enumerable.Empty(); + protected void InsertSnip(string typeName) { // Insert the custom snippets if there are any