Documentation
¶
Overview ¶
Package tpm2 is the transport-agnostic, pure-Go TPM 2.0 command API. It sits one layer above github.com/go-tpm2/common: common owns the big-endian wire codec and the Transport contract, and this package turns that codec into typed TPM 2.0 commands.
A TPM value wraps a common.Transport. Each command method marshals its parameters (with common.BuildCommand and the appropriate TPM_ST tag and TPM_CC code), hands the buffer to Transport.Send, parses the reply with common.ParseResponse, checks the response code, and unmarshals the response parameters. A non-success response code is surfaced as a typed *TPMError carrying both the raw rc and the command code it came from.
All multi-byte fields are encoded big-endian, as the TPM 2.0 wire format mandates (TCG "TPM 2.0 Part 1: Architecture", "Data Marshaling").
This covers the measured-boot milestones: the starter set (Startup, Shutdown, SelfTest, GetRandom, GetCapability, PCR_Read, PCR_Extend); the attestation flow (CreatePrimary, Quote, VerifyQuote); the PCR-sealing payoff (CreateStoragePrimary, Create, Load, StartAuthSession, PolicyPCR, PolicyGetDigest, Unseal, plus the offline PolicyPCRDigest computation and the SealToPCR/UnsealWithPCR helpers — see seal.go); NV storage (NVDefineSpace, NVWrite, NVRead, NVReadPublic, NVUndefineSpace — see nv.go); typed GetCapability decoders (GetPCRBanks, GetTPMProperties, GetManufacturer, GetAlgorithms, GetHandles — see capability.go); the Endorsement Key (CreateEK, the EK Credential Profile ECC-P256 L-2 template — see ek.go); and Credential Protection / credential activation — the identity step of remote attestation that binds an Attestation Key to a TPM's Endorsement Key. That last flow is the off-TPM verifier side MakeCredential (ECDH + KDFe + KDFa + AES-CFB + HMAC, see makecred.go and the KDFa/KDFe helpers in kdf.go), the object Name it commits to (ObjectName, see name.go), and the attesting side TPM2_ActivateCredential with its dual-session authorization plus TPM2_PolicySecret to satisfy the EK policy, tied together by ActivateAKWithEK (see activate.go). Each method cites the relevant clause of TCG "TPM 2.0 Part 3: Commands" (with structure shapes from "Part 2: Structures", the policy digest / authorization rules from "Part 1: Architecture", and the EK template from the TCG "EK Credential Profile for TPM Family 2.0").
Conventions: pure Go, CGO_ENABLED=0, no architecture-specific assembly, BSD-3-Clause on every file, 100% statement coverage, and GOWORK=off (the module is not part of any workspace).
Index ¶
- Constants
- func KDFa(key []byte, label string, contextU, contextV []byte, bits int) []byte
- func KDFe(z []byte, label string, partyU, partyV []byte, bits int) []byte
- func ObjectName(publicArea []byte) ([]byte, error)
- func PolicyPCRDigest(sel []PCRSelection, pcrValues [][]byte) []byte
- type AKPublic
- type AlgProperty
- type AttestInfo
- type ECCPublic
- type ECDSASignature
- type EKPublic
- type MakeCredentialResult
- type NVPublic
- type PCRSelection
- type QuoteInfo
- type TPM
- func (tpm *TPM) ActivateAKWithEK(ak, ek uint32, akPublic, ekPublic, credential, nonceCaller []byte) ([]byte, error)
- func (tpm *TPM) ActivateCredential(activateHandle, keyHandle, policySession uint32, credentialBlob, secret []byte) ([]byte, error)
- func (tpm *TPM) Create(parent uint32, secret, policyDigest []byte) (priv, pub []byte, err error)
- func (tpm *TPM) CreateEK() (ekHandle uint32, pub EKPublic, err error)
- func (tpm *TPM) CreatePrimary() (akHandle uint32, pub AKPublic, err error)
- func (tpm *TPM) CreatePrimaryPublic() (akHandle uint32, outPublic []byte, err error)
- func (tpm *TPM) CreateStoragePrimary() (handle uint32, err error)
- func (tpm *TPM) CreateStoragePrimaryPub() (handle uint32, pub ECCPublic, err error)
- func (tpm *TPM) GetAlgorithms(firstAlg, count uint32) ([]AlgProperty, error)
- func (tpm *TPM) GetCapability(cap, prop, count uint32) (more bool, data []byte, err error)
- func (tpm *TPM) GetHandles(firstHandle, count uint32) ([]uint32, error)
- func (tpm *TPM) GetManufacturer() (uint32, error)
- func (tpm *TPM) GetPCRBanks() ([]PCRSelection, error)
- func (tpm *TPM) GetRandom(n uint16) ([]byte, error)
- func (tpm *TPM) GetTPMProperties(firstProp, count uint32) ([]TaggedProperty, error)
- func (tpm *TPM) Import(parent uint32, objectPublic, duplicate, inSymSeed []byte) (outPrivate []byte, err error)
- func (tpm *TPM) ImportAndUnseal(parent uint32, objectPublic, duplicate, inSymSeed []byte, sel []PCRSelection, ...) ([]byte, error)
- func (tpm *TPM) Load(parent uint32, priv, pub []byte) (handle uint32, err error)
- func (tpm *TPM) NVDefineSpace(pub NVPublic) error
- func (tpm *TPM) NVRead(nvIndex uint32, size, offset uint16) ([]byte, error)
- func (tpm *TPM) NVReadPublic(nvIndex uint32) (NVPublic, []byte, error)
- func (tpm *TPM) NVUndefineSpace(nvIndex uint32) error
- func (tpm *TPM) NVWrite(nvIndex uint32, data []byte, offset uint16) error
- func (tpm *TPM) PCRExtend(pcr int, hash uint16, digest []byte) error
- func (tpm *TPM) PCRRead(sel []PCRSelection) (updateCounter uint32, digests [][]byte, err error)
- func (tpm *TPM) PolicyGetDigest(session uint32) ([]byte, error)
- func (tpm *TPM) PolicyPCR(session uint32, sel []PCRSelection) error
- func (tpm *TPM) PolicySecret(authHandle, policySession uint32) error
- func (tpm *TPM) Quote(keyHandle uint32, qualifyingData []byte, sel []PCRSelection) (quoted []byte, sig ECDSASignature, err error)
- func (tpm *TPM) SealToPCR(parent uint32, secret []byte, sel []PCRSelection, pcrValues [][]byte) (priv, pub, policyDigest []byte, err error)
- func (tpm *TPM) SelfTest(full bool) error
- func (tpm *TPM) Shutdown(su uint16) error
- func (tpm *TPM) StartAuthSession(nonceCaller []byte) (sessionHandle uint32, nonceTPM []byte, err error)
- func (tpm *TPM) Startup(su uint16) error
- func (tpm *TPM) Unseal(item, session uint32) ([]byte, error)
- func (tpm *TPM) UnsealWithPCR(parent uint32, priv, pub []byte, sel []PCRSelection, nonceCaller []byte) ([]byte, error)
- type TPMError
- type TaggedProperty
- type WrapToPCRResult
Constants ¶
const ( // AlgRSA is TPM_ALG_RSA (an object/asymmetric algorithm). Unused by the // ECC AK flow but listed for completeness of the registry transcription. AlgRSA uint16 = 0x0001 // AlgECDSA is TPM_ALG_ECDSA, the ECC signing scheme used by the AK. AlgECDSA uint16 = 0x0018 // AlgECC is TPM_ALG_ECC, the object type of an ECC key. AlgECC uint16 = 0x0023 )
Algorithm identifiers used by the attestation flow that are not already in common's starter set. Values are TPM_ALG_ID per TCG "TPM 2.0 Part 2: Structures", clause "TPM_ALG_ID", as registered in the TCG "Algorithm Registry" (the "Part 4" algorithm IDs). They are encoded big-endian as UINT16 on the wire.
const ( // PTFixed is PT_FIXED, the group base; it is also the property value to // start a fixed-property enumeration from. PTFixed uint32 = 0x00000100 // PTManufacturer is TPM_PT_MANUFACTURER (PT_FIXED + 5): the four-character // vendor identifier (e.g. "IBM" for swtpm) packed big-endian into a UINT32. PTManufacturer uint32 = PTFixed + 5 )
TPM_PT property tags within TPM_CAP_TPM_PROPERTIES. TCG "TPM 2.0 Part 2: Structures", clause "TPM_PT". PTFixed (0x100) is the base of the fixed (manufacturer/firmware) property group.
const ( // NVOwnerWrite (bit 1): owner authorization may write the index. NVOwnerWrite uint32 = 1 << 1 // NVAuthWrite (bit 2): the index's authValue may authorize a write. NVAuthWrite uint32 = 1 << 2 // NVOwnerRead (bit 17): owner authorization may read the index. NVOwnerRead uint32 = 1 << 17 // NVAuthRead (bit 18): the index's authValue may authorize a read. NVAuthRead uint32 = 1 << 18 )
TPMA_NV attribute bits. TPMA_NV is a UINT32 bit field (encoded big-endian). TCG "TPM 2.0 Part 2: Structures", clause "TPMA_NV". The four bits below are the read/write controls an owner-authorized ordinary index sets: the index may be written/read either by presenting owner authorization (OWNERWRITE / OWNERREAD) or by presenting the index's own authValue (AUTHWRITE / AUTHREAD).
const ( // ErrBadMagic is returned when a TPMS_ATTEST does not begin with // TPM_GENERATED_VALUE (0xFF544347). ErrBadMagic = common.Error("tpm2: attest magic is not TPM_GENERATED_VALUE") // ErrNotQuote is returned when a TPMS_ATTEST is not a TPM_ST_ATTEST_QUOTE. ErrNotQuote = common.Error("tpm2: attest type is not TPM_ST_ATTEST_QUOTE") // ErrSigInvalid is returned when the ECDSA signature over the attest does // not verify against the AK public key. ErrSigInvalid = common.Error("tpm2: ECDSA signature does not verify") // ErrPCRDigestMismatch is returned when the quoted pcrDigest does not // equal the SHA-256 of the concatenated expected PCR values. ErrPCRDigestMismatch = common.Error("tpm2: quoted pcrDigest != recomputed PCR digest") )
Attestation/verification error sentinels (typed and constant for ==).
const ( // ECCNistP256 is TPM_ECC_NIST_P256, the NIST P-256 (secp256r1) curve. ECCNistP256 uint16 = 0x0003 )
TPM_ECC_CURVE identifiers. TCG "TPM 2.0 Part 2: Structures", clause "TPM_ECC_CURVE"; the registered curve values are in the TCG "Algorithm Registry". Encoded big-endian as UINT16.
const ErrEKPointNotOnCurve = common.Error("tpm2: EK public point is not on the P-256 curve")
ErrEKPointNotOnCurve is returned by MakeCredential when the supplied EK public point does not lie on NIST P-256 (a malformed or wrong EK public).
const ErrPropertyNotFound = common.Error("tpm2: requested TPM property not found")
ErrPropertyNotFound is returned when a requested TPM_PT property is absent from the TPM's reply.
const ErrSRKPointNotOnCurve = common.Error("tpm2: SRK public point is not on the P-256 curve")
ErrSRKPointNotOnCurve is returned by WrapToPCR when the supplied storage-key public point does not lie on NIST P-256 (a malformed or wrong SRK public).
const ErrUnexpectedCapability = common.Error("tpm2: unexpected capability in response")
ErrUnexpectedCapability is returned when the TPM echoes a capability selector in TPMS_CAPABILITY_DATA other than the one requested.
const ErrUnexpectedSigAlg = common.Error("tpm2: unexpected signature algorithm (want ECDSA)")
ErrUnexpectedSigAlg is returned when a TPMT_SIGNATURE carries a signature algorithm other than the ECDSA this package decodes.
const ErrUnsupportedNameAlg = common.Error("tpm2: unsupported nameAlg for ObjectName (want SHA-256)")
ErrUnsupportedNameAlg is returned by ObjectName when the public area's nameAlg is not one this package can compute a Name for (only SHA-256 is supported, matching the AK/EK templates).
const RHEndorsement uint32 = 0x4000000B
RHEndorsement is TPM_RH_ENDORSEMENT, the endorsement hierarchy permanent handle under which the EK primary is created. TCG "TPM 2.0 Part 2: Structures", clause "TPM_RH (Permanent Handles)".
const RHOwner uint32 = 0x40000001
RHOwner is TPM_RH_OWNER (the storage/owner hierarchy permanent handle), the authHandle under which these NV operations are authorized. It mirrors common.RHOwner as a bare uint32 for this package's marshaling helpers. TCG "TPM 2.0 Part 2: Structures", clause "TPM_RH (Permanent Handles)".
const TPM_RS_PW uint32 = 0x40000009
TPM_RS_PW is the password-authorization session handle: the well-known handle that selects a cleartext-password authorization in a command's session area, in lieu of a real HMAC/policy session. TCG "TPM 2.0 Part 2: Structures", clause "TPM_RS (Reserved Handles)"; used by the password authorization described in "TPM 2.0 Part 1: Architecture", "Password Authorizations".
Variables ¶
This section is empty.
Functions ¶
func KDFa ¶ added in v0.5.0
KDFa implements the TPM 2.0 SP800-108 counter-mode HMAC KDF (KDFa) with SHA-256 as the hash. It derives `bits` bits of key material from `key`, bound to a textual `label` and a (contextU || contextV) context.
Per TCG "TPM 2.0 Part 1: Architecture", "Key Derivation Functions" (KDFa()):
KDFa(hashAlg, key, label, contextU, contextV, bits):
bytes = ceil(bits / 8)
for i = 1, 2, ... until `bytes` produced:
K_i = HMAC(key, BE32(i) || // the SP800-108 counter
label || 0x00 || // Label, NULL-terminated
contextU || // PartyUInfo
contextV || // PartyVInfo
BE32(bits)) // the requested bit length
result = (K_1 || K_2 || ...) truncated to `bytes`
When `bits` is not a whole number of bytes the leftmost `bits` bits are kept and the excess low-order bits of the last produced byte are masked to zero (TCG "Part 1": "the resulting string of bits is the least number of bytes ... the bits not used are zeroed"). For the 128- and 256-bit uses in Credential Protection `bits` is byte-aligned, but the masking is implemented for completeness/correctness.
func KDFe ¶ added in v0.5.0
KDFe implements the TPM 2.0 SP800-56A concatenation KDF (KDFe) with SHA-256 as the hash. It derives `bits` bits of shared key material from the ECDH shared secret `z` (the x-coordinate of the shared point), bound to a textual `label` and the two parties' contributions partyU and partyV.
Per TCG "TPM 2.0 Part 1: Architecture", "Key Derivation Functions" (KDFe()):
KDFe(hashAlg, Z, label, partyUInfo, partyVInfo, bits):
bytes = ceil(bits / 8)
for counter = 1, 2, ... until `bytes` produced:
K_i = H(BE32(counter) || // SP800-56A counter, starts at 1
Z || // the ECDH shared secret (point x)
label || 0x00 || // the NULL-terminated label
partyUInfo || // initiator contribution
partyVInfo) // responder contribution
result = (K_1 || K_2 || ...) truncated to `bytes`
For Credential Protection the seed is a single SHA-256 block (256 bits), so exactly one iteration runs; the loop and masking handle the general case.
func ObjectName ¶ added in v0.5.0
ObjectName computes the Name of an object from its public area (the TPMT_PUBLIC bytes, i.e. the CONTENTS of the TPM2B_PUBLIC, without the 2-byte size prefix). For an object whose nameAlg is a hash algorithm, the Name is:
Name = nameAlg (UINT16, big-endian) || H_nameAlg( TPMT_PUBLIC )
where the hash covers the entire marshaled TPMT_PUBLIC. The nameAlg is the second UINT16 of the public area (after the 2-byte `type`). This package supports the SHA-256 nameAlg used by the AK/EK templates; a public area with any other nameAlg is rejected. TCG "Part 1", "Names" (the Name of a loaded object); "Part 2", "TPMT_PUBLIC" (field order) and "TPM2B_NAME".
The returned Name is the bare (algorithm-id || digest) value — NOT wrapped in a TPM2B. Callers that need a TPM2B_NAME wrap it with common.MarshalTPM2B.
func PolicyPCRDigest ¶ added in v0.3.0
func PolicyPCRDigest(sel []PCRSelection, pcrValues [][]byte) []byte
PolicyPCRDigest computes, offline, the policyDigest that a TPM2_PolicyPCR over a SHA-256 policy session would accumulate for the given selection and PCR values. It is the value placed in the sealed object's authPolicy so the TPM will release the secret only to a session whose policyDigest matches.
Per TCG "TPM 2.0 Part 1: Architecture", clause "TPM2_PolicyPCR" / "Policy Digest" (the policy update rule), with SHA-256 as the session's authHash:
policyDigestStart = 0x00 * 32 (an all-zero digest)
pcrDigest = SHA256( value_0 || value_1 || ... ) over the
selected PCR values in selection order
policyDigest = SHA256( policyDigestStart
|| TPM_CC_PolicyPCR (0x0000017F, big-endian)
|| marshal(TPML_PCR_SELECTION pcrs)
|| pcrDigest )
The TPML_PCR_SELECTION marshaled into the hash is the SAME selection sent to TPM2_PolicyPCR. sel and pcrValues must be in corresponding order (the ascending order PCRRead returns). TCG "TPM 2.0 Part 1", "Policy PCR"; "Part 3", "TPM2_PolicyPCR".
Types ¶
type AKPublic ¶ added in v0.2.0
type AKPublic struct {
// X is the big-endian x coordinate of the public point.
X []byte
// Y is the big-endian y coordinate of the public point.
Y []byte
}
AKPublic is the parsed public part of an ECC Attestation Key: the affine coordinates of the public point on NIST P-256, big-endian. X and Y are the raw TPM2B contents of the TPMS_ECC_POINT in the key's TPMT_PUBLIC.unique field. TCG "TPM 2.0 Part 2: Structures", clauses "TPMS_ECC_POINT" and "TPMT_PUBLIC".
type AlgProperty ¶ added in v0.4.0
type AlgProperty struct {
// Alg is the TPM_ALG_ID.
Alg uint16
// Attributes is the TPMA_ALGORITHM bit field (asymmetric, symmetric,
// hash, object, signing, encrypting, method).
Attributes uint32
}
AlgProperty is one entry of a TPML_ALG_PROPERTY: an algorithm id and its TPMA_ALGORITHM attribute bits. TCG "TPM 2.0 Part 2: Structures", clause "TPMS_ALG_PROPERTY".
type AttestInfo ¶ added in v0.2.0
type AttestInfo struct {
// ExtraData echoes the caller's qualifyingData nonce (the TPM2B_DATA
// extraData field), so a verifier can bind the quote to its challenge.
ExtraData []byte
// Quote is the TPMS_QUOTE_INFO union member.
Quote QuoteInfo
}
AttestInfo is the parsed, attestation-relevant subset of a TPMS_ATTEST of type TPM_ST_ATTEST_QUOTE. TCG "TPM 2.0 Part 2: Structures", clause "TPMS_ATTEST".
func ParseAttest ¶ added in v0.2.0
func ParseAttest(data []byte) (AttestInfo, error)
ParseAttest decodes a TPMS_ATTEST of type TPM_ST_ATTEST_QUOTE from the raw TPM2B_ATTEST data (i.e. the bytes that were signed, NOT including the TPM2B size prefix). The fixed prefix is:
magic : UINT32 (must be 0xFF544347)
type : TPM_ST (UINT16; must be 0x8018 ATTEST_QUOTE)
qualifiedSigner : TPM2B_NAME
extraData : TPM2B_DATA
clockInfo : TPMS_CLOCK_INFO = clock:u64, resetCount:u32,
restartCount:u32, safe:u8 (17 bytes)
firmwareVersion : UINT64
attested : TPMS_QUOTE_INFO = TPML_PCR_SELECTION pcrSelect,
TPM2B_DIGEST pcrDigest
TCG "TPM 2.0 Part 2: Structures", clauses "TPMS_ATTEST", "TPMS_CLOCK_INFO", "TPMS_QUOTE_INFO".
func VerifyQuote ¶ added in v0.2.0
func VerifyQuote(akPub AKPublic, quoted []byte, sig ECDSASignature, expectedPCRs [][]byte) (AttestInfo, error)
VerifyQuote performs the full attestation check for an ECDSA-P256 AK:
- parse the TPMS_ATTEST from quoted (the TPM2B_ATTEST.data) and confirm it is a genuine TPM_GENERATED quote;
- verify the ECDSA signature (sig.R, sig.S) over SHA-256(quoted) using the AK public point (akPub.X, akPub.Y) on NIST P-256;
- recompute the PCR digest as SHA-256(expectedPCRs[0] || expectedPCRs[1] || ...) and confirm it equals the pcrDigest the TPM committed to.
expectedPCRs must be the selected PCR values, in the TPM's ascending selection order, exactly as PCRRead returns them. On success it returns the parsed AttestInfo (so callers can also check extraData against their nonce).
All cryptography is pure-Go (crypto/ecdsa + crypto/elliptic P-256), so the helper is usable from a tamago guest with CGO disabled.
type ECCPublic ¶ added in v0.6.0
type ECCPublic struct {
// X is the big-endian x coordinate of the storage key's public point.
X []byte
// Y is the big-endian y coordinate of the storage key's public point.
Y []byte
}
ECCPublic is an ECC P-256 public point (big-endian x, y) — the storage key's public the node exposes to the control plane. It is the same shape as EKPublic/AKPublic; a distinct name documents its role as the duplication PARENT public. TCG "TPM 2.0 Part 2: Structures", "TPMS_ECC_POINT".
type ECDSASignature ¶ added in v0.2.0
type ECDSASignature struct {
// R is the big-endian r component.
R []byte
// S is the big-endian s component.
S []byte
}
ECDSASignature is a parsed TPMS_SIGNATURE_ECDSA: the (r, s) pair as big-endian byte strings. TCG "TPM 2.0 Part 2: Structures", clause "TPMS_SIGNATURE_ECDSA".
type EKPublic ¶ added in v0.4.0
type EKPublic struct {
// X is the big-endian x coordinate of the public point.
X []byte
// Y is the big-endian y coordinate of the public point.
Y []byte
}
EKPublic is the parsed public point of the ECC Endorsement Key: the affine (x, y) coordinates on NIST P-256, big-endian, from the TPMS_ECC_POINT in the key's TPMT_PUBLIC.unique. TCG "TPM 2.0 Part 2: Structures", clauses "TPMS_ECC_POINT" and "TPMT_PUBLIC".
type MakeCredentialResult ¶ added in v0.5.0
type MakeCredentialResult struct {
// CredentialBlob is the TPM2B_ID_OBJECT { integrityHMAC || encIdentity }
// (the size-prefixed id-object), ready to pass as ActivateCredential's
// credentialBlob parameter.
CredentialBlob []byte
// Secret is the TPM2B_ENCRYPTED_SECRET carrying the ephemeral public point
// (TPMS_ECC_POINT), ready to pass as ActivateCredential's secret parameter.
Secret []byte
}
MakeCredentialResult is the output of MakeCredential: the two blobs a verifier hands to the attesting platform for TPM2_ActivateCredential.
func MakeCredential ¶ added in v0.5.0
func MakeCredential(ekPublic EKPublic, akName, credential []byte, rng io.Reader) (MakeCredentialResult, error)
MakeCredential performs the off-TPM verifier side of Credential Protection for an ECC P-256 Endorsement Key. ekPublic is the EK's public point, akName is the loaded AK's Name (from ObjectName), and credential is the secret challenge to bind (a TPM2B_DIGEST payload, at most 32 bytes for the SHA-256 scheme). It returns the credentialBlob and secret to feed to TPM2_ActivateCredential.
The ephemeral key is drawn from crypto/rand; rng may override the source for deterministic testing (pass nil for crypto/rand).
type NVPublic ¶ added in v0.4.0
type NVPublic struct {
// Index is the NV index handle (nvIndex), a handle in the 0x01xxxxxx
// (TPM_HT_NV_INDEX) range.
Index uint32
// NameAlg is the index's name algorithm (a TPM_ALG_ID).
NameAlg uint16
// Attributes is the TPMA_NV attribute bit field.
Attributes uint32
// AuthPolicy is the index's authorization policy digest (empty for an
// index with no policy).
AuthPolicy []byte
// DataSize is the size in bytes of the index's data area.
DataSize uint16
}
NVPublic is the parsed public area of an NV index: the typed form of the TPMS_NV_PUBLIC wire structure. TCG "TPM 2.0 Part 2: Structures", clause "TPMS_NV_PUBLIC".
type PCRSelection ¶
type PCRSelection struct {
// Hash is the bank's hash algorithm (a TPM_ALG_ID value, e.g.
// common.AlgSHA256).
Hash uint16
// PCRs is the list of PCR indices selected in this bank.
PCRs []int
}
PCRSelection names a set of PCRs within one PCR bank, identified by its hash algorithm. It is the typed form of the TPMS_PCR_SELECTION wire structure { hash, sizeofSelect, pcrSelect[] }. TCG "TPM 2.0 Part 2: Structures", clause "TPMS_PCR_SELECTION".
type QuoteInfo ¶ added in v0.2.0
type QuoteInfo struct {
// PCRSelect is the TPML_PCR_SELECTION the TPM committed to.
PCRSelect []PCRSelection
// PCRDigest is the TPM2B_DIGEST: H(concatenation of selected PCR values).
PCRDigest []byte
}
QuoteInfo is the parsed TPMS_QUOTE_INFO carried in a quote attestation: the set of PCRs that were quoted and the digest the TPM computed over their values. TCG "TPM 2.0 Part 2: Structures", clause "TPMS_QUOTE_INFO".
type TPM ¶
type TPM struct {
// contains filtered or unexported fields
}
TPM is the command-layer handle. It wraps a common.Transport and issues fully-marshaled TPM 2.0 commands through it. It holds no state of its own; concurrency and framing are the transport's concern.
func (*TPM) ActivateAKWithEK ¶ added in v0.5.0
func (tpm *TPM) ActivateAKWithEK(ak, ek uint32, akPublic, ekPublic, credential, nonceCaller []byte) ([]byte, error)
ActivateAKWithEK ties the whole credential-activation flow together. It computes MakeCredential OFF the TPM from ekPublic and the AK's Name (derived from akPublic), opens a policy session and satisfies the EK policy with PolicySecret(TPM_RH_ENDORSEMENT), then runs TPM2_ActivateCredential with the AK as activateHandle and the EK as keyHandle. It returns the recovered credential, which a caller asserts equals the original challenge — proving the AK and EK are on the same TPM.
ak and ek are the loaded transient handles; akPublic and ekPublic are the corresponding TPMT_PUBLIC bytes (the contents of TPM2B_PUBLIC, used to derive the AK Name and the EK point). credential is the challenge to bind. nonceCaller is the 32-byte caller nonce for the policy session.
func (*TPM) ActivateCredential ¶ added in v0.5.0
func (tpm *TPM) ActivateCredential(activateHandle, keyHandle, policySession uint32, credentialBlob, secret []byte) ([]byte, error)
ActivateCredential runs TPM2_ActivateCredential. activateHandle is the AK (authorized with the empty RS_PW password, since the AK has userWithAuth); keyHandle is the EK (authorized with a POLICY SESSION that already satisfies the EK policy via PolicySecret). credentialBlob is the TPM2B_ID_OBJECT and secret the TPM2B_ENCRYPTED_SECRET produced by MakeCredential — each passed as its complete, already-TPM2B-wrapped wire form (i.e. the MakeCredentialResult fields verbatim). The TPM unwraps them and returns certInfo: the recovered credential (a TPM2B_DIGEST), which equals the original iff the AK Name and EK match.
Body (TagSessions) — note TWO handles and TWO sessions:
handle area: activateHandle (u32) = AK || keyHandle (u32) = EK
auth area: authorizationSize (u32) ||
TPMS_AUTH_COMMAND #1 (AK: RS_PW, empty) ||
TPMS_AUTH_COMMAND #2 (EK: policy session)
param area: TPM2B_ID_OBJECT credentialBlob || TPM2B_ENCRYPTED_SECRET secret
The two sessions are in handle order: the AK's password session first (activateHandle is handle #1), the EK's policy session second (keyHandle is handle #2). TCG "Part 3", "TPM2_ActivateCredential".
Response (TagSessions): parameterSize (u32) || TPM2B_DIGEST certInfo.
func (*TPM) Create ¶ added in v0.3.0
Create runs TPM2_Create under the parent (empty-auth password session), creating a sealed keyedhash object that holds `secret` and is bound to `policyDigest`. It returns the object's TPM2B_PRIVATE and TPM2B_PUBLIC, which Load later turns back into a transient handle.
Body (TagSessions):
handle area: parentHandle (u32)
auth area: authorizationSize (u32) || TPMS_AUTH_COMMAND (RS_PW, empty)
param area: TPM2B_SENSITIVE_CREATE inSensitive (userAuth empty, the
secret as data) || TPM2B_PUBLIC inPublic (keyedhash, sealed
object, authPolicy=policyDigest) || TPM2B_DATA outsideInfo
(empty) || TPML_PCR_SELECTION creationPCR (count 0)
Wire: TagSessions, CC 0x00000153. TCG "Part 3", "TPM2_Create".
Response (TagSessions): parameterSize (u32) || TPM2B_PRIVATE outPrivate || TPM2B_PUBLIC outPublic || (creation data/hash/ticket, not parsed).
func (*TPM) CreateEK ¶ added in v0.4.0
CreateEK runs TPM2_CreatePrimary under TPM_RH_ENDORSEMENT (empty-auth password session) with the EK Credential Profile L-2 ECC P-256 template, creating the Endorsement Key. It returns the transient EK handle and the EK's public point.
Body (TagSessions):
handle area: primaryHandle (u32) = TPM_RH_ENDORSEMENT
auth area: authorizationSize (u32) || TPMS_AUTH_COMMAND (RS_PW, empty)
param area: TPM2B_SENSITIVE_CREATE (empty) || TPM2B_PUBLIC (EK template) ||
TPM2B_DATA outsideInfo (empty) || TPML_PCR_SELECTION (count 0)
Wire: TagSessions, CC 0x00000131. TCG "TPM 2.0 Part 3: Commands", clause "TPM2_CreatePrimary"; "EK Credential Profile", "Template L-2".
Response: objectHandle (u32) || parameterSize (u32) || TPM2B_PUBLIC outPublic (from which the EK point is extracted) || trailing creation fields.
func (*TPM) CreatePrimary ¶ added in v0.2.0
CreatePrimary runs TPM2_CreatePrimary under TPM_RH_OWNER with empty password authorization, creating a primary ECC P-256 restricted signing Attestation Key. It returns the transient object handle the TPM assigned to the new key and the key's public point.
This command carries a session (authorization) area, so the body has three regions (TCG "TPM 2.0 Part 1: Architecture", "Command Authorization Area Structure"):
handle area: primaryHandle (u32) = TPM_RH_OWNER
auth area: authorizationSize (u32) || TPMS_AUTH_COMMAND (RS_PW, empty)
param area: TPM2B_SENSITIVE_CREATE || TPM2B_PUBLIC ||
TPM2B_DATA outsideInfo || TPML_PCR_SELECTION creationPCR
The TPM2B_SENSITIVE_CREATE wraps a TPMS_SENSITIVE_CREATE with empty userAuth and empty data (the TPM originates the key material), so its inner bytes are two empty TPM2B (0x0000 0x0000), size-prefixed to 0x0004.
The TPM2B_PUBLIC wraps a TPMT_PUBLIC describing the ECC restricted signing key (see marshalECCAKPublic). outsideInfo is an empty TPM2B_DATA, and creationPCR is an empty TPML_PCR_SELECTION (count 0).
Wire: TagSessions, CC 0x00000131. TCG "TPM 2.0 Part 3: Commands", clause "TPM2_CreatePrimary".
Response (TCG "Part 3", "TPM2_CreatePrimary" response):
handle area: objectHandle (u32)
(no auth area parsed here: it is present but trailing)
param area: parameterSize (u32, present because TagSessions) ||
TPM2B_PUBLIC outPublic || TPM2B_CREATION_DATA creationData ||
TPM2B_DIGEST creationHash || TPMT_TK_CREATION creationTicket ||
TPM2B_NAME name
We parse outPublic to extract the AK's public point and consume (but do not further decode) the remaining creation fields.
func (*TPM) CreatePrimaryPublic ¶ added in v0.5.0
CreatePrimaryPublic is CreatePrimary but also returns the AK's TPMT_PUBLIC bytes (the CONTENTS of the response TPM2B_PUBLIC, without the 2-byte size prefix). Those bytes are exactly what the TPM loaded, so ObjectName over them yields the AK's Name — the value MakeCredential must commit to. The credential-activation flow needs the Name, which cannot be reconstructed reliably from the template alone, so it is taken from the TPM's own outPublic here. TCG "Part 3", "TPM2_CreatePrimary" (outPublic); "Part 1", "Names".
func (*TPM) CreateStoragePrimary ¶ added in v0.3.0
CreateStoragePrimary runs TPM2_CreatePrimary under TPM_RH_OWNER with empty password authorization, creating a primary ECC P-256 RESTRICTED DECRYPT (storage) key — the standard SRK-shaped parent under which a sealed object is created and loaded. It returns the transient parent handle.
The TPMT_PUBLIC differs from the AK's in two ways that define a storage key (TCG "TPM 2.0 Part 2: Structures", "TPMT_PUBLIC", "TPMS_ECC_PARMS"):
- objectAttributes = restricted|decrypt (storageObjectAttributes), not restricted|sign;
- the TPMS_ECC_PARMS.symmetric is a real TPMT_SYM_DEF_OBJECT (AES-128-CFB), because a parent MUST carry a symmetric algorithm to protect (encrypt) the sensitive areas of its children. A signing key uses symmetric=NULL; a storage key cannot. (TCG "Part 1", "Protected Storage".)
scheme=NULL, curve=P256, kdf=NULL as for the AK.
Wire: TagSessions, CC 0x00000131. TCG "Part 3", "TPM2_CreatePrimary".
func (*TPM) CreateStoragePrimaryPub ¶ added in v0.6.0
CreateStoragePrimaryPub is CreateStoragePrimary that ALSO returns the storage key's public point (x, y). The node exposes that point to a control plane so it can WrapToPCR a secret to this exact key offline (the duplication ECDH is against this public). It is the same TPM2_CreatePrimary command; only the response parse extends to the TPM2B_PUBLIC outPublic's TPMS_ECC_POINT.
Wire: TagSessions, CC 0x00000131. Response: objectHandle (u32) || parameterSize (u32) || TPM2B_PUBLIC outPublic || (creation tail, ignored). TCG "TPM 2.0 Part 3: Commands", "TPM2_CreatePrimary"; "Part 2", "TPMS_ECC_POINT".
func (*TPM) GetAlgorithms ¶ added in v0.4.0
func (tpm *TPM) GetAlgorithms(firstAlg, count uint32) ([]AlgProperty, error)
GetAlgorithms runs TPM2_GetCapability(TPM_CAP_ALGS) starting at firstAlg and decodes the TPML_ALG_PROPERTY: a count followed by that many TPMS_ALG_PROPERTY { alg:u16, algProperties:TPMA_ALGORITHM(u32) }. TCG "TPM 2.0 Part 2: Structures", clauses "TPM_CAP_ALGS" / "TPML_ALG_PROPERTY".
func (*TPM) GetCapability ¶
GetCapability runs TPM2_GetCapability. cap is a TPM_CAP selector, prop is the first property to return, and count caps how many values to return. It reports moreData (whether the TPM has further values beyond this reply) and the raw TPMS_CAPABILITY_DATA blob.
The TPMS_CAPABILITY_DATA union is large and capability-specific; decoding it fully is a deliberate follow-up. The documented boundary here is: the returned data is everything after the one-byte moreData flag, i.e. the complete TPMS_CAPABILITY_DATA { capability:u32, data:union } as the TPM sent it, ready to be parsed by a capability-aware caller.
Wire request: TagNoSessions, CC 0x0000017A, parameters TPM_CAP capability (u32), UINT32 property, UINT32 propertyCount. Wire response: TPMI_YES_NO moreData (u8) followed by TPMS_CAPABILITY_DATA. TCG "TPM 2.0 Part 3: Commands", clause "TPM2_GetCapability".
func (*TPM) GetHandles ¶ added in v0.4.0
GetHandles runs TPM2_GetCapability(TPM_CAP_HANDLES) starting at firstHandle and decodes the TPML_HANDLE: a count followed by that many TPM_HANDLE (u32). The starting handle selects the handle range (e.g. 0x81000000 for persistent objects, 0x80000000 for transient). TCG "TPM 2.0 Part 2: Structures", clauses "TPM_CAP_HANDLES" / "TPML_HANDLE".
func (*TPM) GetManufacturer ¶ added in v0.4.0
GetManufacturer is a convenience over GetTPMProperties: it reads TPM_PT_MANUFACTURER and returns its raw UINT32 value (the four packed ASCII vendor characters, big-endian). TCG "TPM 2.0 Part 2: Structures", clause "TPM_PT".
func (*TPM) GetPCRBanks ¶ added in v0.4.0
func (tpm *TPM) GetPCRBanks() ([]PCRSelection, error)
GetPCRBanks runs TPM2_GetCapability(TPM_CAP_PCRS) and decodes the resulting TPML_PCR_SELECTION: the TPM's allocated PCR banks (one TPMS_PCR_SELECTION per bank, the selection bitmap marking which PCRs the bank implements). TCG "TPM 2.0 Part 2: Structures", clauses "TPM_CAP_PCRS" / "TPML_PCR_SELECTION".
func (*TPM) GetRandom ¶
GetRandom runs TPM2_GetRandom and returns up to n bytes from the TPM's random number generator. The TPM may return fewer than n bytes.
Wire request: TagNoSessions, CC 0x0000017B, parameter UINT16 bytesRequested. Wire response: TPM2B_DIGEST randomBytes (a u16 size prefix followed by the bytes). TCG "TPM 2.0 Part 3: Commands", clause "TPM2_GetRandom".
func (*TPM) GetTPMProperties ¶ added in v0.4.0
func (tpm *TPM) GetTPMProperties(firstProp, count uint32) ([]TaggedProperty, error)
GetTPMProperties runs TPM2_GetCapability(TPM_CAP_TPM_PROPERTIES) starting at firstProp and decodes the TPML_TAGGED_TPM_PROPERTY: a count followed by that many TPMS_TAGGED_PROPERTY { property:u32, value:u32 }. TCG "TPM 2.0 Part 2: Structures", clauses "TPM_CAP_TPM_PROPERTIES" / "TPML_TAGGED_TPM_PROPERTY".
func (*TPM) Import ¶ added in v0.6.0
func (tpm *TPM) Import(parent uint32, objectPublic, duplicate, inSymSeed []byte) (outPrivate []byte, err error)
Import runs TPM2_Import under parent (empty-auth RS_PW password session), importing a duplicated object into the parent's hierarchy. It returns the object's outPrivate (TPM2B_PRIVATE), which Load turns into a transient handle.
objectPublic is the bare TPMT_PUBLIC (as produced by WrapToPCR); Import wraps it in a TPM2B_PUBLIC. duplicate and inSymSeed are WrapToPCR's outputs, each already a complete TPM2B (TPM2B_PRIVATE and TPM2B_ENCRYPTED_SECRET respectively) and emitted on the wire verbatim.
Body (TagSessions):
handle area: parentHandle (u32)
auth area: authorizationSize (u32) || TPMS_AUTH_COMMAND (RS_PW, empty)
param area: TPM2B_DATA encryptionKey (empty) ||
TPM2B_PUBLIC objectPublic ||
TPM2B_PRIVATE duplicate ||
TPM2B_ENCRYPTED_SECRET inSymSeed ||
TPMT_SYM_DEF_OBJECT symmetricAlg = TPM_ALG_NULL (no inner wrap)
encryptionKey is empty AND symmetricAlg is TPM_ALG_NULL because WrapToPCR produces an OUTER-WRAP-ONLY duplication: there is no INNER symmetric wrap of the sensitive area. The Import symmetricAlg argument describes the optional INNER wrapper on `duplicate`, NOT the parent's child-protection cipher; with no inner wrap it MUST be NULL and encryptionKey MUST be empty (per TCG and the go-tpm reference: "encryptionKey and sym non-nil iff an inner wrapper is used"). Passing the parent's AES-128-CFB here makes the TPM expect a non-empty encryptionKey of the AES key size and reject the empty one with TPM_RC_SIZE on parameter 1 (rc 0x1D5) — the bug a real swtpm caught. Wire: TagSessions, CC 0x00000156. TCG "TPM 2.0 Part 3: Commands", "TPM2_Import"; "Part 2", "TPMT_SYM_DEF_OBJECT".
Response (TagSessions): parameterSize (u32) || TPM2B_PRIVATE outPrivate.
func (*TPM) ImportAndUnseal ¶ added in v0.6.0
func (tpm *TPM) ImportAndUnseal(parent uint32, objectPublic, duplicate, inSymSeed []byte, sel []PCRSelection, nonceCaller []byte) ([]byte, error)
ImportAndUnseal is the high-level node-side recover path: it TPM2_Imports the duplicated object under parent, TPM2_Loads the resulting (outPrivate, objectPublic) into a transient handle, opens a fresh PCR policy session, runs PolicyPCR(sel) against the node's CURRENT PCR state, and Unseals. It returns the recovered secret on success, or the TPM's error — a policy failure (TPM_RC_POLICY_FAIL) if the live PCRs no longer match the values the control plane wrapped to.
objectPublic, duplicate, inSymSeed are exactly WrapToPCR's outputs; sel is the same PCR selection used at wrap time. nonceCaller is the 32-byte caller nonce for the policy session. This ties TPM2_Import -> TPM2_Load -> TPM2_PolicyPCR -> TPM2_Unseal into one call.
func (*TPM) Load ¶ added in v0.3.0
Load runs TPM2_Load under the parent (empty-auth password session), turning a sealed object's (priv, pub) pair back into a transient object handle usable by Unseal.
Body (TagSessions):
handle area: parentHandle (u32) auth area: authorizationSize (u32) || TPMS_AUTH_COMMAND (RS_PW, empty) param area: TPM2B_PRIVATE inPrivate || TPM2B_PUBLIC inPublic
Wire: TagSessions, CC 0x00000157. TCG "Part 3", "TPM2_Load".
Response (TagSessions): objectHandle (u32) || parameterSize (u32) || TPM2B_NAME name (not parsed).
func (*TPM) NVDefineSpace ¶ added in v0.4.0
NVDefineSpace runs TPM2_NV_DefineSpace under TPM_RH_OWNER (empty-auth password session), defining an ordinary NV index. The new index gets an empty authValue (the TPM2B_AUTH inSensitive is empty) and the public area built from the supplied NVPublic.
Body (TagSessions):
handle area: authHandle (u32) = TPM_RH_OWNER auth area: authorizationSize (u32) || TPMS_AUTH_COMMAND (RS_PW, empty) param area: TPM2B_AUTH auth (empty) || TPM2B_NV_PUBLIC publicInfo
Wire: TagSessions, CC 0x0000012A. TCG "TPM 2.0 Part 3: Commands", clause "TPM2_NV_DefineSpace".
func (*TPM) NVRead ¶ added in v0.4.0
NVRead runs TPM2_NV_Read under TPM_RH_OWNER (empty-auth password session), reading size bytes from the index at nvIndex starting at offset. The OWNER authorization is accepted because the index carries OWNERREAD.
Body (TagSessions):
handle area: authHandle (u32) = TPM_RH_OWNER || nvIndex (u32) auth area: authorizationSize (u32) || TPMS_AUTH_COMMAND (RS_PW, empty) param area: UINT16 size || UINT16 offset
Wire: TagSessions, CC 0x0000014E. TCG "TPM 2.0 Part 3: Commands", clause "TPM2_NV_Read".
Response (TagSessions): parameterSize (u32) || TPM2B_MAX_NV_BUFFER data.
func (*TPM) NVReadPublic ¶ added in v0.4.0
NVReadPublic runs TPM2_NV_ReadPublic, reading back the public area and the computed Name of the index at nvIndex. It carries no authorization (the public area is world-readable).
Body (TagNoSessions):
handle area: nvIndex (u32) (no parameters)
Wire: TagNoSessions, CC 0x00000169. TCG "TPM 2.0 Part 3: Commands", clause "TPM2_NV_ReadPublic".
Response (TagNoSessions): TPM2B_NV_PUBLIC nvPublic || TPM2B_NAME nvName.
func (*TPM) NVUndefineSpace ¶ added in v0.4.0
NVUndefineSpace runs TPM2_NV_UndefineSpace under TPM_RH_OWNER (empty-auth password session), deleting the index at nvIndex.
Body (TagSessions):
handle area: authHandle (u32) = TPM_RH_OWNER || nvIndex (u32) auth area: authorizationSize (u32) || TPMS_AUTH_COMMAND (RS_PW, empty) (no parameters)
Wire: TagSessions, CC 0x00000122. TCG "TPM 2.0 Part 3: Commands", clause "TPM2_NV_UndefineSpace".
func (*TPM) NVWrite ¶ added in v0.4.0
NVWrite runs TPM2_NV_Write under TPM_RH_OWNER (empty-auth password session), writing data into the index at nvIndex starting at offset. The authHandle is the OWNER hierarchy, which authorizes the write because the index carries OWNERWRITE.
Body (TagSessions):
handle area: authHandle (u32) = TPM_RH_OWNER || nvIndex (u32) auth area: authorizationSize (u32) || TPMS_AUTH_COMMAND (RS_PW, empty) param area: TPM2B_MAX_NV_BUFFER data || UINT16 offset
Wire: TagSessions, CC 0x00000137. TCG "TPM 2.0 Part 3: Commands", clause "TPM2_NV_Write".
func (*TPM) PCRExtend ¶
PCRExtend runs TPM2_PCR_Extend, folding digest into PCR pcr in the bank named by hash (a TPM_ALG_ID). It authorizes the operation with a cleartext password session over the empty authValue — the standard way to extend an unowned platform PCR.
This is the one command in the starter set that carries an authorization area, so the body is laid out in three regions (TCG "TPM 2.0 Part 1: Architecture", "Command Authorization Area Structure"):
handle area: pcrHandle (u32) — the PCR being extended
auth area: authorizationSize (u32) || TPMS_AUTH_COMMAND
param area: TPML_DIGEST_VALUES — { count, {hashAlg, digest} }
The TPMS_AUTH_COMMAND is the password session:
sessionHandle = TPM_RS_PW (0x40000009) nonce = empty TPM2B -> 0x0000 sessionAttributes = continueSession (0x01) hmac = empty TPM2B -> 0x0000
which is 9 bytes on the wire (4 sessionHandle + 2 empty-nonce size + 1 attributes + 2 empty-hmac size), so authorizationSize is 0x00000009. The 0x00 high byte of TPM_HT_PCR (the PCR handle type) is INFERRED from "Part 2: Structures", "TPM_HT (Handle Types)": PCR handles occupy 0x00000000..0x0000001F, so PCR[n] marshals as the bare index n.
Wire: TagSessions, CC 0x00000182. TCG "TPM 2.0 Part 3: Commands", clause "TPM2_PCR_Extend"; TPML_DIGEST_VALUES / TPMT_HA per "Part 2: Structures".
func (*TPM) PCRRead ¶
func (tpm *TPM) PCRRead(sel []PCRSelection) (updateCounter uint32, digests [][]byte, err error)
PCRRead runs TPM2_PCR_Read for the banks/PCRs named in sel. It returns the PCR update counter, and the digests in the order the TPM returns them (which follows the selection's ascending PCR order, possibly split across multiple replies when more PCRs are selected than fit in one response — this starter reads exactly one reply).
Wire request: TagNoSessions, CC 0x0000017E, parameter TPML_PCR_SELECTION pcrSelectionIn. Wire response: UINT32 pcrUpdateCounter, TPML_PCR_SELECTION pcrSelectionOut (echoed; skipped here), TPML_DIGEST pcrValues (a u32 count followed by that many TPM2B_DIGEST). TCG "TPM 2.0 Part 3: Commands", clause "TPM2_PCR_Read".
func (*TPM) PolicyGetDigest ¶ added in v0.3.0
PolicyGetDigest runs TPM2_PolicyGetDigest, reading back the current policyDigest accumulated in the session. It is a debugging aid: comparing it to PolicyPCRDigest confirms the offline construction matches what the TPM computed.
Body (TagNoSessions): handle area policySession (u32). Response: TPM2B_DIGEST policyDigest.
Wire: TagNoSessions, CC 0x00000189. TCG "Part 3", "TPM2_PolicyGetDigest".
func (*TPM) PolicyPCR ¶ added in v0.3.0
func (tpm *TPM) PolicyPCR(session uint32, sel []PCRSelection) error
PolicyPCR runs TPM2_PolicyPCR in the given policy session, extending the session's policyDigest by the selected PCRs. pcrDigest is passed as an EMPTY TPM2B so the TPM uses the CURRENT PCR values to compute the digest it folds in — which means the session's resulting policyDigest equals PolicyPCRDigest(sel, currentPCRs). Unseal then succeeds iff that equals the sealed object's authPolicy.
Body (TagNoSessions — PolicyPCR's session handle is in the HANDLE area, not an auth area):
handle area: policySession (u32) param area: TPM2B_DIGEST pcrDigest (empty) || TPML_PCR_SELECTION pcrs
Wire: TagNoSessions, CC 0x0000017F. TCG "Part 3", "TPM2_PolicyPCR".
func (*TPM) PolicySecret ¶ added in v0.5.0
PolicySecret runs TPM2_PolicySecret in policySession, asserting knowledge of authHandle's authValue. For the EK policy, authHandle is TPM_RH_ENDORSEMENT authorized with the empty endorsement password (RS_PW), and the call extends the session's policyDigest by the PolicySecret assertion. With empty nonceTPM, cpHashA, policyRef and expiration=0, the resulting policyDigest equals the well-known EK authPolicy (= policyDigest of TPM2_PolicySecret(TPM_RH_ENDORSEMENT)).
Body (TagSessions):
handle area: authHandle (u32) = TPM_RH_ENDORSEMENT
policySession (u32) — second handle, NO auth area
auth area: authorizationSize (u32) || TPMS_AUTH_COMMAND (RS_PW, empty)
param area: TPM2B_NONCE nonceTPM (empty) || TPM2B_DIGEST cpHashA (empty) ||
TPM2B_NONCE policyRef (empty) || INT32 expiration (0)
Only authHandle requires authorization, so the auth area carries exactly ONE TPMS_AUTH_COMMAND (for authHandle); policySession sits in the handle area without an auth entry. TCG "Part 3", "TPM2_PolicySecret".
Response (TagSessions): parameterSize (u32) || TPM2B_TIMEOUT timeout || TPMT_TK_AUTH policyTicket. Neither is needed when expiration is 0, so they are not parsed.
func (*TPM) Quote ¶ added in v0.2.0
func (tpm *TPM) Quote(keyHandle uint32, qualifyingData []byte, sel []PCRSelection) (quoted []byte, sig ECDSASignature, err error)
Quote runs TPM2_Quote: the AK signs a TPMS_ATTEST that commits to the current values of the selected PCRs, with qualifyingData (a caller nonce) folded into the attest's extraData. It returns the raw TPM2B_ATTEST data (the bytes that were signed) and the parsed ECDSA signature.
Body (TagSessions):
handle area: keyHandle (u32) = the AK handle from CreatePrimary
auth area: authorizationSize (u32) || TPMS_AUTH_COMMAND (RS_PW, empty)
param area: TPM2B_DATA qualifyingData || TPMT_SIG_SCHEME inScheme ||
TPML_PCR_SELECTION pcrSelect
inScheme is passed as TPM_ALG_NULL (0x0010) to use the key's own scheme (ECDSA+SHA256); a NULL scheme has no details, so it marshals as the bare 2-byte algorithm id.
Wire: TagSessions, CC 0x00000158. TCG "TPM 2.0 Part 3: Commands", clause "TPM2_Quote".
Response:
param area: parameterSize (u32, present for TagSessions) ||
TPM2B_ATTEST quoted || TPMT_SIGNATURE signature
func (*TPM) SealToPCR ¶ added in v0.3.0
func (tpm *TPM) SealToPCR(parent uint32, secret []byte, sel []PCRSelection, pcrValues [][]byte) (priv, pub, policyDigest []byte, err error)
SealToPCR is the high-level seal helper: it computes the PCR-bound policyDigest from the given selection and PCR values, then runs TPM2_Create under parent to produce a sealed object holding secret. It returns the object's (priv, pub) blobs and the policyDigest it sealed to (so a caller can record/compare it). The PCR values must be the ones the object should later unseal against (typically the result of PCRRead just before sealing).
func (*TPM) SelfTest ¶
SelfTest runs TPM2_SelfTest. When full is true (TPMI_YES_NO == YES) the TPM tests every implemented function; when false it tests only those not yet tested since the last reset.
Wire: TagNoSessions, CC 0x00000143, parameter TPMI_YES_NO fullTest (u8; YES = 1, NO = 0). TCG "TPM 2.0 Part 3: Commands", clause "TPM2_SelfTest"; TPMI_YES_NO per "Part 2: Structures".
func (*TPM) Shutdown ¶
Shutdown runs TPM2_Shutdown, preparing the TPM for power loss. su is a TPM_SU: common.SUClear or common.SUState.
Wire: TagNoSessions, CC 0x00000145, parameter TPM_SU shutdownType (u16). TCG "TPM 2.0 Part 3: Commands", clause "TPM2_Shutdown".
func (*TPM) StartAuthSession ¶ added in v0.3.0
func (tpm *TPM) StartAuthSession(nonceCaller []byte) (sessionHandle uint32, nonceTPM []byte, err error)
StartAuthSession runs TPM2_StartAuthSession to open a POLICY session (TPM_SE_POLICY) with SHA-256 as its authHash, unsalted and unbound (tpmKey = bind = TPM_RH_NULL), no parameter encryption (symmetric = TPM_ALG_NULL). nonceCaller is the caller's initial nonce (32 random bytes for SHA-256). It returns the session handle and the TPM's nonceTPM.
Body (TagNoSessions — StartAuthSession itself carries no auth area):
handle area: tpmKey (u32) = TPM_RH_NULL, bind (u32) = TPM_RH_NULL
param area: TPM2B_NONCE nonceCaller || TPM2B_ENCRYPTED_SECRET
encryptedSalt (empty) || TPM_SE sessionType (u8) ||
TPMT_SYM_DEF symmetric (algorithm = TPM_ALG_NULL) ||
TPMI_ALG_HASH authHash (u16)
A NULL TPMT_SYM_DEF is just the 2-byte algorithm id (no keyBits/mode).
Wire: TagNoSessions, CC 0x00000176. TCG "Part 3", "TPM2_StartAuthSession"; "Part 2", "TPMT_SYM_DEF", "TPM_SE".
Response: sessionHandle (u32) || TPM2B_NONCE nonceTPM.
func (*TPM) Startup ¶
Startup runs TPM2_Startup, which the platform firmware issues exactly once after _TPM_Init to bring the TPM out of reset. su is a TPM_SU: common.SUClear for Startup(CLEAR) or common.SUState for Startup(STATE).
Wire: TagNoSessions, CC 0x00000144, parameter TPM_SU startupType (u16). TCG "TPM 2.0 Part 3: Commands", clause "TPM2_Startup".
func (*TPM) Unseal ¶ added in v0.3.0
Unseal runs TPM2_Unseal on the loaded sealed object, authorizing it with the POLICY SESSION (which must already have been driven through PolicyPCR so its policyDigest matches the object's authPolicy). It returns the secret the object holds.
Body (TagSessions):
handle area: itemHandle (u32) = the loaded sealed object
auth area: authorizationSize (u32) || TPMS_AUTH_COMMAND carrying the
POLICY SESSION handle (marshalPolicyAuth)
(no parameters)
Wire: TagSessions, CC 0x0000015E. TCG "Part 3", "TPM2_Unseal".
Response (TagSessions): parameterSize (u32) || TPM2B_SENSITIVE_DATA outData (the secret).
func (*TPM) UnsealWithPCR ¶ added in v0.3.0
func (tpm *TPM) UnsealWithPCR(parent uint32, priv, pub []byte, sel []PCRSelection, nonceCaller []byte) ([]byte, error)
UnsealWithPCR is the high-level unseal helper: it loads the sealed object under parent, opens a fresh PCR policy session, runs PolicyPCR(sel) against the CURRENT PCR state, and unseals. It returns the secret on success, or the TPM's error (a policy failure if the current PCRs no longer match the sealed-to state). nonceCaller is the 32-byte caller nonce for the session.
type TPMError ¶
type TPMError struct {
// CC is the command code the failing command was issued under.
CC uint32
// RC is the raw response code returned by the TPM (non-zero).
RC uint32
}
TPMError is the typed error returned when a command completes with a non-success response code. It carries the raw TPM_RC reported by the device and the TPM_CC the command was issued under, so callers can distinguish, for example, a TPM_RC_VALUE from PCR_Extend from the same rc raised by some other command.
type TaggedProperty ¶ added in v0.4.0
type TaggedProperty struct {
// Property is the TPM_PT tag.
Property uint32
// Value is the property's UINT32 value.
Value uint32
}
TaggedProperty is one entry of a TPML_TAGGED_TPM_PROPERTY: a property tag and its UINT32 value. TCG "TPM 2.0 Part 2: Structures", clause "TPMS_TAGGED_PROPERTY".
type WrapToPCRResult ¶ added in v0.6.0
type WrapToPCRResult struct {
// ObjectPublic is the marshaled TPMT_PUBLIC (the CONTENTS of TPM2B_PUBLIC,
// without the 2-byte size prefix) of the sealed keyedhash object. It is
// passed to Import (which wraps it in a TPM2B_PUBLIC) and later to Load.
ObjectPublic []byte
// Duplicate is the TPM2B_PRIVATE-shaped duplication blob:
// TPM2B( TPM2B(outerHMAC) || encSensitive ).
Duplicate []byte
// InSymSeed is the TPM2B_ENCRYPTED_SECRET carrying the ephemeral public
// point (TPMS_ECC_POINT) the node's TPM uses to recover the outer-wrap
// seed by ECDH against its storage key.
InSymSeed []byte
}
WrapToPCRResult is the output of WrapToPCR: the three blobs the control plane ships to the node for TPM2_Import.
func WrapToPCR ¶ added in v0.6.0
func WrapToPCR(srkPub ECCPublic, secret []byte, sel []PCRSelection, pcrValues [][]byte, rng io.Reader) (WrapToPCRResult, error)
WrapToPCR performs the OFFLINE, no-TPM control-plane side of object duplication: it builds a KEYEDHASH sealed-data object holding secret and bound to authPolicy = PolicyPCRDigest(sel, pcrValues), then OUTER-WRAPS its sensitive area for the node's ECC P-256 storage key srkPub. The returned (ObjectPublic, Duplicate, InSymSeed) are exactly the inputs to TPM2_Import.
sel/pcrValues are the PCR selection and the values the object must unseal against (the node's boot state); they are folded into the object's authPolicy via the same PolicyPCRDigest construction the seal/unseal path uses, so a node can Import + Load the object but only Unseal it when its live PCRs reproduce pcrValues.
The ephemeral key is drawn from crypto/rand; rng may override the source for deterministic testing (pass nil for crypto/rand).
TCG "TPM 2.0 Part 1: Architecture", "Duplication" / "Protected Storage" (the outer wrap: KDFe seed "DUPLICATE", KDFa "STORAGE"/"INTEGRITY", the HMAC over encSensitive||Name); "Part 2", "TPMT_SENSITIVE", "TPMT_PUBLIC".
