diff --git a/efi/efi.go b/efi/efi.go index cf1a4aa0..d66ecd85 100644 --- a/efi/efi.go +++ b/efi/efi.go @@ -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 ) diff --git a/efi/efi_test.go b/efi/efi_test.go index 5b53e171..97e89584 100644 --- a/efi/efi_test.go +++ b/efi/efi_test.go @@ -61,6 +61,7 @@ type mockPcrBranchEventType int const ( mockPcrBranchResetEvent mockPcrBranchEventType = iota + mockPcrBranchResetCRTMPCREvent mockPcrBranchExtendEvent mockPcrBranchMeasureVariableEvent ) @@ -69,6 +70,8 @@ type mockPcrBranchEvent struct { pcr int eventType mockPcrBranchEventType + locality uint8 + digest tpm2.Digest varName efi.VariableDescriptor @@ -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, @@ -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 +} diff --git a/efi/export_test.go b/efi/export_test.go index f6bfe58d..cf4256a3 100644 --- a/efi/export_test.go +++ b/efi/export_test.go @@ -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 diff --git a/efi/fw_load_handler.go b/efi/fw_load_handler.go index db6962ec..95c46522 100644 --- a/efi/fw_load_handler.go +++ b/efi/fw_load_handler.go @@ -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) @@ -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) } diff --git a/efi/fw_load_handler_test.go b/efi/fw_load_handler_test.go index 46e9cc16..8499fa22 100644 --- a/efi/fw_load_handler_test.go +++ b/efi/fw_load_handler_test.go @@ -20,6 +20,9 @@ package efi_test import ( + "fmt" + "io" + . "gopkg.in/check.v1" efi "github.com/canonical/go-efilib" @@ -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() } @@ -193,6 +199,9 @@ 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}, @@ -200,14 +209,67 @@ func (s *fwLoadHandlerSuite) TestMeasureImageStartSecureBootPolicyAndBootManager {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, @@ -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, @@ -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, @@ -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, @@ -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 diff --git a/efi/pcr_branch_context.go b/efi/pcr_branch_context.go index 23f2a4ff..3825b190 100644 --- a/efi/pcr_branch_context.go +++ b/efi/pcr_branch_context.go @@ -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 } @@ -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) { diff --git a/efi/pcr_profile.go b/efi/pcr_profile.go index 7cf2159b..e9d4c29f 100644 --- a/efi/pcr_profile.go +++ b/efi/pcr_profile.go @@ -39,6 +39,24 @@ func (o pcrProfileSetFlagsOption) applyOptionTo(gen *pcrProfileGenerator) { gen.flags |= pcrProfileFlags(o) } +// WithPlatformFirmwareProfile adds the SRTM, POST BIOS and Embedded Drivers +// profile (measured to PCR0). This is copied directly from the current host +// environment configuration. +// +// It is suitable in environments where platform firmware is measured by a +// hardware root of trust as opposed to being verified as authentic and prevented +// from running otherwise. +func WithPlatformFirmwareProfile() PCRProfileOption { + return pcrProfileSetFlagsOption(platformFirmwareProfile) +} + +// WithDriversAndAppsProfile adds the UEFI Drivers and UEFI Applications profile +// (measured to PCR2). This is copied directly from the current host environment +// configiguration. +func WithDriversAndAppsProfile() PCRProfileOption { + return pcrProfileSetFlagsOption(driversAndAppsProfile) +} + // WithSecureBootPolicyProfile requests that the UEFI secure boot policy profile is // added, which restricts access to a resource based on a set of secure boot policies // measured to PCR7. The secure boot policy that is measured to PCR7 is defined in @@ -163,8 +181,10 @@ func AddPCRProfile(pcrAlg tpm2.HashAlgorithmId, branch *secboot_tpm2.PCRProtecti type pcrProfileFlags int const ( - secureBootPolicyProfile pcrProfileFlags = 1 << iota + platformFirmwareProfile pcrProfileFlags = 1 << iota + driversAndAppsProfile bootManagerCodeProfile + secureBootPolicyProfile kernelConfigProfile ) diff --git a/efi/pcr_profile_test.go b/efi/pcr_profile_test.go index cc804af6..c102e078 100644 --- a/efi/pcr_profile_test.go +++ b/efi/pcr_profile_test.go @@ -706,6 +706,117 @@ func (s *pcrProfileSuite) TestAddPCRProfileUC20(c *C) { c.Check(err, IsNil) } +func (s *pcrProfileSuite) TestAddPCRProfileUC20WithExtraProfiles(c *C) { + // Test with a standard UC20 profile + shim := newMockUbuntuShimImage15_7(c) + grub := newMockUbuntuGrubImage3(c) + recoverKernel := newMockUbuntuKernelImage2(c) + runKernel := newMockUbuntuKernelImage3(c) + + err := s.testAddPCRProfile(c, &testAddPCRProfileData{ + vars: makeMockVars(c, withMsSecureBootConfig(), withSbatLevel([]byte("sbat,1,2022052400\ngrub,2\n"))), + log: efitest.NewLog(c, &efitest.LogOptions{ + Algorithms: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256, tpm2.HashAlgorithmSHA1}, + }), + alg: tpm2.HashAlgorithmSHA256, + loadSequences: NewImageLoadSequences( + SnapModelParams(testutil.MakeMockCore20ModelAssertion(c, map[string]interface{}{ + "authority-id": "fake-brand", + "series": "16", + "brand-id": "fake-brand", + "model": "fake-model", + "grade": "secured", + }, "Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij")), + ).Append( + NewImageLoadActivity(shim).Loads( + NewImageLoadActivity(grub, KernelCommandlineParams("console=ttyS0 console=tty1 panic=-1 systemd.gpt_auto=0 snapd_recovery_mode=recover")).Loads( + NewImageLoadActivity(grub, KernelCommandlineParams("console=ttyS0 console=tty1 panic=-1 systemd.gpt_auto=0 snapd_recovery_mode=run")).Loads( + NewImageLoadActivity(runKernel), + ), + NewImageLoadActivity(recoverKernel), + ), + ), + ), + expected: []tpm2.PCRValues{ + { + tpm2.HashAlgorithmSHA256: { + 0: testutil.DecodeHexString(c, "3d2b11b4c5cb623acbde6d14205217e47ebd368eab861e4fed782bb99be4598a"), + 2: testutil.DecodeHexString(c, "3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969"), + 4: testutil.DecodeHexString(c, "bec6121586508581e08a41244944292ef452879f8e19c7f93d166e912c6aac5e"), + 7: testutil.DecodeHexString(c, "3d65dbe406e9427d402488ea4f87e07e8b584c79c578a735d48d21a6405fc8bb"), + 12: testutil.DecodeHexString(c, "fd1000c6f691c3054e2ff5cfacb39305820c9f3534ba67d7894cb753aa85074b"), + }, + }, + { + tpm2.HashAlgorithmSHA256: { + 0: testutil.DecodeHexString(c, "3d2b11b4c5cb623acbde6d14205217e47ebd368eab861e4fed782bb99be4598a"), + 2: testutil.DecodeHexString(c, "3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969"), + 4: testutil.DecodeHexString(c, "c731a39b7fc6475c7d8a9264e704902157c7cee40c22f59fa1690ea99ff70c67"), + 7: testutil.DecodeHexString(c, "3d65dbe406e9427d402488ea4f87e07e8b584c79c578a735d48d21a6405fc8bb"), + 12: testutil.DecodeHexString(c, "5b354c57a61bb9f71fcf596d7e9ef9e2e0d6f4ad8151c9f358e6f0aaa7823756"), + }, + }, + }, + }, WithPlatformFirmwareProfile(), WithDriversAndAppsProfile(), WithSecureBootPolicyProfile(), WithBootManagerCodeProfile(), WithKernelConfigProfile()) + c.Check(err, IsNil) +} + +func (s *pcrProfileSuite) TestAddPCRProfileUC20WithPlatformFirmwareProfileSL3(c *C) { + // Test with a standard UC20 profile + shim := newMockUbuntuShimImage15_7(c) + grub := newMockUbuntuGrubImage3(c) + recoverKernel := newMockUbuntuKernelImage2(c) + runKernel := newMockUbuntuKernelImage3(c) + + err := s.testAddPCRProfile(c, &testAddPCRProfileData{ + vars: makeMockVars(c, withMsSecureBootConfig(), withSbatLevel([]byte("sbat,1,2022052400\ngrub,2\n"))), + log: efitest.NewLog(c, &efitest.LogOptions{ + Algorithms: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256, tpm2.HashAlgorithmSHA1}, + StartupLocality: 3, + }), + alg: tpm2.HashAlgorithmSHA256, + loadSequences: NewImageLoadSequences( + SnapModelParams(testutil.MakeMockCore20ModelAssertion(c, map[string]interface{}{ + "authority-id": "fake-brand", + "series": "16", + "brand-id": "fake-brand", + "model": "fake-model", + "grade": "secured", + }, "Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij")), + ).Append( + NewImageLoadActivity(shim).Loads( + NewImageLoadActivity(grub, KernelCommandlineParams("console=ttyS0 console=tty1 panic=-1 systemd.gpt_auto=0 snapd_recovery_mode=recover")).Loads( + NewImageLoadActivity(grub, KernelCommandlineParams("console=ttyS0 console=tty1 panic=-1 systemd.gpt_auto=0 snapd_recovery_mode=run")).Loads( + NewImageLoadActivity(runKernel), + ), + NewImageLoadActivity(recoverKernel), + ), + ), + ), + expected: []tpm2.PCRValues{ + { + tpm2.HashAlgorithmSHA256: { + 0: testutil.DecodeHexString(c, "25a58800ba22dff433a8bb1b5084a53ddf02dc71f204053b38036fe1c0f146e2"), + 2: testutil.DecodeHexString(c, "3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969"), + 4: testutil.DecodeHexString(c, "bec6121586508581e08a41244944292ef452879f8e19c7f93d166e912c6aac5e"), + 7: testutil.DecodeHexString(c, "3d65dbe406e9427d402488ea4f87e07e8b584c79c578a735d48d21a6405fc8bb"), + 12: testutil.DecodeHexString(c, "fd1000c6f691c3054e2ff5cfacb39305820c9f3534ba67d7894cb753aa85074b"), + }, + }, + { + tpm2.HashAlgorithmSHA256: { + 0: testutil.DecodeHexString(c, "25a58800ba22dff433a8bb1b5084a53ddf02dc71f204053b38036fe1c0f146e2"), + 2: testutil.DecodeHexString(c, "3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969"), + 4: testutil.DecodeHexString(c, "c731a39b7fc6475c7d8a9264e704902157c7cee40c22f59fa1690ea99ff70c67"), + 7: testutil.DecodeHexString(c, "3d65dbe406e9427d402488ea4f87e07e8b584c79c578a735d48d21a6405fc8bb"), + 12: testutil.DecodeHexString(c, "5b354c57a61bb9f71fcf596d7e9ef9e2e0d6f4ad8151c9f358e6f0aaa7823756"), + }, + }, + }, + }, WithPlatformFirmwareProfile(), WithDriversAndAppsProfile(), WithSecureBootPolicyProfile(), WithBootManagerCodeProfile(), WithKernelConfigProfile()) + c.Check(err, IsNil) +} + func (s *pcrProfileSuite) TestAddPCRProfileUC20WithTryKernel(c *C) { // Test with a standard UC20 profile that includes a try kernel shim := newMockUbuntuShimImage15_7(c) diff --git a/internal/efitest/log.go b/internal/efitest/log.go index 7a79d2ce..12c65a99 100644 --- a/internal/efitest/log.go +++ b/internal/efitest/log.go @@ -93,10 +93,11 @@ type LogOptions struct { Algorithms []tpm2.HashAlgorithmId // the digest algorithms to include SecureBootDisabled bool - IncludeDriverLaunch bool // include a driver launch in the log - IncludeSysPrepAppLaunch bool // include a system-preparation app launch in the log - NoCallingEFIApplicationEvent bool // omit the EV_EFI_ACTION "Calling EFI Application from Boot Option" event. - NoSBAT bool // omit the SbatLevel measurement. + IncludeDriverLaunch bool // include a driver launch in the log + IncludeSysPrepAppLaunch bool // include a system-preparation app launch in the log + NoCallingEFIApplicationEvent bool // omit the EV_EFI_ACTION "Calling EFI Application from Boot Option" event. + NoSBAT bool // omit the SbatLevel measurement. + StartupLocality uint8 // specify a startup locality other than 0 } // NewLog creates a mock TCG log for testing. The log will look like a standard @@ -127,6 +128,18 @@ func NewLog(c *C, opts *LogOptions) *tcglog.Log { }, }, } + if opts.StartupLocality > 0 { + ev := &tcglog.Event{ + PCRIndex: 0, + EventType: tcglog.EventTypeNoAction, + Digests: make(tcglog.DigestMap), + Data: &tcglog.StartupLocalityEventData{StartupLocality: opts.StartupLocality}, + } + for _, alg := range opts.Algorithms { + ev.Digests[alg] = make(tcglog.Digest, alg.Size()) + } + builder.events = append(builder.events, ev) + } // Mock S-CRTM measurements {