Handle StartupLocality events

Systems with TXT enabled may issue the TPM2_Startup() command from a
locality other than 0. In this case, the initial value of PCR0 will
represent the locality that the call was made from. This is exposed to
higher layers by an EV_NO_ACTION event that has data containing the
NULL-terminated string "StartupLocality" followed by a single byte
representing the state of the locality. As this event is EV_NO_ACTION,
it does not represent an extension in itself.

So:

1) Ignore events that are EV_NO_ACTION when replaying the log, except:
2) For PCR0, if an event is EV_NO_ACTION and contains the string
"StartupLocality", use the final byte of the event data as the initial
value of PCR0 for the replay.
This commit is contained in:
Matthew Garrett 2020-06-11 12:55:03 -07:00 committed by Matthew Garrett
parent 5e360d3104
commit fe22f29ec8

View File

@ -25,6 +25,7 @@ import (
"fmt"
"io"
"sort"
"strings"
// Ensure hashes are available.
_ "crypto/sha256"
@ -287,7 +288,7 @@ func (a *AKPublic) validate20Quote(quote Quote, pcrs []PCR, nonce []byte) error
return nil
}
func extend(pcr PCR, replay []byte, e rawEvent) (pcrDigest []byte, eventDigest []byte, err error) {
func extend(pcr PCR, replay []byte, e rawEvent, locality byte) (pcrDigest []byte, eventDigest []byte, err error) {
h := pcr.DigestAlg
for _, digest := range e.digests {
@ -295,13 +296,14 @@ func extend(pcr PCR, replay []byte, e rawEvent) (pcrDigest []byte, eventDigest [
continue
}
if len(digest.data) != len(pcr.Digest) {
return nil, nil, fmt.Errorf("digest data length (%d) doesn't match PCR digest length (%d)", len(digest.data), len(pcr.Digest));
return nil, nil, fmt.Errorf("digest data length (%d) doesn't match PCR digest length (%d)", len(digest.data), len(pcr.Digest))
}
hash := h.New()
if len(replay) != 0 {
hash.Write(replay)
} else {
b := make([]byte, h.Size())
b[h.Size()-1] = locality
hash.Write(b)
}
hash.Write(digest.data)
@ -318,14 +320,25 @@ func replayPCR(rawEvents []rawEvent, pcr PCR) ([]Event, bool) {
var (
replay []byte
outEvents []Event
locality byte
)
for _, e := range rawEvents {
if e.index != pcr.Index {
continue
}
replayValue, digest, err := extend(pcr, replay, e)
// If TXT is enabled then the first event for PCR0
// should be a StartupLocality event. The final byte
// of this event indicates the locality from which
// TPM2_Startup() was issued. The initial value of
// PCR0 is equal to the locality.
if e.typ == eventTypeNoAction {
if pcr.Index == 0 && len(e.data) == 17 && strings.HasPrefix(string(e.data), "StartupLocality") {
locality = e.data[len(e.data)-1]
}
continue
}
replayValue, digest, err := extend(pcr, replay, e, locality)
if err != nil {
return nil, false
}