mirror of
https://github.com/google/go-attestation.git
synced 2025-04-15 06:56:40 +00:00
attest: Implement discovery of supported PCR banks, rather than always blithely assuming we have exactly SHA1 and SHA256. (#404)
Some checks failed
CodeQL / Analyze (go) (push) Has been cancelled
Test / test-linux (1.22.x) (push) Has been cancelled
Test / test-linux-tpm12 (1.22.x) (push) Has been cancelled
Test / test-macos (1.22.x) (push) Has been cancelled
Test / test-windows (1.22.x) (push) Has been cancelled
Some checks failed
CodeQL / Analyze (go) (push) Has been cancelled
Test / test-linux (1.22.x) (push) Has been cancelled
Test / test-linux-tpm12 (1.22.x) (push) Has been cancelled
Test / test-macos (1.22.x) (push) Has been cancelled
Test / test-windows (1.22.x) (push) Has been cancelled
To do this, add a function to attest.TPM called PCRBanks() which enumerates the available PCR banks on a TPM. This requires plumbing through tpmBase and its implementations; the TPM1.2 implementations statically return []HashAlg{HashSHA1}, as one might expect. To accomplish all of this, the implementation of HashAlg needed to be rethought. Now, instead of a reimplementation of tpm2.Algorithm, it's a lightweight wrapper around it. Dependent methods -- like Hash() and String() -- no longer have case HashSHA1/case HashSHA256 blocks; instead, they simply delegate to go-tpm2 for their implementations. As a result, we should never need to do something like this again. Also add convenience constants HashSHA384 and HashSHA512.
This commit is contained in:
parent
f44f5ffe7e
commit
d9d8fdc48e
@ -399,41 +399,30 @@ func (a *AKPublic) VerifyAll(quotes []Quote, pcrs []PCR, nonce []byte) error {
|
||||
// HashAlg identifies a hashing Algorithm.
|
||||
type HashAlg uint8
|
||||
|
||||
// Valid hash algorithms.
|
||||
// Known valid hash algorithms.
|
||||
var (
|
||||
HashSHA1 = HashAlg(tpm2.AlgSHA1)
|
||||
HashSHA256 = HashAlg(tpm2.AlgSHA256)
|
||||
HashSHA384 = HashAlg(tpm2.AlgSHA384)
|
||||
HashSHA512 = HashAlg(tpm2.AlgSHA512)
|
||||
)
|
||||
|
||||
func (a HashAlg) cryptoHash() crypto.Hash {
|
||||
switch a {
|
||||
case HashSHA1:
|
||||
return crypto.SHA1
|
||||
case HashSHA256:
|
||||
return crypto.SHA256
|
||||
g := a.goTPMAlg()
|
||||
h, err := g.Hash()
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("HashAlg %v (corresponding to TPM2.Algorithm %v) has no corresponding crypto.Hash", a, g))
|
||||
}
|
||||
return 0
|
||||
return h
|
||||
}
|
||||
|
||||
func (a HashAlg) goTPMAlg() tpm2.Algorithm {
|
||||
switch a {
|
||||
case HashSHA1:
|
||||
return tpm2.AlgSHA1
|
||||
case HashSHA256:
|
||||
return tpm2.AlgSHA256
|
||||
}
|
||||
return 0
|
||||
return tpm2.Algorithm(a)
|
||||
}
|
||||
|
||||
// String returns a human-friendly representation of the hash algorithm.
|
||||
func (a HashAlg) String() string {
|
||||
switch a {
|
||||
case HashSHA1:
|
||||
return "SHA1"
|
||||
case HashSHA256:
|
||||
return "SHA256"
|
||||
}
|
||||
return fmt.Sprintf("HashAlg<%d>", int(a))
|
||||
return a.goTPMAlg().String()
|
||||
}
|
||||
|
||||
// PlatformParameters encapsulates the set of information necessary to attest
|
||||
|
@ -533,15 +533,7 @@ func ParseEventLog(measurementLog []byte) (*EventLog, error) {
|
||||
return nil, fmt.Errorf("failed to parse spec ID event: %v", err)
|
||||
}
|
||||
for _, alg := range specID.algs {
|
||||
switch tpm2.Algorithm(alg.ID) {
|
||||
case tpm2.AlgSHA1:
|
||||
el.Algs = append(el.Algs, HashSHA1)
|
||||
case tpm2.AlgSHA256:
|
||||
el.Algs = append(el.Algs, HashSHA256)
|
||||
}
|
||||
}
|
||||
if len(el.Algs) == 0 {
|
||||
return nil, fmt.Errorf("measurement log didn't use sha1 or sha256 digests")
|
||||
el.Algs = append(el.Algs, HashAlg(alg.ID))
|
||||
}
|
||||
// Switch to parsing crypto agile events. Don't include this in the
|
||||
// replayed events since it intentionally doesn't extend the PCRs.
|
||||
|
@ -29,6 +29,7 @@ import (
|
||||
|
||||
"github.com/google/go-tpm/legacy/tpm2"
|
||||
"github.com/google/go-tpm/tpmutil"
|
||||
"go.uber.org/multierr"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -312,6 +313,27 @@ func quote20(tpm io.ReadWriter, akHandle tpmutil.Handle, hashAlg tpm2.Algorithm,
|
||||
}, err
|
||||
}
|
||||
|
||||
func pcrbanks(tpm io.ReadWriter) ([]HashAlg, error) {
|
||||
vals, _, err := tpm2.GetCapability(tpm, tpm2.CapabilityPCRs, 1024, 0)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get TPM available PCR banks: %w", err)
|
||||
}
|
||||
|
||||
var hAlgs []HashAlg
|
||||
var errs error
|
||||
for i, v := range vals {
|
||||
pcrb, ok := v.(tpm2.PCRSelection)
|
||||
if !ok {
|
||||
errs = multierr.Append(errs, fmt.Errorf("failed to convert value %d to tpm2.PCRSelection: %v", i, v))
|
||||
continue
|
||||
}
|
||||
|
||||
hAlgs = append(hAlgs, HashAlg(pcrb.Hash))
|
||||
}
|
||||
|
||||
return hAlgs, errs
|
||||
}
|
||||
|
||||
func readAllPCRs20(tpm io.ReadWriter, alg tpm2.Algorithm) (map[uint32][]byte, error) {
|
||||
numPCRs := 24
|
||||
out := map[uint32][]byte{}
|
||||
@ -357,6 +379,7 @@ type tpmBase interface {
|
||||
eks() ([]EK, error)
|
||||
ekCertificates() ([]EK, error)
|
||||
info() (*TPMInfo, error)
|
||||
pcrbanks() ([]HashAlg, error)
|
||||
|
||||
loadAK(opaqueBlob []byte) (*AK, error)
|
||||
loadAKWithParent(opaqueBlob []byte, parent ParentKeyConfig) (*AK, error)
|
||||
@ -483,6 +506,14 @@ func (t *TPM) PCRs(alg HashAlg) ([]PCR, error) {
|
||||
return t.tpm.pcrs(alg)
|
||||
}
|
||||
|
||||
// PCRBanks returns the list of supported PCR banks on the TPM.
|
||||
//
|
||||
// This is a low-level API. Consumers seeking to attest the state of the
|
||||
// platform should use tpm.AttestPlatform() instead.
|
||||
func (t *TPM) PCRBanks() ([]HashAlg, error) {
|
||||
return t.tpm.pcrbanks()
|
||||
}
|
||||
|
||||
func (t *TPM) attestPCRs(ak *AK, nonce []byte, alg HashAlg) (*Quote, []PCR, error) {
|
||||
pcrs, err := t.PCRs(alg)
|
||||
if err != nil {
|
||||
@ -514,9 +545,9 @@ func (t *TPM) attestPlatform(ak *AK, nonce []byte, eventLog []byte) (*PlatformPa
|
||||
EventLog: eventLog,
|
||||
}
|
||||
|
||||
algs := []HashAlg{HashSHA1}
|
||||
if t.Version() == TPMVersion20 {
|
||||
algs = []HashAlg{HashSHA1, HashSHA256}
|
||||
algs, err := t.PCRBanks()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get PCR banks: %w", err)
|
||||
}
|
||||
|
||||
var lastErr error
|
||||
|
@ -163,6 +163,10 @@ func allPCRs12(ctx *tspi.Context) (map[uint32][]byte, error) {
|
||||
return PCRs, nil
|
||||
}
|
||||
|
||||
func (t *trousersTPM) pcrbanks() ([]HashAlg, error) {
|
||||
return []HashAlg{HashSHA1}, nil
|
||||
}
|
||||
|
||||
func (t *trousersTPM) pcrs(alg HashAlg) ([]PCR, error) {
|
||||
if alg != HashSHA1 {
|
||||
return nil, fmt.Errorf("non-SHA1 algorithm %v is not supported on TPM 1.2", alg)
|
||||
|
@ -376,6 +376,23 @@ func allPCRs12(tpm io.ReadWriter) (map[uint32][]byte, error) {
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (t *windowsTPM) pcrbanks() ([]HashAlg, error) {
|
||||
switch t.version {
|
||||
case TPMVersion12:
|
||||
return []HashAlg{HashSHA1}, nil
|
||||
|
||||
case TPMVersion20:
|
||||
tpm, err := t.pcp.TPMCommandInterface()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("TPMCommandInterface() failed: %v", err)
|
||||
}
|
||||
return pcrbanks(tpm)
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported TPM version: %x", t.version)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *windowsTPM) pcrs(alg HashAlg) ([]PCR, error) {
|
||||
var PCRs map[uint32][]byte
|
||||
|
||||
|
@ -462,6 +462,10 @@ func (t *wrappedTPM20) loadKeyWithParent(opaqueBlob []byte, parent ParentKeyConf
|
||||
return &Key{key: newWrappedKey20(hnd, sKey.Blob, sKey.Public, sKey.CreateData, sKey.CreateAttestation, sKey.CreateSignature), pub: pub, tpm: t}, nil
|
||||
}
|
||||
|
||||
func (t *wrappedTPM20) pcrbanks() ([]HashAlg, error) {
|
||||
return pcrbanks(t.rwc)
|
||||
}
|
||||
|
||||
func (t *wrappedTPM20) pcrs(alg HashAlg) ([]PCR, error) {
|
||||
PCRs, err := readAllPCRs20(t.rwc, alg.goTPMAlg())
|
||||
if err != nil {
|
||||
|
Loading…
x
Reference in New Issue
Block a user