diff --git a/attest/attest.go b/attest/attest.go index 4e3aded..e55d382 100644 --- a/attest/attest.go +++ b/attest/attest.go @@ -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 diff --git a/attest/eventlog.go b/attest/eventlog.go index 6cc7de8..6547c70 100644 --- a/attest/eventlog.go +++ b/attest/eventlog.go @@ -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. diff --git a/attest/tpm.go b/attest/tpm.go index 9e430e1..8495cb1 100644 --- a/attest/tpm.go +++ b/attest/tpm.go @@ -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 diff --git a/attest/tpm12_linux.go b/attest/tpm12_linux.go index 10c9c69..9b150a6 100644 --- a/attest/tpm12_linux.go +++ b/attest/tpm12_linux.go @@ -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) diff --git a/attest/tpm_windows.go b/attest/tpm_windows.go index 151f171..e1daeae 100644 --- a/attest/tpm_windows.go +++ b/attest/tpm_windows.go @@ -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 diff --git a/attest/wrapped_tpm20.go b/attest/wrapped_tpm20.go index 0771191..732ea09 100644 --- a/attest/wrapped_tpm20.go +++ b/attest/wrapped_tpm20.go @@ -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 { diff --git a/go.mod b/go.mod index d1bd4f3..9dd337b 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( github.com/google/go-tpm v0.9.3 github.com/google/go-tpm-tools v0.4.4 github.com/google/go-tspi v0.3.0 + go.uber.org/multierr v1.11.0 golang.org/x/sys v0.30.0 )