Skip to content

Commit 10bfabe

Browse files
committed
Add option to skip Calling EFI Application check
The server library supports a check that requires EV_EFI_BOOT_SERVICES_APPLICATION to occur after a "Calling EFI Application from Boot Option" event. This check is generally useful for VMs and some physical firmware. However, some vendors load services as PE/COFF EFI applications before the OS loading process starts. This option will allow verifiers of those platforms to skip the check above. Closes google#535.
1 parent 938b9de commit 10bfabe

File tree

6 files changed

+89
-34
lines changed

6 files changed

+89
-34
lines changed
49.2 KB
Binary file not shown.

internal/test/test_data.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ var (
2626
Cos93AmdSevEventLog []byte
2727
//go:embed eventlogs/cos-101-amd-sev.bin
2828
Cos101AmdSevEventLog []byte
29+
//go:embed eventlogs/gdc-host.bin
30+
GdcHost []byte
2931
)
3032

3133
// Kernel command lines from event logs.

server/eventlog.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ var (
4343
// It is the caller's responsibility to ensure that the passed PCR values can be
4444
// trusted. Users can establish trust in PCR values by either calling
4545
// client.ReadPCRs() themselves or by verifying the values via a PCR quote.
46-
func parsePCClientEventLog(rawEventLog []byte, pcrs *tpmpb.PCRs, loader Bootloader) (*pb.MachineState, error) {
46+
func parsePCClientEventLog(rawEventLog []byte, pcrs *tpmpb.PCRs, opts VerifyOpts) (*pb.MachineState, error) {
4747
var errors []error
4848
events, err := parseReplayHelper(rawEventLog, pcrs)
4949
if err != nil {
@@ -61,14 +61,14 @@ func parsePCClientEventLog(rawEventLog []byte, pcrs *tpmpb.PCRs, loader Bootload
6161
if err != nil {
6262
errors = append(errors, err)
6363
}
64-
efiState, err := getEfiState(cryptoHash, rawEvents)
64+
efiState, err := getEfiState(cryptoHash, rawEvents, opts)
6565
if err != nil {
6666
errors = append(errors, err)
6767
}
6868

6969
var grub *pb.GrubState
7070
var kernel *pb.LinuxKernelState
71-
if loader == GRUB {
71+
if opts.Loader == GRUB {
7272
grub, err = getGrubState(cryptoHash, rawEvents)
7373
if err != nil {
7474
errors = append(errors, err)
@@ -541,7 +541,7 @@ func verifyDataDigest(hasher hash.Hash, data []byte, digest []byte) error {
541541
return nil
542542
}
543543

544-
func getEfiState(hash crypto.Hash, events []*pb.Event) (*pb.EfiState, error) {
544+
func getEfiState(hash crypto.Hash, events []*pb.Event, opts VerifyOpts) (*pb.EfiState, error) {
545545
// We pre-compute various event digests, and check if those event type have
546546
// been modified. We only trust events that come before the
547547
// ExitBootServices() request.
@@ -590,7 +590,7 @@ func getEfiState(hash crypto.Hash, events []*pb.Event) (*pb.EfiState, error) {
590590
}
591591

592592
if evtType == EFIBootServicesApplication {
593-
if !seenCallingEfiApp {
593+
if !opts.AllowEFIAppBeforeCallingEvent && !seenCallingEfiApp {
594594
return nil, fmt.Errorf("found EFIBootServicesApplication in PCR%d before CallingEFIApp event", index)
595595
}
596596
efiAppStates = append(efiAppStates, &pb.EfiApp{Digest: event.GetDigest()})

server/eventlog_test.go

Lines changed: 68 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ type eventLog struct {
3333
// The Arch Linux event log has two known failures due to our parser's strict checks.
3434
var archLinuxKnownParsingFailures = []string{
3535
"SecureBoot data len is 0, expected 1",
36-
"found EFIBootServicesApplication in PCR4 before CallingEFIApp event",
3736
}
3837

3938
// Agile Event Log from a RHEL 8 GCE instance with Secure Boot enabled
@@ -534,30 +533,59 @@ var COS101AmdSev = eventLog{
534533
},
535534
}
536535

536+
var GdcHost = eventLog{
537+
RawLog: test.GdcHost,
538+
Banks: []*pb.PCRs{{
539+
Hash: pb.HashAlgo_SHA256,
540+
Pcrs: map[uint32][]byte{
541+
0: decodeHex("dab77c454bd12c27ff6b6ce1f9adca90b7a330c1cef0b5cd01cb89fb3bd0dffa"),
542+
1: decodeHex("e9c706539943b2d9770715914f9b3946fab0265327bace4c479913acb9014051"),
543+
2: decodeHex("7fde57284c6a0eabdc9b829db4e2ab0bb565c4189410de2474dd116bc18bafcc"),
544+
3: decodeHex("3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969"),
545+
4: decodeHex("ded8b5d91a09c328b9859d8c9db5a346f1065224616b0ba66d6c83dba2b465e8"),
546+
5: decodeHex("163ee251955b844012f1493aa962b2a18acbec194ea4856cdc45cd54c8540058"),
547+
6: decodeHex("3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969"),
548+
7: decodeHex("2c9252609eda09899d96abe16b947d0e736c43271997c1fa5189e9bcd37ba516"),
549+
8: decodeHex("8edecd4daa5194ea70a2a9f2c71c7c816bd3b1e0a1ca6f4abea7306250191eba"),
550+
9: decodeHex("731d336f9f3255e80b429de54fb77b2ad5e485829eb386d661c668245f30f44b"),
551+
14: decodeHex("306f9d8b94f17d93dc6e7cf8f5c79d652eb4c6c4d13de2dddc24af416e13ecaf"),
552+
},
553+
}},
554+
ExpectedEFIAppDigests: map[pb.HashAlgo][]string{
555+
pb.HashAlgo_SHA256: {
556+
"c7ac5d44444affd8d4a7c5d3dea0ce20a71e05812fc18777a428d092f78ae3ff",
557+
"c5d3b47de11a9a2a4a15ef5cb7202d7800a10609c0dcecc46e3e963d476b76ce",
558+
"af4161084115c9d5c1872f4473fe974b535e3a9a767688293720ac2cc6f7f9a3",
559+
"af4161084115c9d5c1872f4473fe974b535e3a9a767688293720ac2cc6f7f9a3",
560+
},
561+
},
562+
}
563+
537564
func TestParseEventLogs(t *testing.T) {
538565
sbatErrorStr := "asn1: structure error: tags don't match (16 vs {class:0 tag:24 length:10 isCompound:true})"
539566
logs := []struct {
540567
eventLog
541568
name string
542-
Bootloader
569+
opts VerifyOpts
543570
// This field handles known issues with event log parsing or bad event
544571
// logs.
545572
// Set to nil when the event log has no known issues.
546573
errorSubstrs []string
547574
}{
548-
{Debian10GCE, "Debian10GCE", UnsupportedLoader, nil},
549-
{Rhel8GCE, "Rhel8GCE", GRUB, nil},
550-
{UbuntuAmdSevGCE, "UbuntuAmdSevGCE", GRUB, nil},
575+
{Debian10GCE, "Debian10GCE", VerifyOpts{Loader: UnsupportedLoader}, nil},
576+
{Rhel8GCE, "Rhel8GCE", VerifyOpts{Loader: GRUB}, nil},
577+
{UbuntuAmdSevGCE, "UbuntuAmdSevGCE", VerifyOpts{Loader: GRUB}, nil},
551578
// TODO: remove once the fix is pulled in
552579
// https://github.com/google/go-attestation/pull/222
553-
{Ubuntu2104NoDbxGCE, "Ubuntu2104NoDbxGCE", GRUB, []string{sbatErrorStr}},
554-
{Ubuntu2104NoSecureBootGCE, "Ubuntu2104NoSecureBootGCE", GRUB, []string{sbatErrorStr}},
580+
{Ubuntu2104NoDbxGCE, "Ubuntu2104NoDbxGCE", VerifyOpts{Loader: GRUB}, []string{sbatErrorStr}},
581+
{Ubuntu2104NoSecureBootGCE, "Ubuntu2104NoSecureBootGCE", VerifyOpts{Loader: GRUB}, []string{sbatErrorStr}},
555582
// This event log has a SecureBoot variable length of 0.
556-
{ArchLinuxWorkstation, "ArchLinuxWorkstation", UnsupportedLoader, archLinuxKnownParsingFailures},
557-
{COS85AmdSev, "COS85AmdSev", GRUB, nil},
558-
{COS93AmdSev, "COS93AmdSev", GRUB, nil},
559-
{COS101AmdSev, "COS101AmdSev", GRUB, nil},
560-
{Ubuntu2404AmdSevSnp, "Ubuntu2404AmdSevSnp", GRUB, nil},
583+
{ArchLinuxWorkstation, "ArchLinuxWorkstation", VerifyOpts{Loader: UnsupportedLoader, AllowEFIAppBeforeCallingEvent: true}, archLinuxKnownParsingFailures},
584+
{COS85AmdSev, "COS85AmdSev", VerifyOpts{Loader: GRUB}, nil},
585+
{COS93AmdSev, "COS93AmdSev", VerifyOpts{Loader: GRUB}, nil},
586+
{COS101AmdSev, "COS101AmdSev", VerifyOpts{Loader: GRUB}, nil},
587+
{Ubuntu2404AmdSevSnp, "Ubuntu2404AmdSevSnp", VerifyOpts{Loader: GRUB}, nil},
588+
{GdcHost, "GdcHost", VerifyOpts{Loader: GRUB, AllowEFIAppBeforeCallingEvent: true}, []string{"invalid SCRTM version event for PCR0"}},
561589
}
562590

563591
for _, log := range logs {
@@ -566,7 +594,7 @@ func TestParseEventLogs(t *testing.T) {
566594
hashName := pb.HashAlgo_name[int32(bank.Hash)]
567595
subtestName := fmt.Sprintf("%s-%s", log.name, hashName)
568596
t.Run(subtestName, func(t *testing.T) {
569-
if _, err := parsePCClientEventLog(rawLog, bank, log.Bootloader); err != nil {
597+
if _, err := parsePCClientEventLog(rawLog, bank, log.opts); err != nil {
570598
gErr, ok := err.(*GroupedError)
571599
if !ok {
572600
t.Errorf("ParseMachineState should return a GroupedError")
@@ -589,7 +617,7 @@ func TestParseMachineStateReplayFail(t *testing.T) {
589617
pcrMap[0] = []byte{0, 0, 0, 0}
590618
badPcrs.Pcrs = pcrMap
591619

592-
_, err := parsePCClientEventLog(Debian10GCE.RawLog, &badPcrs, UnsupportedLoader)
620+
_, err := parsePCClientEventLog(Debian10GCE.RawLog, &badPcrs, VerifyOpts{Loader: UnsupportedLoader})
593621
if err == nil {
594622
t.Errorf("ParseMachineState should fail to replay the event log")
595623
}
@@ -614,7 +642,7 @@ func TestSystemParseEventLog(t *testing.T) {
614642
t.Fatalf("failed to read PCRs: %v", err)
615643
}
616644

617-
if _, err = parsePCClientEventLog(evtLog, pcrs, UnsupportedLoader); err != nil {
645+
if _, err = parsePCClientEventLog(evtLog, pcrs, VerifyOpts{Loader: UnsupportedLoader}); err != nil {
618646
t.Errorf("failed to parse MachineState: %v", err)
619647
}
620648
}
@@ -652,7 +680,7 @@ func TestEmptyEventlog(t *testing.T) {
652680
}
653681
for _, c := range cases {
654682
t.Run(c.name, func(t *testing.T) {
655-
state, err := parsePCClientEventLog(emptyLog, c.pcrs, UnsupportedLoader)
683+
state, err := parsePCClientEventLog(emptyLog, c.pcrs, VerifyOpts{Loader: UnsupportedLoader})
656684
if err != nil {
657685
t.Errorf("parsing empty eventlog: %v", err)
658686
}
@@ -665,7 +693,7 @@ func TestEmptyEventlog(t *testing.T) {
665693

666694
func TestParseSecureBootState(t *testing.T) {
667695
for _, bank := range UbuntuAmdSevGCE.Banks {
668-
msState, err := parsePCClientEventLog(UbuntuAmdSevGCE.RawLog, bank, UnsupportedLoader)
696+
msState, err := parsePCClientEventLog(UbuntuAmdSevGCE.RawLog, bank, VerifyOpts{Loader: UnsupportedLoader})
669697
if err != nil {
670698
t.Errorf("failed to parse and replay log: %v", err)
671699
}
@@ -1071,7 +1099,7 @@ func TestParseLinuxKernelState(t *testing.T) {
10711099
hashName := pb.HashAlgo_name[int32(bank.Hash)]
10721100
subtestName := fmt.Sprintf("%s-%s", log.name, hashName)
10731101
t.Run(subtestName, func(t *testing.T) {
1074-
msState, err := parsePCClientEventLog(log.RawLog, bank, GRUB)
1102+
msState, err := parsePCClientEventLog(log.RawLog, bank, VerifyOpts{Loader: GRUB})
10751103
if err != nil {
10761104
t.Errorf("failed to parse and replay log: %v", err)
10771105
}
@@ -1145,7 +1173,7 @@ func TestParseGrubState(t *testing.T) {
11451173
hashName := pb.HashAlgo_name[int32(bank.Hash)]
11461174
subtestName := fmt.Sprintf("%s-%s", log.name, hashName)
11471175
t.Run(subtestName, func(t *testing.T) {
1148-
msState, err := parsePCClientEventLog(log.RawLog, bank, GRUB)
1176+
msState, err := parsePCClientEventLog(log.RawLog, bank, VerifyOpts{Loader: GRUB})
11491177
if err != nil {
11501178
t.Errorf("failed to parse and replay log: %v", err)
11511179
}
@@ -1175,7 +1203,7 @@ func TestParseGrubStateFail(t *testing.T) {
11751203
hashName := pb.HashAlgo_name[int32(bank.Hash)]
11761204
subtestName := fmt.Sprintf("GlinuxNoSecureBootLaptop-%s", hashName)
11771205
t.Run(subtestName, func(t *testing.T) {
1178-
_, err := parsePCClientEventLog(eventlog.RawLog, bank, GRUB)
1206+
_, err := parsePCClientEventLog(eventlog.RawLog, bank, VerifyOpts{Loader: GRUB})
11791207
if err == nil {
11801208
t.Error("expected error when parsing GRUB state")
11811209
}
@@ -1207,7 +1235,7 @@ func TestParseEfiState(t *testing.T) {
12071235
hashName := pb.HashAlgo_name[int32(bank.Hash)]
12081236
subtestName := fmt.Sprintf("%s-%s", log.name, hashName)
12091237
t.Run(subtestName, func(t *testing.T) {
1210-
msState, err := parsePCClientEventLog(log.RawLog, bank, UnsupportedLoader)
1238+
msState, err := parsePCClientEventLog(log.RawLog, bank, VerifyOpts{Loader: UnsupportedLoader})
12111239
if err != nil {
12121240
t.Errorf("parsePCClientEventLog(%v, %v) got err = %v, want nil", log.name, bank.GetHash().String(), err)
12131241
}
@@ -1271,6 +1299,25 @@ func TestGetGrubStateWithModifiedNullTerminator(t *testing.T) {
12711299
}
12721300
}
12731301

1302+
func TestParseEventLogCallingEFIAppError(t *testing.T) {
1303+
tests := []struct {
1304+
eventLog
1305+
name string
1306+
}{
1307+
{ArchLinuxWorkstation, "ArchLinuxWorkstation"},
1308+
{GdcHost, "GdcHost"},
1309+
}
1310+
for _, test := range tests {
1311+
t.Run(test.name, func(t *testing.T) {
1312+
for _, bank := range test.Banks {
1313+
if _, err := parsePCClientEventLog(test.RawLog, bank, VerifyOpts{AllowEFIAppBeforeCallingEvent: false}); err == nil || !strings.Contains(err.Error(), "before CallingEFIApp event") {
1314+
t.Errorf("parsePCClientEventLog(%s): expected Calling EFI App error, received %v", test.name, err)
1315+
}
1316+
}
1317+
})
1318+
}
1319+
}
1320+
12741321
func decodeHex(hexStr string) []byte {
12751322
bytes, err := hex.DecodeString(hexStr)
12761323
if err != nil {

server/policy_test.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ func TestEvaluatePolicy(t *testing.T) {
6565

6666
for _, test := range tests {
6767
t.Run(test.name, func(t *testing.T) {
68-
machineState, err := parsePCClientEventLog(test.log.RawLog, test.log.Banks[0], UnsupportedLoader)
68+
machineState, err := parsePCClientEventLog(test.log.RawLog, test.log.Banks[0], VerifyOpts{Loader: UnsupportedLoader})
6969
if err != nil {
7070
t.Fatalf("failed to get machine state: %v", err)
7171
}
@@ -83,7 +83,7 @@ func TestEvaluatePolicySCRTM(t *testing.T) {
8383
0x4e, 0xf4, 0xbf, 0x17, 0xb8, 0x3a}},
8484
},
8585
}
86-
machineState, err := parsePCClientEventLog(ArchLinuxWorkstation.RawLog, ArchLinuxWorkstation.Banks[0], UnsupportedLoader)
86+
machineState, err := parsePCClientEventLog(ArchLinuxWorkstation.RawLog, ArchLinuxWorkstation.Banks[0], VerifyOpts{Loader: UnsupportedLoader, AllowEFIAppBeforeCallingEvent: true})
8787
if err != nil {
8888
gErr := err.(*GroupedError)
8989
if !gErr.containsKnownSubstrings(archLinuxKnownParsingFailures) {
@@ -123,22 +123,23 @@ func TestEvaluatePolicyFailure(t *testing.T) {
123123
name string
124124
log eventLog
125125
policy *pb.Policy
126+
opts VerifyOpts
126127
// This field handles known issues with event log parsing or bad event
127128
// logs.
128129
// Set to nil when the event log has no known issues.
129130
errorSubstrs []string
130131
}{
131-
{"Debian10-SHA1", Debian10GCE, &badGcePolicyVersion, nil},
132-
{"Debian10-SHA1", Debian10GCE, &badGcePolicySEV, nil},
132+
{"Debian10-SHA1", Debian10GCE, &badGcePolicyVersion, VerifyOpts{Loader: UnsupportedLoader}, nil},
133+
{"Debian10-SHA1", Debian10GCE, &badGcePolicySEV, VerifyOpts{Loader: UnsupportedLoader}, nil},
133134
{"Ubuntu1804AmdSev-CryptoAgile", UbuntuAmdSevGCE, &badGcePolicySEVES,
134-
nil},
135+
VerifyOpts{Loader: UnsupportedLoader}, nil},
135136
{"ArchLinuxWorkstation-CryptoAgile", ArchLinuxWorkstation,
136-
&badPhysicalPolicy, archLinuxKnownParsingFailures},
137+
&badPhysicalPolicy, VerifyOpts{Loader: UnsupportedLoader, AllowEFIAppBeforeCallingEvent: true}, archLinuxKnownParsingFailures},
137138
}
138139

139140
for _, test := range tests {
140141
t.Run(test.name, func(t *testing.T) {
141-
machineState, err := parsePCClientEventLog(test.log.RawLog, test.log.Banks[0], UnsupportedLoader)
142+
machineState, err := parsePCClientEventLog(test.log.RawLog, test.log.Banks[0], test.opts)
142143
if err != nil {
143144
gErr := err.(*GroupedError)
144145
if len(test.errorSubstrs) == 0 || !gErr.containsKnownSubstrings(test.errorSubstrs) {

server/verify.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@ type VerifyOpts struct {
6363
// Deprecated: go-tpm-tools no longer verifies SNP or TDX attestation.
6464
// Please use go-sev-guest and go-tdx-guest.
6565
TEEOpts interface{}
66+
// AllowEFIAppBeforeCallingEvent skips a check that requires
67+
// EV_EFI_BOOT_SERVICES_APPLICATION to occur after a
68+
// "Calling EFI Application from Boot Option". This option is useful when
69+
// the host platform loads EFI Applications unrelated to OS boot.
70+
AllowEFIAppBeforeCallingEvent bool
6671
}
6772

6873
// Bootloader refers to the second-stage bootloader that loads and transfers
@@ -353,7 +358,7 @@ func makePool(certs []*x509.Certificate) *x509.CertPool {
353358
// 2. verify GceTechnology since the GCE Technology event is directly related to the TPM.
354359
// 3. populate the machineState TeeAttestatation field with the verified TDX/SNP attestation data.
355360
func parseMachineStateFromTPM(attestation *pb.Attestation, pcrs *tpmpb.PCRs, opts VerifyOpts) (*pb.MachineState, error) {
356-
ms, err := parsePCClientEventLog(attestation.GetEventLog(), pcrs, opts.Loader)
361+
ms, err := parsePCClientEventLog(attestation.GetEventLog(), pcrs, opts)
357362
if err != nil {
358363
return nil, fmt.Errorf("failed to validate the PCClient event log: %w", err)
359364
}

0 commit comments

Comments
 (0)