attest

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 13, 2026 License: BSD-3-Clause Imports: 9 Imported by: 0

README

go-tpm2/attest

CI Go Reference Coverage License

Pure-Go TPM 2.0 remote-attestation protocol: a Verifier (control plane) and a Node (agent) that together implement node-admission-on-Quote. A node joins a fleet only if it proves — via a TPM Quote over a fresh verifier nonce, signed by an EK-bound Attestation Key — that it booted an approved stack.

It sits one layer above github.com/go-tpm2/tpm2: the Verifier is pure Go and never touches a TPM (MakeCredential + VerifyQuote are off-TPM crypto); the Node drives a real *tpm2.TPM (CreateEK/CreatePrimary/ActivateCredential/Quote).

Install

go get github.com/go-tpm2/attest

Protocol

Two phases. Enrolment (once per node) binds an AK to a trusted EK; Admission (every join) proves an approved boot.

Node                                   Verifier
 ── EnrollRequest{EKPub,EKCert,          ──▶  Trusted(EKPub)? MakeCredential
                  AKPub,AKName}                (off-TPM) → blob+secret
 ◀─ EnrollChallenge{CredentialBlob,Secret} ──
 ActivateCredential(AK,EK,…) → secret
 ── EnrollProof{ActivationSecret}        ──▶  const-time compare → BindAK
 ─────────────────────────────────────────────────────────────────────────
 ── AdmissionRequest{AKName}             ──▶  AK bound? fresh Nonce
 ◀─ AdmissionChallenge{Nonce}            ──
 Quote(AK,pcrSel,Nonce) + PCRRead
 ── AdmissionResponse{Quoted,Signature,  ──▶  VerifyQuote (sig+pcrDigest),
                      PCRs,EventLog}            extraData==Nonce (anti-replay),
                                               Policy.Matches(PCRs) → granted

Usage — the two-phase handshake

// --- Verifier (control plane, pure Go, no TPM). ---
reg := attest.NewMemRegistry()
reg.TrustEK(ekPub)                        // or chain the EK cert to a root
v := attest.NewVerifier(reg, attest.GoldenPolicy{ /* set after first boot */ },
	attest.RandNonce)

// --- Node (agent, on the attesting platform). ---
node, _ := attest.NewNode(tpm2.New(transport),
	[]tpm2.PCRSelection{{Hash: uint16(common.AlgSHA256), PCRs: []int{0, 7}}})

// Enrolment: bind the AK to a trusted EK.
chal, _ := v.Enroll(node.EnrollRequest(ekCert))
proof, _ := node.RespondEnroll(chal)      // TPM2_ActivateCredential
if err := v.CompleteEnroll(node.AKName(), proof); err != nil {
	log.Fatal(err)                        // attest.ErrActivationFailed
}

// Admission: prove an approved boot on each join.
adChal, _ := v.Challenge(node.AdmissionRequest())
resp, _ := node.RespondAdmission(adChal)  // TPM2_Quote + PCR_Read
granted, err := v.Admit(node.AKName(), resp)
// err is one of: ErrUnboundAK, ErrStaleNonce, ErrQuoteSignature,
// ErrPCRDigestMismatch, ErrUntrustedBoot (errors.As → *UntrustedBootError).

Wire format

A small, versioned, big-endian, length-prefixed codec (codec.go): every frame is magic("ATT2") | version | kind | body; []byte is u32 len | bytes; the 32-byte admission nonce is fixed-width; PCR maps are emitted in ascending key order so the encoding is byte-stable. Decoders reject foreign magic, wrong version, wrong message kind, and trailing bytes; every message round-trips.

Security model

  • EK enrolment / identity. MakeCredential binds the activation secret to the AK's Name and the EK's public key; only a TPM holding the EK private key and an AK with that Name can recover it via ActivateCredential. A successful CompleteEnroll proves the AK and a trusted EK live on the same TPM.
  • Nonce anti-replay. Every admission uses a fresh nonce folded into the quote's extraData; Admit checks it and consumes it, so a captured quote cannot be replayed.
  • Golden PCR policy. GoldenPolicy admits only if every required PCR equals its golden digest, naming the first mismatch in *UntrustedBootError. (A TCG event-log-replay EventLogPolicy is the documented v0.2 follow-up.)
  • TOCTOU caveat. A Quote attests boot-time measurements, not runtime state; attestation gates admission, it is not a continuous integrity monitor. Pair it with short admission leases / re-attestation.

Conventions

Pure Go, CGO_ENABLED=0, no workspace (GOWORK=off), BSD-3 (SPDX per file), 100 % statement coverage (CI gate). Validated end-to-end against a real swtpm in go-tpm2/validate (cmd/attestvalidate): the full handshake runs in a tamago/amd64 guest against live TPM crypto, asserting ADMITTED and rejecting bad-PCR, stale-nonce, and wrong-AK.

Sibling repos: common, tpm2, crb, tis, validate.

Documentation

Overview

Package attest is a reusable TPM 2.0 remote-attestation protocol: a Verifier (control-plane) side and a Node (agent) side that together implement NODE-ADMISSION-ON-QUOTE. A node joins a fleet only if it proves, via a TPM Quote over a fresh verifier nonce signed by an EK-bound Attestation Key, that it booted an approved stack. It builds on github.com/go-tpm2/tpm2: the Verifier is pure Go and off-TPM (MakeCredential + VerifyQuote); the Node drives a real *tpm2.TPM (CreateEK/CreatePrimary/ActivateCredential/Quote).

Protocol

The handshake has two phases. ENROLMENT runs once per node and binds an AK to a trusted EK; ADMISSION runs on every join and proves an approved boot.

Enrolment (proves AK and a trusted EK live on the SAME TPM):

Node                                  Verifier
  -- EnrollRequest{EKPub,EKCert,         -->  Trusted(EKPub)? pick random
                   AKPub,AKName}              activation secret; MakeCredential
                                             (off-TPM) -> blob+secret
  <-- EnrollChallenge{CredentialBlob,    --
                      Secret}
  ActivateCredential(AK,EK,blob,secret)
  -> recovered secret
  -- EnrollProof{ActivationSecret}       -->  constant-time compare to pending;
                                             on match BindAK(AKName, AKPub)

Admission (proves an approved boot, fresh each join):

Node                                  Verifier
  -- AdmissionRequest{AKName}            -->  AK bound? fresh Nonce; stash
  <-- AdmissionChallenge{Nonce}          --
  Quote(AK, pcrSel, Nonce) + PCRRead
  -- AdmissionResponse{Quoted,Signature, -->  VerifyQuote (sig + pcrDigest);
                       PCRs,EventLog}         extraData==Nonce (anti-replay);
                                             Policy.Matches(PCRs) -> granted

Security model

  • EK enrolment / identity. MakeCredential binds an activation secret to the AK's Name AND the EK's public key; only a TPM holding the EK private key and an AK with that exact Name can recover it via ActivateCredential. A successful CompleteEnroll therefore proves the AK and a TRUSTED EK live on the same TPM. Which EKs are trusted is the EKRegistry's decision (an allowlist, or an EK-certificate chain to a manufacturer root).

  • Nonce anti-replay. Every admission uses a fresh verifier nonce, folded into the quote's extraData (qualifyingData). Admit checks the signed attest's extraData equals exactly the issued nonce and consumes the pending nonce, so a captured quote cannot be replayed.

  • Golden PCR policy. GoldenPolicy admits a node only if every required PCR equals its expected ("golden") digest, naming the first mismatch in a typed *UntrustedBootError (errors.Is ErrUntrustedBoot). The PCR values are trusted only because the signature and the quoted pcrDigest were verified first.

  • TOCTOU caveat. A Quote attests the platform's BOOT-TIME measurements (the PCR state at quote time), NOT its runtime state. An approved boot says nothing about post-boot compromise; attestation gates admission, it is not a continuous runtime-integrity monitor. Pair it with short admission leases / re-attestation for stronger guarantees.

tpm2 wiring

The Node calls tpm2.CreateEK, tpm2.CreatePrimaryPublic, tpm2.ObjectName, tpm2.StartAuthSession, tpm2.PolicySecret, tpm2.ActivateCredential, tpm2.Quote and tpm2.PCRRead. The Verifier calls tpm2.MakeCredential and tpm2.VerifyQuote. VerifyQuote checks the ECDSA signature and the pcrDigest but does NOT compare extraData to a nonce, so Admit performs the nonce (anti-replay) check itself against the parsed AttestInfo.ExtraData.

Index

Constants

View Source
const (
	// ErrShortBuffer is returned when a buffer ends before a field could be
	// fully decoded.
	ErrShortBuffer = common.Error("attest: short buffer")
	// ErrBadMagic is returned when a frame does not begin with wireMagic.
	ErrBadMagic = common.Error("attest: bad frame magic")
	// ErrBadVersion is returned when a frame's version != wireVersion.
	ErrBadVersion = common.Error("attest: unsupported codec version")
	// ErrWrongKind is returned when a frame's kind tag does not match the
	// message type being decoded into.
	ErrWrongKind = common.Error("attest: wrong message kind")
	// ErrTrailingBytes is returned when a frame has bytes left over after the
	// message was fully decoded (a strict, non-malleable decode).
	ErrTrailingBytes = common.Error("attest: trailing bytes after message")
)

Codec error sentinels (typed and constant for ==).

View Source
const (
	// ErrUnknownEK is returned by Enroll when the presented EK is not trusted.
	ErrUnknownEK = common.Error("attest: unknown or untrusted EK")
	// ErrActivationFailed is returned by CompleteEnroll when the returned
	// activation secret does not match the issued one (or no enrolment is
	// pending for the AK).
	ErrActivationFailed = common.Error("attest: credential activation failed")
	// ErrUnboundAK is returned when an admission step references an AK that was
	// never bound via a successful enrolment.
	ErrUnboundAK = common.Error("attest: AK is not bound")
	// ErrStaleNonce is returned by Admit when no challenge is pending for the
	// AK or the quote's extraData does not equal the issued nonce (anti-replay).
	ErrStaleNonce = common.Error("attest: stale or replayed nonce")
	// ErrQuoteSignature is returned when the quote's ECDSA signature does not
	// verify under the bound AK public key.
	ErrQuoteSignature = common.Error("attest: quote signature invalid")
	// ErrPCRDigestMismatch is returned when the quoted pcrDigest does not equal
	// the digest recomputed over the claimed PCR values.
	ErrPCRDigestMismatch = common.Error("attest: quoted pcrDigest != claimed PCRs")
	// ErrMalformedQuote is returned when the quote or signature cannot be
	// parsed (e.g. a signature that is not the expected r||s width).
	ErrMalformedQuote = common.Error("attest: malformed quote or signature")
)

Verifier error sentinels (typed and constant for ==).

View Source
const ErrBadPublic = common.Error("attest: malformed ECC TPMT_PUBLIC")

ErrBadPublic is returned when a public area is not a parseable ECC TPMT_PUBLIC.

View Source
const ErrUntrustedBoot = common.Error("attest: untrusted boot (PCR policy mismatch)")

ErrUntrustedBoot is the sentinel every Policy mismatch satisfies under errors.Is. A concrete *UntrustedBootError additionally names the PCR.

Variables

This section is empty.

Functions

func JoinSignature

func JoinSignature(sig tpm2.ECDSASignature) []byte

JoinSignature is the inverse of splitSignature: it renders a tpm2.ECDSASignature (as Quote returns it) into the fixed-width r||s wire form AdmissionResponse carries. r and s are left-padded to p256HalfLen bytes.

func RandNonce

func RandNonce() ([32]byte, error)

RandNonce is the default Nonce source, drawing from crypto/rand.

Types

type AdmissionChallenge

type AdmissionChallenge struct {
	Nonce [32]byte
}

AdmissionChallenge is the verifier's fresh 32-byte anti-replay nonce, which the node folds into the Quote's extraData (qualifyingData). The verifier later checks the quoted attest's extraData equals exactly this nonce.

func (AdmissionChallenge) Marshal

func (m AdmissionChallenge) Marshal() []byte

Marshal encodes the AdmissionChallenge to a frame.

func (*AdmissionChallenge) Unmarshal

func (m *AdmissionChallenge) Unmarshal(buf []byte) error

Unmarshal decodes a frame into the AdmissionChallenge.

type AdmissionRequest

type AdmissionRequest struct {
	AKName []byte
}

AdmissionRequest is the node's request to join the fleet, naming the AK it enrolled. The verifier looks the AK Name up in its registry and refuses unbound AKs.

func (AdmissionRequest) Marshal

func (m AdmissionRequest) Marshal() []byte

Marshal encodes the AdmissionRequest to a frame.

func (*AdmissionRequest) Unmarshal

func (m *AdmissionRequest) Unmarshal(buf []byte) error

Unmarshal decodes a frame into the AdmissionRequest.

type AdmissionResponse

type AdmissionResponse struct {
	Quoted    []byte
	Signature []byte
	PCRs      map[int][]byte
	EventLog  []byte
}

AdmissionResponse carries the node's TPM Quote: the raw TPM2B_ATTEST data (Quoted, the signed bytes), the ECDSA signature over it (Signature, as a concatenated r||s of equal halves), the claimed PCR values (PCRs, by index), and an optional measured-boot event log (EventLog, reserved for the v0.2 EventLogPolicy). The verifier reconstructs the (r,s) split from the signed curve (P-256 => 32-byte halves).

func (AdmissionResponse) Marshal

func (m AdmissionResponse) Marshal() []byte

Marshal encodes the AdmissionResponse to a frame.

func (*AdmissionResponse) Unmarshal

func (m *AdmissionResponse) Unmarshal(buf []byte) error

Unmarshal decodes a frame into the AdmissionResponse.

type EKRegistry

type EKRegistry interface {
	// Trusted reports whether the given EK public area is acceptable for
	// enrolment. ekPub is the TPMT_PUBLIC of the EK.
	Trusted(ekPub []byte) bool
	// BindAK records that akName (the AK's Name) is bound to a trusted EK and
	// stores akPub (the AK's TPMT_PUBLIC) for later signature verification. It
	// is called only after a successful credential activation.
	BindAK(akName, akPub []byte) error
	// AKPub returns the stored AK public area for a bound AK Name, and whether
	// the AK is bound at all.
	AKPub(akName []byte) (akPub []byte, ok bool)
}

EKRegistry is the verifier's trust store for Endorsement Keys and the EK->AK bindings established at enrolment. It is the policy boundary for "which TPMs may ever join": Trusted decides whether an EK public is acceptable (e.g. its certificate chains to a known manufacturer root, or it is on an explicit allowlist), and BindAK records that an AK Name has been cryptographically tied — via ActivateCredential — to such an EK.

Implementations MUST be safe for concurrent use by multiple goroutines.

type EnrollChallenge

type EnrollChallenge struct {
	CredentialBlob []byte
	Secret         []byte
}

EnrollChallenge is the verifier's MakeCredential response: the credentialBlob (TPM2B_ID_OBJECT) and secret (TPM2B_ENCRYPTED_SECRET) the node feeds to TPM2_ActivateCredential. Only a TPM holding the EK private key AND an AK with the committed Name can recover the embedded activation secret.

func (EnrollChallenge) Marshal

func (m EnrollChallenge) Marshal() []byte

Marshal encodes the EnrollChallenge to a frame.

func (*EnrollChallenge) Unmarshal

func (m *EnrollChallenge) Unmarshal(buf []byte) error

Unmarshal decodes a frame into the EnrollChallenge.

type EnrollProof

type EnrollProof struct {
	ActivationSecret []byte
}

EnrollProof is the node's proof of possession: the activation secret it recovered from ActivateCredential. The verifier constant-time-compares it to the secret it embedded; equality binds the AK to the trusted EK.

func (EnrollProof) Marshal

func (m EnrollProof) Marshal() []byte

Marshal encodes the EnrollProof to a frame.

func (*EnrollProof) Unmarshal

func (m *EnrollProof) Unmarshal(buf []byte) error

Unmarshal decodes a frame into the EnrollProof.

type EnrollRequest

type EnrollRequest struct {
	EKPub  []byte
	EKCert []byte
	AKPub  []byte
	AKName []byte
}

EnrollRequest is the node's opening enrolment message: its Endorsement Key public area, the EK certificate (carried opaquely; trust is decided by the EKRegistry), the AK public area, and the AK Name (the value MakeCredential must commit to). EKPub is the TPMT_PUBLIC of the EK; AKPub the TPMT_PUBLIC of the AK; AKName the bare (alg||digest) Name from tpm2.ObjectName.

func (EnrollRequest) Marshal

func (m EnrollRequest) Marshal() []byte

Marshal encodes the EnrollRequest to a self-describing frame.

func (*EnrollRequest) Unmarshal

func (m *EnrollRequest) Unmarshal(buf []byte) error

Unmarshal decodes a frame into the EnrollRequest.

type EventLogPolicy

type EventLogPolicy interface {
	Policy
	// Replay folds the event log into virtual PCRs and reports whether it is
	// consistent with the attested PCRs (stub for v0.2).
	Replay(eventLog []byte, pcrs map[int][]byte) error
}

EventLogPolicy is the planned v0.2 Policy that REPLAYS a TCG measured-boot event log against the attested PCRs and checks every measured event against an allowlist — closing the gap that GoldenPolicy needs a precomputed golden digest per platform. It is declared here as a documented stub so the interface and intent are stable.

TODO(v0.2): implement TCG event-log (TPM2_EventLog / EFI_TCG2 format) replay:

  • parse the event stream (spec-id header + per-event digests),
  • fold each event's digest into a virtual PCR bank and assert the result equals the attested PCR value (proves the log is consistent with the quote), and
  • check every event against an allowlist of approved measurements,

then satisfy Policy by delegating value-level checks to a GoldenPolicy or to the replayed expectations.

type GoldenPolicy

type GoldenPolicy map[int][]byte

GoldenPolicy is the v0.1.0 Policy: a map of required PCR index -> expected digest. Matches requires every golden PCR to be present in the attested set AND to equal its golden value exactly; the first PCR that is missing or differs is named in the returned *UntrustedBootError. Attested PCRs not named in the golden map are ignored (the policy constrains only the PCRs it lists).

func (GoldenPolicy) Matches

func (g GoldenPolicy) Matches(pcrs map[int][]byte) error

Matches checks every golden PCR against the attested values in ascending index order (so the "first mismatch" reported is deterministic).

type MemRegistry

type MemRegistry struct {
	// contains filtered or unexported fields
}

MemRegistry is a simple thread-safe in-memory EKRegistry. EKs are trusted by an explicit allowlist keyed on the exact EK public bytes; bound AKs are held in a map from AK Name to AK public. It is intended for tests, single-process control planes, and as a reference implementation.

func NewMemRegistry

func NewMemRegistry() *MemRegistry

NewMemRegistry returns an empty MemRegistry. Use TrustEK to allow EKs before enrolling nodes.

func (*MemRegistry) AKPub

func (r *MemRegistry) AKPub(akName []byte) ([]byte, bool)

AKPub returns the bound AK public for akName, if any.

func (*MemRegistry) BindAK

func (r *MemRegistry) BindAK(akName, akPub []byte) error

BindAK stores akPub under akName. It never fails for MemRegistry (the error is part of the interface so a backing store can report a write failure).

func (*MemRegistry) TrustEK

func (r *MemRegistry) TrustEK(ekPub []byte)

TrustEK adds an EK public area to the allowlist, so a node presenting this exact EK may enrol. A production registry would instead validate the EK certificate against a manufacturer root; this explicit allowlist keeps the reference impl dependency-free.

func (*MemRegistry) Trusted

func (r *MemRegistry) Trusted(ekPub []byte) bool

Trusted reports whether ekPub is on the allowlist.

type Node

type Node struct {
	// contains filtered or unexported fields
}

Node is the agent side of the protocol, running on the attesting platform. It drives a real *tpm2.TPM: it owns the EK and AK transient handles, their public areas, and the AK Name, and it answers the verifier's two challenges — RespondEnroll (ActivateCredential) and RespondAdmission (Quote + PCRRead).

A Node is NOT safe for concurrent use: it serializes onto a single TPM, and credential activation opens a policy session per call.

func FromHandles

func FromHandles(tpm *tpm2.TPM, ekHandle uint32, ekPub []byte, akHandle uint32, akPub, akName []byte, pcrSel []tpm2.PCRSelection) (*Node, error)

FromHandles builds a Node from pre-loaded EK and AK handles and their public areas (the contents of TPM2B_PUBLIC). akName is the AK Name; if nil it is derived from akPub via ObjectName. This is for callers that created or loaded the keys themselves. ekPub must be an ECC TPMT_PUBLIC carrying the EK point.

func NewNode

func NewNode(tpm *tpm2.TPM, pcrSel []tpm2.PCRSelection) (*Node, error)

NewNode creates the EK and the AK on tpm and returns a ready Node. It runs CreateEK (the EK Credential Profile L-2 ECC P-256 key), CreatePrimaryPublic (an ECC P-256 restricted signing AK, returning its TPMT_PUBLIC), and derives the AK Name with ObjectName. pcrSel is the PCR selection the node will quote (e.g. SHA-256 bank, PCRs 0..7).

func (*Node) AKName

func (n *Node) AKName() []byte

AKName returns the node's AK Name (used in AdmissionRequest and as the verifier's lookup key).

func (*Node) AdmissionRequest

func (n *Node) AdmissionRequest() AdmissionRequest

AdmissionRequest returns the node's admission message naming its AK.

func (*Node) EnrollRequest

func (n *Node) EnrollRequest(ekCert []byte) EnrollRequest

EnrollRequest returns the node's enrolment message: its EK public area, an (optional) EK certificate, its AK public area, and its AK Name. ekCert may be nil when the trust decision is made on the EK public alone.

func (*Node) RespondAdmission

func (n *Node) RespondAdmission(ch AdmissionChallenge) (AdmissionResponse, error)

RespondAdmission answers the verifier's nonce challenge with a TPM Quote over the node's PCR selection, folding the nonce into the quote's extraData, plus the current PCR values from PCRRead. The signature is rendered as the fixed-width r||s form the wire carries.

func (*Node) RespondEnroll

func (n *Node) RespondEnroll(ch EnrollChallenge) (EnrollProof, error)

RespondEnroll answers the verifier's MakeCredential challenge by running TPM2_ActivateCredential: it opens a policy session, satisfies the EK policy with PolicySecret(TPM_RH_ENDORSEMENT), and activates the credential with the AK as activateHandle and the EK as keyHandle. The recovered activation secret (which only this TPM can produce) is returned as the proof.

type Nonce

type Nonce func() ([32]byte, error)

Nonce is the verifier's source of fresh 32-byte challenges. It is injected so tests can supply a deterministic source; production code uses RandNonce.

type Policy

type Policy interface {
	// Matches reports nil if the PCRs represent an approved stack, or a typed
	// error (e.g. *UntrustedBootError) naming the first failing PCR otherwise.
	Matches(pcrs map[int][]byte) error
}

Policy decides whether a set of attested PCR values represents an approved boot. The verifier calls Matches AFTER it has cryptographically established that the PCR values are genuine (signature + nonce + pcrDigest all checked), so a Policy only has to compare values, never crypto.

type UntrustedBootError

type UntrustedBootError struct {
	// PCR is the index of the first failing PCR.
	PCR int
	// Reason describes the failure (missing vs. value mismatch).
	Reason string
}

UntrustedBootError is the typed Policy failure: the index of the first PCR that did not match the policy, and a short reason. errors.As lets callers recover the PCR index for diagnostics. It satisfies ErrUntrustedBoot under errors.Is so callers can branch on the sentinel without unwrapping.

func (*UntrustedBootError) Error

func (e *UntrustedBootError) Error() string

Error implements the error interface.

func (*UntrustedBootError) Is

func (e *UntrustedBootError) Is(target error) bool

Is reports that an *UntrustedBootError matches the ErrUntrustedBoot sentinel, so callers can write errors.Is(err, ErrUntrustedBoot).

type Verifier

type Verifier struct {
	// contains filtered or unexported fields
}

Verifier is the control-plane side of the protocol: it admits nodes onto a fleet on proof of an approved boot. It is PURE GO and never touches a TPM — the verifier side of TPM credential protection (MakeCredential) and of quote verification (VerifyQuote) is all off-TPM crypto. A Verifier is safe for concurrent use.

func NewVerifier

func NewVerifier(registry EKRegistry, policy Policy, nonce Nonce) *Verifier

NewVerifier builds a Verifier over a trust registry, an admission policy, and a nonce source. Pass RandNonce for production; a deterministic source for tests.

func (*Verifier) Admit

func (v *Verifier) Admit(akName []byte, resp AdmissionResponse) (bool, error)

Admit decides whether to grant the node admission. It looks up the bound AK and the pending nonce, then in order:

  1. verifies the Quote's ECDSA signature under the AK public AND that the quoted pcrDigest equals the digest over the claimed PCRs (tpm2.VerifyQuote does both);
  2. checks the attest's extraData equals exactly the issued nonce (anti-replay — VerifyQuote returns the parsed AttestInfo but does NOT check the nonce, so it is checked explicitly here);
  3. applies the boot Policy to the claimed PCRs.

Each failure returns a precise sentinel. The pending nonce is consumed on every call so a quote cannot be replayed against the same challenge.

func (*Verifier) Challenge

func (v *Verifier) Challenge(req AdmissionRequest) (AdmissionChallenge, error)

Challenge issues a fresh admission nonce for a bound AK and stashes it pending the node's quote. An unbound AK is refused.

func (*Verifier) CompleteEnroll

func (v *Verifier) CompleteEnroll(akName []byte, proof EnrollProof) error

CompleteEnroll finishes enrolment: it constant-time-compares the node's recovered ActivationSecret to the pending one and, on a match, binds the AK to the trusted EK in the registry. The pending entry is dropped either way (so a failed proof cannot be retried against the same challenge).

func (*Verifier) Enroll

func (v *Verifier) Enroll(req EnrollRequest) (EnrollChallenge, error)

Enroll begins enrolment: it rejects an untrusted EK, draws a random activation secret, and runs MakeCredential OFF the TPM (from the EK public point and the AK Name) to produce the credentialBlob/secret challenge. The activation secret is stashed pending the node's proof. Only a TPM holding the EK private key and an AK with this exact Name can recover the secret.

func (*Verifier) SetPolicy

func (v *Verifier) SetPolicy(p Policy)

SetPolicy swaps the admission Policy. It is used after the first boot to install a GoldenPolicy built from the freshly measured PCRs (the common "trust on first attestation" bootstrap). It is safe for concurrent use.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL