mirror of
https://github.com/google/go-attestation.git
synced 2024-12-18 20:47:57 +00:00
Add workaround in validation for missing exit boot services event log messages (#153)
This commit is contained in:
parent
0815f5e221
commit
67c0b4ad07
@ -40,6 +40,15 @@ type ReplayError struct {
|
||||
invalidPCRs []int
|
||||
}
|
||||
|
||||
func (e ReplayError) affected(pcr int) bool {
|
||||
for _, p := range e.invalidPCRs {
|
||||
if p == pcr {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Error returns a human-friendly description of replay failures.
|
||||
func (e ReplayError) Error() string {
|
||||
return fmt.Sprintf("event log failed to verify: the following registers failed to replay: %v", e.invalidPCRs)
|
||||
@ -111,11 +120,44 @@ type EventLog struct {
|
||||
rawEvents []rawEvent
|
||||
}
|
||||
|
||||
func (e *EventLog) clone() *EventLog {
|
||||
out := EventLog{
|
||||
Algs: make([]HashAlg, len(e.Algs)),
|
||||
rawEvents: make([]rawEvent, len(e.rawEvents)),
|
||||
}
|
||||
copy(out.Algs, e.Algs)
|
||||
copy(out.rawEvents, e.rawEvents)
|
||||
return &out
|
||||
}
|
||||
|
||||
// Verify replays the event log against a TPM's PCR values, returning the
|
||||
// events which could be matched to a provided PCR value.
|
||||
// An error is returned if the replayed digest for events with a given PCR
|
||||
// index do not match any provided value for that PCR index.
|
||||
func (e *EventLog) Verify(pcrs []PCR) ([]Event, error) {
|
||||
events, err := e.verify(pcrs)
|
||||
// If there were any issues replaying the PCRs, try each of the workarounds
|
||||
// in turn.
|
||||
// TODO(jsonp): Allow workarounds to be combined.
|
||||
if rErr, isReplayErr := err.(ReplayError); isReplayErr {
|
||||
for _, wkrd := range eventlogWorkarounds {
|
||||
if !rErr.affected(wkrd.affectedPCR) {
|
||||
continue
|
||||
}
|
||||
el := e.clone()
|
||||
if err := wkrd.apply(el); err != nil {
|
||||
return nil, fmt.Errorf("failed applying workaround %q: %v", wkrd.id, err)
|
||||
}
|
||||
if events, err := el.verify(pcrs); err == nil {
|
||||
return events, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return events, err
|
||||
}
|
||||
|
||||
func (e *EventLog) verify(pcrs []PCR) ([]Event, error) {
|
||||
events, err := replayEvents(e.rawEvents, pcrs)
|
||||
if err != nil {
|
||||
if _, isReplayErr := err.(ReplayError); isReplayErr {
|
||||
|
@ -261,3 +261,37 @@ func TestParseSpecIDEvent(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEBSVerifyWorkaround(t *testing.T) {
|
||||
pcr5 := []PCR{
|
||||
{
|
||||
Index: 5,
|
||||
Digest: []byte{
|
||||
0x31, 0x24, 0x58, 0x08, 0xd6, 0xd3, 0x58, 0x49, 0xbc, 0x39,
|
||||
0x4f, 0x63, 0x43, 0xf2, 0xb3, 0xff, 0x90, 0x8e, 0xd5, 0xe3,
|
||||
},
|
||||
DigestAlg: HashSHA1.cryptoHash(),
|
||||
},
|
||||
{
|
||||
Index: 5,
|
||||
Digest: []byte{
|
||||
0x6c, 0xae, 0xa1, 0x23, 0xfa, 0x61, 0x11, 0x30, 0x5e, 0xe6, 0x24,
|
||||
0xe4, 0x52, 0xe2, 0x69, 0xad, 0x14, 0xac, 0x52, 0x2a, 0xb8, 0xbf,
|
||||
0x0c, 0x88, 0xe1, 0x16, 0x16, 0xde, 0x4c, 0x22, 0x2f, 0x7d,
|
||||
},
|
||||
DigestAlg: HashSHA256.cryptoHash(),
|
||||
},
|
||||
}
|
||||
|
||||
elr, err := ioutil.ReadFile("testdata/ebs_event_missing_eventlog")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
el, err := ParseEventLog(elr)
|
||||
if err != nil {
|
||||
t.Fatalf("ParseEventLog() failed: %v", err)
|
||||
}
|
||||
if _, err := el.Verify(pcr5); err != nil {
|
||||
t.Errorf("Verify() failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
86
attest/eventlog_workarounds.go
Normal file
86
attest/eventlog_workarounds.go
Normal file
@ -0,0 +1,86 @@
|
||||
// Copyright 2020 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
// use this file except in compliance with the License. You may obtain a copy of
|
||||
// the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations under
|
||||
// the License.
|
||||
|
||||
package attest
|
||||
|
||||
type elWorkaround struct {
|
||||
id string
|
||||
affectedPCR int
|
||||
apply func(e *EventLog) error
|
||||
}
|
||||
|
||||
// inject3 appends two new events into the event log.
|
||||
func inject3(e *EventLog, pcr int, data1, data2, data3 string) error {
|
||||
if err := inject(e, pcr, data1); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := inject(e, pcr, data2); err != nil {
|
||||
return err
|
||||
}
|
||||
return inject(e, pcr, data3)
|
||||
}
|
||||
|
||||
// inject2 appends two new events into the event log.
|
||||
func inject2(e *EventLog, pcr int, data1, data2 string) error {
|
||||
if err := inject(e, pcr, data1); err != nil {
|
||||
return err
|
||||
}
|
||||
return inject(e, pcr, data2)
|
||||
}
|
||||
|
||||
// inject appends a new event into the event log.
|
||||
func inject(e *EventLog, pcr int, data string) error {
|
||||
evt := rawEvent{
|
||||
data: []byte(data),
|
||||
index: pcr,
|
||||
sequence: e.rawEvents[len(e.rawEvents)-1].sequence + 1,
|
||||
}
|
||||
for _, alg := range e.Algs {
|
||||
h := alg.cryptoHash().New()
|
||||
h.Write([]byte(data))
|
||||
evt.digests = append(evt.digests, h.Sum(nil))
|
||||
}
|
||||
e.rawEvents = append(e.rawEvents, evt)
|
||||
return nil
|
||||
}
|
||||
|
||||
const (
|
||||
ebsInvocation = "Exit Boot Services Invocation"
|
||||
ebsSuccess = "Exit Boot Services Returned with Success"
|
||||
ebsFailure = "Exit Boot Services Returned with Failure"
|
||||
)
|
||||
|
||||
var eventlogWorkarounds = []elWorkaround{
|
||||
{
|
||||
id: "EBS Invocation + Success",
|
||||
affectedPCR: 5,
|
||||
apply: func(e *EventLog) error {
|
||||
return inject2(e, 5, ebsInvocation, ebsSuccess)
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "EBS Invocation + Failure",
|
||||
affectedPCR: 5,
|
||||
apply: func(e *EventLog) error {
|
||||
return inject2(e, 5, ebsInvocation, ebsFailure)
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "EBS Invocation + Failure + Success",
|
||||
affectedPCR: 5,
|
||||
apply: func(e *EventLog) error {
|
||||
return inject3(e, 5, ebsInvocation, ebsFailure, ebsSuccess)
|
||||
},
|
||||
},
|
||||
}
|
BIN
attest/testdata/ebs_event_missing_eventlog
vendored
Normal file
BIN
attest/testdata/ebs_event_missing_eventlog
vendored
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user