Add Nix flake for mciasctl and mciasgrpcctl

Vendor dependencies and expose control program binaries via
nix build. Uses nixpkgs-unstable for Go 1.26 support.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-25 21:01:21 -07:00
parent 35e96444aa
commit 115f23a3ea
2485 changed files with 6802335 additions and 0 deletions

202
vendor/github.com/google/go-tpm/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

35
vendor/github.com/google/go-tpm/legacy/tpm2/README.md generated vendored Normal file
View File

@@ -0,0 +1,35 @@
# TPM 2.0 client library
## Tests
This library contains unit tests in `github.com/google/go-tpm/tpm2`, which just
tests that various encoding and error checking functions work correctly. It also
contains more comprehensive integration tests in
`github.com/google/go-tpm/tpm2/test`, which run actual commands on a TPM.
By default, these integration tests are run against the
[`go-tpm-tools`](https://github.com/google/go-tpm-tools)
simulator, which is baesed on the
[Microsoft Reference TPM2 code](https://github.com/microsoft/ms-tpm-20-ref). To
run both the unit and integration tests, run (in this directory)
```bash
go test . ./test
```
These integration tests can also be run against a real TPM device. This is
slightly more complex as the tests often need to be built as a normal user and
then executed as root. For example,
```bash
# Build the test binary without running it
go test -c github.com/google/go-tpm/tpm2/test
# Execute the test binary as root
sudo ./test.test --tpm-path=/dev/tpmrm0
```
On Linux, The `--tpm-path` causes the integration tests to be run against a
real TPM located at that path (usually `/dev/tpmrm0` or `/dev/tpm0`). On Windows, the story is similar, execept that
the `--use-tbs` flag is used instead.
Tip: if your TPM host is remote and you don't want to install Go on it, this
same two-step process can be used. The test binary can be copied to a remote
host and run without extra installation (as the test binary has very few
*runtime* dependancies).

View File

@@ -0,0 +1,576 @@
// Copyright (c) 2018, Google LLC All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package tpm2
import (
"crypto"
"crypto/elliptic"
"fmt"
"strings"
// Register the relevant hash implementations to prevent a runtime failure.
_ "crypto/sha1"
_ "crypto/sha256"
_ "crypto/sha512"
"github.com/google/go-tpm/tpmutil"
)
var hashInfo = []struct {
alg Algorithm
hash crypto.Hash
}{
{AlgSHA1, crypto.SHA1},
{AlgSHA256, crypto.SHA256},
{AlgSHA384, crypto.SHA384},
{AlgSHA512, crypto.SHA512},
{AlgSHA3_256, crypto.SHA3_256},
{AlgSHA3_384, crypto.SHA3_384},
{AlgSHA3_512, crypto.SHA3_512},
}
// MAX_DIGEST_BUFFER is the maximum size of []byte request or response fields.
// Typically used for chunking of big blobs of data (such as for hashing or
// encryption).
const maxDigestBuffer = 1024
// Algorithm represents a TPM_ALG_ID value.
type Algorithm uint16
// HashToAlgorithm looks up the TPM2 algorithm corresponding to the provided crypto.Hash
func HashToAlgorithm(hash crypto.Hash) (Algorithm, error) {
for _, info := range hashInfo {
if info.hash == hash {
return info.alg, nil
}
}
return AlgUnknown, fmt.Errorf("go hash algorithm #%d has no TPM2 algorithm", hash)
}
// IsNull returns true if a is AlgNull or zero (unset).
func (a Algorithm) IsNull() bool {
return a == AlgNull || a == AlgUnknown
}
// UsesCount returns true if a signature algorithm uses count value.
func (a Algorithm) UsesCount() bool {
return a == AlgECDAA
}
// UsesHash returns true if the algorithm requires the use of a hash.
func (a Algorithm) UsesHash() bool {
return a == AlgOAEP
}
// Hash returns a crypto.Hash based on the given TPM_ALG_ID.
// An error is returned if the given algorithm is not a hash algorithm or is not available.
func (a Algorithm) Hash() (crypto.Hash, error) {
for _, info := range hashInfo {
if info.alg == a {
if !info.hash.Available() {
return crypto.Hash(0), fmt.Errorf("go hash algorithm #%d not available", info.hash)
}
return info.hash, nil
}
}
return crypto.Hash(0), fmt.Errorf("hash algorithm not supported: 0x%x", a)
}
func (a Algorithm) String() string {
var s strings.Builder
var err error
switch a {
case AlgUnknown:
_, err = s.WriteString("AlgUnknown")
case AlgRSA:
_, err = s.WriteString("RSA")
case AlgSHA1:
_, err = s.WriteString("SHA1")
case AlgHMAC:
_, err = s.WriteString("HMAC")
case AlgAES:
_, err = s.WriteString("AES")
case AlgKeyedHash:
_, err = s.WriteString("KeyedHash")
case AlgXOR:
_, err = s.WriteString("XOR")
case AlgSHA256:
_, err = s.WriteString("SHA256")
case AlgSHA384:
_, err = s.WriteString("SHA384")
case AlgSHA512:
_, err = s.WriteString("SHA512")
case AlgNull:
_, err = s.WriteString("AlgNull")
case AlgRSASSA:
_, err = s.WriteString("RSASSA")
case AlgRSAES:
_, err = s.WriteString("RSAES")
case AlgRSAPSS:
_, err = s.WriteString("RSAPSS")
case AlgOAEP:
_, err = s.WriteString("OAEP")
case AlgECDSA:
_, err = s.WriteString("ECDSA")
case AlgECDH:
_, err = s.WriteString("ECDH")
case AlgECDAA:
_, err = s.WriteString("ECDAA")
case AlgKDF2:
_, err = s.WriteString("KDF2")
case AlgECC:
_, err = s.WriteString("ECC")
case AlgSymCipher:
_, err = s.WriteString("SymCipher")
case AlgSHA3_256:
_, err = s.WriteString("SHA3_256")
case AlgSHA3_384:
_, err = s.WriteString("SHA3_384")
case AlgSHA3_512:
_, err = s.WriteString("SHA3_512")
case AlgCTR:
_, err = s.WriteString("CTR")
case AlgOFB:
_, err = s.WriteString("OFB")
case AlgCBC:
_, err = s.WriteString("CBC")
case AlgCFB:
_, err = s.WriteString("CFB")
case AlgECB:
_, err = s.WriteString("ECB")
default:
return fmt.Sprintf("Alg?<%d>", int(a))
}
if err != nil {
return fmt.Sprintf("Writing to string builder failed: %v", err)
}
return s.String()
}
// Supported Algorithms.
const (
AlgUnknown Algorithm = 0x0000
AlgRSA Algorithm = 0x0001
AlgSHA1 Algorithm = 0x0004
AlgHMAC Algorithm = 0x0005
AlgAES Algorithm = 0x0006
AlgKeyedHash Algorithm = 0x0008
AlgXOR Algorithm = 0x000A
AlgSHA256 Algorithm = 0x000B
AlgSHA384 Algorithm = 0x000C
AlgSHA512 Algorithm = 0x000D
AlgNull Algorithm = 0x0010
AlgRSASSA Algorithm = 0x0014
AlgRSAES Algorithm = 0x0015
AlgRSAPSS Algorithm = 0x0016
AlgOAEP Algorithm = 0x0017
AlgECDSA Algorithm = 0x0018
AlgECDH Algorithm = 0x0019
AlgECDAA Algorithm = 0x001A
AlgKDF2 Algorithm = 0x0021
AlgECC Algorithm = 0x0023
AlgSymCipher Algorithm = 0x0025
AlgSHA3_256 Algorithm = 0x0027
AlgSHA3_384 Algorithm = 0x0028
AlgSHA3_512 Algorithm = 0x0029
AlgCTR Algorithm = 0x0040
AlgOFB Algorithm = 0x0041
AlgCBC Algorithm = 0x0042
AlgCFB Algorithm = 0x0043
AlgECB Algorithm = 0x0044
)
// HandleType defines a type of handle.
type HandleType uint8
// Supported handle types
const (
HandleTypePCR HandleType = 0x00
HandleTypeNVIndex HandleType = 0x01
HandleTypeHMACSession HandleType = 0x02
HandleTypeLoadedSession HandleType = 0x02
HandleTypePolicySession HandleType = 0x03
HandleTypeSavedSession HandleType = 0x03
HandleTypePermanent HandleType = 0x40
HandleTypeTransient HandleType = 0x80
HandleTypePersistent HandleType = 0x81
)
// SessionType defines the type of session created in StartAuthSession.
type SessionType uint8
// Supported session types.
const (
SessionHMAC SessionType = 0x00
SessionPolicy SessionType = 0x01
SessionTrial SessionType = 0x03
)
// SessionAttributes represents an attribute of a session.
type SessionAttributes byte
// Session Attributes (Structures 8.4 TPMA_SESSION)
const (
AttrContinueSession SessionAttributes = 1 << iota
AttrAuditExclusive
AttrAuditReset
_ // bit 3 reserved
_ // bit 4 reserved
AttrDecrypt
AttrEcrypt
AttrAudit
)
// EmptyAuth represents the empty authorization value.
var EmptyAuth []byte
// KeyProp is a bitmask used in Attributes field of key templates. Individual
// flags should be OR-ed to form a full mask.
type KeyProp uint32
// Key properties.
const (
FlagFixedTPM KeyProp = 0x00000002
FlagStClear KeyProp = 0x00000004
FlagFixedParent KeyProp = 0x00000010
FlagSensitiveDataOrigin KeyProp = 0x00000020
FlagUserWithAuth KeyProp = 0x00000040
FlagAdminWithPolicy KeyProp = 0x00000080
FlagNoDA KeyProp = 0x00000400
FlagRestricted KeyProp = 0x00010000
FlagDecrypt KeyProp = 0x00020000
FlagSign KeyProp = 0x00040000
FlagSealDefault = FlagFixedTPM | FlagFixedParent
FlagSignerDefault = FlagSign | FlagRestricted | FlagFixedTPM |
FlagFixedParent | FlagSensitiveDataOrigin | FlagUserWithAuth
FlagStorageDefault = FlagDecrypt | FlagRestricted | FlagFixedTPM |
FlagFixedParent | FlagSensitiveDataOrigin | FlagUserWithAuth
)
// TPMProp represents a Property Tag (TPM_PT) used with calls to GetCapability(CapabilityTPMProperties).
type TPMProp uint32
// TPM Capability Properties, see TPM 2.0 Spec, Rev 1.38, Table 23.
// Fixed TPM Properties (PT_FIXED)
const (
FamilyIndicator TPMProp = 0x100 + iota
SpecLevel
SpecRevision
SpecDayOfYear
SpecYear
Manufacturer
VendorString1
VendorString2
VendorString3
VendorString4
VendorTPMType
FirmwareVersion1
FirmwareVersion2
InputMaxBufferSize
TransientObjectsMin
PersistentObjectsMin
LoadedObjectsMin
ActiveSessionsMax
PCRCount
PCRSelectMin
ContextGapMax
_ // (PT_FIXED + 21) is skipped
NVCountersMax
NVIndexMax
MemoryMethod
ClockUpdate
ContextHash
ContextSym
ContextSymSize
OrderlyCount
CommandMaxSize
ResponseMaxSize
DigestMaxSize
ObjectContextMaxSize
SessionContextMaxSize
PSFamilyIndicator
PSSpecLevel
PSSpecRevision
PSSpecDayOfYear
PSSpecYear
SplitSigningMax
TotalCommands
LibraryCommands
VendorCommands
NVMaxBufferSize
TPMModes
CapabilityMaxBufferSize
)
// Variable TPM Properties (PT_VAR)
const (
TPMAPermanent TPMProp = 0x200 + iota
TPMAStartupClear
HRNVIndex
HRLoaded
HRLoadedAvail
HRActive
HRActiveAvail
HRTransientAvail
CurrentPersistent
AvailPersistent
NVCounters
NVCountersAvail
AlgorithmSet
LoadedCurves
LockoutCounter
MaxAuthFail
LockoutInterval
LockoutRecovery
NVWriteRecovery
AuditCounter0
AuditCounter1
)
// Allowed ranges of different kinds of Handles (TPM_HANDLE)
// These constants have type TPMProp for backwards compatibility.
const (
PCRFirst TPMProp = 0x00000000
HMACSessionFirst TPMProp = 0x02000000
LoadedSessionFirst TPMProp = 0x02000000
PolicySessionFirst TPMProp = 0x03000000
ActiveSessionFirst TPMProp = 0x03000000
TransientFirst TPMProp = 0x80000000
PersistentFirst TPMProp = 0x81000000
PersistentLast TPMProp = 0x81FFFFFF
PlatformPersistent TPMProp = 0x81800000
NVIndexFirst TPMProp = 0x01000000
NVIndexLast TPMProp = 0x01FFFFFF
PermanentFirst TPMProp = 0x40000000
PermanentLast TPMProp = 0x4000010F
)
// Reserved Handles.
const (
HandleOwner tpmutil.Handle = 0x40000001 + iota
HandleRevoke
HandleTransport
HandleOperator
HandleAdmin
HandleEK
HandleNull
HandleUnassigned
HandlePasswordSession
HandleLockout
HandleEndorsement
HandlePlatform
)
// Capability identifies some TPM property or state type.
type Capability uint32
// TPM Capabilities.
const (
CapabilityAlgs Capability = iota
CapabilityHandles
CapabilityCommands
CapabilityPPCommands
CapabilityAuditCommands
CapabilityPCRs
CapabilityTPMProperties
CapabilityPCRProperties
CapabilityECCCurves
CapabilityAuthPolicies
)
// TPM Structure Tags. Tags are used to disambiguate structures, similar to Alg
// values: tag value defines what kind of data lives in a nested field.
const (
TagNull tpmutil.Tag = 0x8000
TagNoSessions tpmutil.Tag = 0x8001
TagSessions tpmutil.Tag = 0x8002
TagAttestCertify tpmutil.Tag = 0x8017
TagAttestQuote tpmutil.Tag = 0x8018
TagAttestCreation tpmutil.Tag = 0x801a
TagAuthSecret tpmutil.Tag = 0x8023
TagHashCheck tpmutil.Tag = 0x8024
TagAuthSigned tpmutil.Tag = 0x8025
)
// StartupType instructs the TPM on how to handle its state during Shutdown or
// Startup.
type StartupType uint16
// Startup types
const (
StartupClear StartupType = iota
StartupState
)
// EllipticCurve identifies specific EC curves.
type EllipticCurve uint16
// ECC curves supported by TPM 2.0 spec.
const (
CurveNISTP192 = EllipticCurve(iota + 1)
CurveNISTP224
CurveNISTP256
CurveNISTP384
CurveNISTP521
CurveBNP256 = EllipticCurve(iota + 10)
CurveBNP638
CurveSM2P256 = EllipticCurve(0x0020)
)
var toGoCurve = map[EllipticCurve]elliptic.Curve{
CurveNISTP224: elliptic.P224(),
CurveNISTP256: elliptic.P256(),
CurveNISTP384: elliptic.P384(),
CurveNISTP521: elliptic.P521(),
}
// Supported TPM operations.
const (
CmdNVUndefineSpaceSpecial tpmutil.Command = 0x0000011F
CmdEvictControl tpmutil.Command = 0x00000120
CmdUndefineSpace tpmutil.Command = 0x00000122
CmdClear tpmutil.Command = 0x00000126
CmdHierarchyChangeAuth tpmutil.Command = 0x00000129
CmdDefineSpace tpmutil.Command = 0x0000012A
CmdPCRAllocate tpmutil.Command = 0x0000012B
CmdCreatePrimary tpmutil.Command = 0x00000131
CmdIncrementNVCounter tpmutil.Command = 0x00000134
CmdWriteNV tpmutil.Command = 0x00000137
CmdWriteLockNV tpmutil.Command = 0x00000138
CmdDictionaryAttackLockReset tpmutil.Command = 0x00000139
CmdDictionaryAttackParameters tpmutil.Command = 0x0000013A
CmdPCREvent tpmutil.Command = 0x0000013C
CmdPCRReset tpmutil.Command = 0x0000013D
CmdSequenceComplete tpmutil.Command = 0x0000013E
CmdStartup tpmutil.Command = 0x00000144
CmdShutdown tpmutil.Command = 0x00000145
CmdActivateCredential tpmutil.Command = 0x00000147
CmdCertify tpmutil.Command = 0x00000148
CmdCertifyCreation tpmutil.Command = 0x0000014A
CmdReadNV tpmutil.Command = 0x0000014E
CmdReadLockNV tpmutil.Command = 0x0000014F
CmdPolicySecret tpmutil.Command = 0x00000151
CmdCreate tpmutil.Command = 0x00000153
CmdECDHZGen tpmutil.Command = 0x00000154
CmdImport tpmutil.Command = 0x00000156
CmdLoad tpmutil.Command = 0x00000157
CmdQuote tpmutil.Command = 0x00000158
CmdRSADecrypt tpmutil.Command = 0x00000159
CmdSequenceUpdate tpmutil.Command = 0x0000015C
CmdSign tpmutil.Command = 0x0000015D
CmdUnseal tpmutil.Command = 0x0000015E
CmdPolicySigned tpmutil.Command = 0x00000160
CmdContextLoad tpmutil.Command = 0x00000161
CmdContextSave tpmutil.Command = 0x00000162
CmdECDHKeyGen tpmutil.Command = 0x00000163
CmdEncryptDecrypt tpmutil.Command = 0x00000164
CmdFlushContext tpmutil.Command = 0x00000165
CmdLoadExternal tpmutil.Command = 0x00000167
CmdMakeCredential tpmutil.Command = 0x00000168
CmdReadPublicNV tpmutil.Command = 0x00000169
CmdPolicyCommandCode tpmutil.Command = 0x0000016C
CmdPolicyOr tpmutil.Command = 0x00000171
CmdReadPublic tpmutil.Command = 0x00000173
CmdRSAEncrypt tpmutil.Command = 0x00000174
CmdStartAuthSession tpmutil.Command = 0x00000176
CmdGetCapability tpmutil.Command = 0x0000017A
CmdGetRandom tpmutil.Command = 0x0000017B
CmdHash tpmutil.Command = 0x0000017D
CmdPCRRead tpmutil.Command = 0x0000017E
CmdPolicyPCR tpmutil.Command = 0x0000017F
CmdReadClock tpmutil.Command = 0x00000181
CmdPCRExtend tpmutil.Command = 0x00000182
CmdEventSequenceComplete tpmutil.Command = 0x00000185
CmdHashSequenceStart tpmutil.Command = 0x00000186
CmdPolicyGetDigest tpmutil.Command = 0x00000189
CmdPolicyPassword tpmutil.Command = 0x0000018C
CmdEncryptDecrypt2 tpmutil.Command = 0x00000193
)
// Regular TPM 2.0 devices use 24-bit mask (3 bytes) for PCR selection.
const sizeOfPCRSelect = 3
const defaultRSAExponent = 1<<16 + 1
// NVAttr is a bitmask used in Attributes field of NV indexes. Individual
// flags should be OR-ed to form a full mask.
type NVAttr uint32
// NV Attributes
const (
AttrPPWrite NVAttr = 0x00000001
AttrOwnerWrite NVAttr = 0x00000002
AttrAuthWrite NVAttr = 0x00000004
AttrPolicyWrite NVAttr = 0x00000008
AttrPolicyDelete NVAttr = 0x00000400
AttrWriteLocked NVAttr = 0x00000800
AttrWriteAll NVAttr = 0x00001000
AttrWriteDefine NVAttr = 0x00002000
AttrWriteSTClear NVAttr = 0x00004000
AttrGlobalLock NVAttr = 0x00008000
AttrPPRead NVAttr = 0x00010000
AttrOwnerRead NVAttr = 0x00020000
AttrAuthRead NVAttr = 0x00040000
AttrPolicyRead NVAttr = 0x00080000
AttrNoDA NVAttr = 0x02000000
AttrOrderly NVAttr = 0x04000000
AttrClearSTClear NVAttr = 0x08000000
AttrReadLocked NVAttr = 0x10000000
AttrWritten NVAttr = 0x20000000
AttrPlatformCreate NVAttr = 0x40000000
AttrReadSTClear NVAttr = 0x80000000
)
var permMap = map[NVAttr]string{
AttrPPWrite: "PPWrite",
AttrOwnerWrite: "OwnerWrite",
AttrAuthWrite: "AuthWrite",
AttrPolicyWrite: "PolicyWrite",
AttrPolicyDelete: "PolicyDelete",
AttrWriteLocked: "WriteLocked",
AttrWriteAll: "WriteAll",
AttrWriteDefine: "WriteDefine",
AttrWriteSTClear: "WriteSTClear",
AttrGlobalLock: "GlobalLock",
AttrPPRead: "PPRead",
AttrOwnerRead: "OwnerRead",
AttrAuthRead: "AuthRead",
AttrPolicyRead: "PolicyRead",
AttrNoDA: "No Do",
AttrOrderly: "Oderly",
AttrClearSTClear: "ClearSTClear",
AttrReadLocked: "ReadLocked",
AttrWritten: "Writte",
AttrPlatformCreate: "PlatformCreate",
AttrReadSTClear: "ReadSTClear",
}
// String returns a textual representation of the set of NVAttr
func (p NVAttr) String() string {
var retString strings.Builder
for iterator, item := range permMap {
if (p & iterator) != 0 {
retString.WriteString(item + " + ")
}
}
if retString.String() == "" {
return "Permission/s not found"
}
return strings.TrimSuffix(retString.String(), " + ")
}

362
vendor/github.com/google/go-tpm/legacy/tpm2/error.go generated vendored Normal file
View File

@@ -0,0 +1,362 @@
package tpm2
import (
"fmt"
"github.com/google/go-tpm/tpmutil"
)
type (
// RCFmt0 holds Format 0 error codes
RCFmt0 uint8
// RCFmt1 holds Format 1 error codes
RCFmt1 uint8
// RCWarn holds error codes used in warnings
RCWarn uint8
// RCIndex is used to reference arguments, handles and sessions in errors
RCIndex uint8
)
// Format 0 error codes.
const (
RCInitialize RCFmt0 = 0x00
RCFailure RCFmt0 = 0x01
RCSequence RCFmt0 = 0x03
RCPrivate RCFmt0 = 0x0B
RCHMAC RCFmt0 = 0x19
RCDisabled RCFmt0 = 0x20
RCExclusive RCFmt0 = 0x21
RCAuthType RCFmt0 = 0x24
RCAuthMissing RCFmt0 = 0x25
RCPolicy RCFmt0 = 0x26
RCPCR RCFmt0 = 0x27
RCPCRChanged RCFmt0 = 0x28
RCUpgrade RCFmt0 = 0x2D
RCTooManyContexts RCFmt0 = 0x2E
RCAuthUnavailable RCFmt0 = 0x2F
RCReboot RCFmt0 = 0x30
RCUnbalanced RCFmt0 = 0x31
RCCommandSize RCFmt0 = 0x42
RCCommandCode RCFmt0 = 0x43
RCAuthSize RCFmt0 = 0x44
RCAuthContext RCFmt0 = 0x45
RCNVRange RCFmt0 = 0x46
RCNVSize RCFmt0 = 0x47
RCNVLocked RCFmt0 = 0x48
RCNVAuthorization RCFmt0 = 0x49
RCNVUninitialized RCFmt0 = 0x4A
RCNVSpace RCFmt0 = 0x4B
RCNVDefined RCFmt0 = 0x4C
RCBadContext RCFmt0 = 0x50
RCCPHash RCFmt0 = 0x51
RCParent RCFmt0 = 0x52
RCNeedsTest RCFmt0 = 0x53
RCNoResult RCFmt0 = 0x54
RCSensitive RCFmt0 = 0x55
)
var fmt0Msg = map[RCFmt0]string{
RCInitialize: "TPM not initialized by TPM2_Startup or already initialized",
RCFailure: "commands not being accepted because of a TPM failure",
RCSequence: "improper use of a sequence handle",
RCPrivate: "not currently used",
RCHMAC: "not currently used",
RCDisabled: "the command is disabled",
RCExclusive: "command failed because audit sequence required exclusivity",
RCAuthType: "authorization handle is not correct for command",
RCAuthMissing: "5 command requires an authorization session for handle and it is not present",
RCPolicy: "policy failure in math operation or an invalid authPolicy value",
RCPCR: "PCR check fail",
RCPCRChanged: "PCR have changed since checked",
RCUpgrade: "TPM is in field upgrade mode unless called via TPM2_FieldUpgradeData(), then it is not in field upgrade mode",
RCTooManyContexts: "context ID counter is at maximum",
RCAuthUnavailable: "authValue or authPolicy is not available for selected entity",
RCReboot: "a _TPM_Init and Startup(CLEAR) is required before the TPM can resume operation",
RCUnbalanced: "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",
RCCommandSize: "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",
RCCommandCode: "command code not supported",
RCAuthSize: "the value of authorizationSize is out of range or the number of octets in the Authorization Area is greater than required",
RCAuthContext: "use of an authorization session with a context command or another command that cannot have an authorization session",
RCNVRange: "NV offset+size is out of range",
RCNVSize: "Requested allocation size is larger than allowed",
RCNVLocked: "NV access locked",
RCNVAuthorization: "NV access authorization fails in command actions",
RCNVUninitialized: "an NV Index is used before being initialized or the state saved by TPM2_Shutdown(STATE) could not be restored",
RCNVSpace: "insufficient space for NV allocation",
RCNVDefined: "NV Index or persistent object already defined",
RCBadContext: "context in TPM2_ContextLoad() is not valid",
RCCPHash: "cpHash value already set or not correct for use",
RCParent: "handle for parent is not a valid parent",
RCNeedsTest: "some function needs testing",
RCNoResult: "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",
RCSensitive: "the sensitive area did not unmarshal correctly after decryption",
}
// Format 1 error codes.
const (
RCAsymmetric = 0x01
RCAttributes = 0x02
RCHash = 0x03
RCValue = 0x04
RCHierarchy = 0x05
RCKeySize = 0x07
RCMGF = 0x08
RCMode = 0x09
RCType = 0x0A
RCHandle = 0x0B
RCKDF = 0x0C
RCRange = 0x0D
RCAuthFail = 0x0E
RCNonce = 0x0F
RCPP = 0x10
RCScheme = 0x12
RCSize = 0x15
RCSymmetric = 0x16
RCTag = 0x17
RCSelector = 0x18
RCInsufficient = 0x1A
RCSignature = 0x1B
RCKey = 0x1C
RCPolicyFail = 0x1D
RCIntegrity = 0x1F
RCTicket = 0x20
RCReservedBits = 0x21
RCBadAuth = 0x22
RCExpired = 0x23
RCPolicyCC = 0x24
RCBinding = 0x25
RCCurve = 0x26
RCECCPoint = 0x27
)
var fmt1Msg = map[RCFmt1]string{
RCAsymmetric: "asymmetric algorithm not supported or not correct",
RCAttributes: "inconsistent attributes",
RCHash: "hash algorithm not supported or not appropriate",
RCValue: "value is out of range or is not correct for the context",
RCHierarchy: "hierarchy is not enabled or is not correct for the use",
RCKeySize: "key size is not supported",
RCMGF: "mask generation function not supported",
RCMode: "mode of operation not supported",
RCType: "the type of the value is not appropriate for the use",
RCHandle: "the handle is not correct for the use",
RCKDF: "unsupported key derivation function or function not appropriate for use",
RCRange: "value was out of allowed range",
RCAuthFail: "the authorization HMAC check failed and DA counter incremented",
RCNonce: "invalid nonce size or nonce value mismatch",
RCPP: "authorization requires assertion of PP",
RCScheme: "unsupported or incompatible scheme",
RCSize: "structure is the wrong size",
RCSymmetric: "unsupported symmetric algorithm or key size, or not appropriate for instance",
RCTag: "incorrect structure tag",
RCSelector: "union selector is incorrect",
RCInsufficient: "the TPM was unable to unmarshal a value because there were not enough octets in the input buffer",
RCSignature: "the signature is not valid",
RCKey: "key fields are not compatible with the selected use",
RCPolicyFail: "a policy check failed",
RCIntegrity: "integrity check failed",
RCTicket: "invalid ticket",
RCReservedBits: "reserved bits not set to zero as required",
RCBadAuth: "authorization failure without DA implications",
RCExpired: "the policy has expired",
RCPolicyCC: "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",
RCBinding: "public and sensitive portions of an object are not cryptographically bound",
RCCurve: "curve not supported",
RCECCPoint: "point is not on the required curve",
}
// Warning codes.
const (
RCContextGap RCWarn = 0x01
RCObjectMemory RCWarn = 0x02
RCSessionMemory RCWarn = 0x03
RCMemory RCWarn = 0x04
RCSessionHandles RCWarn = 0x05
RCObjectHandles RCWarn = 0x06
RCLocality RCWarn = 0x07
RCYielded RCWarn = 0x08
RCCanceled RCWarn = 0x09
RCTesting RCWarn = 0x0A
RCReferenceH0 RCWarn = 0x10
RCReferenceH1 RCWarn = 0x11
RCReferenceH2 RCWarn = 0x12
RCReferenceH3 RCWarn = 0x13
RCReferenceH4 RCWarn = 0x14
RCReferenceH5 RCWarn = 0x15
RCReferenceH6 RCWarn = 0x16
RCReferenceS0 RCWarn = 0x18
RCReferenceS1 RCWarn = 0x19
RCReferenceS2 RCWarn = 0x1A
RCReferenceS3 RCWarn = 0x1B
RCReferenceS4 RCWarn = 0x1C
RCReferenceS5 RCWarn = 0x1D
RCReferenceS6 RCWarn = 0x1E
RCNVRate RCWarn = 0x20
RCLockout RCWarn = 0x21
RCRetry RCWarn = 0x22
RCNVUnavailable RCWarn = 0x23
)
var warnMsg = map[RCWarn]string{
RCContextGap: "gap for context ID is too large",
RCObjectMemory: "out of memory for object contexts",
RCSessionMemory: "out of memory for session contexts",
RCMemory: "out of shared object/session memory or need space for internal operations",
RCSessionHandles: "out of session handles",
RCObjectHandles: "out of object handles",
RCLocality: "bad locality",
RCYielded: "the TPM has suspended operation on the command; forward progress was made and the command may be retried",
RCCanceled: "the command was canceled",
RCTesting: "TPM is performing self-tests",
RCReferenceH0: "the 1st handle in the handle area references a transient object or session that is not loaded",
RCReferenceH1: "the 2nd handle in the handle area references a transient object or session that is not loaded",
RCReferenceH2: "the 3rd handle in the handle area references a transient object or session that is not loaded",
RCReferenceH3: "the 4th handle in the handle area references a transient object or session that is not loaded",
RCReferenceH4: "the 5th handle in the handle area references a transient object or session that is not loaded",
RCReferenceH5: "the 6th handle in the handle area references a transient object or session that is not loaded",
RCReferenceH6: "the 7th handle in the handle area references a transient object or session that is not loaded",
RCReferenceS0: "the 1st authorization session handle references a session that is not loaded",
RCReferenceS1: "the 2nd authorization session handle references a session that is not loaded",
RCReferenceS2: "the 3rd authorization session handle references a session that is not loaded",
RCReferenceS3: "the 4th authorization session handle references a session that is not loaded",
RCReferenceS4: "the 5th authorization session handle references a session that is not loaded",
RCReferenceS5: "the 6th authorization session handle references a session that is not loaded",
RCReferenceS6: "the 7th authorization session handle references a session that is not loaded",
RCNVRate: "the TPM is rate-limiting accesses to prevent wearout of NV",
RCLockout: "authorizations for objects subject to DA protection are not allowed at this time because the TPM is in DA lockout mode",
RCRetry: "the TPM was not able to start the command",
RCNVUnavailable: "the command may require writing of NV and NV is not current accessible",
}
// Indexes for arguments, handles and sessions.
const (
RC1 RCIndex = iota + 1
RC2
RC3
RC4
RC5
RC6
RC7
RC8
RC9
RCA
RCB
RCC
RCD
RCE
RCF
)
const unknownCode = "unknown error code"
// Error is returned for all Format 0 errors from the TPM. It is used for general
// errors not specific to a parameter, handle or session.
type Error struct {
Code RCFmt0
}
func (e Error) Error() string {
msg := fmt0Msg[e.Code]
if msg == "" {
msg = unknownCode
}
return fmt.Sprintf("error code 0x%x : %s", e.Code, msg)
}
// VendorError represents a vendor-specific error response. These types of responses
// are not decoded and Code contains the complete response code.
type VendorError struct {
Code uint32
}
func (e VendorError) Error() string {
return fmt.Sprintf("vendor error code 0x%x", e.Code)
}
// Warning is typically used to report transient errors.
type Warning struct {
Code RCWarn
}
func (w Warning) Error() string {
msg := warnMsg[w.Code]
if msg == "" {
msg = unknownCode
}
return fmt.Sprintf("warning code 0x%x : %s", w.Code, msg)
}
// ParameterError describes an error related to a parameter, and the parameter number.
type ParameterError struct {
Code RCFmt1
Parameter RCIndex
}
func (e ParameterError) Error() string {
msg := fmt1Msg[e.Code]
if msg == "" {
msg = unknownCode
}
return fmt.Sprintf("parameter %d, error code 0x%x : %s", e.Parameter, e.Code, msg)
}
// HandleError describes an error related to a handle, and the handle number.
type HandleError struct {
Code RCFmt1
Handle RCIndex
}
func (e HandleError) Error() string {
msg := fmt1Msg[e.Code]
if msg == "" {
msg = unknownCode
}
return fmt.Sprintf("handle %d, error code 0x%x : %s", e.Handle, e.Code, msg)
}
// SessionError describes an error related to a session, and the session number.
type SessionError struct {
Code RCFmt1
Session RCIndex
}
func (e SessionError) Error() string {
msg := fmt1Msg[e.Code]
if msg == "" {
msg = unknownCode
}
return fmt.Sprintf("session %d, error code 0x%x : %s", e.Session, e.Code, msg)
}
// Decode a TPM2 response code and return the appropriate error. Logic
// according to the "Response Code Evaluation" chart in Part 1 of the TPM 2.0
// spec.
func decodeResponse(code tpmutil.ResponseCode) error {
if code == tpmutil.RCSuccess {
return nil
}
if code&0x180 == 0 { // Bits 7:8 == 0 is a TPM1 error
return fmt.Errorf("response status 0x%x", code)
}
if code&0x80 == 0 { // Bit 7 unset
if code&0x400 > 0 { // Bit 10 set, vendor specific code
return VendorError{uint32(code)}
}
if code&0x800 > 0 { // Bit 11 set, warning with code in bit 0:6
return Warning{RCWarn(code & 0x7f)}
}
// error with code in bit 0:6
return Error{RCFmt0(code & 0x7f)}
}
if code&0x40 > 0 { // Bit 6 set, code in 0:5, parameter number in 8:11
return ParameterError{RCFmt1(code & 0x3f), RCIndex((code & 0xf00) >> 8)}
}
if code&0x800 == 0 { // Bit 11 unset, code in 0:5, handle in 8:10
return HandleError{RCFmt1(code & 0x3f), RCIndex((code & 0x700) >> 8)}
}
// Code in 0:5, Session in 8:10
return SessionError{RCFmt1(code & 0x3f), RCIndex((code & 0x700) >> 8)}
}

116
vendor/github.com/google/go-tpm/legacy/tpm2/kdf.go generated vendored Normal file
View File

@@ -0,0 +1,116 @@
// Copyright (c) 2018, Google LLC All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package tpm2
import (
"crypto"
"crypto/hmac"
"encoding/binary"
"hash"
)
// KDFa implements TPM 2.0's default key derivation function, as defined in
// section 11.4.9.2 of the TPM revision 2 specification part 1.
// See: https://trustedcomputinggroup.org/resource/tpm-library-specification/
// The key & label parameters must not be zero length.
// The label parameter is a non-null-terminated string.
// The contextU & contextV parameters are optional.
// Deprecated: Use KDFaHash.
func KDFa(hashAlg Algorithm, key []byte, label string, contextU, contextV []byte, bits int) ([]byte, error) {
h, err := hashAlg.Hash()
if err != nil {
return nil, err
}
return KDFaHash(h, key, label, contextU, contextV, bits), nil
}
// KDFe implements TPM 2.0's ECDH key derivation function, as defined in
// section 11.4.9.3 of the TPM revision 2 specification part 1.
// See: https://trustedcomputinggroup.org/resource/tpm-library-specification/
// The z parameter is the x coordinate of one party's private ECC key multiplied
// by the other party's public ECC point.
// The use parameter is a non-null-terminated string.
// The partyUInfo and partyVInfo are the x coordinates of the initiator's and
// Deprecated: Use KDFeHash.
func KDFe(hashAlg Algorithm, z []byte, use string, partyUInfo, partyVInfo []byte, bits int) ([]byte, error) {
h, err := hashAlg.Hash()
if err != nil {
return nil, err
}
return KDFeHash(h, z, use, partyUInfo, partyVInfo, bits), nil
}
// KDFaHash implements TPM 2.0's default key derivation function, as defined in
// section 11.4.9.2 of the TPM revision 2 specification part 1.
// See: https://trustedcomputinggroup.org/resource/tpm-library-specification/
// The key & label parameters must not be zero length.
// The label parameter is a non-null-terminated string.
// The contextU & contextV parameters are optional.
func KDFaHash(h crypto.Hash, key []byte, label string, contextU, contextV []byte, bits int) []byte {
mac := hmac.New(h.New, key)
out := kdf(mac, bits, func() {
mac.Write([]byte(label))
mac.Write([]byte{0}) // Terminating null character for C-string.
mac.Write(contextU)
mac.Write(contextV)
binary.Write(mac, binary.BigEndian, uint32(bits))
})
return out
}
// KDFeHash implements TPM 2.0's ECDH key derivation function, as defined in
// section 11.4.9.3 of the TPM revision 2 specification part 1.
// See: https://trustedcomputinggroup.org/resource/tpm-library-specification/
// The z parameter is the x coordinate of one party's private ECC key multiplied
// by the other party's public ECC point.
// The use parameter is a non-null-terminated string.
// The partyUInfo and partyVInfo are the x coordinates of the initiator's and
// the responder's ECC points, respectively.
func KDFeHash(h crypto.Hash, z []byte, use string, partyUInfo, partyVInfo []byte, bits int) []byte {
hash := h.New()
out := kdf(hash, bits, func() {
hash.Write(z)
hash.Write([]byte(use))
hash.Write([]byte{0}) // Terminating null character for C-string.
hash.Write(partyUInfo)
hash.Write(partyVInfo)
})
return out
}
func kdf(h hash.Hash, bits int, update func()) []byte {
bytes := (bits + 7) / 8
out := []byte{}
for counter := 1; len(out) < bytes; counter++ {
h.Reset()
binary.Write(h, binary.BigEndian, uint32(counter))
update()
out = h.Sum(out)
}
// out's length is a multiple of hash size, so there will be excess
// bytes if bytes isn't a multiple of hash size.
out = out[:bytes]
// As mentioned in the KDFa and KDFe specs mentioned above,
// the unused bits of the most significant octet are masked off.
if maskBits := uint8(bits % 8); maskBits > 0 {
out[0] &= (1 << maskBits) - 1
}
return out
}

View File

@@ -0,0 +1,57 @@
//go:build !windows
// Copyright (c) 2019, Google LLC All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package tpm2
import (
"errors"
"fmt"
"io"
"os"
"github.com/google/go-tpm/tpmutil"
)
// OpenTPM opens a channel to the TPM at the given path. If the file is a
// device, then it treats it like a normal TPM device, and if the file is a
// Unix domain socket, then it opens a connection to the socket.
//
// This function may also be invoked with no paths, as tpm2.OpenTPM(). In this
// case, the default paths on Linux (/dev/tpmrm0 then /dev/tpm0), will be used.
func OpenTPM(path ...string) (tpm io.ReadWriteCloser, err error) {
switch len(path) {
case 0:
tpm, err = tpmutil.OpenTPM("/dev/tpmrm0")
if errors.Is(err, os.ErrNotExist) {
tpm, err = tpmutil.OpenTPM("/dev/tpm0")
}
case 1:
tpm, err = tpmutil.OpenTPM(path[0])
default:
return nil, errors.New("cannot specify multiple paths to tpm2.OpenTPM")
}
if err != nil {
return nil, err
}
// Make sure this is a TPM 2.0
_, err = GetManufacturer(tpm)
if err != nil {
tpm.Close()
return nil, fmt.Errorf("open %s: device is not a TPM 2.0", path)
}
return tpm, nil
}

View File

@@ -0,0 +1,39 @@
//go:build windows
// Copyright (c) 2018, Google LLC All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package tpm2
import (
"fmt"
"io"
"github.com/google/go-tpm/tpmutil"
"github.com/google/go-tpm/tpmutil/tbs"
)
// OpenTPM opens a channel to the TPM.
func OpenTPM() (io.ReadWriteCloser, error) {
info, err := tbs.GetDeviceInfo()
if err != nil {
return nil, err
}
if info.TPMVersion != tbs.TPMVersion20 {
return nil, fmt.Errorf("openTPM: device is not a TPM 2.0")
}
return tpmutil.OpenTPM()
}

1112
vendor/github.com/google/go-tpm/legacy/tpm2/structures.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

2354
vendor/github.com/google/go-tpm/legacy/tpm2/tpm2.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

87
vendor/github.com/google/go-tpm/tpm2/audit.go generated vendored Normal file
View File

@@ -0,0 +1,87 @@
package tpm2
import (
"bytes"
"fmt"
"reflect"
)
// CommandAudit represents an audit session for attesting the execution of a
// series of commands in the TPM. It is useful for both command and session
// auditing.
type CommandAudit struct {
hash TPMIAlgHash
digest []byte
}
// NewAudit initializes a new CommandAudit with the specified hash algorithm.
func NewAudit(hash TPMIAlgHash) (*CommandAudit, error) {
h, err := hash.Hash()
if err != nil {
return nil, err
}
return &CommandAudit{
hash: hash,
digest: make([]byte, h.Size()),
}, nil
}
// AuditCommand extends the audit digest with the given command and response.
// Go Generics do not allow type parameters on methods, otherwise this would be
// a method on CommandAudit.
// See https://github.com/golang/go/issues/49085 for more information.
func AuditCommand[C Command[R, *R], R any](a *CommandAudit, cmd C, rsp *R) error {
cc := cmd.Command()
cpHash, err := auditCPHash[R](cc, a.hash, cmd)
if err != nil {
return err
}
rpHash, err := auditRPHash(cc, a.hash, rsp)
if err != nil {
return err
}
ha, err := a.hash.Hash()
if err != nil {
return err
}
h := ha.New()
h.Write(a.digest)
h.Write(cpHash)
h.Write(rpHash)
a.digest = h.Sum(nil)
return nil
}
// Digest returns the current digest of the audit.
func (a *CommandAudit) Digest() []byte {
return a.digest
}
// auditCPHash calculates the command parameter hash for a given command with
// the given hash algorithm. The command is assumed to not have any decrypt
// sessions.
func auditCPHash[R any](cc TPMCC, h TPMIAlgHash, c Command[R, *R]) ([]byte, error) {
names, err := cmdNames(c)
if err != nil {
return nil, err
}
parms, err := cmdParameters(c, nil)
if err != nil {
return nil, err
}
return cpHash(h, cc, names, parms)
}
// auditRPHash calculates the response parameter hash for a given response with
// the given hash algorithm. The command is assumed to be successful and to not
// have any encrypt sessions.
func auditRPHash(cc TPMCC, h TPMIAlgHash, r any) ([]byte, error) {
var parms bytes.Buffer
parameters := taggedMembers(reflect.ValueOf(r).Elem(), "handle", true)
for i, parameter := range parameters {
if err := marshal(&parms, parameter); err != nil {
return nil, fmt.Errorf("marshalling parameter %v: %w", i+1, err)
}
}
return rpHash(h, TPMRCSuccess, cc, parms.Bytes())
}

82
vendor/github.com/google/go-tpm/tpm2/bitfield.go generated vendored Normal file
View File

@@ -0,0 +1,82 @@
package tpm2
import (
"fmt"
)
// Bitfield represents a TPM bitfield (i.e., TPMA_*) type.
type Bitfield interface {
// Length returns the length of the bitfield.
Length() int
}
// BitGetter represents a TPM bitfield (i.e., TPMA_*) type that can be read.
type BitGetter interface {
Bitfield
// GetReservedBit returns the value of the given reserved bit.
// If the bit is not reserved, returns false.
GetReservedBit(pos int) bool
}
// BitSetter represents a TPM bitfield (i.e., TPMA_*) type that can be written.
type BitSetter interface {
Bitfield
// GetReservedBit sets the value of the given reserved bit.
SetReservedBit(pos int, val bool)
}
func checkPos(pos int, len int) {
if pos >= len || pos < 0 {
panic(fmt.Errorf("bit %d out of range for %d-bit field", pos, len))
}
}
// bitfield8 represents an 8-bit bitfield which may have reserved bits.
// 8-bit TPMA_* types embed this one, and the reserved bits are stored in it.
type bitfield8 uint8
// Length implements the Bitfield interface.
func (bitfield8) Length() int {
return 8
}
// GetReservedBit implements the BitGetter interface.
func (r bitfield8) GetReservedBit(pos int) bool {
checkPos(pos, 8)
return r&(1<<pos) != 0
}
// SetReservedBit implements the BitSetter interface.
func (r *bitfield8) SetReservedBit(pos int, val bool) {
checkPos(pos, 8)
if val {
*r |= 1 << pos
} else {
*r &= ^(1 << pos)
}
}
// bitfield32 represents a 32-bit bitfield which may have reserved bits.
// 32-bit TPMA_* types embed this one, and the reserved bits are stored in it.
type bitfield32 uint32
// Length implements the Bitfield interface.
func (bitfield32) Length() int {
return 32
}
// GetReservedBit implements the BitGetter interface.
func (r bitfield32) GetReservedBit(pos int) bool {
checkPos(pos, 32)
return r&(1<<pos) != 0
}
// SetReservedBit implements the BitSetter interface.
func (r *bitfield32) SetReservedBit(pos int, val bool) {
checkPos(pos, 32)
if val {
*r |= 1 << pos
} else {
*r &= ^(1 << pos)
}
}

View File

@@ -0,0 +1,62 @@
package tpm2
import (
"crypto/aes"
"crypto/cipher"
"crypto/hmac"
"errors"
"fmt"
)
var (
labelStorage = "STORAGE"
labelIntegrity = "INTEGRITY"
ErrUnsupportedCipher = errors.New("unsupported block cipher")
ErrUnsupportedMode = errors.New("unsupported block cipher mode of operation")
)
// deriveAndEncrypt derives a symmetric key and uses it to encrypt the plaintext.
func deriveAndEncrypt(pub LabeledEncapsulationKey, seed []byte, context []byte, plaintext []byte) ([]byte, error) {
// Only AES is supported.
if pub.SymmetricParameters().Algorithm != TPMAlgAES {
return nil, fmt.Errorf("%w %v", ErrUnsupportedCipher, pub.SymmetricParameters().Algorithm)
}
mode, err := pub.SymmetricParameters().Mode.AES()
if err != nil {
return nil, err
}
if *mode != TPMAlgCFB {
return nil, fmt.Errorf("%w %v", ErrUnsupportedMode, *mode)
}
bits, err := pub.SymmetricParameters().KeyBits.AES()
if err != nil {
return nil, err
}
hash, err := pub.NameAlg().Hash()
if err != nil {
return nil, err
}
key, err := aes.NewCipher(KDFa(hash, seed, labelStorage, context, nil, int(*bits)))
if err != nil {
return nil, err
}
ciphertext := make([]byte, len(plaintext))
cipher.NewCFBEncrypter(key, make([]byte, key.BlockSize())).XORKeyStream(ciphertext, plaintext)
return ciphertext, nil
}
// deriveAndHMAC derives an HMAC key and uses it to HMAC the data, which can be provided in multiple chunks.
func deriveAndHMAC(pub LabeledEncapsulationKey, seed []byte, data ...[]byte) ([]byte, error) {
hash, err := pub.NameAlg().Hash()
if err != nil {
return nil, err
}
key := KDFa(hash, seed, labelIntegrity, nil, nil, hash.Size()*8)
hmac := hmac.New(hash.New, key)
for _, data := range data {
hmac.Write(data)
}
return hmac.Sum(nil), nil
}

718
vendor/github.com/google/go-tpm/tpm2/constants.go generated vendored Normal file
View File

@@ -0,0 +1,718 @@
package tpm2
//go:generate stringer -trimprefix=TPM -type=TPMAlgID,TPMECCCurve,TPMCC,TPMRC,TPMEO,TPMST,TPMCap,TPMPT,TPMPTPCR,TPMHT,TPMHandle,TPMNT -output=constants_string.go constants.go
import (
// Register the relevant hash implementations.
_ "crypto/sha1"
_ "crypto/sha256"
_ "crypto/sha512"
)
// TPMAlgID represents a TPM_ALG_ID.
// See definition in Part 2: Structures, section 6.3.
type TPMAlgID uint16
// TPMAlgID values come from Part 2: Structures, section 6.3.
const (
TPMAlgRSA TPMAlgID = 0x0001
TPMAlgTDES TPMAlgID = 0x0003
TPMAlgSHA1 TPMAlgID = 0x0004
TPMAlgHMAC TPMAlgID = 0x0005
TPMAlgAES TPMAlgID = 0x0006
TPMAlgMGF1 TPMAlgID = 0x0007
TPMAlgKeyedHash TPMAlgID = 0x0008
TPMAlgXOR TPMAlgID = 0x000A
TPMAlgSHA256 TPMAlgID = 0x000B
TPMAlgSHA384 TPMAlgID = 0x000C
TPMAlgSHA512 TPMAlgID = 0x000D
TPMAlgSHA256192 TPMAlgID = 0x000E
TPMAlgNull TPMAlgID = 0x0010
TPMAlgSM3256 TPMAlgID = 0x0012
TPMAlgSM4 TPMAlgID = 0x0013
TPMAlgRSASSA TPMAlgID = 0x0014
TPMAlgRSAES TPMAlgID = 0x0015
TPMAlgRSAPSS TPMAlgID = 0x0016
TPMAlgOAEP TPMAlgID = 0x0017
TPMAlgECDSA TPMAlgID = 0x0018
TPMAlgECDH TPMAlgID = 0x0019
TPMAlgECDAA TPMAlgID = 0x001A
TPMAlgSM2 TPMAlgID = 0x001B
TPMAlgECSchnorr TPMAlgID = 0x001C
TPMAlgECMQV TPMAlgID = 0x001D
TPMAlgKDF1SP80056A TPMAlgID = 0x0020
TPMAlgKDF2 TPMAlgID = 0x0021
TPMAlgKDF1SP800108 TPMAlgID = 0x0022
TPMAlgECC TPMAlgID = 0x0023
TPMAlgSymCipher TPMAlgID = 0x0025
TPMAlgCamellia TPMAlgID = 0x0026
TPMAlgSHA3256 TPMAlgID = 0x0027
TPMAlgSHA3384 TPMAlgID = 0x0028
TPMAlgSHA3512 TPMAlgID = 0x0029
TPMAlgSHAKE128 TPMAlgID = 0x002A
TPMAlgSHAKE256 TPMAlgID = 0x002B
TPMAlgSHAKE256192 TPMAlgID = 0x002C
TPMAlgSHAKE256256 TPMAlgID = 0x002D
TPMAlgSHAKE256512 TPMAlgID = 0x002E
TPMAlgCMAC TPMAlgID = 0x003F
TPMAlgCTR TPMAlgID = 0x0040
TPMAlgOFB TPMAlgID = 0x0041
TPMAlgCBC TPMAlgID = 0x0042
TPMAlgCFB TPMAlgID = 0x0043
TPMAlgECB TPMAlgID = 0x0044
TPMAlgCCM TPMAlgID = 0x0050
TPMAlgGCM TPMAlgID = 0x0051
TPMAlgKW TPMAlgID = 0x0052
TPMAlgKWP TPMAlgID = 0x0053
TPMAlgEAX TPMAlgID = 0x0054
TPMAlgEDDSA TPMAlgID = 0x0060
TPMAlgEDDSAPH TPMAlgID = 0x0061
TPMAlgLMS TPMAlgID = 0x0070
TPMAlgXMSS TPMAlgID = 0x0071
TPMAlgKEYEDXOF TPMAlgID = 0x0080
TPMAlgKMACXOF128 TPMAlgID = 0x0081
TPMAlgKMACXOF256 TPMAlgID = 0x0082
TPMAlgKMAC128 TPMAlgID = 0x0090
TPMAlgKMAC256 TPMAlgID = 0x0091
)
// TPMECCCurve represents a TPM_ECC_Curve.
// See definition in Part 2: Structures, section 6.4.
type TPMECCCurve uint16
// TPMECCCurve values come from Part 2: Structures, section 6.4.
const (
TPMECCNone TPMECCCurve = 0x0000
TPMECCNistP192 TPMECCCurve = 0x0001
TPMECCNistP224 TPMECCCurve = 0x0002
TPMECCNistP256 TPMECCCurve = 0x0003
TPMECCNistP384 TPMECCCurve = 0x0004
TPMECCNistP521 TPMECCCurve = 0x0005
TPMECCBNP256 TPMECCCurve = 0x0010
TPMECCBNP638 TPMECCCurve = 0x0011
TPMECCSM2P256 TPMECCCurve = 0x0020
TPMECCBrainpoolP256R1 TPMECCCurve = 0x0030
TPMECCBrainpoolP384R1 TPMECCCurve = 0x0031
TPMECCBrainpoolP512R1 TPMECCCurve = 0x0032
TPMECCCurve25519 TPMECCCurve = 0x0040
TPMECCCurve448 TPMECCCurve = 0x0041
)
// TPMCC represents a TPM_CC.
// See definition in Part 2: Structures, section 6.5.2.
type TPMCC uint32
// TPMCC values come from Part 2: Structures, section 6.5.2.
const (
TPMCCNVUndefineSpaceSpecial TPMCC = 0x0000011F
TPMCCEvictControl TPMCC = 0x00000120
TPMCCHierarchyControl TPMCC = 0x00000121
TPMCCNVUndefineSpace TPMCC = 0x00000122
TPMCCChangeEPS TPMCC = 0x00000124
TPMCCChangePPS TPMCC = 0x00000125
TPMCCClear TPMCC = 0x00000126
TPMCCClearControl TPMCC = 0x00000127
TPMCCClockSet TPMCC = 0x00000128
TPMCCHierarchyChanegAuth TPMCC = 0x00000129
TPMCCNVDefineSpace TPMCC = 0x0000012A
TPMCCPCRAllocate TPMCC = 0x0000012B
TPMCCPCRSetAuthPolicy TPMCC = 0x0000012C
TPMCCPPCommands TPMCC = 0x0000012D
TPMCCSetPrimaryPolicy TPMCC = 0x0000012E
TPMCCFieldUpgradeStart TPMCC = 0x0000012F
TPMCCClockRateAdjust TPMCC = 0x00000130
TPMCCCreatePrimary TPMCC = 0x00000131
TPMCCNVGlobalWriteLock TPMCC = 0x00000132
TPMCCGetCommandAuditDigest TPMCC = 0x00000133
TPMCCNVIncrement TPMCC = 0x00000134
TPMCCNVSetBits TPMCC = 0x00000135
TPMCCNVExtend TPMCC = 0x00000136
TPMCCNVWrite TPMCC = 0x00000137
TPMCCNVWriteLock TPMCC = 0x00000138
TPMCCDictionaryAttackLockReset TPMCC = 0x00000139
TPMCCDictionaryAttackParameters TPMCC = 0x0000013A
TPMCCNVChangeAuth TPMCC = 0x0000013B
TPMCCPCREvent TPMCC = 0x0000013C
TPMCCPCRReset TPMCC = 0x0000013D
TPMCCSequenceComplete TPMCC = 0x0000013E
TPMCCSetAlgorithmSet TPMCC = 0x0000013F
TPMCCSetCommandCodeAuditStatus TPMCC = 0x00000140
TPMCCFieldUpgradeData TPMCC = 0x00000141
TPMCCIncrementalSelfTest TPMCC = 0x00000142
TPMCCSelfTest TPMCC = 0x00000143
TPMCCStartup TPMCC = 0x00000144
TPMCCShutdown TPMCC = 0x00000145
TPMCCStirRandom TPMCC = 0x00000146
TPMCCActivateCredential TPMCC = 0x00000147
TPMCCCertify TPMCC = 0x00000148
TPMCCPolicyNV TPMCC = 0x00000149
TPMCCCertifyCreation TPMCC = 0x0000014A
TPMCCDuplicate TPMCC = 0x0000014B
TPMCCGetTime TPMCC = 0x0000014C
TPMCCGetSessionAuditDigest TPMCC = 0x0000014D
TPMCCNVRead TPMCC = 0x0000014E
TPMCCNVReadLock TPMCC = 0x0000014F
TPMCCObjectChangeAuth TPMCC = 0x00000150
TPMCCPolicySecret TPMCC = 0x00000151
TPMCCRewrap TPMCC = 0x00000152
TPMCCCreate TPMCC = 0x00000153
TPMCCECDHZGen TPMCC = 0x00000154
TPMCCMAC TPMCC = 0x00000155
TPMCCImport TPMCC = 0x00000156
TPMCCLoad TPMCC = 0x00000157
TPMCCQuote TPMCC = 0x00000158
TPMCCRSADecrypt TPMCC = 0x00000159
TPMCCMACStart TPMCC = 0x0000015B
TPMCCSequenceUpdate TPMCC = 0x0000015C
TPMCCSign TPMCC = 0x0000015D
TPMCCUnseal TPMCC = 0x0000015E
TPMCCPolicySigned TPMCC = 0x00000160
TPMCCContextLoad TPMCC = 0x00000161
TPMCCContextSave TPMCC = 0x00000162
TPMCCECDHKeyGen TPMCC = 0x00000163
TPMCCEncryptDecrypt TPMCC = 0x00000164
TPMCCFlushContext TPMCC = 0x00000165
TPMCCLoadExternal TPMCC = 0x00000167
TPMCCMakeCredential TPMCC = 0x00000168
TPMCCNVReadPublic TPMCC = 0x00000169
TPMCCPolicyAuthorize TPMCC = 0x0000016A
TPMCCPolicyAuthValue TPMCC = 0x0000016B
TPMCCPolicyCommandCode TPMCC = 0x0000016C
TPMCCPolicyCounterTimer TPMCC = 0x0000016D
TPMCCPolicyCpHash TPMCC = 0x0000016E
TPMCCPolicyLocality TPMCC = 0x0000016F
TPMCCPolicyNameHash TPMCC = 0x00000170
TPMCCPolicyOR TPMCC = 0x00000171
TPMCCPolicyTicket TPMCC = 0x00000172
TPMCCReadPublic TPMCC = 0x00000173
TPMCCRSAEncrypt TPMCC = 0x00000174
TPMCCStartAuthSession TPMCC = 0x00000176
TPMCCVerifySignature TPMCC = 0x00000177
TPMCCECCParameters TPMCC = 0x00000178
TPMCCFirmwareRead TPMCC = 0x00000179
TPMCCGetCapability TPMCC = 0x0000017A
TPMCCGetRandom TPMCC = 0x0000017B
TPMCCGetTestResult TPMCC = 0x0000017C
TPMCCHash TPMCC = 0x0000017D
TPMCCPCRRead TPMCC = 0x0000017E
TPMCCPolicyPCR TPMCC = 0x0000017F
TPMCCPolicyRestart TPMCC = 0x00000180
TPMCCReadClock TPMCC = 0x00000181
TPMCCPCRExtend TPMCC = 0x00000182
TPMCCPCRSetAuthValue TPMCC = 0x00000183
TPMCCNVCertify TPMCC = 0x00000184
TPMCCEventSequenceComplete TPMCC = 0x00000185
TPMCCHashSequenceStart TPMCC = 0x00000186
TPMCCPolicyPhysicalPresence TPMCC = 0x00000187
TPMCCPolicyDuplicationSelect TPMCC = 0x00000188
TPMCCPolicyGetDigest TPMCC = 0x00000189
TPMCCTestParms TPMCC = 0x0000018A
TPMCCCommit TPMCC = 0x0000018B
TPMCCPolicyPassword TPMCC = 0x0000018C
TPMCCZGen2Phase TPMCC = 0x0000018D
TPMCCECEphemeral TPMCC = 0x0000018E
TPMCCPolicyNvWritten TPMCC = 0x0000018F
TPMCCPolicyTemplate TPMCC = 0x00000190
TPMCCCreateLoaded TPMCC = 0x00000191
TPMCCPolicyAuthorizeNV TPMCC = 0x00000192
TPMCCEncryptDecrypt2 TPMCC = 0x00000193
TPMCCACGetCapability TPMCC = 0x00000194
TPMCCACSend TPMCC = 0x00000195
TPMCCPolicyACSendSelect TPMCC = 0x00000196
TPMCCCertifyX509 TPMCC = 0x00000197
TPMCCACTSetTimeout TPMCC = 0x00000198
)
// TPMRC represents a TPM_RC.
// See definition in Part 2: Structures, section 6.6.
type TPMRC uint32
// TPMRC values come from Part 2: Structures, section 6.6.3.
const (
rcVer1 = 0x00000100
rcFmt1 = 0x00000080
rcWarn = 0x00000900
rcP = 0x00000040
rcS = 0x00000800
TPMRCSuccess TPMRC = 0x00000000
// FMT0 error codes
TPMRCInitialize TPMRC = rcVer1 + 0x000
TPMRCFailure TPMRC = rcVer1 + 0x001
TPMRCSequence TPMRC = rcVer1 + 0x003
TPMRCPrivate TPMRC = rcVer1 + 0x00B
TPMRCHMAC TPMRC = rcVer1 + 0x019
TPMRCDisabled TPMRC = rcVer1 + 0x020
TPMRCExclusive TPMRC = rcVer1 + 0x021
TPMRCAuthType TPMRC = rcVer1 + 0x024
TPMRCAuthMissing TPMRC = rcVer1 + 0x025
TPMRCPolicy TPMRC = rcVer1 + 0x026
TPMRCPCR TPMRC = rcVer1 + 0x027
TPMRCPCRChanged TPMRC = rcVer1 + 0x028
TPMRCUpgrade TPMRC = rcVer1 + 0x02D
TPMRCTooManyContexts TPMRC = rcVer1 + 0x02E
TPMRCAuthUnavailable TPMRC = rcVer1 + 0x02F
TPMRCReboot TPMRC = rcVer1 + 0x030
TPMRCUnbalanced TPMRC = rcVer1 + 0x031
TPMRCCommandSize TPMRC = rcVer1 + 0x042
TPMRCCommandCode TPMRC = rcVer1 + 0x043
TPMRCAuthSize TPMRC = rcVer1 + 0x044
TPMRCAuthContext TPMRC = rcVer1 + 0x045
TPMRCNVRange TPMRC = rcVer1 + 0x046
TPMRCNVSize TPMRC = rcVer1 + 0x047
TPMRCNVLocked TPMRC = rcVer1 + 0x048
TPMRCNVAuthorization TPMRC = rcVer1 + 0x049
TPMRCNVUninitialized TPMRC = rcVer1 + 0x04A
TPMRCNVSpace TPMRC = rcVer1 + 0x04B
TPMRCNVDefined TPMRC = rcVer1 + 0x04C
TPMRCBadContext TPMRC = rcVer1 + 0x050
TPMRCCPHash TPMRC = rcVer1 + 0x051
TPMRCParent TPMRC = rcVer1 + 0x052
TPMRCNeedsTest TPMRC = rcVer1 + 0x053
TPMRCNoResult TPMRC = rcVer1 + 0x054
TPMRCSensitive TPMRC = rcVer1 + 0x055
// FMT1 error codes
TPMRCAsymmetric TPMRC = rcFmt1 + 0x001
TPMRCAttributes TPMRC = rcFmt1 + 0x002
TPMRCHash TPMRC = rcFmt1 + 0x003
TPMRCValue TPMRC = rcFmt1 + 0x004
TPMRCHierarchy TPMRC = rcFmt1 + 0x005
TPMRCKeySize TPMRC = rcFmt1 + 0x007
TPMRCMGF TPMRC = rcFmt1 + 0x008
TPMRCMode TPMRC = rcFmt1 + 0x009
TPMRCType TPMRC = rcFmt1 + 0x00A
TPMRCHandle TPMRC = rcFmt1 + 0x00B
TPMRCKDF TPMRC = rcFmt1 + 0x00C
TPMRCRange TPMRC = rcFmt1 + 0x00D
TPMRCAuthFail TPMRC = rcFmt1 + 0x00E
TPMRCNonce TPMRC = rcFmt1 + 0x00F
TPMRCPP TPMRC = rcFmt1 + 0x010
TPMRCScheme TPMRC = rcFmt1 + 0x012
TPMRCSize TPMRC = rcFmt1 + 0x015
TPMRCSymmetric TPMRC = rcFmt1 + 0x016
TPMRCTag TPMRC = rcFmt1 + 0x017
TPMRCSelector TPMRC = rcFmt1 + 0x018
TPMRCInsufficient TPMRC = rcFmt1 + 0x01A
TPMRCSignature TPMRC = rcFmt1 + 0x01B
TPMRCKey TPMRC = rcFmt1 + 0x01C
TPMRCPolicyFail TPMRC = rcFmt1 + 0x01D
TPMRCIntegrity TPMRC = rcFmt1 + 0x01F
TPMRCTicket TPMRC = rcFmt1 + 0x020
TPMRCReservedBits TPMRC = rcFmt1 + 0x021
TPMRCBadAuth TPMRC = rcFmt1 + 0x022
TPMRCExpired TPMRC = rcFmt1 + 0x023
TPMRCPolicyCC TPMRC = rcFmt1 + 0x024
TPMRCBinding TPMRC = rcFmt1 + 0x025
TPMRCCurve TPMRC = rcFmt1 + 0x026
TPMRCECCPoint TPMRC = rcFmt1 + 0x027
// Warnings
TPMRCContextGap TPMRC = rcWarn + 0x001
TPMRCObjectMemory TPMRC = rcWarn + 0x002
TPMRCSessionMemory TPMRC = rcWarn + 0x003
TPMRCMemory TPMRC = rcWarn + 0x004
TPMRCSessionHandles TPMRC = rcWarn + 0x005
TPMRCObjectHandles TPMRC = rcWarn + 0x006
TPMRCLocality TPMRC = rcWarn + 0x007
TPMRCYielded TPMRC = rcWarn + 0x008
TPMRCCanceled TPMRC = rcWarn + 0x009
TPMRCTesting TPMRC = rcWarn + 0x00A
TPMRCReferenceH0 TPMRC = rcWarn + 0x010
TPMRCReferenceH1 TPMRC = rcWarn + 0x011
TPMRCReferenceH2 TPMRC = rcWarn + 0x012
TPMRCReferenceH3 TPMRC = rcWarn + 0x013
TPMRCReferenceH4 TPMRC = rcWarn + 0x014
TPMRCReferenceH5 TPMRC = rcWarn + 0x015
TPMRCReferenceH6 TPMRC = rcWarn + 0x016
TPMRCReferenceS0 TPMRC = rcWarn + 0x018
TPMRCReferenceS1 TPMRC = rcWarn + 0x019
TPMRCReferenceS2 TPMRC = rcWarn + 0x01A
TPMRCReferenceS3 TPMRC = rcWarn + 0x01B
TPMRCReferenceS4 TPMRC = rcWarn + 0x01C
TPMRCReferenceS5 TPMRC = rcWarn + 0x01D
TPMRCReferenceS6 TPMRC = rcWarn + 0x01E
TPMRCNVRate TPMRC = rcWarn + 0x020
TPMRCLockout TPMRC = rcWarn + 0x021
TPMRCRetry TPMRC = rcWarn + 0x022
TPMRCNVUnavailable TPMRC = rcWarn + 0x023
)
// TPMEO represents a TPM_EO.
// See definition in Part 2: Structures, section 6.8.
type TPMEO uint16
// TPMEO values come from Part 2: Structures, section 6.8.
const (
TPMEOEq TPMEO = 0x0000
TPMEONeq TPMEO = 0x0001
TPMEOSignedGT TPMEO = 0x0002
TPMEOUnsignedGT TPMEO = 0x0003
TPMEOSignedLT TPMEO = 0x0004
TPMEOUnsignedLT TPMEO = 0x0005
TPMEOSignedGE TPMEO = 0x0006
TPMEOUnsignedGE TPMEO = 0x0007
TPMEOSignedLE TPMEO = 0x0008
TPMEOUnsignedLE TPMEO = 0x0009
TPMEOBitSet TPMEO = 0x000A
TPMEOBitClear TPMEO = 0x000B
)
// TPMST represents a TPM_ST.
// See definition in Part 2: Structures, section 6.9.
type TPMST uint16
// TPMST values come from Part 2: Structures, section 6.9.
const (
TPMSTRspCommand TPMST = 0x00C4
TPMSTNull TPMST = 0x8000
TPMSTNoSessions TPMST = 0x8001
TPMSTSessions TPMST = 0x8002
TPMSTAttestNV TPMST = 0x8014
TPMSTAttestCommandAudit TPMST = 0x8015
TPMSTAttestSessionAudit TPMST = 0x8016
TPMSTAttestCertify TPMST = 0x8017
TPMSTAttestQuote TPMST = 0x8018
TPMSTAttestTime TPMST = 0x8019
TPMSTAttestCreation TPMST = 0x801A
TPMSTAttestNVDigest TPMST = 0x801C
TPMSTCreation TPMST = 0x8021
TPMSTVerified TPMST = 0x8022
TPMSTAuthSecret TPMST = 0x8023
TPMSTHashCheck TPMST = 0x8024
TPMSTAuthSigned TPMST = 0x8025
TPMSTFuManifest TPMST = 0x8029
)
// TPMSU represents a TPM_SU.
// See definition in Part 2: Structures, section 6.10.
type TPMSU uint16
// TPMSU values come from Part 2: Structures, section 6.10.
const (
TPMSUClear TPMSU = 0x0000
TPMSUState TPMSU = 0x0001
)
// TPMSE represents a TPM_SE.
// See definition in Part 2: Structures, section 6.11.
type TPMSE uint8
// TPMSE values come from Part 2: Structures, section 6.11.
const (
TPMSEHMAC TPMSE = 0x00
TPMSEPolicy TPMSE = 0x01
TPMSETrial TPMSE = 0x03
)
// TPMCap represents a TPM_CAP.
// See definition in Part 2: Structures, section 6.12.
type TPMCap uint32
// TPMCap values come from Part 2: Structures, section 6.12.
const (
TPMCapAlgs TPMCap = 0x00000000
TPMCapHandles TPMCap = 0x00000001
TPMCapCommands TPMCap = 0x00000002
TPMCapPPCommands TPMCap = 0x00000003
TPMCapAuditCommands TPMCap = 0x00000004
TPMCapPCRs TPMCap = 0x00000005
TPMCapTPMProperties TPMCap = 0x00000006
TPMCapPCRProperties TPMCap = 0x00000007
TPMCapECCCurves TPMCap = 0x00000008
TPMCapAuthPolicies TPMCap = 0x00000009
TPMCapACT TPMCap = 0x0000000A
)
// TPMPT represents a TPM_PT.
// See definition in Part 2: Structures, section 6.13.
type TPMPT uint32
// TPMPT values come from Part 2: Structures, section 6.13.
const (
// a 4-octet character string containing the TPM Family value
// (TPM_SPEC_FAMILY)
TPMPTFamilyIndicator TPMPT = 0x00000100
// the level of the specification
TPMPTLevel TPMPT = 0x00000101
// the specification Revision times 100
TPMPTRevision TPMPT = 0x00000102
// the specification day of year using TCG calendar
TPMPTDayofYear TPMPT = 0x00000103
// the specification year using the CE
TPMPTYear TPMPT = 0x00000104
// the vendor ID unique to each TPM manufacturer
TPMPTManufacturer TPMPT = 0x00000105
// the first four characters of the vendor ID string
TPMPTVendorString1 TPMPT = 0x00000106
// the second four characters of the vendor ID string
TPMPTVendorString2 TPMPT = 0x00000107
// the third four characters of the vendor ID string
TPMPTVendorString3 TPMPT = 0x00000108
// the fourth four characters of the vendor ID sting
TPMPTVendorString4 TPMPT = 0x00000109
// vendor-defined value indicating the TPM model
TPMPTVendorTPMType TPMPT = 0x0000010A
// the most-significant 32 bits of a TPM vendor-specific value
// indicating the version number of the firmware.
TPMPTFirmwareVersion1 TPMPT = 0x0000010B
// the least-significant 32 bits of a TPM vendor-specific value
// indicating the version number of the firmware.
TPMPTFirmwareVersion2 TPMPT = 0x0000010C
// the maximum size of a parameter TPM2B_MAX_BUFFER)
TPMPTInputBuffer TPMPT = 0x0000010D
// the minimum number of transient objects that can be held in TPM RAM
TPMPTHRTransientMin TPMPT = 0x0000010E
// the minimum number of persistent objects that can be held in TPM NV
// memory
TPMPTHRPersistentMin TPMPT = 0x0000010F
// the minimum number of authorization sessions that can be held in TPM
// RAM
TPMPTHRLoadedMin TPMPT = 0x00000110
// the number of authorization sessions that may be active at a time
TPMPTActiveSessionsMax TPMPT = 0x00000111
// the number of PCR implemented
TPMPTPCRCount TPMPT = 0x00000112
// the minimum number of octets in a TPMS_PCR_SELECT.sizeOfSelect
TPMPTPCRSelectMin TPMPT = 0x00000113
// the maximum allowed difference (unsigned) between the contextID
// values of two saved session contexts
TPMPTContextGapMax TPMPT = 0x00000114
// the maximum number of NV Indexes that are allowed to have the
// TPM_NT_COUNTER attribute
TPMPTNVCountersMax TPMPT = 0x00000116
// the maximum size of an NV Index data area
TPMPTNVIndexMax TPMPT = 0x00000117
// a TPMA_MEMORY indicating the memory management method for the TPM
TPMPTMemory TPMPT = 0x00000118
// interval, in milliseconds, between updates to the copy of
// TPMS_CLOCK_INFO.clock in NV
TPMPTClockUpdate TPMPT = 0x00000119
// the algorithm used for the integrity HMAC on saved contexts and for
// hashing the fuData of TPM2_FirmwareRead()
TPMPTContextHash TPMPT = 0x0000011A
// TPM_ALG_ID, the algorithm used for encryption of saved contexts
TPMPTContextSym TPMPT = 0x0000011B
// TPM_KEY_BITS, the size of the key used for encryption of saved
// contexts
TPMPTContextSymSize TPMPT = 0x0000011C
// the modulus - 1 of the count for NV update of an orderly counter
TPMPTOrderlyCount TPMPT = 0x0000011D
// the maximum value for commandSize in a command
TPMPTMaxCommandSize TPMPT = 0x0000011E
// the maximum value for responseSize in a response
TPMPTMaxResponseSize TPMPT = 0x0000011F
// the maximum size of a digest that can be produced by the TPM
TPMPTMaxDigest TPMPT = 0x00000120
// the maximum size of an object context that will be returned by
// TPM2_ContextSave
TPMPTMaxObjectContext TPMPT = 0x00000121
// the maximum size of a session context that will be returned by
// TPM2_ContextSave
TPMPTMaxSessionContext TPMPT = 0x00000122
// platform-specific family (a TPM_PS value)(see Table 25)
TPMPTPSFamilyIndicator TPMPT = 0x00000123
// the level of the platform-specific specification
TPMPTPSLevel TPMPT = 0x00000124
// a platform specific value
TPMPTPSRevision TPMPT = 0x00000125
// the platform-specific TPM specification day of year using TCG
// calendar
TPMPTPSDayOfYear TPMPT = 0x00000126
// the platform-specific TPM specification year using the CE
TPMPTPSYear TPMPT = 0x00000127
// the number of split signing operations supported by the TPM
TPMPTSplitMax TPMPT = 0x00000128
// total number of commands implemented in the TPM
TPMPTTotalCommands TPMPT = 0x00000129
// number of commands from the TPM library that are implemented
TPMPTLibraryCommands TPMPT = 0x0000012A
// number of vendor commands that are implemented
TPMPTVendorCommands TPMPT = 0x0000012B
// the maximum data size in one NV write, NV read, NV extend, or NV
// certify command
TPMPTNVBufferMax TPMPT = 0x0000012C
// a TPMA_MODES value, indicating that the TPM is designed for these
// modes.
TPMPTModes TPMPT = 0x0000012D
// the maximum size of a TPMS_CAPABILITY_DATA structure returned in
// TPM2_GetCapability().
TPMPTMaxCapBuffer TPMPT = 0x0000012E
// TPMA_PERMANENT
TPMPTPermanent TPMPT = 0x00000200
// TPMA_STARTUP_CLEAR
TPMPTStartupClear TPMPT = 0x00000201
// the number of NV Indexes currently defined
TPMPTHRNVIndex TPMPT = 0x00000202
// the number of authorization sessions currently loaded into TPM RAM
TPMPTHRLoaded TPMPT = 0x00000203
// the number of additional authorization sessions, of any type, that
// could be loaded into TPM RAM
TPMPTHRLoadedAvail TPMPT = 0x00000204
// the number of active authorization sessions currently being tracked
// by the TPM
TPMPTHRActive TPMPT = 0x00000205
// the number of additional authorization sessions, of any type, that
// could be created
TPMPTHRActiveAvail TPMPT = 0x00000206
// estimate of the number of additional transient objects that could be
// loaded into TPM RAM
TPMPTHRTransientAvail TPMPT = 0x00000207
// the number of persistent objects currently loaded into TPM NV memory
TPMPTHRPersistent TPMPT = 0x00000208
// the number of additional persistent objects that could be loaded into
// NV memory
TPMPTHRPersistentAvail TPMPT = 0x00000209
// the number of defined NV Indexes that have NV the TPM_NT_COUNTER
// attribute
TPMPTNVCounters TPMPT = 0x0000020A
// 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
TPMPTNVCountersAvail TPMPT = 0x0000020B
// code that limits the algorithms that may be used with the TPM
TPMPTAlgorithmSet TPMPT = 0x0000020C
// the number of loaded ECC curves
TPMPTLoadedCurves TPMPT = 0x0000020D
// the current value of the lockout counter (failedTries)
TPMPTLockoutCounter TPMPT = 0x0000020E
// the number of authorization failures before DA lockout is invoked
TPMPTMaxAuthFail TPMPT = 0x0000020F
// the number of seconds before the value reported by
// TPM_PT_LOCKOUT_COUNTER is decremented
TPMPTLockoutInterval TPMPT = 0x00000210
// the number of seconds after a lockoutAuth failure before use of
// lockoutAuth may be attempted again
TPMPTLockoutRecovery TPMPT = 0x00000211
// number of milliseconds before the TPM will accept another command
// that will modify NV
TPMPTNVWriteRecovery TPMPT = 0x00000212
// the high-order 32 bits of the command audit counter
TPMPTAuditCounter0 TPMPT = 0x00000213
// the low-order 32 bits of the command audit counter
TPMPTAuditCounter1 TPMPT = 0x00000214
)
// TPMPTPCR represents a TPM_PT_PCR.
// See definition in Part 2: Structures, section 6.14.
type TPMPTPCR uint32
// TPMPTPCR values come from Part 2: Structures, section 6.14.
const (
// a SET bit in the TPMS_PCR_SELECT indicates that the PCR is saved and
// restored by TPM_SU_STATE
TPMPTPCRSave TPMPTPCR = 0x00000000
// a SET bit in the TPMS_PCR_SELECT indicates that the PCR may be
// extended from locality 0
TPMPTPCRExtendL0 TPMPTPCR = 0x00000001
// a SET bit in the TPMS_PCR_SELECT indicates that the PCR may be reset
// by TPM2_PCR_Reset() from locality 0
TPMPTPCRResetL0 TPMPTPCR = 0x00000002
// a SET bit in the TPMS_PCR_SELECT indicates that the PCR may be
// extended from locality 1
TPMPTPCRExtendL1 TPMPTPCR = 0x00000003
// a SET bit in the TPMS_PCR_SELECT indicates that the PCR may be reset
// by TPM2_PCR_Reset() from locality 1
TPMPTPCRResetL1 TPMPTPCR = 0x00000004
// a SET bit in the TPMS_PCR_SELECT indicates that the PCR may be
// extended from locality 2
TPMPTPCRExtendL2 TPMPTPCR = 0x00000005
// a SET bit in the TPMS_PCR_SELECT indicates that the PCR may be reset
// by TPM2_PCR_Reset() from locality 2
TPMPTPCRResetL2 TPMPTPCR = 0x00000006
// a SET bit in the TPMS_PCR_SELECT indicates that the PCR may be
// extended from locality 3
TPMPTPCRExtendL3 TPMPTPCR = 0x00000007
// a SET bit in the TPMS_PCR_SELECT indicates that the PCR may be reset
// by TPM2_PCR_Reset() from locality 3
TPMPTPCRResetL3 TPMPTPCR = 0x00000008
// a SET bit in the TPMS_PCR_SELECT indicates that the PCR may be
// extended from locality 4
TPMPTPCRExtendL4 TPMPTPCR = 0x00000009
// a SET bit in the TPMS_PCR_SELECT indicates that the PCR may be reset
// by TPM2_PCR_Reset() from locality 4
TPMPTPCRResetL4 TPMPTPCR = 0x0000000A
// a SET bit in the TPMS_PCR_SELECT indicates that modifications to this
// PCR (reset or Extend) will not increment the pcrUpdateCounter
TPMPTPCRNoIncrement TPMPTPCR = 0x00000011
// a SET bit in the TPMS_PCR_SELECT indicates that the PCR is reset by a
// D-RTM event
TPMPTPCRDRTMRest TPMPTPCR = 0x00000012
// a SET bit in the TPMS_PCR_SELECT indicates that the PCR is controlled
// by policy
TPMPTPCRPolicy TPMPTPCR = 0x00000013
// a SET bit in the TPMS_PCR_SELECT indicates that the PCR is controlled
// by an authorization value
TPMPTPCRAuth TPMPTPCR = 0x00000014
)
// TPMHT represents a TPM_HT.
// See definition in Part 2: Structures, section 7.2.
type TPMHT uint8
// TPMHT values come from Part 2: Structures, section 7.2.
const (
TPMHTPCR TPMHT = 0x00
TPMHTNVIndex TPMHT = 0x01
TPMHTHMACSession TPMHT = 0x02
TPMHTPolicySession TPMHT = 0x03
TPMHTPermanent TPMHT = 0x40
TPMHTTransient TPMHT = 0x80
TPMHTPersistent TPMHT = 0x81
TPMHTAC TPMHT = 0x90
)
// Saved Context transient object handles.
// See definition in Part 2: Structures, section 14.6.2
// Context Handle Values come from table 211
const (
// an ordinary transient object
TPMIDHSavedTransient TPMIDHSaved = 0x80000000
// a sequence object
TPMIDHSavedSequence TPMIDHSaved = 0x80000001
// a transient object with the stClear attribute SET
TPMIDHSavedTransientClear TPMIDHSaved = 0x80000002
)
// TPMHandle represents a TPM_HANDLE.
// See definition in Part 2: Structures, section 7.1.
type TPMHandle uint32
// TPMHandle values come from Part 2: Structures, section 7.4.
const (
TPMRHOwner TPMHandle = 0x40000001
TPMRHNull TPMHandle = 0x40000007
TPMRSPW TPMHandle = 0x40000009
TPMRHLockout TPMHandle = 0x4000000A
TPMRHEndorsement TPMHandle = 0x4000000B
TPMRHPlatform TPMHandle = 0x4000000C
TPMRHPlatformNV TPMHandle = 0x4000000D
TPMRHFWOwner TPMHandle = 0x40000140
TPMRHFWEndorsement TPMHandle = 0x40000141
TPMRHFWPlatform TPMHandle = 0x40000142
TPMRHFWNull TPMHandle = 0x40000143
)
// TPMNT represents a TPM_NT.
// See definition in Part 2: Structures, section 13.4.
type TPMNT uint8
// TPMNT values come from Part 2: Structures, section 13.2.
const (
// contains data that is opaque to the TPM that can only be modified
// using TPM2_NV_Write().
TPMNTOrdinary TPMNT = 0x0
// contains an 8-octet value that is to be used as a counter and can
// only be modified with TPM2_NV_Increment()
TPMNTCounter TPMNT = 0x1
// contains an 8-octet value to be used as a bit field and can only be
// modified with TPM2_NV_SetBits().
TPMNTBits TPMNT = 0x2
// 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.
TPMNTExtend TPMNT = 0x4
// contains pinCount that increments on a PIN authorization failure and
// a pinLimit
TPMNTPinFail TPMNT = 0x8
// contains pinCount that increments on a PIN authorization success and
// a pinLimit
TPMNTPinPass TPMNT = 0x9
)

View File

@@ -0,0 +1,14 @@
package tpm2
// This file contains constant definitions we don't want to use stringer with
// (because they are duplicates of other values, and we would prefer those values
// to influence the string representations).
// Hash algorithm IDs and command codes that got re-used.
const (
TPMAlgSHA = TPMAlgSHA1
TPMCCHMAC = TPMCCMAC
TPMCCHMACStart = TPMCCMACStart
TPMHTLoadedSession = TPMHTHMACSession
TPMHTSavedSession = TPMHTPolicySession
)

View File

@@ -0,0 +1,40 @@
package tpm2
import (
"io"
)
var (
labelIdentity = "IDENTITY"
)
// CreateCredential creates an encrypted secret that can be recovered using ActivateCredential as part of a key-attestation flow.
func CreateCredential(rand io.Reader, pub LabeledEncapsulationKey, name []byte, credentialValue []byte) (idObject []byte, encSecret []byte, err error) {
secret, ciphertext, err := pub.Encapsulate(rand, labelIdentity)
if err != nil {
return nil, nil, err
}
// Marshal the credentialValue as a TPM2B_DIGEST before encrypting it.
// See Part 1, "Credential Protection", and Part 2, "TPMS_ID_OBJECT".
credential2B := Marshal(TPM2BDigest{Buffer: credentialValue})
// Encrypt the credentialValue as encIdentity.
encIdentity, err := deriveAndEncrypt(pub, secret, name, credential2B)
if err != nil {
return nil, nil, err
}
// Compute the HMAC of (encIdentity || name)
identityHMAC, err := deriveAndHMAC(pub, secret, nil, encIdentity, name)
if err != nil {
return nil, nil, err
}
// Marshal the virtual TPMS_ID_OBJECT ourselves. We have to do this since encIdentity's size is encrypted.
idObject = make([]byte, 0, 2+len(identityHMAC)+len(encIdentity))
idObject = append(idObject, Marshal(TPM2BDigest{Buffer: identityHMAC})...)
idObject = append(idObject, encIdentity...)
return idObject, ciphertext, nil
}

View File

@@ -0,0 +1,41 @@
package tpm2
import (
"io"
)
var (
labelDuplicate = "DUPLICATE"
)
// CreateDuplicate encrypts an object so that it can be imported under a target Storage Key.
// An inner wrapper is not supported.
func CreateDuplicate(rand io.Reader, pub LabeledEncapsulationKey, name []byte, sensitive []byte) (duplicate []byte, encSecret []byte, err error) {
secret, ciphertext, err := pub.Encapsulate(rand, labelDuplicate)
if err != nil {
return nil, nil, err
}
// Marshal the sensitive as a TPM2B_SENSITIVE before encrypting it.
// See Part 1, "Outer Duplication Wrapper"
sensitive2B := Marshal(TPM2BDigest{Buffer: sensitive})
// Encrypt the sensitive2B as dupSensitive.
dupSensitive, err := deriveAndEncrypt(pub, secret, name, sensitive2B)
if err != nil {
return nil, nil, err
}
// Compute the HMAC of (dupSensitive || name)
outerHMAC, err := deriveAndHMAC(pub, secret, nil, dupSensitive, name)
if err != nil {
return nil, nil, err
}
// Marshal the virtual _PRIVATE ourselves. We have to do this since dupSensitive's size is encrypted.
duplicate = make([]byte, 0, 2+len(outerHMAC)+len(dupSensitive))
duplicate = append(duplicate, Marshal(TPM2BDigest{Buffer: outerHMAC})...)
duplicate = append(duplicate, dupSensitive...)
return duplicate, ciphertext, nil
}

14
vendor/github.com/google/go-tpm/tpm2/create_salt.go generated vendored Normal file
View File

@@ -0,0 +1,14 @@
package tpm2
import "io"
var (
labelSecret = "SECRET"
)
// CreateEncryptedSalt encrypts a random salt for secure session establishment.
func CreateEncryptedSalt(rand io.Reader, pub LabeledEncapsulationKey) (salt []byte, encSecret []byte, err error) {
// The salt value is directly used from the Labeled Key Encapsulation operation.
// See Part 1, "Salted and Bound Session Key Generation"
return pub.Encapsulate(rand, labelSecret)
}

193
vendor/github.com/google/go-tpm/tpm2/crypto.go generated vendored Normal file
View File

@@ -0,0 +1,193 @@
package tpm2
import (
"crypto"
"crypto/ecdh"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rsa"
"fmt"
"math/big"
)
// Priv converts a TPM private key into one recognized by the crypto package.
func Priv(public TPMTPublic, sensitive TPMTSensitive) (crypto.PrivateKey, error) {
var privateKey crypto.PrivateKey
publicKey, err := Pub(public)
if err != nil {
return nil, err
}
switch public.Type {
case TPMAlgRSA:
publicKey := publicKey.(*rsa.PublicKey)
if sensitive.SensitiveType != TPMAlgRSA {
return nil, fmt.Errorf("sensitive type is not equal to public type")
}
prime, err := sensitive.Sensitive.RSA()
if err != nil {
return nil, fmt.Errorf("failed to retrieve the RSA prime number")
}
P := new(big.Int).SetBytes(prime.Buffer)
Q := new(big.Int).Div(publicKey.N, P)
phiN := new(big.Int).Mul(new(big.Int).Sub(P, big.NewInt(1)), new(big.Int).Sub(Q, big.NewInt(1)))
D := new(big.Int).ModInverse(big.NewInt(int64(publicKey.E)), phiN)
rsaKey := &rsa.PrivateKey{
PublicKey: *publicKey,
D: D,
Primes: []*big.Int{P, Q},
}
rsaKey.Precompute()
privateKey = rsaKey
case TPMAlgECC:
publicKey := publicKey.(*ecdsa.PublicKey)
if sensitive.SensitiveType != TPMAlgECC {
return nil, fmt.Errorf("sensitive type is not equal to public type")
}
d, err := sensitive.Sensitive.ECC()
if err != nil {
return nil, fmt.Errorf("failed to retrieve the ECC")
}
D := new(big.Int).SetBytes(d.Buffer)
ecdsaKey := &ecdsa.PrivateKey{
PublicKey: *publicKey,
D: D,
}
privateKey = ecdsaKey
default:
return nil, fmt.Errorf("unsupported public key type: %v", public.Type)
}
return privateKey, nil
}
// Pub converts a TPM public key into one recognized by the crypto package.
func Pub(public TPMTPublic) (crypto.PublicKey, error) {
var publicKey crypto.PublicKey
switch public.Type {
case TPMAlgRSA:
parameters, err := public.Parameters.RSADetail()
if err != nil {
return nil, fmt.Errorf("failed to retrieve the RSA parameters")
}
n, err := public.Unique.RSA()
if err != nil {
return nil, fmt.Errorf("failed to parse and retrieve the RSA modulus")
}
publicKey, err = RSAPub(parameters, n)
if err != nil {
return nil, fmt.Errorf("failed to retrieve the RSA public key")
}
case TPMAlgECC:
parameters, err := public.Parameters.ECCDetail()
if err != nil {
return nil, fmt.Errorf("failed to retrieve the ECC parameters")
}
pub, err := public.Unique.ECC()
if err != nil {
return nil, fmt.Errorf("failed to parse and retrieve the ECC point")
}
publicKey, err = ECDSAPub(parameters, pub)
if err != nil {
return nil, fmt.Errorf("failed to retrieve the ECC public key")
}
default:
return nil, fmt.Errorf("unsupported public key type: %v", public.Type)
}
return publicKey, nil
}
// RSAPub converts a TPM RSA public key into one recognized by the rsa package.
func RSAPub(parms *TPMSRSAParms, pub *TPM2BPublicKeyRSA) (*rsa.PublicKey, error) {
result := rsa.PublicKey{
N: big.NewInt(0).SetBytes(pub.Buffer),
E: int(parms.Exponent),
}
// TPM considers 65537 to be the default RSA public exponent, and 0 in
// the parms
// indicates so.
if result.E == 0 {
result.E = 65537
}
return &result, nil
}
// ECDSAPub converts a TPM ECC public key into one recognized by the ecdh package
func ECDSAPub(parms *TPMSECCParms, pub *TPMSECCPoint) (*ecdsa.PublicKey, error) {
var c elliptic.Curve
switch parms.CurveID {
case TPMECCNistP256:
c = elliptic.P256()
case TPMECCNistP384:
c = elliptic.P384()
case TPMECCNistP521:
c = elliptic.P521()
default:
return nil, fmt.Errorf("unknown curve: %v", parms.CurveID)
}
pubKey := ecdsa.PublicKey{
Curve: c,
X: big.NewInt(0).SetBytes(pub.X.Buffer),
Y: big.NewInt(0).SetBytes(pub.Y.Buffer),
}
return &pubKey, nil
}
// ECDHPub converts a TPM ECC public key into one recognized by the ecdh package
func ECDHPub(parms *TPMSECCParms, pub *TPMSECCPoint) (*ecdh.PublicKey, error) {
pubKey, err := ECDSAPub(parms, pub)
if err != nil {
return nil, err
}
return pubKey.ECDH()
}
// ECCPoint returns an uncompressed ECC Point
func ECCPoint(pubKey *ecdh.PublicKey) (*big.Int, *big.Int, error) {
b := pubKey.Bytes()
size, err := elementLength(pubKey.Curve())
if err != nil {
return nil, nil, fmt.Errorf("ECCPoint: %w", err)
}
return big.NewInt(0).SetBytes(b[1 : size+1]),
big.NewInt(0).SetBytes(b[size+1:]), nil
}
func elementLength(c ecdh.Curve) (int, error) {
switch c {
case ecdh.P256():
// crypto/internal/nistec/fiat.p256ElementLen
return 32, nil
case ecdh.P384():
// crypto/internal/nistec/fiat.p384ElementLen
return 48, nil
case ecdh.P521():
// crypto/internal/nistec/fiat.p521ElementLen
return 66, nil
default:
return 0, fmt.Errorf("unknown element length for curve: %v", c)
}
}

561
vendor/github.com/google/go-tpm/tpm2/errors.go generated vendored Normal file
View File

@@ -0,0 +1,561 @@
package tpm2
import (
"fmt"
)
type errorDesc struct {
name string
description string
}
var fmt0Descs = map[TPMRC]errorDesc{
TPMRCInitialize: {
name: "TPM_RC_INITIALIZE",
description: "TPM not initialized by TPM2_Startup or already initialized",
},
TPMRCFailure: {
name: "TPM_RC_FAILURE",
description: "commands not being accepted because of a TPM failure",
},
TPMRCSequence: {
name: "TPM_RC_SEQUENCE",
description: "improper use of a sequence handle",
},
TPMRCPrivate: {
name: "TPM_RC_PRIVATE",
description: "not currently used",
},
TPMRCHMAC: {
name: "TPM_RC_HMAC",
description: "not currently used",
},
TPMRCDisabled: {
name: "TPM_RC_DISABLED",
description: "the command is disabled",
},
TPMRCExclusive: {
name: "TPM_RC_EXCLUSIVE",
description: "command failed because audit sequence required exclusivity",
},
TPMRCAuthType: {
name: "TPM_RC_AUTH_TYPE",
description: "authorization handle is not correct for command",
},
TPMRCAuthMissing: {
name: "TPM_RC_AUTH_MISSING",
description: "command requires an authorization session for handle and it is not present.",
},
TPMRCPolicy: {
name: "TPM_RC_POLICY",
description: "policy failure in math operation or an invalid authPolicy value",
},
TPMRCPCR: {
name: "TPM_RC_PCR",
description: "PCR check fail",
},
TPMRCPCRChanged: {
name: "TPM_RC_PCR_CHANGED",
description: "PCR have changed since checked.",
},
TPMRCUpgrade: {
name: "TPM_RC_UPGRADE",
description: "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",
},
TPMRCTooManyContexts: {
name: "TPM_RC_TOO_MANY_CONTEXTS",
description: "context ID counter is at maximum.",
},
TPMRCAuthUnavailable: {
name: "TPM_RC_AUTH_UNAVAILABLE",
description: "authValue or authPolicy is not available for selected entity.",
},
TPMRCReboot: {
name: "TPM_RC_REBOOT",
description: "a _TPM_Init and Startup(CLEAR) is required before the TPM can resume operation.",
},
TPMRCUnbalanced: {
name: "TPM_RC_UNBALANCED",
description: "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.",
},
TPMRCCommandSize: {
name: "TPM_RC_COMMAND_SIZE",
description: "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",
},
TPMRCCommandCode: {
name: "TPM_RC_COMMAND_CODE",
description: "command code not supported",
},
TPMRCAuthSize: {
name: "TPM_RC_AUTHSIZE",
description: "the value of authorizationSize is out of range or the number of octets in the Authorization Area is greater than required",
},
TPMRCAuthContext: {
name: "TPM_RC_AUTH_CONTEXT",
description: "use of an authorization session with a context command or another command that cannot have an authorization session.",
},
TPMRCNVRange: {
name: "TPM_RC_NV_RANGE",
description: "NV offset+size is out of range.",
},
TPMRCNVSize: {
name: "TPM_RC_NV_SIZE",
description: "Requested allocation size is larger than allowed.",
},
TPMRCNVLocked: {
name: "TPM_RC_NV_LOCKED",
description: "NV access locked.",
},
TPMRCNVAuthorization: {
name: "TPM_RC_NV_AUTHORIZATION",
description: "NV access authorization fails in command actions (this failure does not affect lockout.action)",
},
TPMRCNVUninitialized: {
name: "TPM_RC_NV_UNINITIALIZED",
description: "an NV Index is used before being initialized or the state saved by TPM2_Shutdown(STATE) could not be restored",
},
TPMRCNVSpace: {
name: "TPM_RC_NV_SPACE",
description: "insufficient space for NV allocation",
},
TPMRCNVDefined: {
name: "TPM_RC_NV_DEFINED",
description: "NV Index or persistent object already defined",
},
TPMRCBadContext: {
name: "TPM_RC_BAD_CONTEXT",
description: "context in TPM2_ContextLoad() is not valid",
},
TPMRCCPHash: {
name: "TPM_RC_CPHASH",
description: "cpHash value already set or not correct for use",
},
TPMRCParent: {
name: "TPM_RC_PARENT",
description: "handle for parent is not a valid parent",
},
TPMRCNeedsTest: {
name: "TPM_RC_NEEDS_TEST",
description: "some function needs testing.",
},
TPMRCNoResult: {
name: "TPM_RC_NO_RESULT",
description: "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.",
},
TPMRCSensitive: {
name: "TPM_RC_SENSITIVE",
description: "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",
},
}
var fmt1Descs = map[TPMRC]errorDesc{
TPMRCAsymmetric: {
name: "TPM_RC_ASYMMETRIC RC_FMT1",
description: "asymmetric algorithm not supported or not correct",
},
TPMRCAttributes: {
name: "TPM_RC_ATTRIBUTES",
description: "inconsistent attributes",
},
TPMRCHash: {
name: "TPM_RC_HASH",
description: "hash algorithm not supported or not appropriate",
},
TPMRCValue: {
name: "TPM_RC_VALUE",
description: "value is out of range or is not correct for the context",
},
TPMRCHierarchy: {
name: "TPM_RC_HIERARCHY",
description: "hierarchy is not enabled or is not correct for the use",
},
TPMRCKeySize: {
name: "TPM_RC_KEY_SIZE",
description: "key size is not supported",
},
TPMRCMGF: {
name: "TPM_RC_MGF",
description: "mask generation function not supported",
},
TPMRCMode: {
name: "TPM_RC_MODE",
description: "mode of operation not supported",
},
TPMRCType: {
name: "TPM_RC_TYPE",
description: "the type of the value is not appropriate for the use",
},
TPMRCHandle: {
name: "TPM_RC_HANDLE",
description: "the handle is not correct for the use",
},
TPMRCKDF: {
name: "TPM_RC_KDF",
description: "unsupported key derivation function or function not appropriate for use",
},
TPMRCRange: {
name: "TPM_RC_RANGE",
description: "value was out of allowed range.",
},
TPMRCAuthFail: {
name: "TPM_RC_AUTH_FAIL",
description: "the authorization HMAC check failed and DA counter incremented",
},
TPMRCNonce: {
name: "TPM_RC_NONCE",
description: "invalid nonce size or nonce value mismatch",
},
TPMRCPP: {
name: "TPM_RC_PP",
description: "authorization requires assertion of PP",
},
TPMRCScheme: {
name: "TPM_RC_SCHEME",
description: "unsupported or incompatible scheme",
},
TPMRCSize: {
name: "TPM_RC_SIZE",
description: "structure is the wrong size",
},
TPMRCSymmetric: {
name: "TPM_RC_SYMMETRIC",
description: "unsupported symmetric algorithm or key size, or not appropriate for instance",
},
TPMRCTag: {
name: "TPM_RC_TAG",
description: "incorrect structure tag",
},
TPMRCSelector: {
name: "TPM_RC_SELECTOR",
description: "union selector is incorrect",
},
TPMRCInsufficient: {
name: "TPM_RC_INSUFFICIENT",
description: "the TPM was unable to unmarshal a value because there were not enough octets in the input buffer",
},
TPMRCSignature: {
name: "TPM_RC_SIGNATURE",
description: "the signature is not valid",
},
TPMRCKey: {
name: "TPM_RC_KEY",
description: "key fields are not compatible with the selected use",
},
TPMRCPolicyFail: {
name: "TPM_RC_POLICY_FAIL",
description: "a policy check failed",
},
TPMRCIntegrity: {
name: "TPM_RC_INTEGRITY",
description: "integrity check failed",
},
TPMRCTicket: {
name: "TPM_RC_TICKET",
description: "invalid ticket",
},
TPMRCReservedBits: {
name: "TPM_RC_RESERVED_BITS",
description: "reserved bits not set to zero as required",
},
TPMRCBadAuth: {
name: "TPM_RC_BAD_AUTH",
description: "authorization failure without DA implications",
},
TPMRCExpired: {
name: "TPM_RC_EXPIRED",
description: "the policy has expired",
},
TPMRCPolicyCC: {
name: "TPM_RC_POLICY_CC",
description: "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",
},
TPMRCBinding: {
name: "TPM_RC_BINDING",
description: "public and sensitive portions of an object are not cryptographically bound",
},
TPMRCCurve: {
name: "TPM_RC_CURVE",
description: "curve not supported",
},
TPMRCECCPoint: {
name: "TPM_RC_ECC_POINT",
description: "point is not on the required curve.",
},
}
var warnDescs = map[TPMRC]errorDesc{
TPMRCContextGap: {
name: "TPM_RC_CONTEXT_GAP",
description: "gap for context ID is too large",
},
TPMRCObjectMemory: {
name: "TPM_RC_OBJECT_MEMORY",
description: "out of memory for object contexts",
},
TPMRCSessionMemory: {
name: "TPM_RC_SESSION_MEMORY",
description: "out of memory for session contexts",
},
TPMRCMemory: {
name: "TPM_RC_MEMORY",
description: "out of shared object/session memory or need space for internal operations",
},
TPMRCSessionHandles: {
name: "TPM_RC_SESSION_HANDLES",
description: "out of session handles a session must be flushed before a new session may be created",
},
TPMRCObjectHandles: {
name: "TPM_RC_OBJECT_HANDLES",
description: "out of object handles the handle space for objects is depleted and a reboot is required",
},
TPMRCLocality: {
name: "TPM_RC_LOCALITY",
description: "bad locality",
},
TPMRCYielded: {
name: "TPM_RC_YIELDED",
description: "the TPM has suspended operation on the command; forward progress was made and the command may be retried",
},
TPMRCCanceled: {
name: "TPM_RC_CANCELED",
description: "the command was canceled",
},
TPMRCTesting: {
name: "TPM_RC_TESTING",
description: "TPM is performing self-tests",
},
TPMRCReferenceH0: {
name: "TPM_RC_REFERENCE_H0",
description: "the 1st handle in the handle area references a transient object or session that is not loaded",
},
TPMRCReferenceH1: {
name: "TPM_RC_REFERENCE_H1",
description: "the 2nd handle in the handle area references a transient object or session that is not loaded",
},
TPMRCReferenceH2: {
name: "TPM_RC_REFERENCE_H2",
description: "the 3rd handle in the handle area references a transient object or session that is not loaded",
},
TPMRCReferenceH3: {
name: "TPM_RC_REFERENCE_H3",
description: "the 4th handle in the handle area references a transient object or session that is not loaded",
},
TPMRCReferenceH4: {
name: "TPM_RC_REFERENCE_H4",
description: "the 5th handle in the handle area references a transient object or session that is not loaded",
},
TPMRCReferenceH5: {
name: "TPM_RC_REFERENCE_H5",
description: "the 6th handle in the handle area references a transient object or session that is not loaded",
},
TPMRCReferenceH6: {
name: "TPM_RC_REFERENCE_H6",
description: "the 7th handle in the handle area references a transient object or session that is not loaded",
},
TPMRCReferenceS0: {
name: "TPM_RC_REFERENCE_S0",
description: "the 1st authorization session handle references a session that is not loaded",
},
TPMRCReferenceS1: {
name: "TPM_RC_REFERENCE_S1",
description: "the 2nd authorization session handle references a session that is not loaded",
},
TPMRCReferenceS2: {
name: "TPM_RC_REFERENCE_S2",
description: "the 3rd authorization session handle references a session that is not loaded",
},
TPMRCReferenceS3: {
name: "TPM_RC_REFERENCE_S3",
description: "the 4th authorization session handle references a session that is not loaded",
},
TPMRCReferenceS4: {
name: "TPM_RC_REFERENCE_S4",
description: "the 5th session handle references a session that is not loaded",
},
TPMRCReferenceS5: {
name: "TPM_RC_REFERENCE_S5",
description: "the 6th session handle references a session that is not loaded",
},
TPMRCReferenceS6: {
name: "TPM_RC_REFERENCE_S6",
description: "the 7th authorization session handle references a session that is not loaded",
},
TPMRCNVRate: {
name: "TPM_RC_NV_RATE",
description: "the TPM is rate-limiting accesses to prevent wearout of NV",
},
TPMRCLockout: {
name: "TPM_RC_LOCKOUT",
description: "authorizations for objects subject to DA protection are not allowed at this time because the TPM is in DA lockout mode",
},
TPMRCRetry: {
name: "TPM_RC_RETRY",
description: "the TPM was not able to start the command",
},
TPMRCNVUnavailable: {
name: "TPM_RC_NV_UNAVAILABLE",
description: "the command may require writing of NV and NV is not current accessible",
},
}
// subject represents a subject of a TPM error code with additional details
// (i.e., FMT1 codes)
type subject int
const (
handleRelated subject = iota + 1
parameterRelated
sessionRelated
)
// String returns the string representation of the ErrorSubject.
func (s subject) String() string {
switch s {
case handleRelated:
return "handle"
case parameterRelated:
return "parameter"
case sessionRelated:
return "session"
default:
return "unknown subject"
}
}
// TPMFmt1Error represents a TPM 2.0 format-1 error, with additional information.
type TPMFmt1Error struct {
// The canonical TPM error code, with handle/parameter/session info
// stripped out.
canonical TPMRC
// Whether this was a handle, parameter, or session error.
subject subject
// Which handle, parameter, or session was in error
index int
}
// Error returns the string representation of the error.
func (e TPMFmt1Error) Error() string {
desc, ok := fmt1Descs[e.canonical]
if !ok {
return fmt.Sprintf("unknown format-1 error: %s %d (%x)", e.subject, e.index, uint32(e.canonical))
}
return fmt.Sprintf("%s (%v %d): %s", desc.name, e.subject, e.index, desc.description)
}
// Handle returns whether the error is handle-related and if so, which handle is
// in error.
func (e TPMFmt1Error) Handle() (bool, int) {
if e.subject != handleRelated {
return false, 0
}
return true, e.index
}
// Parameter returns whether the error is handle-related and if so, which handle
// is in error.
func (e TPMFmt1Error) Parameter() (bool, int) {
if e.subject != parameterRelated {
return false, 0
}
return true, e.index
}
// Session returns whether the error is handle-related and if so, which handle
// is in error.
func (e TPMFmt1Error) Session() (bool, int) {
if e.subject != sessionRelated {
return false, 0
}
return true, e.index
}
// isFmt0Error returns true if the result is a format-0 error.
func (r TPMRC) isFmt0Error() bool {
return (r&rcVer1) == rcVer1 && (r&rcWarn) != rcWarn
}
// isFmt1Error returns true and a format-1 error structure if the error is a
// format-1 error.
func (r TPMRC) isFmt1Error() (bool, TPMFmt1Error) {
if (r & rcFmt1) != rcFmt1 {
return false, TPMFmt1Error{}
}
subj := handleRelated
if (r & rcP) == rcP {
subj = parameterRelated
r ^= rcP
} else if (r & rcS) == rcS {
subj = sessionRelated
r ^= rcS
}
idx := int((r & 0xF00) >> 8)
r &= 0xFFFFF0FF
return true, TPMFmt1Error{
canonical: r,
subject: subj,
index: idx,
}
}
// IsWarning returns true if the error is a warning code.
// This usually indicates a problem with the TPM state, and not the command.
// Retrying the command later may succeed.
func (r TPMRC) IsWarning() bool {
if isFmt1, _ := r.isFmt1Error(); isFmt1 {
// There aren't any format-1 warnings.
return false
}
return (r&rcVer1) == rcVer1 && (r&rcWarn) == rcWarn
}
// Error produces a nice human-readable representation of the error, parsing TPM
// FMT1 errors as needed.
func (r TPMRC) Error() string {
if isFmt1, fmt1 := r.isFmt1Error(); isFmt1 {
return fmt1.Error()
}
if r.isFmt0Error() {
desc, ok := fmt0Descs[r]
if !ok {
return fmt.Sprintf("unknown format-0 error code (0x%x)", uint32(r))
}
return fmt.Sprintf("%s: %s", desc.name, desc.description)
}
if r.IsWarning() {
desc, ok := warnDescs[r]
if !ok {
return fmt.Sprintf("unknown warning (0x%x)", uint32(r))
}
return fmt.Sprintf("%s: %s", desc.name, desc.description)
}
return fmt.Sprintf("unrecognized error code (0x%x)", uint32(r))
}
// Is returns whether the TPMRC (which may be a FMT1 error) is equal to the
// given canonical error.
func (r TPMRC) Is(target error) bool {
targetTPMRC, ok := target.(TPMRC)
if !ok {
return false
}
if isFmt1, fmt1 := r.isFmt1Error(); isFmt1 {
return fmt1.canonical == targetTPMRC
}
return r == targetTPMRC
}
// As returns whether the error can be assigned to the given interface type.
// If supported, it updates the value pointed at by target.
// Supports the Fmt1Error type.
func (r TPMRC) As(target interface{}) bool {
pFmt1, ok := target.(*TPMFmt1Error)
if !ok {
return false
}
isFmt1, fmt1 := r.isFmt1Error()
if !isFmt1 {
return false
}
*pFmt1 = fmt1
return true
}

29
vendor/github.com/google/go-tpm/tpm2/kdf.go generated vendored Normal file
View File

@@ -0,0 +1,29 @@
package tpm2
import (
"crypto"
legacy "github.com/google/go-tpm/legacy/tpm2"
)
// KDFa implements TPM 2.0's default key derivation function, as defined in
// section 11.4.9.2 of the TPM revision 2 specification part 1.
// See: https://trustedcomputinggroup.org/resource/tpm-library-specification/
// The key & label parameters must not be zero length.
// The label parameter is a non-null-terminated string.
// The contextU & contextV parameters are optional.
func KDFa(h crypto.Hash, key []byte, label string, contextU, contextV []byte, bits int) []byte {
return legacy.KDFaHash(h, key, label, contextU, contextV, bits)
}
// KDFe implements TPM 2.0's ECDH key derivation function, as defined in
// section 11.4.9.3 of the TPM revision 2 specification part 1.
// See: https://trustedcomputinggroup.org/resource/tpm-library-specification/
// The z parameter is the x coordinate of one party's private ECC key multiplied
// by the other party's public ECC point.
// The use parameter is a non-null-terminated string.
// The partyUInfo and partyVInfo are the x coordinates of the initiator's and
// the responder's ECC points, respectively.
func KDFe(h crypto.Hash, z []byte, use string, partyUInfo, partyVInfo []byte, bits int) []byte {
return legacy.KDFeHash(h, z, use, partyUInfo, partyVInfo, bits)
}

View File

@@ -0,0 +1,33 @@
package tpm2
import (
"errors"
"fmt"
"io"
)
var (
ErrUnsupportedType = errors.New("unsupported key type")
)
// An LabeledEncapsulationKey represents a public key used in a TPM labeled-encapsulation scheme.
type LabeledEncapsulationKey interface {
// Encapsulate performs the labeled key encapsulation.
Encapsulate(random io.Reader, label string) (secret []byte, ciphertext []byte, err error)
// NameAlg fetches the Name hash algorithm of the encapsulation key.
NameAlg() TPMAlgID
// SymmetricParameters fetches the symmetric parameters for protection.
SymmetricParameters() *TPMTSymDefObject
}
// ImportEncapsulationKey imports the TPM-form public key as a LabeledEncapsulationkey.
func ImportEncapsulationKey(pub *TPMTPublic) (LabeledEncapsulationKey, error) {
switch pub.Type {
case TPMAlgRSA:
return importRSAEncapsulationKey(pub)
case TPMAlgECC:
return importECCEncapsulationKey(pub)
default:
return nil, fmt.Errorf("%w %v", ErrUnsupportedType, pub.Type)
}
}

107
vendor/github.com/google/go-tpm/tpm2/labeled_kem_ecc.go generated vendored Normal file
View File

@@ -0,0 +1,107 @@
package tpm2
import (
"crypto/ecdh"
"errors"
"fmt"
"io"
)
var (
// The curve is not supported.
ErrUnsupportedCurve = errors.New("unsupported curve")
// There was an internal error parsing the ephemeral public key during encapsulation.
ErrBadEphemeralKey = errors.New("bad ephemeral ECC key")
)
// An eccKey is an One-Pass-Diffie-Hellman-based Labeled Encapsulation key.
type eccKey struct {
// The actual public key.
eccPub *ecdh.PublicKey
// The name algorithm of the key.
nameAlg TPMIAlgHash
// The symmetric parameters of the key.
symParms *TPMTSymDefObject
}
// importECCEncapsulationKey imports an ECC key for use in labeled encapsulation.
func importECCEncapsulationKey(pub *TPMTPublic) (*eccKey, error) {
eccParms, err := pub.Parameters.ECCDetail()
if err != nil {
return nil, err
}
eccPub, err := pub.Unique.ECC()
if err != nil {
return nil, err
}
ecdhPub, err := ECDHPub(eccParms, eccPub)
if err != nil {
return nil, err
}
return &eccKey{
eccPub: ecdhPub,
nameAlg: pub.NameAlg,
symParms: &eccParms.Symmetric,
}, nil
}
// getXY gets the big-endian X/Y coordinates as full-length buffers.
func getXY(pub *ecdh.PublicKey) ([]byte, []byte, error) {
// Check and strip the leading 0x04 byte, which indicates an uncompressed ECC point.
rawPub := pub.Bytes()
if len(rawPub) == 0 || rawPub[0] != 0x04 {
return nil, nil, fmt.Errorf("%w: could not decode %x as an uncompressed point", ErrBadEphemeralKey, rawPub)
}
rawPub = rawPub[1:]
return rawPub[:len(rawPub)/2], rawPub[len(rawPub)/2:], nil
}
// Encapsulate implements LabeledEncapsulationKey.
func (pub *eccKey) Encapsulate(random io.Reader, label string) (secret []byte, ciphertext []byte, err error) {
ephemeralPriv, err := pub.eccPub.Curve().GenerateKey(random)
if err != nil {
return nil, nil, err
}
return pub.encapsulateDerandomized(ephemeralPriv, label)
}
// encapsulateDerandomized is a derandomized internal version of Encapsulate for testing.
func (pub *eccKey) encapsulateDerandomized(ephPrivate *ecdh.PrivateKey, label string) (secret []byte, ciphertext []byte, err error) {
nameHash, err := pub.nameAlg.Hash()
if err != nil {
return nil, nil, err
}
pubX, _, err := getXY(pub.eccPub)
if err != nil {
return nil, nil, err
}
ephX, ephY, err := getXY(ephPrivate.PublicKey())
if err != nil {
return nil, nil, err
}
z, err := ephPrivate.ECDH(pub.eccPub)
if err != nil {
return nil, nil, err
}
secret = KDFe(nameHash, z, label, ephX, pubX, nameHash.Size()*8)
ciphertext = Marshal(TPMSECCPoint{
X: TPM2BECCParameter{
Buffer: ephX,
},
Y: TPM2BECCParameter{
Buffer: ephY,
},
})
return secret, ciphertext, nil
}
// NameAlg implements LabeledEncapsulationKey.
func (pub *eccKey) NameAlg() TPMAlgID {
return pub.nameAlg
}
// SymmetricParameters implements LabeledEncapsulationkey.
func (pub *eccKey) SymmetricParameters() *TPMTSymDefObject {
return pub.symParms
}

112
vendor/github.com/google/go-tpm/tpm2/labeled_kem_rsa.go generated vendored Normal file
View File

@@ -0,0 +1,112 @@
package tpm2
import (
"crypto"
"crypto/rsa"
"errors"
"fmt"
"io"
"strings"
)
var (
// The source of randomness used for encapsulation ran out of data.
ErrInsufficientRandom = errors.New("random source did not provide enough data")
)
// An rsaKey is an RSA-OAEP-based Labeled Encapsulation key.
type rsaKey struct {
// The actual public key.
rsaPub rsa.PublicKey
// The scheme hash algorithm to use for the OAEP-based encapsulation.
hash crypto.Hash
// The name algorithm of the key.
nameAlg TPMIAlgHash
// The symmetric parameters of the key.
symParms *TPMTSymDefObject
}
func importRSAEncapsulationKey(pub *TPMTPublic) (*rsaKey, error) {
rsaParms, err := pub.Parameters.RSADetail()
if err != nil {
return nil, err
}
rsaPub, err := pub.Unique.RSA()
if err != nil {
return nil, err
}
rsa, err := RSAPub(rsaParms, rsaPub)
if err != nil {
return nil, err
}
// Decide what hash algorithm to use for OAEP.
// It's the scheme hash algorithm if not null, otherwise it's the name algorithm.
hashAlgID := pub.NameAlg
if rsaParms.Scheme.Scheme == TPMAlgOAEP {
oaep, err := rsaParms.Scheme.Details.OAEP()
if err != nil {
return nil, err
}
if oaep.HashAlg != TPMAlgNull {
hashAlgID = oaep.HashAlg
}
}
hashAlg, err := hashAlgID.Hash()
if err != nil {
return nil, err
}
return &rsaKey{
rsaPub: *rsa,
hash: hashAlg,
nameAlg: pub.NameAlg,
symParms: &rsaParms.Symmetric,
}, nil
}
// Encapsulate performs the OAEP-based RSA Labeled Encapsulation.
func (pub *rsaKey) Encapsulate(random io.Reader, label string) (secret []byte, ciphertext []byte, err error) {
secret = make([]byte, pub.hash.Size())
n, err := random.Read(secret)
if err != nil {
return nil, nil, err
}
if n != len(secret) {
return nil, nil, fmt.Errorf("%w: only read %d bytes but %d were needed", ErrInsufficientRandom, n, len(secret))
}
ciphertext, err = pub.encapsulateDerandomized(random, secret, label)
if err != nil {
return nil, nil, err
}
return secret, ciphertext, err
}
// encapsulateDerandomized is a derandomized internal version of Encapsulate for testing.
func (pub *rsaKey) encapsulateDerandomized(oaepSaltReader io.Reader, secret []byte, label string) (ciphertext []byte, err error) {
// Ensure label is null-terminated.
if !strings.HasSuffix(label, "\x00") {
label = label + "\x00"
}
if len(secret) != pub.hash.Size() {
return nil, fmt.Errorf("%w: secret was only %d bytes but %d were needed", ErrInsufficientRandom, len(secret), pub.hash.Size())
}
ciphertext, err = rsa.EncryptOAEP(pub.hash.New(), oaepSaltReader, &pub.rsaPub, secret, []byte(label))
if err != nil {
return nil, err
}
return ciphertext, err
}
// NameAlg implements LabeledEncapsulationKey.
func (pub *rsaKey) NameAlg() TPMAlgID {
return pub.nameAlg
}
// SymmetricParameters implements LabeledEncapsulationkey.
func (pub *rsaKey) SymmetricParameters() *TPMTSymDefObject {
return pub.symParms
}

377
vendor/github.com/google/go-tpm/tpm2/marshalling.go generated vendored Normal file
View File

@@ -0,0 +1,377 @@
package tpm2
import (
"bytes"
"encoding/binary"
"fmt"
"reflect"
)
// Marshallable represents any TPM type that can be marshalled.
type Marshallable interface {
// marshal will serialize the given value, appending onto the given buffer.
// Returns an error if the value is not marshallable.
marshal(buf *bytes.Buffer)
}
// marshallableWithHint represents any TPM type that can be marshalled,
// but that requires a selector ("hint") value when marshalling. Most TPMU_ are
// an example of this.
type marshallableWithHint interface {
// get will return the corresponding union member by copy. If the union is
// uninitialized, it will initialize a new zero-valued one.
get(hint int64) (reflect.Value, error)
}
// Unmarshallable represents any TPM type that can be marshalled or unmarshalled.
type Unmarshallable interface {
Marshallable
// marshal will deserialize the given value from the given buffer.
// Returns an error if there was an unmarshalling error or if there was not
// enough data in the buffer.
unmarshal(buf *bytes.Buffer) error
}
// unmarshallableWithHint represents any TPM type that can be marshalled or unmarshalled,
// but that requires a selector ("hint") value when unmarshalling. Most TPMU_ are
// an example of this.
type unmarshallableWithHint interface {
marshallableWithHint
// create will instantiate and return the corresponding union member.
create(hint int64) (reflect.Value, error)
}
// Marshal will serialize the given values, returning them as a byte slice.
func Marshal(v Marshallable) []byte {
var buf bytes.Buffer
if err := marshal(&buf, reflect.ValueOf(v)); err != nil {
panic(fmt.Sprintf("unexpected error marshalling %v: %v", reflect.TypeOf(v).Name(), err))
}
return buf.Bytes()
}
// Unmarshal unmarshals the given type from the byte array.
// Returns an error if the buffer does not contain enough data to satisfy the
// types, or if the types are not unmarshallable.
func Unmarshal[T Marshallable, P interface {
*T
Unmarshallable
}](data []byte) (*T, error) {
buf := bytes.NewBuffer(data)
var t T
value := reflect.New(reflect.TypeOf(t))
if err := unmarshal(buf, value.Elem()); err != nil {
return nil, err
}
return value.Interface().(*T), nil
}
// marshallableByReflection is a placeholder interface, to hint to the unmarshalling
// library that it is supposed to use reflection.
type marshallableByReflection interface {
reflectionSafe()
}
// marshalByReflection is embedded into any type that can be marshalled by reflection,
// needing no custom logic.
type marshalByReflection struct{}
func (marshalByReflection) reflectionSafe() {}
// These placeholders are required because a type constraint cannot union another interface
// that contains methods.
// Otherwise, marshalByReflection would not implement Unmarshallable, and the Marshal/Unmarshal
// functions would accept interface{ Marshallable | marshallableByReflection } instead.
// Placeholder: because this type implements the defaultMarshallable interface,
// the reflection library knows not to call this.
func (marshalByReflection) marshal(_ *bytes.Buffer) {
panic("not implemented")
}
// Placeholder: because this type implements the defaultMarshallable interface,
// the reflection library knows not to call this.
func (*marshalByReflection) unmarshal(_ *bytes.Buffer) error {
panic("not implemented")
}
// boxed is a helper type for corner cases such as unions, where all members must be structs.
type boxed[T any] struct {
Contents *T
}
// box will put a value into a box.
func box[T any](contents *T) boxed[T] {
return boxed[T]{
Contents: contents,
}
}
// unbox will take a value out of a box.
func (b *boxed[T]) unbox() *T {
return b.Contents
}
// marshal implements the Marshallable interface.
func (b *boxed[T]) marshal(buf *bytes.Buffer) {
if b.Contents == nil {
var contents T
marshal(buf, reflect.ValueOf(&contents))
} else {
marshal(buf, reflect.ValueOf(b.Contents))
}
}
// unmarshal implements the Unmarshallable interface.
func (b *boxed[T]) unmarshal(buf *bytes.Buffer) error {
b.Contents = new(T)
return unmarshal(buf, reflect.ValueOf(b.Contents))
}
// MarshalCommand marshals a TPM command into its raw cpHash preimage format.
// The returned bytes can be directly hashed to compute cpHash.
//
// Example:
//
// cmdData, _ := MarshalCommand(myCmd)
// cpHash := sha256.Sum256(cmdData)
//
// Note: Encrypted command parameters (via sessions) are not currently supported.
// The marshaled parameters are in their unencrypted form.
func MarshalCommand[C Command[R, *R], R any](cmd C) ([]byte, error) {
cc := cmd.Command()
names, err := cmdNames(cmd)
if err != nil {
return nil, err
}
params, err := cmdParameters(cmd, nil)
if err != nil {
return nil, err
}
// Build raw cpHash preimage: CommandCode {∥ Name1 {∥ Name2 {∥ Name3 }}} {∥ Parameters }
// See section 16.7 of TPM 2.0 specification, part 1.
buf := new(bytes.Buffer)
if err := binary.Write(buf, binary.BigEndian, cc); err != nil {
return nil, fmt.Errorf("marshalling command code: %w", err)
}
for i, name := range names {
if _, err := buf.Write(name.Buffer); err != nil {
return nil, fmt.Errorf("marshalling name %d: %w", i, err)
}
}
if _, err := buf.Write(params); err != nil {
return nil, fmt.Errorf("marshalling parameters: %w", err)
}
return buf.Bytes(), nil
}
// UnmarshalCommand unmarshals a raw cpHash preimage back into a TPM command.
// The data should be the output from [MarshalCommand].
//
// Example:
//
// cmdData, _ := MarshalCommand(myCmd)
// cmd, _ := UnmarshalCommand[MyCommandType](cmdData)
//
// Notes:
// - command produced from this function is not meant to be executed directly on a TPM,
// instead it is expected to be used for purposes such as auditing or inspection.
// - encrypted command parameters (via sessions) are not currently supported.
func UnmarshalCommand[C Command[R, *R], R any](data []byte) (C, error) {
var cmd C
if data == nil {
return cmd, fmt.Errorf("data cannot be nil")
}
buf := bytes.NewBuffer(data)
var cc TPMCC
if err := binary.Read(buf, binary.BigEndian, &cc); err != nil {
return cmd, fmt.Errorf("unmarshalling command code: %w", err)
}
if cc != cmd.Command() {
return cmd, fmt.Errorf("command code mismatch: expected %v, got %v", cmd.Command(), cc)
}
expectedNames, err := cmdNames(cmd)
if err != nil {
return cmd, fmt.Errorf("getting expected names count: %w", err)
}
numNames := len(expectedNames)
names := make([]TPM2BName, numNames)
for i := range numNames {
remaining := buf.Bytes()
if len(remaining) == 0 {
return cmd, fmt.Errorf("unexpected end of data while parsing name %d", i)
}
nameSize, err := parseNameSize(remaining)
if err != nil {
return cmd, fmt.Errorf("parsing name %d size: %w", i, err)
}
if len(remaining) < nameSize {
return cmd, fmt.Errorf("insufficient data for name %d: need %d bytes, have %d", i, nameSize, len(remaining))
}
nameBytes := make([]byte, nameSize)
if _, err := buf.Read(nameBytes); err != nil {
return cmd, fmt.Errorf("reading name %d: %w", i, err)
}
names[i] = TPM2BName{Buffer: nameBytes}
}
// Populate the command's handle fields from the names
if err := populateHandlesFromNames(&cmd, names); err != nil {
return cmd, err
}
params := buf.Bytes()
paramsBuf := bytes.NewBuffer(params)
if err := unmarshalCmdParameters(paramsBuf, &cmd, nil); err != nil {
return cmd, err
}
return cmd, nil
}
// parseNameSize determines the size of a TPM2BName by inspecting its first bytes.
// Returns the total size in bytes for the name.
//
// Case 1: Handle-based names (4 bytes)
// - 0x0000... → PCR
// - 0x02... → HMAC Session
// - 0x03... → Policy Session
// - 0x40... → Permanent Values
//
// Case 2: Hash-based names (2 + hash_size bytes) - for all other entities
// - Format: nameAlg (2 bytes) || H_nameAlg (hash digest)
//
// See section 14 of TPM 2.0 specification, part 1.
func parseNameSize(buf []byte) (int, error) {
if len(buf) < 2 {
return 0, fmt.Errorf("buffer too short to parse name")
}
firstByte := TPMHT(buf[0])
firstTwoBytes := binary.BigEndian.Uint16(buf[0:2])
// Case 1: Handle-based names (4 bytes)
switch {
case firstTwoBytes == 0x0000:
// PCR handles (pattern: 0x0000XXXX)
// Must check both bytes to distinguish from hash algorithms
// that also start with 0x00 (e.g., TPMAlgSHA256 = 0x000B)
return 4, nil
case firstByte == TPMHTHMACSession: // 0x02
return 4, nil
case firstByte == TPMHTPolicySession: // 0x03
return 4, nil
case firstByte == TPMHTPermanent: // 0x40
return 4, nil
}
// Case 2: Hash-based names (nameAlg || hash)
// firstTwoBytes is the algorithm ID (0x0001 to 0x00B3)
algID := TPMIAlgHash(firstTwoBytes)
hashAlg, err := algID.Hash()
if err != nil {
return 0, fmt.Errorf("unsupported hash algorithm 0x%x in name: %w", firstTwoBytes, err)
}
// 2 bytes for algID + hash size
return 2 + hashAlg.Size(), nil
}
// MarshalResponse marshals a TPM response into its raw rpHash preimage format.
// The returned bytes can be directly hashed to compute rpHash.
//
// Example:
//
// rspData, _ := MarshalResponse(myCmd, myRsp)
// rpHash := sha256.Sum256(rspData)
//
// Note: Encrypted response parameters (via sessions) are not currently supported.
func MarshalResponse[C Command[R, *R], R any](cmd C, rsp *R) ([]byte, error) {
cc := cmd.Command()
params, err := marshalRspParameters(rsp, nil)
if err != nil {
return nil, err
}
// Build raw rpHash preimage: responseCode || commandCode || parameters
buf := new(bytes.Buffer)
// Write responseCode (4 bytes, always 0 for successful responses)
if err := binary.Write(buf, binary.BigEndian, uint32(0)); err != nil {
return nil, fmt.Errorf("marshalling response code: %w", err)
}
if err := binary.Write(buf, binary.BigEndian, cc); err != nil {
return nil, fmt.Errorf("marshalling command code: %w", err)
}
if _, err := buf.Write(params); err != nil {
return nil, fmt.Errorf("marshalling parameters: %w", err)
}
return buf.Bytes(), nil
}
// UnmarshalResponse unmarshals a raw rpHash preimage back into a TPM response.
// The data should be the output from [MarshalResponse].
//
// Example:
//
// rspData, _ := MarshalResponse(commandCode, myRsp)
// rsp, _ := UnmarshalResponse[MyResponseType](rspData)
//
// Notes:
// - the result from this function is expected to be used for purposes such as auditing or inspection.
// - encrypted response parameters (via sessions) are not currently supported.
func UnmarshalResponse[R any](data []byte) (*R, error) {
var rsp R
if data == nil {
return nil, fmt.Errorf("data cannot be nil")
}
if len(data) < 8 {
return nil, fmt.Errorf("data too short: need at least 8 bytes (responseCode + commandCode), got %d", len(data))
}
buf := bytes.NewBuffer(data)
var responseCode uint32
if err := binary.Read(buf, binary.BigEndian, &responseCode); err != nil {
return nil, fmt.Errorf("unmarshalling response code: %w", err)
}
if responseCode != 0 {
return nil, fmt.Errorf("invalid response code: expected 0, got 0x%x", responseCode)
}
var cc TPMCC
if err := binary.Read(buf, binary.BigEndian, &cc); err != nil {
return nil, fmt.Errorf("unmarshalling command code: %w", err)
}
params := buf.Bytes()
if err := rspParameters(params, nil, &rsp); err != nil {
return nil, err
}
return &rsp, nil
}

62
vendor/github.com/google/go-tpm/tpm2/names.go generated vendored Normal file
View File

@@ -0,0 +1,62 @@
package tpm2
import (
"bytes"
"encoding/binary"
"reflect"
)
// HandleName returns the TPM Name of a PCR, session, or permanent value
// (e.g., hierarchy) handle.
func HandleName(h TPMHandle) TPM2BName {
result := make([]byte, 4)
binary.BigEndian.PutUint32(result, uint32(h))
return TPM2BName{
Buffer: result,
}
}
// objectOrNVName calculates the Name of an NV index or object.
// pub is a pointer to either a TPMTPublic or TPMSNVPublic.
func objectOrNVName(alg TPMAlgID, pub interface{}) (*TPM2BName, error) {
h, err := alg.Hash()
if err != nil {
return nil, err
}
// Create a byte slice with the correct reserved size and marshal the
// NameAlg to it.
result := make([]byte, 2, 2+h.Size())
binary.BigEndian.PutUint16(result, uint16(alg))
// Calculate the hash of the entire Public contents and append it to the
// result.
ha := h.New()
var buf bytes.Buffer
if err := marshal(&buf, reflect.ValueOf(pub)); err != nil {
return nil, err
}
ha.Write(buf.Bytes())
result = ha.Sum(result)
return &TPM2BName{
Buffer: result,
}, nil
}
// ObjectName returns the TPM Name of an object.
func ObjectName(p *TPMTPublic) (*TPM2BName, error) {
return objectOrNVName(p.NameAlg, p)
}
// NVName returns the TPM Name of an NV index.
func NVName(p *TPMSNVPublic) (*TPM2BName, error) {
return objectOrNVName(p.NameAlg, p)
}
// PrimaryHandleName returns the TPM Name of a primary handle.
func PrimaryHandleName(h TPMHandle) []byte {
result := make([]byte, 4)
binary.BigEndian.PutUint32(result, uint32(h))
return result
}

55
vendor/github.com/google/go-tpm/tpm2/pcrs.go generated vendored Normal file
View File

@@ -0,0 +1,55 @@
package tpm2
// pcrSelectionFormatter is a Platform TPM Profile-specific interface for
// formatting TPM PCR selections.
// This interface isn't (yet) part of the go-tpm public interface. After we
// add a second implementation, we should consider making it public.
type pcrSelectionFormatter interface {
// PCRs returns the TPM PCR selection bitmask associated with the given PCR indices.
PCRs(pcrs ...uint) []byte
}
// PCClientCompatible is a pcrSelectionFormatter that formats PCR selections
// suitable for use in PC Client PTP-compatible TPMs (the vast majority):
// https://trustedcomputinggroup.org/resource/pc-client-platform-tpm-profile-ptp-specification/
// PC Client mandates at least 24 PCRs but does not provide an upper limit.
var PCClientCompatible pcrSelectionFormatter = pcClient{}
type pcClient struct{}
// The TPM requires all PCR selections to be at least big enough to select all
// the PCRs in the minimum PCR allocation.
const pcClientMinimumPCRCount = 24
func (pcClient) PCRs(pcrs ...uint) []byte {
// Find the biggest PCR we selected.
maxPCR := uint(0)
for _, pcr := range pcrs {
if pcr > maxPCR {
maxPCR = pcr
}
}
selectionSize := maxPCR/8 + 1
// Enforce the minimum PCR selection size.
if selectionSize < (pcClientMinimumPCRCount / 8) {
selectionSize = (pcClientMinimumPCRCount / 8)
}
// Allocate a byte array to store the bitfield, that has at least
// enough bits to store our selections.
selection := make([]byte, selectionSize)
for _, pcr := range pcrs {
// The PCR selection mask is byte-wise little-endian:
// select[0] contains bits representing the selection of PCRs 0 through 7
// select[1] contains PCRs 8 through 15, and so on.
byteIdx := pcr / 8
// Within the byte, the PCR selection is bit-wise big-endian:
// bit 0 of select[0] contains the selection of PCR 0
// bit 1 of select[0] contains the selection of PCR 1, and so on.
bitIdx := pcr % 8
selection[byteIdx] |= (1 << bitIdx)
}
return selection
}

60
vendor/github.com/google/go-tpm/tpm2/policy.go generated vendored Normal file
View File

@@ -0,0 +1,60 @@
package tpm2
import (
"bytes"
"crypto"
"reflect"
)
// PolicyCalculator represents a TPM 2.0 policy that needs to be calculated
// synthetically (i.e., without a TPM).
type PolicyCalculator struct {
alg TPMIAlgHash
hash crypto.Hash
state []byte
}
// NewPolicyCalculator creates a fresh policy using the given hash algorithm.
func NewPolicyCalculator(alg TPMIAlgHash) (*PolicyCalculator, error) {
hash, err := alg.Hash()
if err != nil {
return nil, err
}
return &PolicyCalculator{
alg: alg,
hash: hash,
state: make([]byte, hash.Size()),
}, nil
}
// Reset resets the internal state of the policy hash to all 0x00.
func (p *PolicyCalculator) Reset() {
p.state = make([]byte, p.hash.Size())
}
// Update updates the internal state of the policy hash by appending the
// current state with the given contents, and updating the new state to the
// hash of that.
func (p *PolicyCalculator) Update(data ...interface{}) error {
hash := p.hash.New()
hash.Write(p.state)
var buf bytes.Buffer
for _, d := range data {
if err := marshal(&buf, reflect.ValueOf(d)); err != nil {
return err
}
}
hash.Write(buf.Bytes())
p.state = hash.Sum(nil)
return nil
}
// Hash returns the current state of the policy hash.
func (p *PolicyCalculator) Hash() *TPMTHA {
result := TPMTHA{
HashAlg: p.alg,
Digest: make([]byte, len(p.state)),
}
copy(result.Digest, p.state)
return &result
}

1300
vendor/github.com/google/go-tpm/tpm2/reflect.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

996
vendor/github.com/google/go-tpm/tpm2/sessions.go generated vendored Normal file
View File

@@ -0,0 +1,996 @@
package tpm2
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/hmac"
"crypto/rand"
"encoding/binary"
"fmt"
"github.com/google/go-tpm/tpm2/transport"
)
// Session represents a session in the TPM.
type Session interface {
// Initializes the session, if needed. Has no effect if not needed or
// already done. Some types of sessions may need to be initialized
// just-in-time, e.g., to support calling patterns that help the user
// securely authorize their actions without writing a lot of code.
Init(tpm transport.TPM) error
// Cleans up the session, if needed.
// Some types of session need to be cleaned up if the command failed,
// again to support calling patterns that help the user securely
// authorize their actions without writing a lot of code.
CleanupFailure(tpm transport.TPM) error
// The last nonceTPM for this session.
NonceTPM() TPM2BNonce
// Updates nonceCaller to a new random value.
NewNonceCaller() error
// Computes the authorization HMAC for the session.
// If this is the first authorization session for a command, and
// there is another session (or sessions) for parameter
// decryption and/or encryption, then addNonces contains the
// nonceTPMs from each of them, respectively (see Part 1, 19.6.5)
Authorize(cc TPMCC, parms, addNonces []byte, names []TPM2BName, authIndex int) (*TPMSAuthCommand, error)
// Validates the response for the session.
// Updates NonceTPM for the session.
Validate(rc TPMRC, cc TPMCC, parms []byte, names []TPM2BName, authIndex int, auth *TPMSAuthResponse) error
// Returns true if this is an encryption session.
IsEncryption() bool
// Returns true if this is a decryption session.
IsDecryption() bool
// If this session is used for parameter decryption, encrypts the
// parameter. Otherwise, does not modify the parameter.
Encrypt(parameter []byte) error
// If this session is used for parameter encryption, encrypts the
// parameter. Otherwise, does not modify the parameter.
Decrypt(parameter []byte) error
// Returns the handle value of this session.
Handle() TPMHandle
}
// CPHash calculates the TPM command parameter hash for a given Command.
// N.B. Authorization sessions on handles are ignored, but names aren't.
func CPHash[R any](alg TPMIAlgHash, cmd Command[R, *R]) (*TPM2BDigest, error) {
cc := cmd.Command()
names, err := cmdNames(cmd)
if err != nil {
return nil, err
}
parms, err := cmdParameters(cmd, nil)
if err != nil {
return nil, err
}
digest, err := cpHash(alg, cc, names, parms)
if err != nil {
return nil, err
}
return &TPM2BDigest{
Buffer: digest,
}, nil
}
// pwSession represents a password-pseudo-session.
type pwSession struct {
auth []byte
}
// PasswordAuth assembles a password pseudo-session with the given auth value.
func PasswordAuth(auth []byte) Session {
return &pwSession{
auth: auth,
}
}
// Init is not required and has no effect for a password session.
func (s *pwSession) Init(_ transport.TPM) error { return nil }
// Cleanup is not required and has no effect for a password session.
func (s *pwSession) CleanupFailure(_ transport.TPM) error { return nil }
// NonceTPM normally returns the last nonceTPM value from the session.
// Since a password session is a pseudo-session with the auth value stuffed
// in where the HMAC should go, this is not used.
func (s *pwSession) NonceTPM() TPM2BNonce { return TPM2BNonce{} }
// NewNonceCaller updates the nonceCaller for this session.
// Password sessions don't have nonces.
func (s *pwSession) NewNonceCaller() error { return nil }
// Computes the authorization structure for the session.
func (s *pwSession) Authorize(_ TPMCC, _, _ []byte, _ []TPM2BName, _ int) (*TPMSAuthCommand, error) {
return &TPMSAuthCommand{
Handle: TPMRSPW,
Nonce: TPM2BNonce{},
Attributes: TPMASession{},
Authorization: TPM2BData{
Buffer: s.auth,
},
}, nil
}
// Validates the response session structure for the session.
func (s *pwSession) Validate(_ TPMRC, _ TPMCC, _ []byte, _ []TPM2BName, _ int, auth *TPMSAuthResponse) error {
if len(auth.Nonce.Buffer) != 0 {
return fmt.Errorf("expected empty nonce in response auth to PW session, got %x", auth.Nonce)
}
expectedAttrs := TPMASession{
ContinueSession: true,
}
if auth.Attributes != expectedAttrs {
return fmt.Errorf("expected only ContinueSession in response auth to PW session, got %v", auth.Attributes)
}
if len(auth.Authorization.Buffer) != 0 {
return fmt.Errorf("expected empty HMAC in response auth to PW session, got %x", auth.Authorization)
}
return nil
}
// IsEncryption returns true if this is an encryption session.
// Password sessions can't be used for encryption.
func (s *pwSession) IsEncryption() bool { return false }
// IsDecryption returns true if this is a decryption session.
// Password sessions can't be used for decryption.
func (s *pwSession) IsDecryption() bool { return false }
// If this session is used for parameter decryption, encrypts the
// parameter. Otherwise, does not modify the parameter.
// Password sessions can't be used for decryption.
func (s *pwSession) Encrypt(_ []byte) error { return nil }
// If this session is used for parameter encryption, encrypts the
// parameter. Otherwise, does not modify the parameter.
// Password sessions can't be used for encryption.
func (s *pwSession) Decrypt(_ []byte) error { return nil }
// Handle returns the handle value associated with this session.
// In the case of a password session, this is always TPM_RS_PW.
func (s *pwSession) Handle() TPMHandle { return TPMRSPW }
// cpHash calculates the TPM command parameter hash.
// cpHash = hash(CC || names || parms)
func cpHash(alg TPMIAlgHash, cc TPMCC, names []TPM2BName, parms []byte) ([]byte, error) {
ha, err := alg.Hash()
if err != nil {
return nil, err
}
h := ha.New()
binary.Write(h, binary.BigEndian, cc)
for _, name := range names {
h.Write(name.Buffer)
}
h.Write(parms)
return h.Sum(nil), nil
}
// rpHash calculates the TPM response parameter hash.
// rpHash = hash(RC || CC || parms)
func rpHash(alg TPMIAlgHash, rc TPMRC, cc TPMCC, parms []byte) ([]byte, error) {
ha, err := alg.Hash()
if err != nil {
return nil, err
}
h := ha.New()
binary.Write(h, binary.BigEndian, rc)
binary.Write(h, binary.BigEndian, cc)
h.Write(parms)
return h.Sum(nil), nil
}
// sessionOptions represents extra options used when setting up an HMAC or policy session.
type sessionOptions struct {
auth []byte
password bool
bindHandle TPMIDHEntity
bindName TPM2BName
bindAuth []byte
saltHandle TPMIDHObject
saltPub TPMTPublic
attrs TPMASession
symmetric TPMTSymDef
trialPolicy bool
}
// defaultOptions represents the default options used when none are provided.
func defaultOptions() sessionOptions {
return sessionOptions{
symmetric: TPMTSymDef{
Algorithm: TPMAlgNull,
},
bindHandle: TPMRHNull,
saltHandle: TPMRHNull,
}
}
// AuthOption is an option for setting up an auth session variadically.
type AuthOption func(*sessionOptions)
// Auth uses the session to prove knowledge of the object's auth value.
func Auth(auth []byte) AuthOption {
return func(o *sessionOptions) {
o.auth = auth
}
}
// Password is a policy-session-only option that specifies to provide the
// object's auth value in place of the authorization HMAC when authorizing.
// For HMAC sessions, has the same effect as using Auth.
// Deprecated: This is not recommended and is only provided for completeness;
// use Auth instead.
func Password(auth []byte) AuthOption {
return func(o *sessionOptions) {
o.auth = auth
o.password = true
}
}
// Bound specifies that this session's session key should depend on the auth
// value of the given object.
func Bound(handle TPMIDHEntity, name TPM2BName, auth []byte) AuthOption {
return func(o *sessionOptions) {
o.bindHandle = handle
o.bindName = name
o.bindAuth = auth
}
}
// Salted specifies that this session's session key should depend on an
// encrypted seed value using the given public key.
// 'handle' must refer to a loaded RSA or ECC key.
func Salted(handle TPMIDHObject, pub TPMTPublic) AuthOption {
return func(o *sessionOptions) {
o.saltHandle = handle
o.saltPub = pub
}
}
// parameterEncryptiontpm2ion specifies whether the session-encrypted
// parameters are encrypted on the way into the TPM, out of the TPM, or both.
type parameterEncryptiontpm2ion int
const (
// EncryptIn specifies a decrypt session.
EncryptIn parameterEncryptiontpm2ion = 1 + iota
// EncryptOut specifies an encrypt session.
EncryptOut
// EncryptInOut specifies a decrypt+encrypt session.
EncryptInOut
)
// AESEncryption uses the session to encrypt the first parameter sent to/from
// the TPM.
// Note that only commands whose first command/response parameter is a 2B can
// support session encryption.
func AESEncryption(keySize TPMKeyBits, dir parameterEncryptiontpm2ion) AuthOption {
return func(o *sessionOptions) {
o.attrs.Decrypt = (dir == EncryptIn || dir == EncryptInOut)
o.attrs.Encrypt = (dir == EncryptOut || dir == EncryptInOut)
o.symmetric = TPMTSymDef{
Algorithm: TPMAlgAES,
KeyBits: NewTPMUSymKeyBits(
TPMAlgAES,
TPMKeyBits(keySize),
),
Mode: NewTPMUSymMode(
TPMAlgAES,
TPMAlgCFB,
),
}
}
}
// Audit uses the session to compute extra HMACs.
// An Audit session can be used with GetSessionAuditDigest to obtain attestation
// over a sequence of commands.
func Audit() AuthOption {
return func(o *sessionOptions) {
o.attrs.Audit = true
}
}
// AuditExclusive is like an audit session, but even more powerful.
// This allows an audit session to additionally indicate that no other auditable
// commands were executed other than the ones described by the audit hash.
func AuditExclusive() AuthOption {
return func(o *sessionOptions) {
o.attrs.Audit = true
o.attrs.AuditExclusive = true
}
}
// Trial indicates that the policy session should be in trial-mode.
// This allows using the TPM to calculate policy hashes.
// This option has no effect on non-Policy sessions.
func Trial() AuthOption {
return func(o *sessionOptions) {
o.trialPolicy = true
}
}
// hmacSession generally implements the HMAC session.
type hmacSession struct {
sessionOptions
hash TPMIAlgHash
nonceSize int
handle TPMHandle
sessionKey []byte
// last nonceCaller
nonceCaller TPM2BNonce
// last nonceTPM
nonceTPM TPM2BNonce
}
// HMAC sets up a just-in-time HMAC session that is used only once.
// A real session is created, but just in time and it is flushed when used.
func HMAC(hash TPMIAlgHash, nonceSize int, opts ...AuthOption) Session {
// Set up a one-off session that knows the auth value.
sess := hmacSession{
sessionOptions: defaultOptions(),
hash: hash,
nonceSize: nonceSize,
handle: TPMRHNull,
}
for _, opt := range opts {
opt(&sess.sessionOptions)
}
return &sess
}
// HMACSession sets up a reusable HMAC session that needs to be closed.
func HMACSession(t transport.TPM, hash TPMIAlgHash, nonceSize int, opts ...AuthOption) (s Session, close func() error, err error) {
// Set up a not-one-off session that knows the auth value.
sess := hmacSession{
sessionOptions: defaultOptions(),
hash: hash,
nonceSize: nonceSize,
handle: TPMRHNull,
}
for _, opt := range opts {
opt(&sess.sessionOptions)
}
// This session is reusable and is closed with the function we'll
// return.
sess.sessionOptions.attrs.ContinueSession = true
// Initialize the session.
if err := sess.Init(t); err != nil {
return nil, nil, err
}
closer := func() error {
_, err := (&FlushContext{FlushHandle: sess.handle}).Execute(t)
return err
}
return &sess, closer, nil
}
// getEncryptedSalt creates a salt value for salted sessions.
// Returns the encrypted salt and plaintext salt, or an error value.
func getEncryptedSalt(pub TPMTPublic) (*TPM2BEncryptedSecret, []byte, error) {
key, err := ImportEncapsulationKey(&pub)
if err != nil {
return nil, nil, err
}
salt, encSalt, err := CreateEncryptedSalt(rand.Reader, key)
if err != nil {
return nil, nil, err
}
return &TPM2BEncryptedSecret{
Buffer: encSalt,
}, salt, nil
}
// Init initializes the session, just in time, if needed.
func (s *hmacSession) Init(t transport.TPM) error {
if s.handle != TPMRHNull {
// Session is already initialized.
return nil
}
// Get a high-quality nonceCaller for our use.
// Store it with the session object for later reference.
s.nonceCaller = TPM2BNonce{
Buffer: make([]byte, s.nonceSize),
}
if _, err := rand.Read(s.nonceCaller.Buffer); err != nil {
return err
}
// Start up the actual auth session.
sasCmd := StartAuthSession{
TPMKey: s.saltHandle,
Bind: s.bindHandle,
NonceCaller: s.nonceCaller,
SessionType: TPMSEHMAC,
Symmetric: s.symmetric,
AuthHash: s.hash,
}
var salt []byte
if s.saltHandle != TPMRHNull {
var err error
var encSalt *TPM2BEncryptedSecret
encSalt, salt, err = getEncryptedSalt(s.saltPub)
if err != nil {
return err
}
sasCmd.EncryptedSalt = *encSalt
}
sasRsp, err := sasCmd.Execute(t)
if err != nil {
return err
}
s.handle = TPMHandle(sasRsp.SessionHandle.HandleValue())
s.nonceTPM = sasRsp.NonceTPM
// Part 1, 19.6
ha, err := s.hash.Hash()
if err != nil {
return err
}
if s.bindHandle != TPMRHNull || len(salt) != 0 {
var authSalt []byte
authSalt = append(authSalt, s.bindAuth...)
authSalt = append(authSalt, salt...)
s.sessionKey = KDFa(ha, authSalt, "ATH", s.nonceTPM.Buffer, s.nonceCaller.Buffer, ha.Size()*8)
}
return nil
}
// Cleanup cleans up the session, if needed.
func (s *hmacSession) CleanupFailure(t transport.TPM) error {
// The user is already responsible to clean up this session.
if s.attrs.ContinueSession {
return nil
}
fc := FlushContext{FlushHandle: s.handle}
if _, err := fc.Execute(t); err != nil {
return err
}
s.handle = TPMRHNull
return nil
}
// NonceTPM returns the last nonceTPM value from the session.
// May be nil, if the session hasn't been initialized yet.
func (s *hmacSession) NonceTPM() TPM2BNonce { return s.nonceTPM }
// To avoid a circular dependency on gotpm by tpm2, implement a
// tiny serialization by hand for TPMASession here
func attrsToBytes(attrs TPMASession) []byte {
var res byte
if attrs.ContinueSession {
res |= (1 << 0)
}
if attrs.AuditExclusive {
res |= (1 << 1)
}
if attrs.AuditReset {
res |= (1 << 2)
}
if attrs.Decrypt {
res |= (1 << 5)
}
if attrs.Encrypt {
res |= (1 << 6)
}
if attrs.Audit {
res |= (1 << 7)
}
return []byte{res}
}
// computeHMAC computes an authorization HMAC according to various equations in
// Part 1.
// This applies to both commands and responses.
// The value of key depends on whether the session is bound and/or salted.
// pHash cpHash for a command, or an rpHash for a response.
// nonceNewer in a command is the new nonceCaller sent in the command session packet.
// nonceNewer in a response is the new nonceTPM sent in the response session packet.
// nonceOlder in a command is the last nonceTPM sent by the TPM for this session.
// This may be when the session was created, or the last time it was used.
// nonceOlder in a response is the corresponding nonceCaller sent in the command.
func computeHMAC(alg TPMIAlgHash, key, pHash, nonceNewer, nonceOlder, addNonces []byte, attrs TPMASession) ([]byte, error) {
ha, err := alg.Hash()
if err != nil {
return nil, err
}
mac := hmac.New(ha.New, key)
mac.Write(pHash)
mac.Write(nonceNewer)
mac.Write(nonceOlder)
mac.Write(addNonces)
mac.Write(attrsToBytes(attrs))
return mac.Sum(nil), nil
}
// Trim trailing zeros from the auth value. Part 1, 19.6.5, Note 2
// Does not allocate a new underlying byte array.
func hmacKeyFromAuthValue(auth []byte) []byte {
key := auth
for i := len(key) - 1; i >= 0; i-- {
if key[i] == 0 {
key = key[:i]
}
}
return key
}
// NewNonceCaller updates the nonceCaller for this session.
func (s *hmacSession) NewNonceCaller() error {
_, err := rand.Read(s.nonceCaller.Buffer)
return err
}
// Authorize computes the authorization structure for the session.
// Unlike the TPM spec, authIndex is zero-based.
func (s *hmacSession) Authorize(cc TPMCC, parms, addNonces []byte, names []TPM2BName, authIndex int) (*TPMSAuthCommand, error) {
if s.handle == TPMRHNull {
// Session is not initialized.
return nil, fmt.Errorf("session not initialized")
}
// Part 1, 19.6
// HMAC key is (sessionKey || auth) unless this session is authorizing
// its bind target
var hmacKey []byte
hmacKey = append(hmacKey, s.sessionKey...)
if len(s.bindName.Buffer) == 0 || authIndex >= len(names) || !bytes.Equal(names[authIndex].Buffer, s.bindName.Buffer) {
hmacKey = append(hmacKey, hmacKeyFromAuthValue(s.auth)...)
}
// Compute the authorization HMAC.
cph, err := cpHash(s.hash, cc, names, parms)
if err != nil {
return nil, err
}
hmac, err := computeHMAC(s.hash, hmacKey, cph, s.nonceCaller.Buffer, s.nonceTPM.Buffer, addNonces, s.attrs)
if err != nil {
return nil, err
}
result := TPMSAuthCommand{
Handle: s.handle,
Nonce: s.nonceCaller,
Attributes: s.attrs,
Authorization: TPM2BData{
Buffer: hmac,
},
}
return &result, nil
}
// Validate validates the response session structure for the session.
// It updates nonceTPM from the TPM's response.
func (s *hmacSession) Validate(rc TPMRC, cc TPMCC, parms []byte, names []TPM2BName, authIndex int, auth *TPMSAuthResponse) error {
// Track the new nonceTPM for the session.
s.nonceTPM = auth.Nonce
// Track the session being automatically flushed.
if !auth.Attributes.ContinueSession {
s.handle = TPMRHNull
}
// Part 1, 19.6
// HMAC key is (sessionKey || auth) unless this session is authorizing
// its bind target
var hmacKey []byte
hmacKey = append(hmacKey, s.sessionKey...)
if len(s.bindName.Buffer) == 0 || authIndex >= len(names) || !bytes.Equal(names[authIndex].Buffer, s.bindName.Buffer) {
hmacKey = append(hmacKey, hmacKeyFromAuthValue(s.auth)...)
}
// Compute the authorization HMAC.
rph, err := rpHash(s.hash, rc, cc, parms)
if err != nil {
return err
}
mac, err := computeHMAC(s.hash, hmacKey, rph, s.nonceTPM.Buffer, s.nonceCaller.Buffer, nil, auth.Attributes)
if err != nil {
return err
}
// Compare the HMAC (constant time)
if !hmac.Equal(mac, auth.Authorization.Buffer) {
return fmt.Errorf("incorrect authorization HMAC")
}
return nil
}
// IsEncryption returns true if this is an encryption session.
func (s *hmacSession) IsEncryption() bool {
return s.attrs.Encrypt
}
// IsDecryption returns true if this is a decryption session.
func (s *hmacSession) IsDecryption() bool {
return s.attrs.Decrypt
}
// Encrypt decrypts the parameter in place, if this session is used for
// parameter decryption. Otherwise, it does not modify the parameter.
func (s *hmacSession) Encrypt(parameter []byte) error {
if !s.IsDecryption() {
return nil
}
// Only AES-CFB is supported.
bits, err := s.symmetric.KeyBits.AES()
if err != nil {
return err
}
keyBytes := *bits / 8
keyIVBytes := int(keyBytes) + 16
var sessionValue []byte
sessionValue = append(sessionValue, s.sessionKey...)
sessionValue = append(sessionValue, s.auth...)
ha, err := s.hash.Hash()
if err != nil {
return err
}
keyIV := KDFa(ha, sessionValue, "CFB", s.nonceCaller.Buffer, s.nonceTPM.Buffer, keyIVBytes*8)
key, err := aes.NewCipher(keyIV[:keyBytes])
if err != nil {
return err
}
stream := cipher.NewCFBEncrypter(key, keyIV[keyBytes:])
stream.XORKeyStream(parameter, parameter)
return nil
}
// Decrypt encrypts the parameter in place, if this session is used for
// parameter encryption. Otherwise, it does not modify the parameter.
func (s *hmacSession) Decrypt(parameter []byte) error {
if !s.IsEncryption() {
return nil
}
// Only AES-CFB is supported.
bits, err := s.symmetric.KeyBits.AES()
if err != nil {
return err
}
keyBytes := *bits / 8
keyIVBytes := int(keyBytes) + 16
// Part 1, 21.1
var sessionValue []byte
sessionValue = append(sessionValue, s.sessionKey...)
sessionValue = append(sessionValue, s.auth...)
ha, err := s.hash.Hash()
if err != nil {
return err
}
keyIV := KDFa(ha, sessionValue, "CFB", s.nonceTPM.Buffer, s.nonceCaller.Buffer, keyIVBytes*8)
key, err := aes.NewCipher(keyIV[:keyBytes])
if err != nil {
return err
}
stream := cipher.NewCFBDecrypter(key, keyIV[keyBytes:])
stream.XORKeyStream(parameter, parameter)
return nil
}
// Handle returns the handle value of the session.
// If the session is created with HMAC (instead of HMACSession) this will be
// TPM_RH_NULL.
func (s *hmacSession) Handle() TPMHandle {
return s.handle
}
// PolicyCallback represents an object's policy in the form of a function.
// This function makes zero or more TPM policy commands and returns error.
type PolicyCallback = func(tpm transport.TPM, handle TPMISHPolicy, nonceTPM TPM2BNonce) error
// policySession generally implements the policy session.
type policySession struct {
sessionOptions
hash TPMIAlgHash
nonceSize int
handle TPMHandle
sessionKey []byte
// last nonceCaller
nonceCaller TPM2BNonce
// last nonceTPM
nonceTPM TPM2BNonce
callback *PolicyCallback
}
// Policy sets up a just-in-time policy session that created each time it's
// needed.
// Each time the policy is created, the callback is invoked to authorize the
// session.
// A real session is created, but just in time, and it is flushed when used.
func Policy(hash TPMIAlgHash, nonceSize int, callback PolicyCallback, opts ...AuthOption) Session {
// Set up a one-off session that knows the auth value.
sess := policySession{
sessionOptions: defaultOptions(),
hash: hash,
nonceSize: nonceSize,
handle: TPMRHNull,
callback: &callback,
}
for _, opt := range opts {
opt(&sess.sessionOptions)
}
return &sess
}
// PolicySession opens a policy session that needs to be closed.
// The caller is responsible to call whichever policy commands they want in the
// session.
// Note that the TPM resets a policy session after it is successfully used.
func PolicySession(t transport.TPM, hash TPMIAlgHash, nonceSize int, opts ...AuthOption) (s Session, close func() error, err error) {
// Set up a not-one-off session that knows the auth value.
sess := policySession{
sessionOptions: defaultOptions(),
hash: hash,
nonceSize: nonceSize,
handle: TPMRHNull,
}
for _, opt := range opts {
opt(&sess.sessionOptions)
}
// This session is reusable and is closed with the function we'll
// return.
sess.sessionOptions.attrs.ContinueSession = true
// Initialize the session.
if err := sess.Init(t); err != nil {
return nil, nil, err
}
closer := func() error {
_, err := (&FlushContext{sess.handle}).Execute(t)
return err
}
return &sess, closer, nil
}
// Init initializes the session, just in time, if needed.
func (s *policySession) Init(t transport.TPM) error {
if s.handle != TPMRHNull {
// Session is already initialized.
return nil
}
// Get a high-quality nonceCaller for our use.
// Store it with the session object for later reference.
s.nonceCaller = TPM2BNonce{
Buffer: make([]byte, s.nonceSize),
}
if _, err := rand.Read(s.nonceCaller.Buffer); err != nil {
return err
}
sessType := TPMSEPolicy
if s.sessionOptions.trialPolicy {
sessType = TPMSETrial
}
// Start up the actual auth session.
sasCmd := StartAuthSession{
TPMKey: s.saltHandle,
Bind: s.bindHandle,
NonceCaller: s.nonceCaller,
SessionType: sessType,
Symmetric: s.symmetric,
AuthHash: s.hash,
}
var salt []byte
if s.saltHandle != TPMRHNull {
var err error
var encSalt *TPM2BEncryptedSecret
encSalt, salt, err = getEncryptedSalt(s.saltPub)
if err != nil {
return err
}
sasCmd.EncryptedSalt = *encSalt
}
sasRsp, err := sasCmd.Execute(t)
if err != nil {
return err
}
s.handle = TPMHandle(sasRsp.SessionHandle.HandleValue())
s.nonceTPM = sasRsp.NonceTPM
// Part 1, 19.6
if s.bindHandle != TPMRHNull || len(salt) != 0 {
var authSalt []byte
authSalt = append(authSalt, s.bindAuth...)
authSalt = append(authSalt, salt...)
ha, err := s.hash.Hash()
if err != nil {
return err
}
s.sessionKey = KDFa(ha, authSalt, "ATH", s.nonceTPM.Buffer, s.nonceCaller.Buffer, ha.Size()*8)
}
// Call the callback to execute the policy, if needed
if s.callback != nil {
if err := (*s.callback)(t, s.handle, s.nonceTPM); err != nil {
return fmt.Errorf("executing policy: %w", err)
}
}
return nil
}
// CleanupFailure cleans up the session, if needed.
func (s *policySession) CleanupFailure(t transport.TPM) error {
// The user is already responsible to clean up this session.
if s.attrs.ContinueSession {
return nil
}
fc := FlushContext{FlushHandle: s.handle}
if _, err := fc.Execute(t); err != nil {
return err
}
s.handle = TPMRHNull
return nil
}
// NonceTPM returns the last nonceTPM value from the session.
// May be nil, if the session hasn't been initialized yet.
func (s *policySession) NonceTPM() TPM2BNonce { return s.nonceTPM }
// NewNonceCaller updates the nonceCaller for this session.
func (s *policySession) NewNonceCaller() error {
_, err := rand.Read(s.nonceCaller.Buffer)
return err
}
// Authorize computes the authorization structure for the session.
func (s *policySession) Authorize(cc TPMCC, parms, addNonces []byte, names []TPM2BName, _ int) (*TPMSAuthCommand, error) {
if s.handle == TPMRHNull {
// Session is not initialized.
return nil, fmt.Errorf("session not initialized")
}
var hmac []byte
if s.password {
hmac = s.auth
} else {
// Part 1, 19.6
// HMAC key is (sessionKey || auth).
var hmacKey []byte
hmacKey = append(hmacKey, s.sessionKey...)
hmacKey = append(hmacKey, hmacKeyFromAuthValue(s.auth)...)
// Compute the authorization HMAC.
cph, err := cpHash(s.hash, cc, names, parms)
if err != nil {
return nil, err
}
hmac, err = computeHMAC(s.hash, hmacKey, cph, s.nonceCaller.Buffer, s.nonceTPM.Buffer, addNonces, s.attrs)
if err != nil {
return nil, err
}
}
result := TPMSAuthCommand{
Handle: s.handle,
Nonce: s.nonceCaller,
Attributes: s.attrs,
Authorization: TPM2BData{
Buffer: hmac,
},
}
return &result, nil
}
// Validate valitades the response session structure for the session.
// Updates nonceTPM from the TPM's response.
func (s *policySession) Validate(rc TPMRC, cc TPMCC, parms []byte, _ []TPM2BName, _ int, auth *TPMSAuthResponse) error {
// Track the new nonceTPM for the session.
s.nonceTPM = auth.Nonce
// Track the session being automatically flushed.
if !auth.Attributes.ContinueSession {
s.handle = TPMRHNull
}
if s.password {
// If we used a password, expect no nonce and no response HMAC.
if len(auth.Nonce.Buffer) != 0 {
return fmt.Errorf("expected empty nonce in response auth to PW policy, got %x", auth.Nonce)
}
if len(auth.Authorization.Buffer) != 0 {
return fmt.Errorf("expected empty HMAC in response auth to PW policy, got %x", auth.Authorization)
}
} else {
// Part 1, 19.6
// HMAC key is (sessionKey || auth).
var hmacKey []byte
hmacKey = append(hmacKey, s.sessionKey...)
hmacKey = append(hmacKey, hmacKeyFromAuthValue(s.auth)...)
// Compute the authorization HMAC.
rph, err := rpHash(s.hash, rc, cc, parms)
if err != nil {
return err
}
mac, err := computeHMAC(s.hash, hmacKey, rph, s.nonceTPM.Buffer, s.nonceCaller.Buffer, nil, auth.Attributes)
if err != nil {
return err
}
// Compare the HMAC (constant time)
if !hmac.Equal(mac, auth.Authorization.Buffer) {
return fmt.Errorf("incorrect authorization HMAC")
}
}
return nil
}
// IsEncryption returns true if this is an encryption session.
func (s *policySession) IsEncryption() bool {
return s.attrs.Encrypt
}
// IsDecryption returns true if this is a decryption session.
func (s *policySession) IsDecryption() bool {
return s.attrs.Decrypt
}
// Encrypt encrypts the parameter in place, if this session is used for
// parameter decryption. Otherwise, it does not modify the parameter.
func (s *policySession) Encrypt(parameter []byte) error {
if !s.IsDecryption() {
return nil
}
// Only AES-CFB is supported.
bits, err := s.symmetric.KeyBits.AES()
if err != nil {
return err
}
keyBytes := *bits / 8
keyIVBytes := int(keyBytes) + 16
var sessionValue []byte
sessionValue = append(sessionValue, s.sessionKey...)
sessionValue = append(sessionValue, s.auth...)
ha, err := s.hash.Hash()
if err != nil {
return err
}
keyIV := KDFa(ha, sessionValue, "CFB", s.nonceCaller.Buffer, s.nonceTPM.Buffer, keyIVBytes*8)
key, err := aes.NewCipher(keyIV[:keyBytes])
if err != nil {
return err
}
stream := cipher.NewCFBEncrypter(key, keyIV[keyBytes:])
stream.XORKeyStream(parameter, parameter)
return nil
}
// Decrypt decrypts the parameter in place, if this session is used for
// parameter encryption. Otherwise, it does not modify the parameter.
func (s *policySession) Decrypt(parameter []byte) error {
if !s.IsEncryption() {
return nil
}
// Only AES-CFB is supported.
bits, err := s.symmetric.KeyBits.AES()
if err != nil {
return err
}
keyBytes := *bits / 8
keyIVBytes := int(keyBytes) + 16
// Part 1, 21.1
var sessionValue []byte
sessionValue = append(sessionValue, s.sessionKey...)
sessionValue = append(sessionValue, s.auth...)
ha, err := s.hash.Hash()
if err != nil {
return err
}
keyIV := KDFa(ha, sessionValue, "CFB", s.nonceTPM.Buffer, s.nonceCaller.Buffer, keyIVBytes*8)
key, err := aes.NewCipher(keyIV[:keyBytes])
if err != nil {
return err
}
stream := cipher.NewCFBDecrypter(key, keyIV[keyBytes:])
stream.XORKeyStream(parameter, parameter)
return nil
}
// Handle returns the handle value of the session.
// If the session is created with Policy (instead of PolicySession) this will be
// TPM_RH_NULL.
func (s *policySession) Handle() TPMHandle {
return s.handle
}

3331
vendor/github.com/google/go-tpm/tpm2/structures.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

200
vendor/github.com/google/go-tpm/tpm2/templates.go generated vendored Normal file
View File

@@ -0,0 +1,200 @@
package tpm2
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),
},
),
}
// 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),
},
),
}
// 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),
},
},
),
}
// 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),
},
},
),
}
)

2258
vendor/github.com/google/go-tpm/tpm2/tpm2.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

83
vendor/github.com/google/go-tpm/tpm2/tpm2b.go generated vendored Normal file
View File

@@ -0,0 +1,83 @@
package tpm2
import (
"bytes"
"encoding/binary"
"fmt"
"io"
)
// TPM2B is a helper type for all sized TPM structures. It can be instantiated with either a raw byte buffer or the actual struct.
type TPM2B[T Marshallable, P interface {
*T
Unmarshallable
}] struct {
contents *T
buffer []byte
}
// New2B creates a new TPM2B containing the given contents.
func New2B[T Marshallable, P interface {
*T
Unmarshallable
}](t T) TPM2B[T, P] {
return TPM2B[T, P]{contents: &t}
}
// BytesAs2B creates a new TPM2B containing the given byte array.
func BytesAs2B[T Marshallable, P interface {
*T
Unmarshallable
}](b []byte) TPM2B[T, P] {
return TPM2B[T, P]{buffer: b}
}
// Contents returns the structured contents of the TPM2B.
// It can fail if the TPM2B was instantiated with an invalid byte buffer.
func (value *TPM2B[T, P]) Contents() (*T, error) {
if value.contents != nil {
return value.contents, nil
}
if value.buffer == nil {
return nil, fmt.Errorf("TPMB had no contents or buffer")
}
contents, err := Unmarshal[T, P](value.buffer)
if err != nil {
return nil, err
}
// Cache the result
value.contents = (*T)(contents)
return value.contents, nil
}
// Bytes returns the inner contents of the TPM2B as a byte array, not including the length field.
func (value *TPM2B[T, P]) Bytes() []byte {
if value.buffer != nil {
return value.buffer
}
if value.contents == nil {
return []byte{}
}
// Cache the result
value.buffer = Marshal(*value.contents)
return value.buffer
}
// marshal implements the tpm2.Marshallable interface.
func (value TPM2B[T, P]) marshal(buf *bytes.Buffer) {
b := value.Bytes()
binary.Write(buf, binary.BigEndian, uint16(len(b)))
buf.Write(b)
}
// unmarshal implements the tpm2.Unmarshallable interface.
// Note: the structure contents are not validated during unmarshalling.
func (value *TPM2B[T, P]) unmarshal(buf *bytes.Buffer) error {
var size uint16
binary.Read(buf, binary.BigEndian, &size)
value.contents = nil
value.buffer = make([]byte, size)
_, err := io.ReadAtLeast(buf, value.buffer, int(size))
return err
}

View File

@@ -0,0 +1,22 @@
//go:build !windows
package transport
import (
legacy "github.com/google/go-tpm/legacy/tpm2"
)
// OpenTPM opens the TPM at the given path. If no path is provided, it will
// attempt to use reasonable defaults.
//
// Deprecated: Please use the individual transport packages (e.g.,
// go-tpm/tpm2/transport/linuxtpm).
func OpenTPM(path ...string) (TPMCloser, error) {
rwc, err := legacy.OpenTPM(path...)
if err != nil {
return nil, err
}
return &wrappedRWC{
transport: rwc,
}, nil
}

View File

@@ -0,0 +1,21 @@
//go:build windows
package transport
import (
legacy "github.com/google/go-tpm/legacy/tpm2"
)
// OpenTPM opens the local system TPM.
//
// Deprecated: Please use the individual transport packages (e.g.,
// go-tpm/tpm2/transport/windowstpm).
func OpenTPM() (TPMCloser, error) {
rwc, err := legacy.OpenTPM()
if err != nil {
return nil, err
}
return &wrappedRWC{
transport: rwc,
}, nil
}

90
vendor/github.com/google/go-tpm/tpm2/transport/tpm.go generated vendored Normal file
View File

@@ -0,0 +1,90 @@
// Package transport implements types for physically talking to TPMs.
package transport
import (
"io"
"github.com/google/go-tpm/tpmutil"
)
// TPM represents a logical connection to a TPM.
type TPM interface {
Send(input []byte) ([]byte, error)
}
// TPMCloser represents a logical connection to a TPM and you can close it.
type TPMCloser interface {
TPM
io.Closer
}
// wrappedRW represents a struct that wraps an io.ReadWriter
// to a transport.TPM to be compatible with tpmdirect.
type wrappedRW struct {
transport io.ReadWriter
}
// wrappedRWC represents a struct that wraps an io.ReadWriteCloser
// to a transport.TPM to be compatible with tpmdirect.
type wrappedRWC struct {
transport io.ReadWriteCloser
}
// wrappedTPM represents a struct that wraps a transport.TPM's underlying
// transport to use with legacy code that expects an io.ReadWriter.
type wrappedTPM struct {
response []byte
tpm TPM
}
// FromReadWriter takes in a io.ReadWriter and returns a
// transport.TPM wrapping the io.ReadWriter.
func FromReadWriter(rw io.ReadWriter) TPM {
return &wrappedRW{transport: rw}
}
// FromReadWriteCloser takes in a io.ReadWriteCloser and returns a
// transport.TPMCloser wrapping the io.ReadWriteCloser.
func FromReadWriteCloser(rwc io.ReadWriteCloser) TPMCloser {
return &wrappedRWC{transport: rwc}
}
// ToReadWriter takes in a transport TPM and returns an
// io.ReadWriter wrapping the transport TPM.
func ToReadWriter(tpm TPM) io.ReadWriter {
return &wrappedTPM{tpm: tpm}
}
// Read copies t.response into the p buffer and return the appropriate length.
func (t *wrappedTPM) Read(p []byte) (int, error) {
n := copy(p, t.response)
t.response = t.response[n:]
if len(t.response) == 0 {
return n, io.EOF
}
return n, nil
}
// Write implements the io.ReadWriter interface.
func (t *wrappedTPM) Write(p []byte) (n int, err error) {
t.response, err = t.tpm.Send(p)
if err != nil {
return 0, err
}
return len(p), nil
}
// Send implements the TPM interface.
func (t *wrappedRW) Send(input []byte) ([]byte, error) {
return tpmutil.RunCommandRaw(t.transport, input)
}
// Send implements the TPM interface.
func (t *wrappedRWC) Send(input []byte) ([]byte, error) {
return tpmutil.RunCommandRaw(t.transport, input)
}
// Close implements the TPM interface.
func (t *wrappedRWC) Close() error {
return t.transport.Close()
}

211
vendor/github.com/google/go-tpm/tpmutil/encoding.go generated vendored Normal file
View File

@@ -0,0 +1,211 @@
// Copyright (c) 2018, Google LLC All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package tpmutil
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"io"
"reflect"
)
var (
selfMarshalerType = reflect.TypeOf((*SelfMarshaler)(nil)).Elem()
handlesAreaType = reflect.TypeOf((*[]Handle)(nil))
)
// packWithHeader takes a header and a sequence of elements that are either of
// fixed length or slices of fixed-length types and packs them into a single
// byte array using binary.Write. It updates the CommandHeader to have the right
// length.
func packWithHeader(ch commandHeader, cmd ...interface{}) ([]byte, error) {
hdrSize := binary.Size(ch)
body, err := Pack(cmd...)
if err != nil {
return nil, fmt.Errorf("couldn't pack message body: %v", err)
}
bodySize := len(body)
ch.Size = uint32(hdrSize + bodySize)
header, err := Pack(ch)
if err != nil {
return nil, fmt.Errorf("couldn't pack message header: %v", err)
}
return append(header, body...), nil
}
// Pack encodes a set of elements into a single byte array, using
// encoding/binary. This means that all the elements must be encodeable
// according to the rules of encoding/binary.
//
// It has one difference from encoding/binary: it encodes byte slices with a
// prepended length, to match how the TPM encodes variable-length arrays. If
// you wish to add a byte slice without length prefix, use RawBytes.
func Pack(elts ...interface{}) ([]byte, error) {
buf := new(bytes.Buffer)
if err := packType(buf, elts...); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
// tryMarshal attempts to use a TPMMarshal() method defined on the type
// to pack v into buf. True is returned if the method exists and the
// marshal was attempted.
func tryMarshal(buf io.Writer, v reflect.Value) (bool, error) {
t := v.Type()
if t.Implements(selfMarshalerType) {
if v.Kind() == reflect.Ptr && v.IsNil() {
return true, fmt.Errorf("cannot call TPMMarshal on a nil pointer of type %T", v)
}
return true, v.Interface().(SelfMarshaler).TPMMarshal(buf)
}
// We might have a non-pointer struct field, but we dont have a
// pointer with which to implement the interface.
// If the pointer of the type implements the interface, we should be
// able to construct a value to call TPMMarshal() with.
// TODO(awly): Try and avoid blowing away private data by using Addr() instead of Set()
if reflect.PtrTo(t).Implements(selfMarshalerType) {
tmp := reflect.New(t)
tmp.Elem().Set(v)
return true, tmp.Interface().(SelfMarshaler).TPMMarshal(buf)
}
return false, nil
}
func packValue(buf io.Writer, v reflect.Value) error {
if v.Type() == handlesAreaType {
v = v.Convert(reflect.TypeOf((*handleList)(nil)))
}
if canMarshal, err := tryMarshal(buf, v); canMarshal {
return err
}
switch v.Kind() {
case reflect.Ptr:
if v.IsNil() {
return fmt.Errorf("cannot pack nil %s", v.Type().String())
}
return packValue(buf, v.Elem())
case reflect.Struct:
for i := 0; i < v.NumField(); i++ {
f := v.Field(i)
if err := packValue(buf, f); err != nil {
return err
}
}
default:
return binary.Write(buf, binary.BigEndian, v.Interface())
}
return nil
}
func packType(buf io.Writer, elts ...interface{}) error {
for _, e := range elts {
if err := packValue(buf, reflect.ValueOf(e)); err != nil {
return err
}
}
return nil
}
// tryUnmarshal attempts to use TPMUnmarshal() to perform the
// unpack, if the given value implements SelfMarshaler.
// True is returned if v implements SelfMarshaler & TPMUnmarshal
// was called, along with an error returned from TPMUnmarshal.
func tryUnmarshal(buf io.Reader, v reflect.Value) (bool, error) {
t := v.Type()
if t.Implements(selfMarshalerType) {
if v.Kind() == reflect.Ptr && v.IsNil() {
return true, fmt.Errorf("cannot call TPMUnmarshal on a nil pointer")
}
return true, v.Interface().(SelfMarshaler).TPMUnmarshal(buf)
}
// We might have a non-pointer struct field, which is addressable,
// If the pointer of the type implements the interface, and the
// value is addressable, we should be able to call TPMUnmarshal().
if v.CanAddr() && reflect.PtrTo(t).Implements(selfMarshalerType) {
return true, v.Addr().Interface().(SelfMarshaler).TPMUnmarshal(buf)
}
return false, nil
}
// Unpack is a convenience wrapper around UnpackBuf. Unpack returns the number
// of bytes read from b to fill elts and error, if any.
func Unpack(b []byte, elts ...interface{}) (int, error) {
buf := bytes.NewBuffer(b)
err := UnpackBuf(buf, elts...)
read := len(b) - buf.Len()
return read, err
}
func unpackValue(buf io.Reader, v reflect.Value) error {
if v.Type() == handlesAreaType {
v = v.Convert(reflect.TypeOf((*handleList)(nil)))
}
if didUnmarshal, err := tryUnmarshal(buf, v); didUnmarshal {
return err
}
switch v.Kind() {
case reflect.Ptr:
if v.IsNil() {
return fmt.Errorf("cannot unpack nil %s", v.Type().String())
}
return unpackValue(buf, v.Elem())
case reflect.Struct:
for i := 0; i < v.NumField(); i++ {
f := v.Field(i)
if err := unpackValue(buf, f); err != nil {
return err
}
}
return nil
default:
// binary.Read can only set pointer values, so we need to take the address.
if !v.CanAddr() {
return fmt.Errorf("cannot unpack unaddressable leaf type %q", v.Type().String())
}
return binary.Read(buf, binary.BigEndian, v.Addr().Interface())
}
}
// UnpackBuf recursively unpacks types from a reader just as encoding/binary
// does under binary.BigEndian, but with one difference: it unpacks a byte
// slice by first reading an integer with lengthPrefixSize bytes, then reading
// that many bytes. It assumes that incoming values are pointers to values so
// that, e.g., underlying slices can be resized as needed.
func UnpackBuf(buf io.Reader, elts ...interface{}) error {
for _, e := range elts {
v := reflect.ValueOf(e)
if v.Kind() != reflect.Ptr {
return fmt.Errorf("non-pointer value %q passed to UnpackBuf", v.Type().String())
}
if v.IsNil() {
return errors.New("nil pointer passed to UnpackBuf")
}
if err := unpackValue(buf, v); err != nil {
return err
}
}
return nil
}

10
vendor/github.com/google/go-tpm/tpmutil/poll_other.go generated vendored Normal file
View File

@@ -0,0 +1,10 @@
//go:build !linux && !darwin
package tpmutil
import (
"os"
)
// Not implemented on Windows.
func poll(_ *os.File) error { return nil }

32
vendor/github.com/google/go-tpm/tpmutil/poll_unix.go generated vendored Normal file
View File

@@ -0,0 +1,32 @@
//go:build linux || darwin
package tpmutil
import (
"fmt"
"os"
"golang.org/x/sys/unix"
)
// poll blocks until the file descriptor is ready for reading or an error occurs.
func poll(f *os.File) error {
var (
fds = []unix.PollFd{{
Fd: int32(f.Fd()),
Events: 0x1, // POLLIN
}}
timeout = -1 // Indefinite timeout
)
if _, err := unix.Poll(fds, timeout); err != nil {
return err
}
// Revents is filled in by the kernel.
// If the expected event happened, Revents should match Events.
if fds[0].Revents != fds[0].Events {
return fmt.Errorf("unexpected poll Revents 0x%x", fds[0].Revents)
}
return nil
}

113
vendor/github.com/google/go-tpm/tpmutil/run.go generated vendored Normal file
View File

@@ -0,0 +1,113 @@
// Copyright (c) 2018, Google LLC All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package tpmutil provides common utility functions for both TPM 1.2 and TPM
// 2.0 devices.
package tpmutil
import (
"errors"
"io"
"os"
"time"
)
// maxTPMResponse is the largest possible response from the TPM. We need to know
// this because we don't always know the length of the TPM response, and
// /dev/tpm insists on giving it all back in a single value rather than
// returning a header and a body in separate responses.
const maxTPMResponse = 4096
// RunCommandRaw executes the given raw command and returns the raw response.
// Does not check the response code except to execute retry logic.
func RunCommandRaw(rw io.ReadWriter, inb []byte) ([]byte, error) {
if rw == nil {
return nil, errors.New("nil TPM handle")
}
// f(t) = (2^t)ms, up to 2s
var backoffFac uint
var rh responseHeader
var outb []byte
for {
if _, err := rw.Write(inb); err != nil {
return nil, err
}
// If the TPM is a real device, it may not be ready for reading
// immediately after writing the command. Wait until the file
// descriptor is ready to be read from.
if f, ok := rw.(*os.File); ok {
if err := poll(f); err != nil {
return nil, err
}
}
outb = make([]byte, maxTPMResponse)
outlen, err := rw.Read(outb)
if err != nil {
return nil, err
}
// Resize the buffer to match the amount read from the TPM.
outb = outb[:outlen]
_, err = Unpack(outb, &rh)
if err != nil {
return nil, err
}
// If TPM is busy, retry the command after waiting a few ms.
if rh.Res == RCRetry {
if backoffFac < 11 {
dur := (1 << backoffFac) * time.Millisecond
time.Sleep(dur)
backoffFac++
} else {
return nil, err
}
} else {
break
}
}
return outb, nil
}
// RunCommand executes cmd with given tag and arguments. Returns TPM response
// body (without response header) and response code from the header. Returned
// error may be nil if response code is not RCSuccess; caller should check
// both.
func RunCommand(rw io.ReadWriter, tag Tag, cmd Command, in ...interface{}) ([]byte, ResponseCode, error) {
inb, err := packWithHeader(commandHeader{tag, 0, cmd}, in...)
if err != nil {
return nil, 0, err
}
outb, err := RunCommandRaw(rw, inb)
if err != nil {
return nil, 0, err
}
var rh responseHeader
read, err := Unpack(outb, &rh)
if err != nil {
return nil, 0, err
}
if rh.Res != RCSuccess {
return nil, rh.Res, nil
}
return outb[read:], rh.Res, nil
}

111
vendor/github.com/google/go-tpm/tpmutil/run_other.go generated vendored Normal file
View File

@@ -0,0 +1,111 @@
//go:build !windows
// Copyright (c) 2018, Google LLC All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package tpmutil
import (
"fmt"
"io"
"net"
"os"
)
// OpenTPM opens a channel to the TPM at the given path. If the file is a
// device, then it treats it like a normal TPM device, and if the file is a
// Unix domain socket, then it opens a connection to the socket.
func OpenTPM(path string) (io.ReadWriteCloser, error) {
// If it's a regular file, then open it
var rwc io.ReadWriteCloser
fi, err := os.Stat(path)
if err != nil {
return nil, err
}
if fi.Mode()&os.ModeDevice != 0 {
var f *os.File
f, err = os.OpenFile(path, os.O_RDWR, 0600)
if err != nil {
return nil, err
}
rwc = io.ReadWriteCloser(f)
} else if fi.Mode()&os.ModeSocket != 0 {
rwc = NewEmulatorReadWriteCloser(path)
} else {
return nil, fmt.Errorf("unsupported TPM file mode %s", fi.Mode().String())
}
return rwc, nil
}
// dialer abstracts the net.Dial call so test code can provide its own net.Conn
// implementation.
type dialer func(network, path string) (net.Conn, error)
// EmulatorReadWriteCloser manages connections with a TPM emulator over a Unix
// domain socket. These emulators often operate in a write/read/disconnect
// sequence, so the Write method always connects, and the Read method always
// closes. EmulatorReadWriteCloser is not thread safe.
type EmulatorReadWriteCloser struct {
path string
conn net.Conn
dialer dialer
}
// NewEmulatorReadWriteCloser stores information about a Unix domain socket to
// write to and read from.
func NewEmulatorReadWriteCloser(path string) *EmulatorReadWriteCloser {
return &EmulatorReadWriteCloser{
path: path,
dialer: net.Dial,
}
}
// Read implements io.Reader by reading from the Unix domain socket and closing
// it.
func (erw *EmulatorReadWriteCloser) Read(p []byte) (int, error) {
// Read is always the second operation in a Write/Read sequence.
if erw.conn == nil {
return 0, fmt.Errorf("must call Write then Read in an alternating sequence")
}
n, err := erw.conn.Read(p)
erw.conn.Close()
erw.conn = nil
return n, err
}
// Write implements io.Writer by connecting to the Unix domain socket and
// writing.
func (erw *EmulatorReadWriteCloser) Write(p []byte) (int, error) {
if erw.conn != nil {
return 0, fmt.Errorf("must call Write then Read in an alternating sequence")
}
var err error
erw.conn, err = erw.dialer("unix", erw.path)
if err != nil {
return 0, err
}
return erw.conn.Write(p)
}
// Close implements io.Closer by closing the Unix domain socket if one is open.
func (erw *EmulatorReadWriteCloser) Close() error {
if erw.conn == nil {
return fmt.Errorf("cannot call Close when no connection is open")
}
err := erw.conn.Close()
erw.conn = nil
return err
}

84
vendor/github.com/google/go-tpm/tpmutil/run_windows.go generated vendored Normal file
View File

@@ -0,0 +1,84 @@
// Copyright (c) 2018, Google LLC All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package tpmutil
import (
"io"
"github.com/google/go-tpm/tpmutil/tbs"
)
// winTPMBuffer is a ReadWriteCloser to access the TPM in Windows.
type winTPMBuffer struct {
context tbs.Context
outBuffer []byte
}
// Executes the TPM command specified by commandBuffer (at Normal Priority), returning the number
// of bytes in the command and any error code returned by executing the TPM command. Command
// response can be read by calling Read().
func (rwc *winTPMBuffer) Write(commandBuffer []byte) (int, error) {
// TPM spec defines longest possible response to be maxTPMResponse.
rwc.outBuffer = rwc.outBuffer[:maxTPMResponse]
outBufferLen, err := rwc.context.SubmitCommand(
tbs.NormalPriority,
commandBuffer,
rwc.outBuffer,
)
if err != nil {
rwc.outBuffer = rwc.outBuffer[:0]
return 0, err
}
// Shrink outBuffer so it is length of response.
rwc.outBuffer = rwc.outBuffer[:outBufferLen]
return len(commandBuffer), nil
}
// Provides TPM response from the command called in the last Write call.
func (rwc *winTPMBuffer) Read(responseBuffer []byte) (int, error) {
if len(rwc.outBuffer) == 0 {
return 0, io.EOF
}
lenCopied := copy(responseBuffer, rwc.outBuffer)
// Cut out the piece of slice which was just read out, maintaining original slice capacity.
rwc.outBuffer = append(rwc.outBuffer[:0], rwc.outBuffer[lenCopied:]...)
return lenCopied, nil
}
func (rwc *winTPMBuffer) Close() error {
return rwc.context.Close()
}
// OpenTPM creates a new instance of a ReadWriteCloser which can interact with a
// Windows TPM.
func OpenTPM() (io.ReadWriteCloser, error) {
tpmContext, err := tbs.CreateContext(tbs.TPMVersion20, tbs.IncludeTPM12|tbs.IncludeTPM20)
rwc := &winTPMBuffer{
context: tpmContext,
outBuffer: make([]byte, 0, maxTPMResponse),
}
return rwc, err
}
// FromContext creates a new instance of a ReadWriteCloser which can
// interact with a Windows TPM, using the specified TBS handle.
func FromContext(ctx tbs.Context) io.ReadWriteCloser {
return &winTPMBuffer{
context: ctx,
outBuffer: make([]byte, 0, maxTPMResponse),
}
}

195
vendor/github.com/google/go-tpm/tpmutil/structures.go generated vendored Normal file
View File

@@ -0,0 +1,195 @@
// Copyright (c) 2018, Google LLC All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package tpmutil
import (
"bytes"
"encoding/binary"
"fmt"
"io"
)
// maxBytesBufferSize sets a sane upper bound on the size of a U32Bytes
// buffer. This limit exists to prevent a maliciously large size prefix
// from resulting in a massive memory allocation, potentially causing
// an OOM condition on the system.
// We expect no buffer from a TPM to approach 1Mb in size.
const maxBytesBufferSize uint32 = 1024 * 1024 // 1Mb.
// RawBytes is for Pack and RunCommand arguments that are already encoded.
// Compared to []byte, RawBytes will not be prepended with slice length during
// encoding.
type RawBytes []byte
// U16Bytes is a byte slice with a 16-bit header
type U16Bytes []byte
// TPMMarshal packs U16Bytes
func (b *U16Bytes) TPMMarshal(out io.Writer) error {
size := len([]byte(*b))
if err := binary.Write(out, binary.BigEndian, uint16(size)); err != nil {
return err
}
n, err := out.Write(*b)
if err != nil {
return err
}
if n != size {
return fmt.Errorf("unable to write all contents of U16Bytes")
}
return nil
}
// TPMUnmarshal unpacks a U16Bytes
func (b *U16Bytes) TPMUnmarshal(in io.Reader) error {
var tmpSize uint16
if err := binary.Read(in, binary.BigEndian, &tmpSize); err != nil {
return err
}
size := int(tmpSize)
if len(*b) >= size {
*b = (*b)[:size]
} else {
*b = append(*b, make([]byte, size-len(*b))...)
}
n, err := in.Read(*b)
if err != nil {
return err
}
if n != size {
return io.ErrUnexpectedEOF
}
return nil
}
// U32Bytes is a byte slice with a 32-bit header
type U32Bytes []byte
// TPMMarshal packs U32Bytes
func (b *U32Bytes) TPMMarshal(out io.Writer) error {
size := len([]byte(*b))
if err := binary.Write(out, binary.BigEndian, uint32(size)); err != nil {
return err
}
n, err := out.Write(*b)
if err != nil {
return err
}
if n != size {
return fmt.Errorf("unable to write all contents of U32Bytes")
}
return nil
}
// TPMUnmarshal unpacks a U32Bytes
func (b *U32Bytes) TPMUnmarshal(in io.Reader) error {
var tmpSize uint32
if err := binary.Read(in, binary.BigEndian, &tmpSize); err != nil {
return err
}
if tmpSize > maxBytesBufferSize {
return bytes.ErrTooLarge
}
// We can now safely cast to an int on 32-bit or 64-bit machines
size := int(tmpSize)
if len(*b) >= size {
*b = (*b)[:size]
} else {
*b = append(*b, make([]byte, size-len(*b))...)
}
n, err := in.Read(*b)
if err != nil {
return err
}
if n != size {
return fmt.Errorf("unable to read all contents in to U32Bytes")
}
return nil
}
// Tag is a command tag.
type Tag uint16
// Command is an identifier of a TPM command.
type Command uint32
// A commandHeader is the header for a TPM command.
type commandHeader struct {
Tag Tag
Size uint32
Cmd Command
}
// ResponseCode is a response code returned by TPM.
type ResponseCode uint32
// RCSuccess is response code for successful command. Identical for TPM 1.2 and
// 2.0.
const RCSuccess ResponseCode = 0x000
// RCRetry is response code for TPM is busy.
const RCRetry ResponseCode = 0x922
// A responseHeader is a header for TPM responses.
type responseHeader struct {
Tag Tag
Size uint32
Res ResponseCode
}
// A Handle is a reference to a TPM object.
type Handle uint32
// HandleValue returns the handle value. This behavior is intended to satisfy
// an interface that can be implemented by other, more complex types as well.
func (h Handle) HandleValue() uint32 {
return uint32(h)
}
type handleList []Handle
func (l *handleList) TPMMarshal(_ io.Writer) error {
return fmt.Errorf("TPMMarhsal on []Handle is not supported yet")
}
func (l *handleList) TPMUnmarshal(in io.Reader) error {
var numHandles uint16
if err := binary.Read(in, binary.BigEndian, &numHandles); err != nil {
return err
}
// Make len(e) match size exactly.
size := int(numHandles)
if len(*l) >= size {
*l = (*l)[:size]
} else {
*l = append(*l, make([]Handle, size-len(*l))...)
}
return binary.Read(in, binary.BigEndian, *l)
}
// SelfMarshaler allows custom types to override default encoding/decoding
// behavior in Pack, Unpack and UnpackBuf.
type SelfMarshaler interface {
TPMMarshal(out io.Writer) error
TPMUnmarshal(in io.Reader) error
}

View File

@@ -0,0 +1,267 @@
// Copyright (c) 2018, Google LLC All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package tbs provides an low-level interface directly mapping to Windows
// Tbs.dll system library commands:
// https://docs.microsoft.com/en-us/windows/desktop/TBS/tpm-base-services-portal
// Public field descriptions contain links to the high-level Windows documentation.
package tbs
import (
"fmt"
"syscall"
"unsafe"
)
// Context references the current TPM context
type Context uintptr
// Version of TPM being used by the application.
type Version uint32
// Flag indicates TPM versions that are supported by the application.
type Flag uint32
// CommandPriority is used to determine which pending command to submit whenever the TPM is free.
type CommandPriority uint32
// Command parameters:
// https://github.com/tpn/winsdk-10/blob/master/Include/10.0.10240.0/shared/tbs.h
const (
// https://docs.microsoft.com/en-us/windows/desktop/api/Tbs/ns-tbs-tdtbs_context_params2
// OR flags to use multiple.
RequestRaw Flag = 1 << iota // Add flag to request raw context
IncludeTPM12 // Add flag to support TPM 1.2
IncludeTPM20 // Add flag to support TPM 2
TPMVersion12 Version = 1 // For TPM 1.2 applications
TPMVersion20 Version = 2 // For TPM 2 applications or applications using multiple TPM versions
// https://docs.microsoft.com/en-us/windows/desktop/tbs/command-scheduling
// https://docs.microsoft.com/en-us/windows/desktop/api/Tbs/nf-tbs-tbsip_submit_command#parameters
LowPriority CommandPriority = 100 // For low priority application use
NormalPriority CommandPriority = 200 // For normal priority application use
HighPriority CommandPriority = 300 // For high priority application use
SystemPriority CommandPriority = 400 // For system tasks that access the TPM
commandLocalityZero uint32 = 0 // Windows currently only supports TBS_COMMAND_LOCALITY_ZERO.
)
// Error is the return type of all functions in this package.
type Error uint32
func (err Error) Error() string {
if description, ok := errorDescriptions[err]; ok {
return fmt.Sprintf("TBS Error 0x%X: %s", uint32(err), description)
}
return fmt.Sprintf("Unrecognized TBS Error 0x%X", uint32(err))
}
func getError(err uintptr) error {
// tbs.dll uses 0x0 as the return value for success.
if err == 0 {
return nil
}
return Error(err)
}
// TBS Return Codes:
// https://docs.microsoft.com/en-us/windows/desktop/TBS/tbs-return-codes
const (
ErrInternalError Error = 0x80284001
ErrBadParameter Error = 0x80284002
ErrInvalidOutputPointer Error = 0x80284003
ErrInvalidContext Error = 0x80284004
ErrInsufficientBuffer Error = 0x80284005
ErrIOError Error = 0x80284006
ErrInvalidContextParam Error = 0x80284007
ErrServiceNotRunning Error = 0x80284008
ErrTooManyTBSContexts Error = 0x80284009
ErrTooManyResources Error = 0x8028400A
ErrServiceStartPending Error = 0x8028400B
ErrPPINotSupported Error = 0x8028400C
ErrCommandCanceled Error = 0x8028400D
ErrBufferTooLarge Error = 0x8028400E
ErrTPMNotFound Error = 0x8028400F
ErrServiceDisabled Error = 0x80284010
ErrNoEventLog Error = 0x80284011
ErrAccessDenied Error = 0x80284012
ErrProvisioningNotAllowed Error = 0x80284013
ErrPPIFunctionUnsupported Error = 0x80284014
ErrOwnerauthNotFound Error = 0x80284015
)
var errorDescriptions = map[Error]string{
ErrInternalError: "An internal software error occurred.",
ErrBadParameter: "One or more parameter values are not valid.",
ErrInvalidOutputPointer: "A specified output pointer is bad.",
ErrInvalidContext: "The specified context handle does not refer to a valid context.",
ErrInsufficientBuffer: "The specified output buffer is too small.",
ErrIOError: "An error occurred while communicating with the TPM.",
ErrInvalidContextParam: "A context parameter that is not valid was passed when attempting to create a TBS context.",
ErrServiceNotRunning: "The TBS service is not running and could not be started.",
ErrTooManyTBSContexts: "A new context could not be created because there are too many open contexts.",
ErrTooManyResources: "A new virtual resource could not be created because there are too many open virtual resources.",
ErrServiceStartPending: "The TBS service has been started but is not yet running.",
ErrPPINotSupported: "The physical presence interface is not supported.",
ErrCommandCanceled: "The command was canceled.",
ErrBufferTooLarge: "The input or output buffer is too large.",
ErrTPMNotFound: "A compatible Trusted Platform Module (TPM) Security Device cannot be found on this computer.",
ErrServiceDisabled: "The TBS service has been disabled.",
ErrNoEventLog: "The TBS event log is not available.",
ErrAccessDenied: "The caller does not have the appropriate rights to perform the requested operation.",
ErrProvisioningNotAllowed: "The TPM provisioning action is not allowed by the specified flags.",
ErrPPIFunctionUnsupported: "The Physical Presence Interface of this firmware does not support the requested method.",
ErrOwnerauthNotFound: "The requested TPM OwnerAuth value was not found.",
}
// Tbs.dll provides an API for making calls to the TPM:
// https://docs.microsoft.com/en-us/windows/desktop/TBS/tpm-base-services-portal
var (
tbsDLL = syscall.NewLazyDLL("Tbs.dll")
tbsGetDeviceInfo = tbsDLL.NewProc("Tbsi_GetDeviceInfo")
tbsCreateContext = tbsDLL.NewProc("Tbsi_Context_Create")
tbsContextClose = tbsDLL.NewProc("Tbsip_Context_Close")
tbsSubmitCommand = tbsDLL.NewProc("Tbsip_Submit_Command")
tbsGetTCGLog = tbsDLL.NewProc("Tbsi_Get_TCG_Log")
)
// Returns the address of the beginning of a slice or 0 for a nil slice.
func sliceAddress(s []byte) uintptr {
if len(s) == 0 {
return 0
}
return uintptr(unsafe.Pointer(&(s[0])))
}
// DeviceInfo is TPM_DEVICE_INFO from tbs.h
type DeviceInfo struct {
StructVersion uint32
TPMVersion Version
TPMInterfaceType uint32
TPMImpRevision uint32
}
// GetDeviceInfo gets the DeviceInfo of the current TPM:
// https://docs.microsoft.com/en-us/windows/win32/api/tbs/nf-tbs-tbsi_getdeviceinfo
func GetDeviceInfo() (*DeviceInfo, error) {
info := DeviceInfo{}
// TBS_RESULT Tbsi_GetDeviceInfo(
// UINT32 Size,
// PVOID Info
// );
if err := tbsGetDeviceInfo.Find(); err != nil {
return nil, err
}
result, _, _ := tbsGetDeviceInfo.Call(
unsafe.Sizeof(info),
uintptr(unsafe.Pointer(&info)),
)
return &info, getError(result)
}
// CreateContext creates a new TPM context:
// https://docs.microsoft.com/en-us/windows/desktop/api/Tbs/nf-tbs-tbsi_context_create
func CreateContext(version Version, flag Flag) (Context, error) {
var context Context
params := struct {
Version
Flag
}{version, flag}
// TBS_RESULT Tbsi_Context_Create(
// _In_ PCTBS_CONTEXT_PARAMS pContextParams,
// _Out_ PTBS_HCONTEXT *phContext
// );
if err := tbsCreateContext.Find(); err != nil {
return context, err
}
result, _, _ := tbsCreateContext.Call(
uintptr(unsafe.Pointer(&params)),
uintptr(unsafe.Pointer(&context)),
)
return context, getError(result)
}
// Close closes an existing TPM context:
// https://docs.microsoft.com/en-us/windows/desktop/api/Tbs/nf-tbs-tbsip_context_close
func (context Context) Close() error {
// TBS_RESULT Tbsip_Context_Close(
// _In_ TBS_HCONTEXT hContext
// );
if err := tbsContextClose.Find(); err != nil {
return err
}
result, _, _ := tbsContextClose.Call(uintptr(context))
return getError(result)
}
// SubmitCommand sends commandBuffer to the TPM, returning the number of bytes
// written to responseBuffer. ErrInsufficientBuffer is returned if the
// responseBuffer is too short. ErrInvalidOutputPointer is returned if the
// responseBuffer is nil. On failure, the returned length is unspecified.
// https://docs.microsoft.com/en-us/windows/desktop/api/Tbs/nf-tbs-tbsip_submit_command
func (context Context) SubmitCommand(
priority CommandPriority,
commandBuffer []byte,
responseBuffer []byte,
) (uint32, error) {
responseBufferLen := uint32(len(responseBuffer))
// TBS_RESULT Tbsip_Submit_Command(
// _In_ TBS_HCONTEXT hContext,
// _In_ TBS_COMMAND_LOCALITY Locality,
// _In_ TBS_COMMAND_PRIORITY Priority,
// _In_ const PCBYTE *pabCommand,
// _In_ UINT32 cbCommand,
// _Out_ PBYTE *pabResult,
// _Inout_ UINT32 *pcbOutput
// );
if err := tbsSubmitCommand.Find(); err != nil {
return 0, err
}
result, _, _ := tbsSubmitCommand.Call(
uintptr(context),
uintptr(commandLocalityZero),
uintptr(priority),
sliceAddress(commandBuffer),
uintptr(len(commandBuffer)),
sliceAddress(responseBuffer),
uintptr(unsafe.Pointer(&responseBufferLen)),
)
return responseBufferLen, getError(result)
}
// GetTCGLog gets the system event log, returning the number of bytes written
// to logBuffer. If logBuffer is nil, the size of the TCG log is returned.
// ErrInsufficientBuffer is returned if the logBuffer is too short. On failure,
// the returned length is unspecified.
// https://docs.microsoft.com/en-us/windows/desktop/api/Tbs/nf-tbs-tbsi_get_tcg_log
func (context Context) GetTCGLog(logBuffer []byte) (uint32, error) {
logBufferLen := uint32(len(logBuffer))
// TBS_RESULT Tbsi_Get_TCG_Log(
// TBS_HCONTEXT hContext,
// PBYTE pOutputBuf,
// PUINT32 pOutputBufLen
// );
if err := tbsGetTCGLog.Find(); err != nil {
return 0, err
}
result, _, _ := tbsGetTCGLog.Call(
uintptr(context),
sliceAddress(logBuffer),
uintptr(unsafe.Pointer(&logBufferLen)),
)
return logBufferLen, getError(result)
}