Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

efi: Add profiles for PCRs 0 and 2 #299

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions efi/efi.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@
package efi

const (
bootManagerCodePCR = 4 // Boot Manager Code and Boot Attempts PCR
secureBootPCR = 7 // Secure Boot Policy Measurements PCR
kernelConfigPCR = 12
platformFirmwarePCR = 0 // SRTM, POST BIOS, and Embedded Drivers
driversAndAppsPCR = 2 // UEFI Drivers and UEFI Applications
bootManagerCodePCR = 4 // Boot Manager Code and Boot Attempts PCR
secureBootPCR = 7 // Secure Boot Policy Measurements PCR
kernelConfigPCR = 12
)
35 changes: 35 additions & 0 deletions efi/efi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ type mockPcrBranchEventType int

const (
mockPcrBranchResetEvent mockPcrBranchEventType = iota
mockPcrBranchResetCRTMPCREvent
mockPcrBranchExtendEvent
mockPcrBranchMeasureVariableEvent
)
Expand All @@ -69,6 +70,8 @@ type mockPcrBranchEvent struct {
pcr int
eventType mockPcrBranchEventType

locality uint8

digest tpm2.Digest

varName efi.VariableDescriptor
Expand Down Expand Up @@ -120,6 +123,14 @@ func (c *mockPcrBranchContext) ResetPCR(pcr int) {
})
}

func (c *mockPcrBranchContext) ResetCRTMPCR(locality uint8) {
c.events = append(c.events, &mockPcrBranchEvent{
pcr: 0,
eventType: mockPcrBranchResetCRTMPCREvent,
locality: locality,
})
}

func (c *mockPcrBranchContext) ExtendPCR(pcr int, digest tpm2.Digest) {
c.events = append(c.events, &mockPcrBranchEvent{
pcr: pcr,
Expand Down Expand Up @@ -652,3 +663,27 @@ func (s *mockSecureBootNamespaceRules) AddAuthorities(certs ...*x509.Certificate
func (mockSecureBootNamespaceRules) NewImageLoadHandler(image PeImageHandle) (ImageLoadHandler, error) {
return nil, errors.New("not implemented")
}

type mockErrLogData struct {
err error
}

func (d *mockErrLogData) String() string {
return fmt.Sprintf("Invalid event data: %v", d.err)
}

func (d *mockErrLogData) Bytes() []byte {
panic("not implemented")
}

func (d *mockErrLogData) Write(w io.Writer) error {
panic("not implemented")
}

func (d *mockErrLogData) Error() string {
return d.err.Error()
}

func (d *mockErrLogData) Unwrap() error {
return d.err
}
2 changes: 2 additions & 0 deletions efi/export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,10 @@ import (
// Export constants for testing
const (
BootManagerCodeProfile = bootManagerCodeProfile
DriversAndAppsProfile = driversAndAppsProfile
GrubChainloaderUsesShimProtocol = grubChainloaderUsesShimProtocol
KernelConfigProfile = kernelConfigProfile
PlatformFirmwareProfile = platformFirmwareProfile
SecureBootPolicyProfile = secureBootPolicyProfile
ShimFixVariableAuthorityEventsMatchSpec = shimFixVariableAuthorityEventsMatchSpec
ShimHasSbatRevocationManagement = shimHasSbatRevocationManagement
Expand Down
64 changes: 61 additions & 3 deletions efi/fw_load_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,56 @@ func (h *fwLoadHandler) measureSecureBootPolicyPreOS(ctx pcrBranchContext) error
return nil
}

func (h *fwLoadHandler) measurePlatformFirmware(ctx pcrBranchContext) error {
donePcrReset := false

for _, event := range h.log.Events {
if event.PCRIndex != platformFirmwarePCR {
continue
}
if event.EventType == tcglog.EventTypeNoAction {
if err, isErr := event.Data.(error); isErr {
return fmt.Errorf("cannot decode EV_NO_ACTION event data: %w", err)
}
if loc, isLoc := event.Data.(*tcglog.StartupLocalityEventData); isLoc {
if donePcrReset {
return errors.New("log for PCR0 has an unexpected StartupLocality event")
}
ctx.ResetCRTMPCR(loc.StartupLocality)
donePcrReset = true
}
continue
}

if !donePcrReset {
ctx.ResetPCR(platformFirmwarePCR)
donePcrReset = true
}

ctx.ExtendPCR(platformFirmwarePCR, tpm2.Digest(event.Digests[ctx.PCRAlg()]))
if event.EventType == tcglog.EventTypeSeparator {
break
}
}

return nil
}

func (h *fwLoadHandler) measureDriversAndApps(ctx pcrBranchContext) {
ctx.ResetPCR(driversAndAppsPCR)

for _, event := range h.log.Events {
if event.PCRIndex != driversAndAppsPCR {
continue
}

ctx.ExtendPCR(driversAndAppsPCR, tpm2.Digest(event.Digests[ctx.PCRAlg()]))
if event.EventType == tcglog.EventTypeSeparator {
break
}
}
}

func (h *fwLoadHandler) measureBootManagerCodePreOS(ctx pcrBranchContext) {
ctx.ResetPCR(bootManagerCodePCR)

Expand Down Expand Up @@ -189,14 +239,22 @@ func (h *fwLoadHandler) MeasureImageStart(ctx pcrBranchContext) error {
return errors.New("the TCG event log does not have the requested algorithm")
}

if ctx.Flags()&secureBootPolicyProfile > 0 {
if err := h.measureSecureBootPolicyPreOS(ctx); err != nil {
return xerrors.Errorf("cannot measure secure boot policy: %w", err)
if ctx.Flags()&platformFirmwareProfile > 0 {
if err := h.measurePlatformFirmware(ctx); err != nil {
return fmt.Errorf("cannot measure platform firmware policy: %w", err)
}
}
if ctx.Flags()&driversAndAppsProfile > 0 {
h.measureDriversAndApps(ctx)
}
if ctx.Flags()&bootManagerCodeProfile > 0 {
h.measureBootManagerCodePreOS(ctx)
}
if ctx.Flags()&secureBootPolicyProfile > 0 {
if err := h.measureSecureBootPolicyPreOS(ctx); err != nil {
return xerrors.Errorf("cannot measure secure boot policy: %w", err)
}
}
if ctx.Flags()&kernelConfigProfile > 0 {
ctx.ResetPCR(kernelConfigPCR)
}
Expand Down
125 changes: 122 additions & 3 deletions efi/fw_load_handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
package efi_test

import (
"fmt"
"io"

. "gopkg.in/check.v1"

efi "github.com/canonical/go-efilib"
Expand Down Expand Up @@ -58,6 +61,9 @@ func (s *fwLoadHandlerSuite) testMeasureImageStart(c *C, data *testFwMeasureImag
handler := NewFwLoadHandler(efitest.NewLog(c, data.logOptions))
c.Check(handler.MeasureImageStart(ctx), IsNil)
c.Check(ctx.events, DeepEquals, data.expectedEvents)
for _, event := range ctx.events {
c.Logf("pcr:%d, type:%v, digest:%#x", event.pcr, event.eventType, event.digest)
}
c.Check(collector.More(), testutil.IsFalse)
return ctx.FwContext()
}
Expand Down Expand Up @@ -193,21 +199,77 @@ func (s *fwLoadHandlerSuite) TestMeasureImageStartSecureBootPolicyAndBootManager
alg: tpm2.HashAlgorithmSHA256,
flags: BootManagerCodeProfile | SecureBootPolicyProfile,
expectedEvents: []*mockPcrBranchEvent{
{pcr: 4, eventType: mockPcrBranchResetEvent},
{pcr: 4, eventType: mockPcrBranchExtendEvent, digest: testutil.DecodeHexString(c, "3d6772b4f84ed47595d72a2c4c5ffd15f5bb72c7507fe26f2aaee2c69d5633ba")},
{pcr: 4, eventType: mockPcrBranchExtendEvent, digest: testutil.DecodeHexString(c, "df3f619804a92fdb4057192dc43dd748ea778adc52bc498ce80524c014b81119")},
{pcr: 7, eventType: mockPcrBranchResetEvent},
{pcr: 7, eventType: mockPcrBranchMeasureVariableEvent, varName: efi.VariableDescriptor{Name: "SecureBoot", GUID: efi.GlobalVariable}, varData: []byte{0x01}},
{pcr: 7, eventType: mockPcrBranchMeasureVariableEvent, varName: PK, varData: vars[PK].Payload},
{pcr: 7, eventType: mockPcrBranchMeasureVariableEvent, varName: KEK, varData: vars[KEK].Payload},
{pcr: 7, eventType: mockPcrBranchMeasureVariableEvent, varName: Db, varData: vars[Db].Payload},
{pcr: 7, eventType: mockPcrBranchMeasureVariableEvent, varName: Dbx, varData: vars[Dbx].Payload},
{pcr: 7, eventType: mockPcrBranchExtendEvent, digest: testutil.DecodeHexString(c, "df3f619804a92fdb4057192dc43dd748ea778adc52bc498ce80524c014b81119")},
{pcr: 4, eventType: mockPcrBranchResetEvent},
{pcr: 4, eventType: mockPcrBranchExtendEvent, digest: testutil.DecodeHexString(c, "3d6772b4f84ed47595d72a2c4c5ffd15f5bb72c7507fe26f2aaee2c69d5633ba")},
{pcr: 4, eventType: mockPcrBranchExtendEvent, digest: testutil.DecodeHexString(c, "df3f619804a92fdb4057192dc43dd748ea778adc52bc498ce80524c014b81119")},
},
})
}

func (s *fwLoadHandlerSuite) TestMeasureImageStartPlatformFirmwareProfile(c *C) {
s.testMeasureImageStart(c, &testFwMeasureImageStartData{
logOptions: &efitest.LogOptions{Algorithms: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256, tpm2.HashAlgorithmSHA1}},
alg: tpm2.HashAlgorithmSHA256,
flags: PlatformFirmwareProfile,
expectedEvents: []*mockPcrBranchEvent{
{pcr: 0, eventType: mockPcrBranchResetEvent},
{pcr: 0, eventType: mockPcrBranchExtendEvent, digest: testutil.DecodeHexString(c, "d0ff5974b6aa52cf562bea5921840c032a860a91a3512f7fe8f768f6bbe005f6")},
{pcr: 0, eventType: mockPcrBranchExtendEvent, digest: testutil.DecodeHexString(c, "aef237d4703e8936530141636186a9f249fa39e194f02f668cd328bd5902cf03")},
{pcr: 0, eventType: mockPcrBranchExtendEvent, digest: testutil.DecodeHexString(c, "8b0eec99d3cccc081edb98c3a2aa74b99a02b785bd74513e1cf7401e99121e80")},
{pcr: 0, eventType: mockPcrBranchExtendEvent, digest: testutil.DecodeHexString(c, "df3f619804a92fdb4057192dc43dd748ea778adc52bc498ce80524c014b81119")},
},
})
}

func (s *fwLoadHandlerSuite) TestMeasureImageStartPlatformFirmwareProfileSL3(c *C) {
s.testMeasureImageStart(c, &testFwMeasureImageStartData{
logOptions: &efitest.LogOptions{Algorithms: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256, tpm2.HashAlgorithmSHA1}, StartupLocality: 3},
alg: tpm2.HashAlgorithmSHA256,
flags: PlatformFirmwareProfile,
expectedEvents: []*mockPcrBranchEvent{
{pcr: 0, eventType: mockPcrBranchResetCRTMPCREvent, locality: 3},
{pcr: 0, eventType: mockPcrBranchExtendEvent, digest: testutil.DecodeHexString(c, "d0ff5974b6aa52cf562bea5921840c032a860a91a3512f7fe8f768f6bbe005f6")},
{pcr: 0, eventType: mockPcrBranchExtendEvent, digest: testutil.DecodeHexString(c, "aef237d4703e8936530141636186a9f249fa39e194f02f668cd328bd5902cf03")},
{pcr: 0, eventType: mockPcrBranchExtendEvent, digest: testutil.DecodeHexString(c, "8b0eec99d3cccc081edb98c3a2aa74b99a02b785bd74513e1cf7401e99121e80")},
{pcr: 0, eventType: mockPcrBranchExtendEvent, digest: testutil.DecodeHexString(c, "df3f619804a92fdb4057192dc43dd748ea778adc52bc498ce80524c014b81119")},
},
})
}

func (s *fwLoadHandlerSuite) TestMeasureImageStartDriversAndAppsProfile(c *C) {
s.testMeasureImageStart(c, &testFwMeasureImageStartData{
logOptions: &efitest.LogOptions{Algorithms: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256, tpm2.HashAlgorithmSHA1}},
alg: tpm2.HashAlgorithmSHA256,
flags: DriversAndAppsProfile,
expectedEvents: []*mockPcrBranchEvent{
{pcr: 2, eventType: mockPcrBranchResetEvent},
{pcr: 2, eventType: mockPcrBranchExtendEvent, digest: testutil.DecodeHexString(c, "df3f619804a92fdb4057192dc43dd748ea778adc52bc498ce80524c014b81119")},
},
})
}

func (s *fwLoadHandlerSuite) TestMeasureImageStartDriversAndAppsProfile2(c *C) {
s.testMeasureImageStart(c, &testFwMeasureImageStartData{
logOptions: &efitest.LogOptions{Algorithms: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256, tpm2.HashAlgorithmSHA1}, IncludeDriverLaunch: true},
alg: tpm2.HashAlgorithmSHA256,
flags: DriversAndAppsProfile,
expectedEvents: []*mockPcrBranchEvent{
{pcr: 2, eventType: mockPcrBranchResetEvent},
{pcr: 2, eventType: mockPcrBranchExtendEvent, digest: testutil.DecodeHexString(c, "1e94aaed2ad59a4409f3230dca2ad8c03ef8e3fde77cc47dc7b81bb8b242f3e6")},
{pcr: 2, eventType: mockPcrBranchExtendEvent, digest: testutil.DecodeHexString(c, "df3f619804a92fdb4057192dc43dd748ea778adc52bc498ce80524c014b81119")},
},
})
}

func (s *fwLoadHandlerSuite) TestMeasureImageStartErrBadLog1(c *C) {
// Insert a second EV_SEPARATOR event into PCR7
collector := NewRootVarsCollector(efitest.NewMockHostEnvironment(makeMockVars(c, withMsSecureBootConfig()), nil))
ctx := newMockPcrBranchContext(&mockPcrProfileContext{
alg: tpm2.HashAlgorithmSHA256,
Expand All @@ -231,6 +293,7 @@ func (s *fwLoadHandlerSuite) TestMeasureImageStartErrBadLog1(c *C) {
}

func (s *fwLoadHandlerSuite) TestMeasureImageStartErrBadLog2(c *C) {
// Prepend a verification event into PCR7 before the EV_SEPARATOR
collector := NewRootVarsCollector(efitest.NewMockHostEnvironment(makeMockVars(c, withMsSecureBootConfig()), nil))
ctx := newMockPcrBranchContext(&mockPcrProfileContext{
alg: tpm2.HashAlgorithmSHA256,
Expand All @@ -257,6 +320,7 @@ func (s *fwLoadHandlerSuite) TestMeasureImageStartErrBadLog2(c *C) {
}

func (s *fwLoadHandlerSuite) TestMeasureImageStartErrBadLog3(c *C) {
// Append a configuration event into PCR7 after the EV_SEPARATOR
collector := NewRootVarsCollector(efitest.NewMockHostEnvironment(makeMockVars(c, withMsSecureBootConfig()), nil))
ctx := newMockPcrBranchContext(&mockPcrProfileContext{
alg: tpm2.HashAlgorithmSHA256,
Expand All @@ -283,6 +347,7 @@ func (s *fwLoadHandlerSuite) TestMeasureImageStartErrBadLog3(c *C) {
}

func (s *fwLoadHandlerSuite) TestMeasureImageStartErrBadLog4(c *C) {
// Insert an unexpected event type into PCR7
collector := NewRootVarsCollector(efitest.NewMockHostEnvironment(makeMockVars(c, withMsSecureBootConfig()), nil))
ctx := newMockPcrBranchContext(&mockPcrProfileContext{
alg: tpm2.HashAlgorithmSHA256,
Expand All @@ -308,6 +373,60 @@ func (s *fwLoadHandlerSuite) TestMeasureImageStartErrBadLog4(c *C) {
c.Check(handler.MeasureImageStart(ctx), ErrorMatches, `cannot measure secure boot policy: unexpected event type \(EV_EFI_BOOT_SERVICES_APPLICATION\) found in log`)
}

func (s *fwLoadHandlerSuite) TestMeasureImageStartErrBadLog5(c *C) {
// Insert an invalid StartupLocality event data into the log
collector := NewRootVarsCollector(efitest.NewMockHostEnvironment(nil, nil))
ctx := newMockPcrBranchContext(&mockPcrProfileContext{
alg: tpm2.HashAlgorithmSHA256,
flags: PlatformFirmwareProfile}, nil, collector.Next())

log := efitest.NewLog(c, &efitest.LogOptions{
Algorithms: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256, tpm2.HashAlgorithmSHA1},
StartupLocality: 3})
for i, event := range log.Events {
if event.PCRIndex == 0 && event.EventType == tcglog.EventTypeNoAction {
if _, isLoc := event.Data.(*tcglog.StartupLocalityEventData); !isLoc {
continue
}
// Overwrite the event data with a mock error event
log.Events[i].Data = &mockErrLogData{fmt.Errorf("cannot decode StartupLocality data: %w", io.EOF)}
break
}
}

handler := NewFwLoadHandler(log)
c.Check(handler.MeasureImageStart(ctx), ErrorMatches, `cannot measure platform firmware policy: cannot decode EV_NO_ACTION event data: cannot decode StartupLocality data: EOF`)
}

func (s *fwLoadHandlerSuite) TestMeasureImageStartErrBadLog6(c *C) {
// Insert an extra StartupLocality event data into the log
collector := NewRootVarsCollector(efitest.NewMockHostEnvironment(nil, nil))
ctx := newMockPcrBranchContext(&mockPcrProfileContext{
alg: tpm2.HashAlgorithmSHA256,
flags: PlatformFirmwareProfile}, nil, collector.Next())

log := efitest.NewLog(c, &efitest.LogOptions{
Algorithms: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256, tpm2.HashAlgorithmSHA1},
StartupLocality: 3})
for i, event := range log.Events {
if event.PCRIndex == 0 && event.EventType == tcglog.EventTypeNoAction {
if _, isLoc := event.Data.(*tcglog.StartupLocalityEventData); !isLoc {
continue
}
events := log.Events[:i]
events = append(events, event, event)
if len(log.Events) > i+1 {
events = append(events, log.Events[i+1:]...)
}
log.Events = events
break
}
}

handler := NewFwLoadHandler(log)
c.Check(handler.MeasureImageStart(ctx), ErrorMatches, `cannot measure platform firmware policy: log for PCR0 has an unexpected StartupLocality event`)
}

type testFwMeasureImageLoadData struct {
alg tpm2.HashAlgorithmId
flags PcrProfileFlags
Expand Down
9 changes: 8 additions & 1 deletion efi/pcr_branch_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ type pcrBranchContext interface {
ShimContext() *shimContext // access the shim state for this branch

ResetPCR(pcr int) // reset the specified PCR for this branch
ResetCRTMPCR(locality uint8) // reset the S-CRTM PCR (0) from the specified locality
ExtendPCR(pcr int, digest tpm2.Digest) // extend the specified PCR for this branch
MeasureVariable(pcr int, guid efi.GUID, name string, data []byte) // measure the specified variable for this branch
}
Expand Down Expand Up @@ -90,7 +91,13 @@ func (c *pcrBranchCtx) ShimContext() *shimContext {
}

func (c *pcrBranchCtx) ResetPCR(pcr int) {
c.branch.AddPCRValue(c.PCRAlg(), pcr, make(tpm2.Digest, c.PCRAlg().Size()))
c.branch.AddPCRValue(c.PCRAlg(), pcr, make([]byte, c.PCRAlg().Size()))
}

func (c *pcrBranchCtx) ResetCRTMPCR(locality uint8) {
value := make([]byte, c.PCRAlg().Size())
value[len(value)-1] = locality
c.branch.AddPCRValue(c.PCRAlg(), platformFirmwarePCR, value)
}

func (c *pcrBranchCtx) ExtendPCR(pcr int, digest tpm2.Digest) {
Expand Down
Loading
Loading