Remove length-based hash lookups

Using the length of a digest to infer the hash algorithm is somewhat
fragile - if we end up with multiple hash algorithms that share the same
digest length, things will break. Instead, pass more complete digest
information through to relevant functions and figure things out by
mapping the TPM hash algorithm to the appropriate Golang type.
This commit is contained in:
Matthew Garrett 2020-04-14 14:38:24 -07:00 committed by GitHub
parent fe41cef1db
commit 0815f5e221
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 34 additions and 33 deletions

View File

@ -223,49 +223,38 @@ func (a *AKPublic) validate20Quote(quote Quote, pcrs []PCR, nonce []byte) error
}
pcrByIndex := map[int][]byte{}
pcrDigestLength := HashAlg(att.AttestedQuoteInfo.PCRSelection.Hash).cryptoHash().Size()
pcrDigestAlg := HashAlg(att.AttestedQuoteInfo.PCRSelection.Hash).cryptoHash()
for _, pcr := range pcrs {
// TODO(jsonp): Use pcr.DigestAlg once #116 is fixed.
if len(pcr.Digest) == pcrDigestLength {
if pcr.DigestAlg == pcrDigestAlg {
pcrByIndex[pcr.Index] = pcr.Digest
}
}
n := len(att.AttestedQuoteInfo.PCRDigest)
hash, ok := hashBySize[n]
if !ok {
return fmt.Errorf("quote used unsupported hash algorithm length: %d", n)
}
h := hash.New()
sigHash.Reset()
for _, index := range att.AttestedQuoteInfo.PCRSelection.PCRs {
digest, ok := pcrByIndex[index]
if !ok {
return fmt.Errorf("quote was over PCR %d which wasn't provided", index)
}
h.Write(digest)
sigHash.Write(digest)
}
if !bytes.Equal(h.Sum(nil), att.AttestedQuoteInfo.PCRDigest) {
if !bytes.Equal(sigHash.Sum(nil), att.AttestedQuoteInfo.PCRDigest) {
return fmt.Errorf("quote digest didn't match pcrs provided")
}
return nil
}
var hashBySize = map[int]crypto.Hash{
crypto.SHA1.Size(): crypto.SHA1,
crypto.SHA256.Size(): crypto.SHA256,
}
func extend(pcr PCR, replay []byte, e rawEvent) (pcrDigest []byte, eventDigest []byte, err error) {
h := pcr.DigestAlg
func extend(pcr, replay []byte, e rawEvent) (pcrDigest []byte, eventDigest []byte, err error) {
h, ok := hashBySize[len(pcr)]
if !ok {
return nil, nil, fmt.Errorf("pcr %d was not a known hash size: %d", e.index, len(pcr))
}
for _, digest := range e.digests {
if len(digest) != len(pcr) {
if digest.hash != pcr.DigestAlg {
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));
}
hash := h.New()
if len(replay) != 0 {
hash.Write(replay)
@ -273,10 +262,10 @@ func extend(pcr, replay []byte, e rawEvent) (pcrDigest []byte, eventDigest []byt
b := make([]byte, h.Size())
hash.Write(b)
}
hash.Write(digest)
return hash.Sum(nil), digest, nil
hash.Write(digest.data)
return hash.Sum(nil), digest.data, nil
}
return nil, nil, fmt.Errorf("no event digest matches pcr length: %d", len(pcr))
return nil, nil, fmt.Errorf("no event digest matches pcr algorithm: %v", pcr.DigestAlg)
}
// replayPCR replays the event log for a specific PCR, using pcr and
@ -294,7 +283,7 @@ func replayPCR(rawEvents []rawEvent, pcr PCR) ([]Event, bool) {
continue
}
replayValue, digest, err := extend(pcr.Digest, replay, e)
replayValue, digest, err := extend(pcr, replay, e)
if err != nil {
return nil, false
}
@ -489,12 +478,17 @@ func parseSpecIDEvent(b []byte) (*specIDEvent, error) {
return &e, nil
}
type digest struct {
hash crypto.Hash
data []byte
}
type rawEvent struct {
sequence int
index int
typ EventType
data []byte
digests [][]byte
digests []digest
}
// TPM 1.2 event log format. See "5.1 SHA1 Event Log Entry Format"
@ -526,15 +520,19 @@ func parseRawEvent(r *bytes.Buffer, specID *specIDEvent) (event rawEvent, err er
if h.EventSize > uint32(r.Len()) {
return event, &eventSizeErr{h.EventSize, r.Len()}
}
data := make([]byte, int(h.EventSize))
if _, err := io.ReadFull(r, data); err != nil {
return event, err
}
digests := []digest{{hash: crypto.SHA1, data: h.Digest[:]}}
return rawEvent{
typ: EventType(h.Type),
data: data,
index: int(h.PCRIndex),
digests: [][]byte{h.Digest[:]},
digests: digests,
}, nil
}
@ -547,6 +545,7 @@ type rawEvent2Header struct {
func parseRawEvent2(r *bytes.Buffer, specID *specIDEvent) (event rawEvent, err error) {
var h rawEvent2Header
if err = binary.Read(r, binary.LittleEndian, &h); err != nil {
return event, err
}
@ -564,7 +563,8 @@ func parseRawEvent2(r *bytes.Buffer, specID *specIDEvent) (event rawEvent, err e
if err := binary.Read(r, binary.LittleEndian, &algID); err != nil {
return event, err
}
var digest []byte
var digest digest
for _, alg := range specID.algs {
if alg.ID != algID {
continue
@ -572,12 +572,13 @@ func parseRawEvent2(r *bytes.Buffer, specID *specIDEvent) (event rawEvent, err e
if uint16(r.Len()) < alg.Size {
return event, fmt.Errorf("reading digest: %v", io.ErrUnexpectedEOF)
}
digest = make([]byte, alg.Size)
digest.data = make([]byte, alg.Size)
digest.hash = HashAlg(alg.ID).cryptoHash()
}
if len(digest) == 0 {
if len(digest.data) == 0 {
return event, fmt.Errorf("unknown algorithm ID %x", algID)
}
if _, err := io.ReadFull(r, digest); err != nil {
if _, err := io.ReadFull(r, digest.data); err != nil {
return event, err
}
event.digests = append(event.digests, digest)

File diff suppressed because one or more lines are too long