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

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()
}