From 06b8a230275ba29da915d6d820c00009ef49d183 Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Tue, 24 Mar 2026 23:11:21 +0000 Subject: [PATCH 1/6] Add High-Range Templates H-1 through H-7 This uses the clearer naming from: https://trustedcomputinggroup.org/resource/tcgek-credential-profile-for-tpm-family-2-0/ This change adds the `Template` type which defines: - a `PublicEK()` method to return a `TPMTPublic` EK Template - a `PublicSRK()` method to return a `TPMTPublic` SRK Template It also defines `AuthPolicy{A,B,C}()` and `AuthPolicyNVPublic()` to help users: - understand the different auth policies - assist in satisfying those policies Signed-off-by: Joe Richey --- tpm2/templates.go | 378 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 378 insertions(+) diff --git a/tpm2/templates.go b/tpm2/templates.go index a0cfa811..84efb424 100644 --- a/tpm2/templates.go +++ b/tpm2/templates.go @@ -1,5 +1,383 @@ package tpm2 +import ( + "bytes" + "encoding/hex" + "fmt" +) + +// Template enumerates the default Endorsement Key (EK) templates. +// +// These templates are defined in the EK Credential Profile: +// https://trustedcomputinggroup.org/resource/tcgek-credential-profile-for-tpm-family-2-0/, +// +// This includes +// - the "Low Range" templates: [TemplateL1] and [TemplateL2] +// - the "High Range" templates: [TemplateH1] to [TemplateH7] +type Template int32 + +const ( + _ = Template(iota) // Skip 0 to ensure [TemplateH1] starts at 1 + // Template H-1: RSA 2048 (Storage) + TemplateH1 + // Template H-2: ECC NIST P256 (Storage) + TemplateH2 + // Template H-3: ECC NIST P384 (Storage) + TemplateH3 + // Template H-4: ECC NIST P521 (Storage) + TemplateH4 + // Template H-5: ECC SM2 P256 (Storage) + TemplateH5 + // Template H-6: RSA 3072 (Storage) + TemplateH6 + // Template H-7: RSA 4096 (Storage) + TemplateH7 + highRangeLast = TemplateH7 + + // Template L-1: RSA 2048 (Storage) + TemplateL1 = Template(-1) + // Template L-2: ECC NIST P256 (Storage) + TemplateL2 = Template(-2) +) + +// IsLowRange returns true if this template is defined in the legacy "Low Range" +// rather than the "High Range". +// +// Low Range templates have a [TPMTPublic.AuthPolicy] of [AuthPolicyA], while +// High Range templates have a [TPMTPublic.AuthPolicy] of [AuthPolicyB]. +func (t Template) IsLowRange() bool { + return t == TemplateL1 || t == TemplateL2 +} + +func (t Template) String() string { + if t.IsLowRange() { + return fmt.Sprintf("TemplateL%d", -int32(t)) // -2 -> TemplateL2 + } else if t > 0 && t <= highRangeLast { + return fmt.Sprintf("TemplateH%d", int32(t)) // 2 -> TemplateH2 + } else { + return fmt.Sprintf("Template(%d)", int32(t)) // -27 -> Template(-27) + } +} + +var ( + aes128 = TPMTSymDefObject{ + Algorithm: TPMAlgAES, + KeyBits: NewTPMUSymKeyBits(TPMAlgAES, TPMKeyBits(128)), + Mode: NewTPMUSymMode(TPMAlgAES, TPMAlgCFB), + } + aes256 = TPMTSymDefObject{ + Algorithm: TPMAlgAES, + KeyBits: NewTPMUSymKeyBits(TPMAlgAES, TPMKeyBits(256)), + Mode: NewTPMUSymMode(TPMAlgAES, TPMAlgCFB), + } + sm4128 = TPMTSymDefObject{ + Algorithm: TPMAlgSM4, + KeyBits: NewTPMUSymKeyBits(TPMAlgSM4, TPMKeyBits(128)), + Mode: NewTPMUSymMode(TPMAlgSM4, TPMAlgCFB), + } +) + +func newRSA(bits TPMIRSAKeyBits, hashAlg TPMIAlgHash, sym TPMTSymDefObject) TPMTPublic { + return TPMTPublic{ + Type: TPMAlgRSA, + NameAlg: hashAlg, + Parameters: NewTPMUPublicParms(TPMAlgRSA, &TPMSRSAParms{ + Symmetric: sym, + KeyBits: bits, + }), + } +} + +func newECC(curve TPMIECCCurve, hashAlg TPMIAlgHash, sym TPMTSymDefObject) TPMTPublic { + return TPMTPublic{ + Type: TPMAlgECC, + NameAlg: hashAlg, + Parameters: NewTPMUPublicParms(TPMAlgECC, &TPMSECCParms{ + Symmetric: sym, + CurveID: curve, + }), + } +} + +// PublicEK returns a [TPMTPublic] for an Endorsement Key (EK). +// +// This template can then be used with [TPMRHEndorsement], [CreatePrimary], and +// [New2B] to create the EK: +// +// createEK := CreatePrimary{ +// PrimaryHandle: TPMRHEndorsement, +// InPublic: New2B(TemplateH3.PublicEK()), +// } +// rsp, err := createEK.Execute(tpm) +func (t Template) PublicEK() TPMTPublic { + var pub TPMTPublic + switch t { + case TemplateL1: + // Low Range RSA-2048 template has a non-empty Unique field. + pub = newRSA(2048, TPMAlgSHA256, aes128) + pub.Unique = NewTPMUPublicID(TPMAlgRSA, &TPM2BPublicKeyRSA{ + Buffer: make([]byte, 2048/8), + }) + case TemplateL2: + // Low Range ECC-P256 template has a non-empty Unique field. + pub = newECC(TPMECCNistP256, TPMAlgSHA256, aes128) + pub.Unique = NewTPMUPublicID(TPMAlgECC, &TPMSECCPoint{ + X: TPM2BECCParameter{Buffer: make([]byte, 256/8)}, + Y: TPM2BECCParameter{Buffer: make([]byte, 256/8)}, + }) + case TemplateH1: + pub = newRSA(2048, TPMAlgSHA256, aes128) // RSA-2048 + case TemplateH2: + pub = newECC(TPMECCNistP256, TPMAlgSHA256, aes128) // ECC-P256 + case TemplateH3: + pub = newECC(TPMECCNistP384, TPMAlgSHA384, aes256) // ECC-P384 + case TemplateH4: + pub = newECC(TPMECCNistP521, TPMAlgSHA512, aes256) // ECC-P521 + case TemplateH5: + pub = newECC(TPMECCSM2P256, TPMAlgSM3256, sm4128) // SM2-P256 + case TemplateH6: + pub = newRSA(3072, TPMAlgSHA384, aes256) // RSA-3072 + case TemplateH7: + pub = newRSA(4096, TPMAlgSHA384, aes256) // RSA-4096 + default: + panic(fmt.Sprintf("unhandled template: %v", t)) + } + + pub.ObjectAttributes = TPMAObject{ + FixedTPM: true, + STClear: false, + FixedParent: true, + SensitiveDataOrigin: true, + UserWithAuth: !t.IsLowRange(), // Set for High Range templates + AdminWithPolicy: true, + FirmwareLimited: false, + NoDA: false, + EncryptedDuplication: false, + Restricted: true, + Decrypt: true, + SignEncrypt: false, + X509Sign: false, + } + + var err error + if t.IsLowRange() { + pub.AuthPolicy, err = AuthPolicyA(pub.NameAlg) + } else { + pub.AuthPolicy, err = AuthPolicyB(pub.NameAlg) + } + if err != nil { + panic(err) + } + return pub +} + +// PublicSRK returns a modified [TPMTPublic] for a shared Storage Root Key (SRK). +// +// Specifically, this template is based on [Template.PublicEK] but with +// [TPMAObject.NoDA] set, and Enhanced Authorization disabled by: +// - clearing [TPMTPublic.AuthPolicy] +// - setting [TPMAObject.UserWithAuth] +// - clearing [TPMAObject.AdminWithPolicy] +// +// This modification is described in the official TPM 2.0 Provisioning Guidance: +// https://trustedcomputinggroup.org/resource/tcg-tpm-v2-0-provisioning-guidance/. +// +// This template can then be used with [TPMRHOwner], [CreatePrimary], and +// [New2B] to create the SRK: +// +// createSRK := CreatePrimary{ +// PrimaryHandle: TPMRHOwner, +// InPublic: New2B(TemplateH3.PublicSRK()), +// } +// rsp, err := createSRK.Execute(tpm) +func (t Template) PublicSRK() TPMTPublic { + pub := t.PublicEK() + pub.ObjectAttributes.UserWithAuth = true + pub.ObjectAttributes.AdminWithPolicy = false + pub.ObjectAttributes.NoDA = true + pub.AuthPolicy = TPM2BDigest{Buffer: nil} + return pub +} + +// Decodes the provided hex strings into a byte array. Panics on non-hex chars. +func hexToBytes(hexStrings ...string) []byte { + var buf []byte + for _, s := range hexStrings { + var err error + buf, err = hex.AppendDecode(buf, []byte(s)) + if err != nil { + panic(err) + } + } + return buf +} + +// Policy and NV Index constants from EK Credential Profile. +var ( + policyA = map[TPMIAlgHash][]byte{ + TPMAlgSHA256: hexToBytes( + "837197674484b3f81a90cc8d46a5d724", + "fd52d76e06520b64f2a1da1b331469aa", + ), + TPMAlgSHA384: hexToBytes( + "8bbf2266537c171cb56e403c4dc1d4b6", + "4f432611dc386e6f532050c3278c930e", + "143e8bb1133824ccb431053871c6db53", + ), + TPMAlgSHA512: hexToBytes( + "1e3b76502c8a1425aa0b7b3fc646a1b0", + "fae063b03b5368f9c4cddecaff0891dd", + "682bac1a85d4d832b781ea451915de5f", + "c5bf0dc4a1917cd42fa041e3f998e0ee", + ), + TPMAlgSM3256: hexToBytes( + "c67f7d35f66f3bec13c89fe898921c65", + "1b0cb5a38a92690a62a43c0012e4fb8b", + ), + } + policyB = map[TPMIAlgHash][]byte{ + TPMAlgSHA256: hexToBytes( + "ca3d0a99a2b93906f7a3342414efcfb3", + "a385d44cd1fd459089d19b5071c0b7a0", + ), + TPMAlgSHA384: hexToBytes( + "b26e7d28d11a50bc53d882bcf5fd3a1a", + "074148bb35d3b4e4cb1c0ad9bde419ca", + "cb47ba09699646150f9fc000f3f80e12", + ), + TPMAlgSHA512: hexToBytes( + "b8221ca69e8550a4914de3faa6a18c07", + "2cc01208073a928d5d66d59ef79e49a4", + "29c41a6b269571d57edb25fbdb183842", + "5608b413cd616a5f6db5b6071af99bea", + ), + TPMAlgSM3256: hexToBytes( + "167860a35f2c5c3567f9c927ac56c032", + "f3b3a6462f8d037998e7a10f77fa454a", + ), + } + policyC = map[TPMIAlgHash][]byte{ + TPMAlgSHA256: hexToBytes( + "3767e2edd43ff45a3a7e1eaefcef7864", + "3dca964632e7aad82c673a30d8633fde", + ), + TPMAlgSHA384: hexToBytes( + "d6032ce61f2fb3c240eb3cf6a33237ef", + "2b6a16f4293c22b455e261cffd217ad5", + "b4947c2d73e63005eed2dc2b3593d165", + ), + TPMAlgSHA512: hexToBytes( + "589ee1e146544716e8deafe6db247b01", + "b81e9f9c7dd16b814aa159138749105f", + "ba5388dd1dea702f35240c184933121e", + "2c61b8f50d3ef91393a49a38c3f73fc8", + ), + TPMAlgSM3256: hexToBytes( + "2d4e81578c3531d9bd1cdd7d02ba298d", + "5699a3e39fc3551bfeffcf132b49e11d", + ), + } + nvIndex = map[TPMIAlgHash]TPMIRHNVIndex{ + TPMAlgSHA256: 0x01c07f01, // Policy Index I-1 + TPMAlgSHA384: 0x01c07f02, // Policy Index I-2 + TPMAlgSHA512: 0x01c07f03, // Policy Index I-3 + TPMAlgSM3256: 0x01c07f04, // Policy Index I-4 + } +) + +// AuthPolicyA is a policy satisfied by proving knowledge of the Endorsement +// Hierarchy password. +// +// This is done by executing [PolicySecret] with [TPMRHEndorsement]. See the +// "Satisfying PolicyA" section of the EK Credential Profile for more info. +// +// This is the [TPMTPublic.AuthPolicy] for all Low Range templates. +func AuthPolicyA(hashAlg TPMIAlgHash) (TPM2BDigest, error) { + if policy, ok := policyA[hashAlg]; ok { + return TPM2BDigest{Buffer: bytes.Clone(policy)}, nil + } + return TPM2BDigest{}, fmt.Errorf("no PolicyA for hash alg 0x%x", hashAlg) +} + +// AuthPolicyB is a policy satisfied by satisfying [AuthPolicyA] or +// [AuthPolicyC]. +// +// This is done by: +// - First, satifying either of the two policies. +// - Then, executing [PolicyOr] with a digest list of {PolicyA, PolicyC}. +// +// See the "Satisfying PolicyB" section of the EK Credential Profile for more info. +// +// This is the [TPMTPublic.AuthPolicy] for all High Range templates. +func AuthPolicyB(hashAlg TPMIAlgHash) (TPM2BDigest, error) { + if policy, ok := policyB[hashAlg]; ok { + return TPM2BDigest{Buffer: bytes.Clone(policy)}, nil + } + return TPM2BDigest{}, fmt.Errorf("no PolicyB for hash alg 0x%x", hashAlg) +} + +// AuthPolicyC is a policy satisfied by satisfying the policy stored at +// [AuthPolicyNVPublic]. +// +// This is done by executing [PolicyAuthorizeNV] with the [TPMSNVPublic.NVIndex] +// of [AuthPolicyNVPublic]. +func AuthPolicyC(hashAlg TPMIAlgHash) (TPM2BDigest, error) { + if policy, ok := policyC[hashAlg]; ok { + return TPM2BDigest{Buffer: bytes.Clone(policy)}, nil + } + return TPM2BDigest{}, fmt.Errorf("no PolicyC for hash alg 0x%x", hashAlg) +} + +// AuthPolicyNVPublic is a [TPMSNVPublic] for the NV Index holding the +// [TPM2BDigest] for the policy needed to satisfy [AuthPolicyC]. +// +// The NV index containing the delegated policy must have this exact public +// information, or the call to [PolicyAuthorizeNV] for [AuthPolicyC] will not +// produce the correct policy digest. Note that the [TPMSNVPublic.AuthPolicy] +// is set to [AuthPolicyA], so knowledge of the Endorsement Hierarchy password +// is necessary to write or change this delegated policy. +func AuthPolicyNVPublic(hashAlg TPMIAlgHash) (TPMSNVPublic, error) { + idx, ok := nvIndex[hashAlg] + if !ok { + err := fmt.Errorf("no Policy NV Index for hash alg 0x%x", hashAlg) + return TPMSNVPublic{}, err + } + authPolicy, err := AuthPolicyA(hashAlg) + if err != nil { + return TPMSNVPublic{}, err + } + return TPMSNVPublic{ + NVIndex: idx, + NameAlg: hashAlg, + Attributes: TPMANV{ + PPWrite: false, + OwnerWrite: false, + AuthWrite: false, + PolicyWrite: true, + NT: TPMNT(0), + PolicyDelete: false, + WriteLocked: false, + WriteAll: true, + WriteDefine: false, + WriteSTClear: false, + GlobalLock: false, + PPRead: true, + OwnerRead: true, + AuthRead: true, + PolicyRead: true, + NoDA: true, + Orderly: false, + ClearSTClear: false, + ReadLocked: false, + Written: true, + PlatformCreate: false, + ReadSTClear: false, + }, + AuthPolicy: authPolicy, + DataSize: uint16(2 + len(authPolicy.Buffer)), + }, nil +} + var ( // RSASRKTemplate contains the TCG reference RSA-2048 SRK template. // https://trustedcomputinggroup.org/wp-content/uploads/TCG-TPM-v2.0-Provisioning-Guidance-Published-v1r1.pdf From 14b3173038baddd132c76ebd872d50ea3a9f8df9 Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Tue, 24 Mar 2026 23:13:48 +0000 Subject: [PATCH 2/6] Deprecate {RSA,ECC}{SRK,EK}Template global variables These variables can be inadvertantly modified by users, making their use error-prone. This change: - Marks them as deprecated - Implements them in terms of the non-deprecated API - Updates the tests and documentation to remove their usage Signed-off-by: Joe Richey --- tpm2/crypto_test.go | 2 +- tpm2/templates.go | 217 +++----------------------- tpm2/test/activate_credential_test.go | 20 +-- tpm2/test/clear_test.go | 2 +- tpm2/test/create_loaded_test.go | 6 +- tpm2/test/duplicate_test.go | 4 +- tpm2/test/ek_test.go | 10 +- tpm2/test/evict_control_test.go | 2 +- tpm2/test/hmac_test.go | 2 +- tpm2/test/import_test.go | 6 +- tpm2/test/names_test.go | 2 +- tpm2/test/object_change_auth_test.go | 2 +- tpm2/test/policy_test.go | 4 +- tpm2/test/read_public_test.go | 2 +- tpm2/test/rsa_encryption_test.go | 2 +- tpm2/test/sealing_test.go | 4 +- 16 files changed, 62 insertions(+), 225 deletions(-) diff --git a/tpm2/crypto_test.go b/tpm2/crypto_test.go index 6fef2e7c..ad8cf0ee 100644 --- a/tpm2/crypto_test.go +++ b/tpm2/crypto_test.go @@ -427,7 +427,7 @@ func TestRoundTrip(t *testing.T) { srkCreate, err := CreatePrimary{ PrimaryHandle: TPMRHOwner, - InPublic: New2B(ECCSRKTemplate), + InPublic: New2B(TemplateL2.PublicSRK()), }.Execute(tpm) if err != nil { t.Fatalf("could not create SRK: %v", err) diff --git a/tpm2/templates.go b/tpm2/templates.go index 84efb424..bf5b4255 100644 --- a/tpm2/templates.go +++ b/tpm2/templates.go @@ -378,201 +378,34 @@ func AuthPolicyNVPublic(hashAlg TPMIAlgHash) (TPMSNVPublic, error) { }, nil } +// Deprecated public global variables (not safe to mutate) var ( // RSASRKTemplate contains the TCG reference RSA-2048 SRK template. - // https://trustedcomputinggroup.org/wp-content/uploads/TCG-TPM-v2.0-Provisioning-Guidance-Published-v1r1.pdf - RSASRKTemplate = TPMTPublic{ - Type: TPMAlgRSA, - NameAlg: TPMAlgSHA256, - ObjectAttributes: TPMAObject{ - FixedTPM: true, - STClear: false, - FixedParent: true, - SensitiveDataOrigin: true, - UserWithAuth: true, - AdminWithPolicy: false, - NoDA: true, - EncryptedDuplication: false, - Restricted: true, - Decrypt: true, - SignEncrypt: false, - }, - Parameters: NewTPMUPublicParms( - TPMAlgRSA, - &TPMSRSAParms{ - Symmetric: TPMTSymDefObject{ - Algorithm: TPMAlgAES, - KeyBits: NewTPMUSymKeyBits( - TPMAlgAES, - TPMKeyBits(128), - ), - Mode: NewTPMUSymMode( - TPMAlgAES, - TPMAlgCFB, - ), - }, - KeyBits: 2048, - }, - ), - Unique: NewTPMUPublicID( - TPMAlgRSA, - &TPM2BPublicKeyRSA{ - Buffer: make([]byte, 256), - }, - ), - } + // + // Deprecated: use the [Template.PublicSRK] method of [TemplateL1] to + // create a new copy of this template, rather than accessing this variable. + // + // srkTemplate := TemplateL1.PublicSRK() + RSASRKTemplate = TemplateL1.PublicSRK() // RSAEKTemplate contains the TCG reference RSA-2048 EK template. - RSAEKTemplate = TPMTPublic{ - Type: TPMAlgRSA, - NameAlg: TPMAlgSHA256, - ObjectAttributes: TPMAObject{ - FixedTPM: true, - STClear: false, - FixedParent: true, - SensitiveDataOrigin: true, - UserWithAuth: false, - AdminWithPolicy: true, - NoDA: false, - EncryptedDuplication: false, - Restricted: true, - Decrypt: true, - SignEncrypt: false, - }, - AuthPolicy: TPM2BDigest{ - Buffer: []byte{ - // TPM2_PolicySecret(RH_ENDORSEMENT) - 0x83, 0x71, 0x97, 0x67, 0x44, 0x84, 0xB3, 0xF8, - 0x1A, 0x90, 0xCC, 0x8D, 0x46, 0xA5, 0xD7, 0x24, - 0xFD, 0x52, 0xD7, 0x6E, 0x06, 0x52, 0x0B, 0x64, - 0xF2, 0xA1, 0xDA, 0x1B, 0x33, 0x14, 0x69, 0xAA, - }, - }, - Parameters: NewTPMUPublicParms( - TPMAlgRSA, - &TPMSRSAParms{ - Symmetric: TPMTSymDefObject{ - Algorithm: TPMAlgAES, - KeyBits: NewTPMUSymKeyBits( - TPMAlgAES, - TPMKeyBits(128), - ), - Mode: NewTPMUSymMode( - TPMAlgAES, - TPMAlgCFB, - ), - }, - KeyBits: 2048, - }, - ), - Unique: NewTPMUPublicID( - TPMAlgRSA, - &TPM2BPublicKeyRSA{ - Buffer: make([]byte, 256), - }, - ), - } - + // + // Deprecated: use the [Template.PublicEK] method of [TemplateL1] to + // create a new copy of this template, rather than accessing this variable. + // + // ekTemplate := TemplateL1.PublicEK() + RSAEKTemplate = TemplateL1.PublicEK() // ECCSRKTemplate contains the TCG reference ECC-P256 SRK template. - // https://trustedcomputinggroup.org/wp-content/uploads/TCG-TPM-v2.0-Provisioning-Guidance-Published-v1r1.pdf - ECCSRKTemplate = TPMTPublic{ - Type: TPMAlgECC, - NameAlg: TPMAlgSHA256, - ObjectAttributes: TPMAObject{ - FixedTPM: true, - STClear: false, - FixedParent: true, - SensitiveDataOrigin: true, - UserWithAuth: true, - AdminWithPolicy: false, - NoDA: true, - EncryptedDuplication: false, - Restricted: true, - Decrypt: true, - SignEncrypt: false, - }, - Parameters: NewTPMUPublicParms( - TPMAlgECC, - &TPMSECCParms{ - Symmetric: TPMTSymDefObject{ - Algorithm: TPMAlgAES, - KeyBits: NewTPMUSymKeyBits( - TPMAlgAES, - TPMKeyBits(128), - ), - Mode: NewTPMUSymMode( - TPMAlgAES, - TPMAlgCFB, - ), - }, - CurveID: TPMECCNistP256, - }, - ), - Unique: NewTPMUPublicID( - TPMAlgECC, - &TPMSECCPoint{ - X: TPM2BECCParameter{ - Buffer: make([]byte, 32), - }, - Y: TPM2BECCParameter{ - Buffer: make([]byte, 32), - }, - }, - ), - } - + // + // Deprecated: use the [Template.PublicSRK] method of [TemplateL2] to + // create a new copy of this template, rather than accessing this variable. + // + // srkTemplate := TemplateL2.PublicSRK() + ECCSRKTemplate = TemplateL2.PublicSRK() // ECCEKTemplate contains the TCG reference ECC-P256 EK template. - ECCEKTemplate = TPMTPublic{ - Type: TPMAlgECC, - NameAlg: TPMAlgSHA256, - ObjectAttributes: TPMAObject{ - FixedTPM: true, - STClear: false, - FixedParent: true, - SensitiveDataOrigin: true, - UserWithAuth: false, - AdminWithPolicy: true, - NoDA: false, - EncryptedDuplication: false, - Restricted: true, - Decrypt: true, - SignEncrypt: false, - }, - AuthPolicy: TPM2BDigest{ - Buffer: []byte{ - // TPM2_PolicySecret(RH_ENDORSEMENT) - 0x83, 0x71, 0x97, 0x67, 0x44, 0x84, 0xB3, 0xF8, - 0x1A, 0x90, 0xCC, 0x8D, 0x46, 0xA5, 0xD7, 0x24, - 0xFD, 0x52, 0xD7, 0x6E, 0x06, 0x52, 0x0B, 0x64, - 0xF2, 0xA1, 0xDA, 0x1B, 0x33, 0x14, 0x69, 0xAA, - }, - }, - Parameters: NewTPMUPublicParms( - TPMAlgECC, - &TPMSECCParms{ - Symmetric: TPMTSymDefObject{ - Algorithm: TPMAlgAES, - KeyBits: NewTPMUSymKeyBits( - TPMAlgAES, - TPMKeyBits(128), - ), - Mode: NewTPMUSymMode( - TPMAlgAES, - TPMAlgCFB, - ), - }, - CurveID: TPMECCNistP256, - }, - ), - Unique: NewTPMUPublicID( - TPMAlgECC, - &TPMSECCPoint{ - X: TPM2BECCParameter{ - Buffer: make([]byte, 32), - }, - Y: TPM2BECCParameter{ - Buffer: make([]byte, 32), - }, - }, - ), - } + // + // Deprecated: use the [Template.PublicEK] method of [TemplateL2] to + // create a new copy of this template, rather than accessing this variable. + // + // ekTemplate := TemplateL2.PublicEK() + ECCEKTemplate = TemplateL2.PublicEK() ) diff --git a/tpm2/test/activate_credential_test.go b/tpm2/test/activate_credential_test.go index caed4d5f..da51837a 100644 --- a/tpm2/test/activate_credential_test.go +++ b/tpm2/test/activate_credential_test.go @@ -67,7 +67,7 @@ func TestActivateTPMCredential(t *testing.T) { ekCreate := CreatePrimary{ PrimaryHandle: TPMRHEndorsement, - InPublic: New2B(ECCEKTemplate), + InPublic: New2B(TemplateL2.PublicEK()), } ekCreateRsp, err := ekCreate.Execute(thetpm) @@ -86,7 +86,7 @@ func TestActivateTPMCredential(t *testing.T) { srkCreate := CreatePrimary{ PrimaryHandle: TPMRHOwner, - InPublic: New2B(ECCSRKTemplate), + InPublic: New2B(TemplateL2.PublicSRK()), } srkCreateRsp, err := srkCreate.Execute(thetpm) @@ -156,33 +156,33 @@ func TestActivateSWCredential(t *testing.T) { }{ { name: "ECDH-P256 SRK activating RSA SRK", - pubTemplate: ECCSRKTemplate, - subTemplate: RSASRKTemplate, + pubTemplate: TemplateL2.PublicSRK(), + subTemplate: TemplateL1.PublicSRK(), }, { name: "RSA-2048 SRK activating P256 SRK", - pubTemplate: RSASRKTemplate, - subTemplate: ECCSRKTemplate, + pubTemplate: TemplateL1.PublicSRK(), + subTemplate: TemplateL2.PublicSRK(), }, { name: "ECDH-P256 SRK activating P384 key", - pubTemplate: ECCSRKTemplate, + pubTemplate: TemplateL2.PublicSRK(), subTemplate: p384Template, }, { name: "RSA-2048 SRK activating P384 key", - pubTemplate: RSASRKTemplate, + pubTemplate: TemplateL1.PublicSRK(), subTemplate: p384Template, }, { name: "P384 key activating P256 SRK", pubTemplate: p384Template, - subTemplate: ECCSRKTemplate, + subTemplate: TemplateL2.PublicSRK(), }, { name: "P384 key activating RSA SRK", pubTemplate: p384Template, - subTemplate: RSASRKTemplate, + subTemplate: TemplateL1.PublicSRK(), }, } { t.Run(tc.name, func(t *testing.T) { diff --git a/tpm2/test/clear_test.go b/tpm2/test/clear_test.go index bdac11f5..9e4a5340 100644 --- a/tpm2/test/clear_test.go +++ b/tpm2/test/clear_test.go @@ -17,7 +17,7 @@ func TestClear(t *testing.T) { srkCreate := CreatePrimary{ PrimaryHandle: TPMRHOwner, - InPublic: New2B(ECCSRKTemplate), + InPublic: New2B(TemplateL2.PublicSRK()), } srkCreateRsp, err := srkCreate.Execute(thetpm) diff --git a/tpm2/test/create_loaded_test.go b/tpm2/test/create_loaded_test.go index fc7114f0..e3e4ecc2 100644 --- a/tpm2/test/create_loaded_test.go +++ b/tpm2/test/create_loaded_test.go @@ -69,14 +69,16 @@ func TestCreateLoaded(t *testing.T) { }, }) + ekTemplate := TemplateL2.PublicEK() + createLoadeds := map[string]*CreateLoaded{ "PrimaryKey": { ParentHandle: TPMRHEndorsement, - InPublic: New2BTemplate(&ECCEKTemplate), + InPublic: New2BTemplate(&ekTemplate), }, "NoParentPrimaryKey": { // Make the object in the null hierarchy and ensure that go-tpm supports not providing the parent handle at all. - InPublic: New2BTemplate(&ECCEKTemplate), + InPublic: New2BTemplate(&ekTemplate), }, "OrdinaryKey": { ParentHandle: TPMRHOwner, diff --git a/tpm2/test/duplicate_test.go b/tpm2/test/duplicate_test.go index 7d537056..99bc43b0 100644 --- a/tpm2/test/duplicate_test.go +++ b/tpm2/test/duplicate_test.go @@ -20,7 +20,7 @@ func TestDuplicate(t *testing.T) { t.Log("### Create Owner SRK") srkCreateResp, err := CreatePrimary{ PrimaryHandle: TPMRHOwner, - InPublic: New2B(ECCSRKTemplate), + InPublic: New2B(TemplateL2.PublicSRK()), }.Execute(thetpm) if err != nil { t.Fatalf("could not generate SRK: %v", err) @@ -85,7 +85,7 @@ func TestDuplicate(t *testing.T) { t.Log("### Create Endorsement SRK (New Parent)") srk2CreateResp, err := CreatePrimary{ PrimaryHandle: TPMRHEndorsement, - InPublic: New2B(ECCSRKTemplate), + InPublic: New2B(TemplateL2.PublicSRK()), }.Execute(thetpm) if err != nil { t.Fatalf("could not generate SRK: %v", err) diff --git a/tpm2/test/ek_test.go b/tpm2/test/ek_test.go index ea901bfa..bc5eb70a 100644 --- a/tpm2/test/ek_test.go +++ b/tpm2/test/ek_test.go @@ -231,8 +231,8 @@ func TestCalculatePolicyB(t *testing.T) { // Test creating a sealed data blob on the standard-template EK using its policy. func TestEKPolicy(t *testing.T) { templates := map[string]TPMTPublic{ - "RSA": RSAEKTemplate, - "ECC": ECCEKTemplate, + "RSA": TemplateL1.PublicEK(), + "ECC": TemplateL2.PublicEK(), } // Run the whole test for each of RSA and ECC EKs. @@ -257,8 +257,10 @@ func ekPolicy(t transport.TPM, handle TPMISHPolicy, nonceTPM TPM2BNonce) error { func ekTest(t *testing.T, ekTemplate TPMTPublic) { // Before using the EK, ensure it has the expected policy. policy := ekTemplate.AuthPolicy - expected := PolicyA[ekTemplate.NameAlg] - if !bytes.Equal(policy.Buffer, expected.Buffer) { + expected, err := AuthPolicyA(ekTemplate.NameAlg) + if err != nil { + t.Error(err) + } else if !bytes.Equal(policy.Buffer, expected.Buffer) { t.Errorf("AuthPolicy = %x,\nwant %x", policy.Buffer, expected.Buffer) } diff --git a/tpm2/test/evict_control_test.go b/tpm2/test/evict_control_test.go index fc84bb9f..c0014143 100644 --- a/tpm2/test/evict_control_test.go +++ b/tpm2/test/evict_control_test.go @@ -16,7 +16,7 @@ func TestEvictControl(t *testing.T) { srkCreate := CreatePrimary{ PrimaryHandle: TPMRHOwner, - InPublic: New2B(ECCSRKTemplate), + InPublic: New2B(TemplateL2.PublicSRK()), } srkCreateRsp, err := srkCreate.Execute(thetpm) diff --git a/tpm2/test/hmac_test.go b/tpm2/test/hmac_test.go index 41feb84b..966a6a45 100644 --- a/tpm2/test/hmac_test.go +++ b/tpm2/test/hmac_test.go @@ -100,7 +100,7 @@ func TestImportedHMACKey(t *testing.T) { // create primary key primaryKey, err := CreatePrimary{ PrimaryHandle: TPMRHOwner, - InPublic: New2B(RSASRKTemplate), + InPublic: New2B(TemplateL1.PublicSRK()), }.Execute(theTPM) if err != nil { diff --git a/tpm2/test/import_test.go b/tpm2/test/import_test.go index 5745f4fc..52502fbb 100644 --- a/tpm2/test/import_test.go +++ b/tpm2/test/import_test.go @@ -21,7 +21,7 @@ func TestCleartextImport(t *testing.T) { srkCreate := CreatePrimary{ PrimaryHandle: TPMRHOwner, - InPublic: New2B(ECCSRKTemplate), + InPublic: New2B(TemplateL2.PublicSRK()), } srkCreateRsp, err := srkCreate.Execute(thetpm) @@ -148,11 +148,11 @@ func TestSWDuplicateImport(t *testing.T) { }{ { name: "ECDH-P256", - pubTemplate: ECCSRKTemplate, + pubTemplate: TemplateL2.PublicSRK(), }, { name: "RSA-2048", - pubTemplate: RSASRKTemplate, + pubTemplate: TemplateL1.PublicSRK(), }, } { t.Run(tc.name, func(t *testing.T) { diff --git a/tpm2/test/names_test.go b/tpm2/test/names_test.go index 270396a6..8bf19feb 100644 --- a/tpm2/test/names_test.go +++ b/tpm2/test/names_test.go @@ -25,7 +25,7 @@ func TestObjectName(t *testing.T) { createPrimary := CreatePrimary{ PrimaryHandle: TPMRHEndorsement, - InPublic: New2B(ECCEKTemplate), + InPublic: New2B(TemplateL2.PublicEK()), } rsp, err := createPrimary.Execute(thetpm) if err != nil { diff --git a/tpm2/test/object_change_auth_test.go b/tpm2/test/object_change_auth_test.go index bd46dd95..2bea9a27 100644 --- a/tpm2/test/object_change_auth_test.go +++ b/tpm2/test/object_change_auth_test.go @@ -27,7 +27,7 @@ func TestObjectChangeAuth(t *testing.T) { }, }, }, - InPublic: New2B(ECCSRKTemplate), + InPublic: New2B(TemplateL2.PublicSRK()), } createSRKRsp, err := createSRKCmd.Execute(thetpm) if err != nil { diff --git a/tpm2/test/policy_test.go b/tpm2/test/policy_test.go index 81a90890..ef590d8e 100644 --- a/tpm2/test/policy_test.go +++ b/tpm2/test/policy_test.go @@ -166,7 +166,7 @@ func primaryRSASRK(t *testing.T, thetpm transport.TPM) (NamedHandle, func()) { t.Helper() createPrimary := CreatePrimary{ PrimaryHandle: TPMRHOwner, - InPublic: New2B(RSASRKTemplate), + InPublic: New2B(TemplateL1.PublicSRK()), } rsp, err := createPrimary.Execute(thetpm) if err != nil { @@ -191,7 +191,7 @@ func primaryRSAEK(t *testing.T, thetpm transport.TPM) (NamedHandle, func()) { t.Helper() createPrimary := CreatePrimary{ PrimaryHandle: TPMRHEndorsement, - InPublic: New2B(RSAEKTemplate), + InPublic: New2B(TemplateL1.PublicEK()), } rsp, err := createPrimary.Execute(thetpm) if err != nil { diff --git a/tpm2/test/read_public_test.go b/tpm2/test/read_public_test.go index 871b8fc5..06cdb80b 100644 --- a/tpm2/test/read_public_test.go +++ b/tpm2/test/read_public_test.go @@ -121,7 +121,7 @@ func TestReadPublicWithHMACSession(t *testing.T) { createPrimaryCmd := CreatePrimary{ PrimaryHandle: TPMRHOwner, - InPublic: New2B(ECCSRKTemplate), + InPublic: New2B(TemplateL2.PublicSRK()), } createRsp, err := createPrimaryCmd.Execute(thetpm) diff --git a/tpm2/test/rsa_encryption_test.go b/tpm2/test/rsa_encryption_test.go index 17011852..fcefaf75 100644 --- a/tpm2/test/rsa_encryption_test.go +++ b/tpm2/test/rsa_encryption_test.go @@ -21,7 +21,7 @@ func TestRSAEncryption(t *testing.T) { createPrimaryCmd := CreatePrimary{ PrimaryHandle: TPMRHOwner, - InPublic: New2B(RSASRKTemplate), + InPublic: New2B(TemplateL1.PublicSRK()), } createPrimaryRsp, err := createPrimaryCmd.Execute(theTpm) if err != nil { diff --git a/tpm2/test/sealing_test.go b/tpm2/test/sealing_test.go index 8f498f61..1960d586 100644 --- a/tpm2/test/sealing_test.go +++ b/tpm2/test/sealing_test.go @@ -12,8 +12,8 @@ import ( // Test creating and unsealing a sealed data blob with a password and HMAC. func TestUnseal(t *testing.T) { templates := map[string]TPMTPublic{ - "RSA": RSASRKTemplate, - "ECC": ECCSRKTemplate, + "RSA": TemplateL1.PublicSRK(), + "ECC": TemplateL2.PublicSRK(), } // Run the whole test for each of RSA and ECC SRKs. From ddbe3d3e6a2fa0e069e9024d3c62f1c59a864d0d Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Tue, 24 Mar 2026 23:25:52 +0000 Subject: [PATCH 3/6] Add binary templates for low range Generated via the following Go program (before any of the changes): ```go package main import ( "log" "os" "github.com/google/go-tpm/tpm2" ) var templates = map[string]tpm2.TPMTPublic{ "L1_EK.bin": tpm2.RSAEKTemplate, "L1_SRK.bin": tpm2.RSASRKTemplate, "L2_EK.bin": tpm2.ECCEKTemplate, "L2_SRK.bin": tpm2.ECCSRKTemplate, } func main() { for name, template := range templates { file, err := os.Create(name) if err != nil { log.Fatal(err) } defer file.Close() _, err = file.Write(tpm2.Marshal(template)) if err != nil { log.Fatal(err) } } } ``` Signed-off-by: Joe Richey --- tpm2/test/templates/L1_EK.bin | Bin 0 -> 314 bytes tpm2/test/templates/L1_SRK.bin | Bin 0 -> 282 bytes tpm2/test/templates/L2_EK.bin | Bin 0 -> 122 bytes tpm2/test/templates/L2_SRK.bin | Bin 0 -> 90 bytes tpm2/test/templates/templates.go | 30 ++++++++++++++++++++++++++++++ 5 files changed, 30 insertions(+) create mode 100644 tpm2/test/templates/L1_EK.bin create mode 100644 tpm2/test/templates/L1_SRK.bin create mode 100644 tpm2/test/templates/L2_EK.bin create mode 100644 tpm2/test/templates/L2_SRK.bin create mode 100644 tpm2/test/templates/templates.go diff --git a/tpm2/test/templates/L1_EK.bin b/tpm2/test/templates/L1_EK.bin new file mode 100644 index 0000000000000000000000000000000000000000..508267e0aeb05b7365ba38d7478704ebbf830748 GIT binary patch literal 314 zcmZQzWZ-6CX4u4_&|Ek@-KAyo52*=fdfk>@SNR)sJ&!GjJLS{DThhiNnX4Gs7#bLy P83Z^OK!6cUj${G=jS~@1 literal 0 HcmV?d00001 diff --git a/tpm2/test/templates/L1_SRK.bin b/tpm2/test/templates/L1_SRK.bin new file mode 100644 index 0000000000000000000000000000000000000000..0cdfb115f7f8a17e36db9e55088561d9bf062e24 GIT binary patch literal 282 icmZQzWZ-6CW+`G|U|?ftU~py--~cii7#P9iNG1S$(E(@x literal 0 HcmV?d00001 diff --git a/tpm2/test/templates/L2_EK.bin b/tpm2/test/templates/L2_EK.bin new file mode 100644 index 0000000000000000000000000000000000000000..0d02831498c19e1588f000f3bc8276c6bcc90868 GIT binary patch literal 122 zcmZQjX5eOEX4u4_&|Ek@-KAyo52*=fdfk>@SNR)sJ&!GjJLS{DThhiNnX4Gs7#bLy Q83cf;1sD_<2myjB0I)?7y8r+H literal 0 HcmV?d00001 diff --git a/tpm2/test/templates/L2_SRK.bin b/tpm2/test/templates/L2_SRK.bin new file mode 100644 index 0000000000000000000000000000000000000000..4b6b2c30eea7180d4013eb2982c762358f27e845 GIT binary patch literal 90 mcmZQjX5eOEW+`G|U|?ftU~py-U| Date: Tue, 24 Mar 2026 23:33:18 +0000 Subject: [PATCH 4/6] Remove TestCalculatePolicyIndexName test Will be incoperated into TestCalculatePolicyC Signed-off-by: Joe Richey --- tpm2/test/ek_test.go | 35 ----------------------------------- 1 file changed, 35 deletions(-) diff --git a/tpm2/test/ek_test.go b/tpm2/test/ek_test.go index bc5eb70a..c0dfb0b4 100644 --- a/tpm2/test/ek_test.go +++ b/tpm2/test/ek_test.go @@ -137,41 +137,6 @@ func TestCalculatePolicyA(t *testing.T) { } } -// Test our Name calculation for the Policy NV Index (part of PolicyC). -func TestCalculatePolicyIndexName(t *testing.T) { - for alg, name := range PolicyIndexName { - hash, err := alg.Hash() - if err != nil { - t.Fatalf("%v", err) - } - t.Run(hash.String(), func(t *testing.T) { - nvPub := TPMSNVPublic{ - NVIndex: PolicyIndex[alg], - NameAlg: alg, - Attributes: TPMANV{ - PolicyWrite: true, - WriteAll: true, - PPRead: true, - OwnerRead: true, - AuthRead: true, - PolicyRead: true, - NoDA: true, - Written: true, - }, - AuthPolicy: PolicyA[alg], - DataSize: uint16(hash.Size() + 2), - } - nvName, err := NVName(&nvPub) - if err != nil { - t.Fatalf("computing NV Name: %v", err) - } - if !bytes.Equal(nvName.Buffer, name.Buffer) { - t.Errorf("NVName = %x,\nwant %x", nvName.Buffer, name.Buffer) - } - }) - } -} - // Test that PolicyCalculator correctly computes PolicyC for all hashes. func TestCalculatePolicyC(t *testing.T) { for alg, policy := range PolicyC { From 5ff1d555c302d78a5644ba8d09cb649baff950a5 Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Tue, 24 Mar 2026 23:34:46 +0000 Subject: [PATCH 5/6] Remove binary constants from tests. We now just directly confirm that the PolicyCalculator computes the right policies. Signed-off-by: Joe Richey --- tpm2/test/ek_test.go | 183 +++++++++++++++---------------------------- 1 file changed, 64 insertions(+), 119 deletions(-) diff --git a/tpm2/test/ek_test.go b/tpm2/test/ek_test.go index c0dfb0b4..488e8254 100644 --- a/tpm2/test/ek_test.go +++ b/tpm2/test/ek_test.go @@ -2,7 +2,6 @@ package tpm2test import ( "bytes" - "encoding/hex" "errors" "testing" @@ -11,104 +10,14 @@ import ( "github.com/google/go-tpm/tpm2/transport/simulator" ) -// Decodes the provided hex strings into a byte array. Panics on non-hex chars. -func hexToBytes(hexStrings ...string) []byte { - buf, err := []byte{}, error(nil) - for _, s := range hexStrings { - buf, err = hex.AppendDecode(buf, []byte(s)) - if err != nil { - panic(err) - } - } - return buf +var testedHashAlgs = []TPMIAlgHash{ + TPMAlgSHA256, + TPMAlgSHA384, + TPMAlgSHA512, + // https://pkg.go.dev/crypto#Hash does not support SM3 + // TPMAlgSM3256, } -// Values for the various EK Policies and Templates specified in: -// TCG EK Credential Profile For TPM Family 2.0; Level 0, Version 2.7 -var ( - // PolicyA values from "Computing PolicyA" section - PolicyA = map[TPMIAlgHash]TPM2BDigest{ - TPMAlgSHA256: {Buffer: hexToBytes( - "837197674484b3f81a90cc8d46a5d724", - "fd52d76e06520b64f2a1da1b331469aa", - )}, - TPMAlgSHA384: {Buffer: hexToBytes( - "8bbf2266537c171cb56e403c4dc1d4b6", - "4f432611dc386e6f532050c3278c930e", - "143e8bb1133824ccb431053871c6db53", - )}, - TPMAlgSHA512: {Buffer: hexToBytes( - "1e3b76502c8a1425aa0b7b3fc646a1b0", - "fae063b03b5368f9c4cddecaff0891dd", - "682bac1a85d4d832b781ea451915de5f", - "c5bf0dc4a1917cd42fa041e3f998e0ee", - )}, - } - // Policy NV Indices from "Handle Values" section - PolicyIndex = map[TPMIAlgHash]TPMIRHNVIndex{ - TPMAlgSHA256: 0x01C07F01, - TPMAlgSHA384: 0x01C07F02, - TPMAlgSHA512: 0x01C07F03, - } - // Policy Index Names from "Computing Policy Index Names" section - PolicyIndexName = map[TPMIAlgHash]TPM2BName{ - TPMAlgSHA256: {Buffer: hexToBytes( - "000b", // TPM_ALG_SHA256 - "0c9d717e9c3fe69fda41769450bb1459", - "57f8b3610e084dbf65591a5d11ecd83f", - )}, - TPMAlgSHA384: {Buffer: hexToBytes( - "000c", // TPM_ALG_SHA384 - "db62fca346612c976732ff4e8621fb4e", - "858be82586486504f7d02e621f8d7d61", - "ae32cfc60c4d120609ed6768afcf090c", - )}, - TPMAlgSHA512: {Buffer: hexToBytes( - "000d", // TPM_ALG_SHA512 - "1c47c0bbcbd3cf7d7cae6987d31937c1", - "71015dde3b7f0d3c869bca1f7e8a223b", - "9acfadb49b7c9cf14d450f41e9327de3", - "4d9291eece2c58ab1dc10e9059cce560", - )}, - } - // PolicyC values from "Computing PolicyC" section - PolicyC = map[TPMIAlgHash]TPM2BDigest{ - TPMAlgSHA256: {Buffer: hexToBytes( - "3767e2edd43ff45a3a7e1eaefcef7864", - "3dca964632e7aad82c673a30d8633fde", - )}, - TPMAlgSHA384: {Buffer: hexToBytes( - "d6032ce61f2fb3c240eb3cf6a33237ef", - "2b6a16f4293c22b455e261cffd217ad5", - "b4947c2d73e63005eed2dc2b3593d165", - )}, - TPMAlgSHA512: {Buffer: hexToBytes( - "589ee1e146544716e8deafe6db247b01", - "b81e9f9c7dd16b814aa159138749105f", - "ba5388dd1dea702f35240c184933121e", - "2c61b8f50d3ef91393a49a38c3f73fc8", - )}, - } - // PolicyB values from "Computing PolicyB" section - PolicyB = map[TPMIAlgHash]TPM2BDigest{ - TPMAlgSHA256: {Buffer: hexToBytes( - "ca3d0a99a2b93906f7a3342414efcfb3", - "a385d44cd1fd459089d19b5071c0b7a0", - )}, - TPMAlgSHA384: {Buffer: hexToBytes( - "b26e7d28d11a50bc53d882bcf5fd3a1a", - "074148bb35d3b4e4cb1c0ad9bde419ca", - "cb47ba09699646150f9fc000f3f80e12", - )}, - TPMAlgSHA512: {Buffer: hexToBytes( - "b8221ca69e8550a4914de3faa6a18c07", - "2cc01208073a928d5d66d59ef79e49a4", - "29c41a6b269571d57edb25fbdb183842", - "5608b413cd616a5f6db5b6071af99bea", - )}, - } -) - // Test that PolicyCalculator correctly computes PolicyA for all hashes. func TestCalculatePolicyA(t *testing.T) { // PolicyA only makes use of TPM2_PolicySecret(TPM_RH_ENDORSEMENT). @@ -116,22 +25,27 @@ func TestCalculatePolicyA(t *testing.T) { AuthHandle: TPMRHEndorsement, } - for alg, policy := range PolicyA { + for _, alg := range testedHashAlgs { hash, err := alg.Hash() if err != nil { - t.Fatalf("%v", err) + t.Fatal(err) } t.Run(hash.String(), func(t *testing.T) { + policyA, err := AuthPolicyA(alg) + if err != nil { + t.Fatal(err) + } + pol, err := NewPolicyCalculator(alg) if err != nil { t.Fatalf("creating policy calculator: %v", err) } if err = policySecretCmd.Update(pol); err != nil { - t.Fatalf("error updating policy calculator: %v", err) + t.Fatalf("updating policy calculator: %v", err) } digest := pol.Hash().Digest - if !bytes.Equal(digest, policy.Buffer) { - t.Errorf("PolicyA = %x,\nwant %x", digest, policy.Buffer) + if !bytes.Equal(digest, policyA.Buffer) { + t.Errorf("PolicyA = %x,\nwant %x", digest, policyA.Buffer) } }) } @@ -139,29 +53,45 @@ func TestCalculatePolicyA(t *testing.T) { // Test that PolicyCalculator correctly computes PolicyC for all hashes. func TestCalculatePolicyC(t *testing.T) { - for alg, policy := range PolicyC { + for _, alg := range testedHashAlgs { hash, err := alg.Hash() if err != nil { - t.Fatalf("%v", err) + t.Fatal(err) } + t.Run(hash.String(), func(t *testing.T) { - pol, err := NewPolicyCalculator(alg) + policyC, err := AuthPolicyC(alg) if err != nil { - t.Fatalf("creating policy calculator: %v", err) + t.Fatal(err) + } + + nvPublic, err := AuthPolicyNVPublic(alg) + if err != nil { + t.Fatal(err) + } + nvName, err := NVName(&nvPublic) + if err != nil { + t.Fatalf("computing NV Name: %v", err) } + // PolicyC uses TPM2_PolicyAuthorizeNV(idx) to delegate policy. authNVCmd := PolicyAuthorizeNV{ NVIndex: NamedHandle{ - Handle: PolicyIndex[alg], - Name: PolicyIndexName[alg], + Handle: nvPublic.NVIndex, + Name: *nvName, }, } + + pol, err := NewPolicyCalculator(alg) + if err != nil { + t.Fatalf("creating policy calculator: %v", err) + } if err = authNVCmd.Update(pol); err != nil { - t.Fatalf("error updating policy calculator: %v", err) + t.Fatalf("updating policy calculator: %v", err) } digest := pol.Hash().Digest - if !bytes.Equal(digest, policy.Buffer) { - t.Errorf("PolicyC = %x,\nwant %x", digest, policy.Buffer) + if !bytes.Equal(digest, policyC.Buffer) { + t.Errorf("PolicyC = %x,\nwant %x", digest, policyC.Buffer) } }) } @@ -169,25 +99,40 @@ func TestCalculatePolicyC(t *testing.T) { // Test that PolicyCalculator correctly computes PolicyB for all hashes. func TestCalculatePolicyB(t *testing.T) { - for alg, policy := range PolicyB { + for _, alg := range testedHashAlgs { hash, err := alg.Hash() if err != nil { - t.Fatalf("%v", err) + t.Fatal(err) } + t.Run(hash.String(), func(t *testing.T) { - pol, err := NewPolicyCalculator(alg) + policyA, err := AuthPolicyA(alg) if err != nil { - t.Fatalf("creating policy calculator: %v", err) + t.Fatal(err) } + policyB, err := AuthPolicyB(alg) + if err != nil { + t.Fatal(err) + } + policyC, err := AuthPolicyC(alg) + if err != nil { + t.Fatal(err) + } + // PolicyB is just the TPM2_PolicyOR of PolicyA and PolicyC. - digests := []TPM2BDigest{PolicyA[alg], PolicyC[alg]} + digests := []TPM2BDigest{policyA, policyC} orCmd := PolicyOr{PHashList: TPMLDigest{Digests: digests}} + + pol, err := NewPolicyCalculator(alg) + if err != nil { + t.Fatalf("creating policy calculator: %v", err) + } if err = orCmd.Update(pol); err != nil { - t.Fatalf("error updating policy calculator: %v", err) + t.Fatalf("updating policy calculator: %v", err) } digest := pol.Hash().Digest - if !bytes.Equal(digest, policy.Buffer) { - t.Errorf("PolicyC = %x,\nwant %x", digest, policy.Buffer) + if !bytes.Equal(digest, policyB.Buffer) { + t.Errorf("PolicyB = %x,\nwant %x", digest, policyB.Buffer) } }) } From 0d84997ed81b693c06ab07f10e5903af751948a0 Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Tue, 24 Mar 2026 23:35:44 +0000 Subject: [PATCH 6/6] Add TestMarshalTemplates test This ensures we can marshall all the templates, and compares the low-range templates to previously marshalled ones. Signed-off-by: Joe Richey --- tpm2/test/ek_test.go | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/tpm2/test/ek_test.go b/tpm2/test/ek_test.go index 488e8254..57807f12 100644 --- a/tpm2/test/ek_test.go +++ b/tpm2/test/ek_test.go @@ -6,6 +6,7 @@ import ( "testing" . "github.com/google/go-tpm/tpm2" + "github.com/google/go-tpm/tpm2/test/templates" "github.com/google/go-tpm/tpm2/transport" "github.com/google/go-tpm/tpm2/transport/simulator" ) @@ -138,6 +139,41 @@ func TestCalculatePolicyB(t *testing.T) { } } +var testedTemplates = []Template{ + TemplateL1, + TemplateL2, + TemplateH1, + TemplateH2, + TemplateH3, + TemplateH4, + // TODO: Test H-5 once https://github.com/google/go-tpm/pull/426 is fixed. + // TemplateH5, + TemplateH6, + TemplateH7, +} + +// Test that EKs and SRKs marshal to their expected values +func TestMarshalTemplates(t *testing.T) { + for _, template := range testedTemplates { + t.Run(template.String(), func(t *testing.T) { + // Check marshaled EK against expected if we have one. + ekBytes := Marshal(template.PublicEK()) + if expected, ok := templates.EKBytes[template]; ok { + if !bytes.Equal(ekBytes, expected) { + t.Errorf("EK bytes mismatch\ngot: %x\nwant: %x", ekBytes, expected) + } + } + // Check marshaled SRK against expected if we have one. + srkBytes := Marshal(template.PublicSRK()) + if expected, ok := templates.SRKBytes[template]; ok { + if !bytes.Equal(srkBytes, expected) { + t.Errorf("SRK bytes mismatch\ngot: %x\nwant: %x", srkBytes, expected) + } + } + }) + } +} + // Test creating a sealed data blob on the standard-template EK using its policy. func TestEKPolicy(t *testing.T) { templates := map[string]TPMTPublic{