From 92228960f10d3ffd450222511e7eb96d4e4c2eef Mon Sep 17 00:00:00 2001 From: Chris Coulson Date: Thu, 20 Jun 2024 23:38:44 +0100 Subject: [PATCH] efi: refactoring to prepare for the introduction of efi/preinstall efi/preinstall will depend on efi so it is necessary to break some cyclic dependencies, which I've done via the efi/internal package. The most problematic dependency is that efi/preinstall needs to use the efi.PCRProfileOption interface which contains an unexported method that takes a pointer to the unexported pcrProfileGenerator type - a type that should remain unexported. This has been solved by adding a simple internal.PCRProfileOptionVisitor interface that is implemented by pcrProfileGenerator and can be consumed in both efi and efi/preinstall packages. This has simplified direct testing of types that implement the efi.PCRProfileOption interface as well. On this note, this did highlight a couple of testing gaps - we had no direct tests for the WithSignatureDBUpdates and WithShimSbatPolicyLatest options. I've added tests for these, which found a bug in the way the branching for the quirk handling worked for WithSignatureDBUpdates. As part of this, I did rename a couple of types to give them names I felt make more sense. Eg, rootVarsCollector is not variableSetCollector, to bring it more in line with the new internal.VariableSet interface. The rootVarReader type is now initialVarReader, but other than that, no other changes to this code has been made - there's just been a lot of moving of types to the new efi/internal package. --- efi/efi.go | 6 +- efi/efi_test.go | 67 +++++--- efi/env.go | 118 +++++++------ efi/env_test.go | 50 +++--- efi/export_test.go | 43 ++--- efi/fw_load_handler.go | 62 +++---- efi/fw_load_handler_test.go | 79 ++++----- efi/grub_load_handler_test.go | 9 +- efi/image_rules_defs.go | 49 +----- efi/internal/MicrosoftKEK.crt | 34 ++++ efi/{ => internal}/default_env.go | 6 +- efi/{ => internal}/default_env_test.go | 36 +++- efi/internal/export_test.go | 38 +++++ efi/internal/known_secureboot_cas.go | 83 ++++++++++ efi/internal/options.go | 67 ++++++++ efi/internal/tcg_pcrs.go | 39 +++++ efi/pcr_branch_context.go | 3 +- efi/pcr_branch_context_test.go | 4 +- efi/pcr_images_measurer_test.go | 24 +-- efi/pcr_profile.go | 74 ++++++--- efi/pcr_profile_test.go | 27 +-- efi/secureboot.go | 30 ++-- efi/secureboot_namespace_rules.go | 65 ++++---- efi/secureboot_test.go | 219 ++++++++++++++++++++++++- efi/shim.go | 18 +- efi/shim_load_handler.go | 13 +- efi/shim_load_handler_test.go | 33 ++-- efi/shim_test.go | 72 ++++++++ 28 files changed, 975 insertions(+), 393 deletions(-) create mode 100644 efi/internal/MicrosoftKEK.crt rename efi/{ => internal}/default_env.go (90%) rename efi/{ => internal}/default_env_test.go (80%) create mode 100644 efi/internal/export_test.go create mode 100644 efi/internal/known_secureboot_cas.go create mode 100644 efi/internal/options.go create mode 100644 efi/internal/tcg_pcrs.go diff --git a/efi/efi.go b/efi/efi.go index fc8e4344..4815ed1b 100644 --- a/efi/efi.go +++ b/efi/efi.go @@ -22,11 +22,7 @@ package efi import "github.com/canonical/go-tpm2" const ( - platformFirmwarePCR tpm2.Handle = 0 // SRTM, POST BIOS, and Embedded Drivers - driversAndAppsPCR tpm2.Handle = 2 // UEFI Drivers and UEFI Applications - bootManagerCodePCR tpm2.Handle = 4 // Boot Manager Code and Boot Attempts PCR - secureBootPolicyPCR tpm2.Handle = 7 // Secure Boot Policy Measurements PCR - kernelConfigPCR tpm2.Handle = 12 + kernelConfigPCR tpm2.Handle = 12 ) // pcrFlags corresponds to a set of PCRs. This can only represent actual PCRs, it diff --git a/efi/efi_test.go b/efi/efi_test.go index c317115b..5be3c25a 100644 --- a/efi/efi_test.go +++ b/efi/efi_test.go @@ -33,6 +33,7 @@ import ( . "gopkg.in/check.v1" . "github.com/snapcore/secboot/efi" + "github.com/snapcore/secboot/efi/internal" "github.com/snapcore/secboot/internal/efitest" "github.com/snapcore/secboot/internal/testutil" ) @@ -693,61 +694,79 @@ type efiSuite struct{} var _ = Suite(&efiSuite{}) func (s *efiSuite) TestMakePcrFlags1(c *C) { - flags := MakePcrFlags(SecureBootPolicyPCR) - c.Check(flags, Equals, PcrFlags(1< 0 } -// Next returns the next starting state to generate a profile branch for. This will -// not return the same starting state more than once. -func (c *rootVarsCollector) Next() *varBranch { +// Next returns the next starting set to generate a profile branch for. This will +// not return the same starting set more than once. +func (c *variableSetCollector) Next() *varBranch { next := c.todo[0] c.todo = c.todo[1:] return c.newVarBranch(next) } -// PeekAll returns all of the pending starting states to generate profile -// branches for. -func (c *rootVarsCollector) PeekAll() []*varBranch { +// PeekAll returns all of the pending starting sets to generate profile +// branches for, without consuming them. It allows them to be added to +// with options that run before the profile generation. +func (c *variableSetCollector) PeekAll() []*varBranch { var out []*varBranch for _, r := range c.todo { out = append(out, c.newVarBranch(r)) } return out } - -type rootVarsModifier func(*rootVarsCollector) error diff --git a/efi/env_test.go b/efi/env_test.go index 1a4ac8e2..cbf75556 100644 --- a/efi/env_test.go +++ b/efi/env_test.go @@ -33,12 +33,12 @@ type envSuite struct{} var _ = Suite(&envSuite{}) -func (s *envSuite) TestRootVarReaderReadVar(c *C) { +func (s *envSuite) TestInitialVarReaderReadVar(c *C) { env := efitest.NewMockHostEnvironment(efitest.MockVars{ {Name: "SecureBoot", GUID: efi.GlobalVariable}: {Payload: []byte{1}, Attrs: efi.AttributeBootserviceAccess | efi.AttributeRuntimeAccess}, }, nil) - reader := NewRootVarReader(env) + reader := NewInitialVarReader(env) data, attrs, err := reader.ReadVar("SecureBoot", efi.GlobalVariable) c.Check(err, IsNil) @@ -46,12 +46,12 @@ func (s *envSuite) TestRootVarReaderReadVar(c *C) { c.Check(attrs, Equals, efi.AttributeBootserviceAccess|efi.AttributeRuntimeAccess) } -func (s *envSuite) TestRootVarReaderApplyOneUpdate(c *C) { +func (s *envSuite) TestInitialVarReaderApplyOneUpdate(c *C) { env := efitest.NewMockHostEnvironment(efitest.MockVars{ {Name: "foo", GUID: testGuid1}: {Payload: []byte{1}, Attrs: efi.AttributeNonVolatile | efi.AttributeBootserviceAccess}, }, nil) - reader := NewRootVarReader(env) + reader := NewInitialVarReader(env) reader.ApplyUpdates(NewVarUpdate(nil, efi.VariableDescriptor{Name: "foo", GUID: testGuid1}, efi.AttributeNonVolatile|efi.AttributeBootserviceAccess, []byte{2})) data, attrs, err := reader.ReadVar("foo", testGuid1) @@ -60,12 +60,12 @@ func (s *envSuite) TestRootVarReaderApplyOneUpdate(c *C) { c.Check(attrs, Equals, efi.AttributeNonVolatile|efi.AttributeBootserviceAccess) } -func (s *envSuite) TestRootVarReaderApplyMultipleUpdates(c *C) { +func (s *envSuite) TestInitialVarReaderApplyMultipleUpdates(c *C) { env := efitest.NewMockHostEnvironment(efitest.MockVars{ {Name: "foo", GUID: testGuid1}: {Payload: []byte{1}, Attrs: efi.AttributeNonVolatile | efi.AttributeBootserviceAccess}, }, nil) - reader := NewRootVarReader(env) + reader := NewInitialVarReader(env) reader.ApplyUpdates( NewVarUpdate( NewVarUpdate(nil, efi.VariableDescriptor{Name: "bar", GUID: testGuid1}, efi.AttributeNonVolatile|efi.AttributeBootserviceAccess, []byte{5}), @@ -82,12 +82,12 @@ func (s *envSuite) TestRootVarReaderApplyMultipleUpdates(c *C) { c.Check(attrs, Equals, efi.AttributeNonVolatile|efi.AttributeBootserviceAccess) } -func (s *envSuite) TestRootVarReaderApplyUpdatesOrdering(c *C) { +func (s *envSuite) TestInitialVarReaderApplyUpdatesOrdering(c *C) { env := efitest.NewMockHostEnvironment(efitest.MockVars{ {Name: "foo", GUID: testGuid1}: {Payload: []byte{1}, Attrs: efi.AttributeNonVolatile | efi.AttributeBootserviceAccess}, }, nil) - reader := NewRootVarReader(env) + reader := NewInitialVarReader(env) reader.ApplyUpdates( NewVarUpdate( NewVarUpdate(nil, efi.VariableDescriptor{Name: "foo", GUID: testGuid1}, efi.AttributeNonVolatile|efi.AttributeBootserviceAccess, []byte{2}), @@ -99,61 +99,61 @@ func (s *envSuite) TestRootVarReaderApplyUpdatesOrdering(c *C) { c.Check(attrs, Equals, efi.AttributeNonVolatile|efi.AttributeBootserviceAccess) } -func (s *envSuite) TestRootVarReaderKey(c *C) { +func (s *envSuite) TestInitialVarReaderKey(c *C) { env := efitest.NewMockHostEnvironment(efitest.MockVars{ {Name: "foo", GUID: testGuid1}: {Payload: []byte{1}, Attrs: efi.AttributeNonVolatile | efi.AttributeBootserviceAccess}, }, nil) - reader := NewRootVarReader(env) - c.Check(reader.Key(), DeepEquals, RootVarReaderKey{}) + reader := NewInitialVarReader(env) + c.Check(reader.Key(), DeepEquals, InitialVarReaderKey{}) } -func (s *envSuite) TestRootVarReaderKeyWithOneUpdate(c *C) { +func (s *envSuite) TestInitialVarReaderKeyWithOneUpdate(c *C) { env := efitest.NewMockHostEnvironment(efitest.MockVars{ {Name: "foo", GUID: testGuid1}: {Payload: []byte{1}, Attrs: efi.AttributeNonVolatile | efi.AttributeBootserviceAccess}, }, nil) - reader := NewRootVarReader(env) + reader := NewInitialVarReader(env) reader.ApplyUpdates(NewVarUpdate(nil, efi.VariableDescriptor{Name: "foo", GUID: testGuid1}, efi.AttributeNonVolatile|efi.AttributeBootserviceAccess, []byte{2})) - var expected RootVarReaderKey + var expected InitialVarReaderKey copy(expected[:], testutil.DecodeHexString(c, "af83642902c9f89dc8f761bb03a29bae54cc648e")) c.Check(reader.Key(), DeepEquals, expected) } -func (s *envSuite) TestRootVarReaderKeyWithMultipleUpdates(c *C) { +func (s *envSuite) TestInitialVarReaderKeyWithMultipleUpdates(c *C) { env := efitest.NewMockHostEnvironment(efitest.MockVars{ {Name: "foo", GUID: testGuid1}: {Payload: []byte{1}, Attrs: efi.AttributeNonVolatile | efi.AttributeBootserviceAccess}, }, nil) - reader := NewRootVarReader(env) + reader := NewInitialVarReader(env) reader.ApplyUpdates( NewVarUpdate( NewVarUpdate(nil, efi.VariableDescriptor{Name: "bar", GUID: testGuid1}, efi.AttributeNonVolatile|efi.AttributeBootserviceAccess, []byte{5}), efi.VariableDescriptor{Name: "foo", GUID: testGuid1}, efi.AttributeNonVolatile|efi.AttributeBootserviceAccess, []byte{2})) - var expected RootVarReaderKey + var expected InitialVarReaderKey copy(expected[:], testutil.DecodeHexString(c, "d9d3425d3e48666ff1ffc66d211b4bbe2dc654ae")) c.Check(reader.Key(), DeepEquals, expected) } -func (s *envSuite) TestRootVarReaderKeyOmitsUnchanged(c *C) { +func (s *envSuite) TestInitialVarReaderKeyOmitsUnchanged(c *C) { env := efitest.NewMockHostEnvironment(efitest.MockVars{ {Name: "foo", GUID: testGuid1}: {Payload: []byte{1}, Attrs: efi.AttributeNonVolatile | efi.AttributeBootserviceAccess}, }, nil) - reader := NewRootVarReader(env) + reader := NewInitialVarReader(env) reader.ApplyUpdates(NewVarUpdate(nil, efi.VariableDescriptor{Name: "foo", GUID: testGuid1}, efi.AttributeNonVolatile|efi.AttributeBootserviceAccess, []byte{1})) - c.Check(reader.Key(), DeepEquals, RootVarReaderKey{}) + c.Check(reader.Key(), DeepEquals, InitialVarReaderKey{}) } -func (s *envSuite) TestRootVarReaderCopy(c *C) { +func (s *envSuite) TestInitialVarReaderCopy(c *C) { env := efitest.NewMockHostEnvironment(efitest.MockVars{ {Name: "foo", GUID: testGuid1}: {Payload: []byte{1}, Attrs: efi.AttributeNonVolatile | efi.AttributeBootserviceAccess}, }, nil) - reader := NewRootVarReader(env) + reader := NewInitialVarReader(env) reader.ApplyUpdates( NewVarUpdate( NewVarUpdate(nil, efi.VariableDescriptor{Name: "bar", GUID: testGuid1}, efi.AttributeNonVolatile|efi.AttributeBootserviceAccess, []byte{5}), @@ -195,7 +195,7 @@ type testRootVarsCollectorData struct { } func (s *envSuite) testRootVarsCollector(c *C, data *testRootVarsCollectorData) { - collector := NewRootVarsCollector(data.env) + collector := NewVariableSetCollector(data.env) c.Assert(collector, NotNil) for i, expected := range data.expected { @@ -531,7 +531,7 @@ func (s *envSuite) TestRootVarsCollectorPeekAll(c *C) { {Name: "SecureBoot", GUID: efi.GlobalVariable}: {Payload: []byte{1}, Attrs: efi.AttributeBootserviceAccess | efi.AttributeRuntimeAccess}, }, nil) - collector := NewRootVarsCollector(env) + collector := NewVariableSetCollector(env) c.Assert(collector, NotNil) roots := collector.PeekAll() @@ -559,7 +559,7 @@ func (s *envSuite) TestRootVarsCollectorPeekAll(c *C) { func (s *envSuite) TestVarBranchReadsUpdate(c *C) { env := efitest.NewMockHostEnvironment(efitest.MockVars{}, nil) - collector := NewRootVarsCollector(env) + collector := NewVariableSetCollector(env) root := collector.Next() c.Check(root.WriteVar("foo", testGuid1, efi.AttributeNonVolatile|efi.AttributeBootserviceAccess, []byte{1}), IsNil) diff --git a/efi/export_test.go b/efi/export_test.go index 31189d73..983d2f15 100644 --- a/efi/export_test.go +++ b/efi/export_test.go @@ -22,16 +22,13 @@ package efi import ( efi "github.com/canonical/go-efilib" "github.com/canonical/tcglog-parser" + "github.com/snapcore/secboot/efi/internal" ) // Export constants for testing const ( - BootManagerCodePCR = bootManagerCodePCR - DriversAndAppsPCR = driversAndAppsPCR GrubChainloaderUsesShimProtocol = grubChainloaderUsesShimProtocol KernelConfigPCR = kernelConfigPCR - PlatformFirmwarePCR = platformFirmwarePCR - SecureBootPolicyPCR = secureBootPolicyPCR ShimFixVariableAuthorityEventsMatchSpec = shimFixVariableAuthorityEventsMatchSpec ShimHasSbatRevocationManagement = shimHasSbatRevocationManagement ShimHasSbatVerification = shimHasSbatVerification @@ -48,7 +45,6 @@ const ( // Export variables and unexported functions for testing var ( ApplySignatureDBUpdate = applySignatureDBUpdate - DefaultEnv = defaultEnv ErrNoHandler = errNoHandler ImageAlwaysMatches = imageAlwaysMatches ImageDigestMatches = imageDigestMatches @@ -69,11 +65,11 @@ var ( NewPcrImagesMeasurer = newPcrImagesMeasurer NewPcrProfileGenerator = newPcrProfileGenerator NewRootPcrBranchCtx = newRootPcrBranchCtx - NewRootVarsCollector = newRootVarsCollector NewSecureBootNamespaceRules = newSecureBootNamespaceRules NewShimImageHandle = newShimImageHandle NewShimLoadHandler = newShimLoadHandler NewShimLoadHandlerConstructor = newShimLoadHandlerConstructor + NewVariableSetCollector = newVariableSetCollector OpenPeImage = openPeImage ParseShimVersion = parseShimVersion ParseShimVersionDataIdent = parseShimVersionDataIdent @@ -100,6 +96,7 @@ type ImageLoadParamsSet = imageLoadParamsSet type ImageRules = imageRules type ImageSectionExists = imageSectionExists type ImageSignedByOrganization = imageSignedByOrganization +type InitialVarReaderKey = initialVarReaderKey type LoadParams = loadParams type NullLoadHandler = nullLoadHandler type PcrBranchContext = pcrBranchContext @@ -107,8 +104,6 @@ type PcrFlags = pcrFlags type PcrImagesMeasurer = pcrImagesMeasurer type PcrProfileContext = pcrProfileContext type PeImageHandle = peImageHandle -type RootVarReaderKey = rootVarReaderKey -type RootVarsCollector = rootVarsCollector type SbatComponent = sbatComponent type SbatComponentExists = sbatComponentExists type SecureBootAuthority = secureBootAuthority @@ -126,6 +121,7 @@ type ShimVersion = shimVersion type SignatureDBUpdateFirmwareQuirk = signatureDBUpdateFirmwareQuirk type UbuntuCoreUKILoadHandler = ubuntuCoreUKILoadHandler type VarBranch = varBranch +type VariableSetCollector = variableSetCollector type VarReadWriter = varReadWriter type VendorAuthorityGetter = vendorAuthorityGetter @@ -146,14 +142,6 @@ func (s *ImageLoadSequences) Params() imageLoadParamsSet { return s.params } -func MockEventLogPath(path string) (restore func()) { - origPath := eventLogPath - eventLogPath = path - return func() { - eventLogPath = origPath - } -} - func MockMakeImageLoadHandlerMap(fn func() imageLoadHandlerMap) (restore func()) { orig := makeImageLoadHandlerMap makeImageLoadHandlerMap = fn @@ -194,14 +182,6 @@ func MockOpenPeImage(fn func(Image) (peImageHandle, error)) (restore func()) { } } -func MockReadVar(fn func(string, efi.GUID) ([]byte, efi.VariableAttributes, error)) (restore func()) { - origReadVar := readVar - readVar = fn - return func() { - readVar = origReadVar - } -} - func MockSnapdenvTesting(testing bool) (restore func()) { orig := snapdenvTesting snapdenvTesting = func() bool { return testing } @@ -210,8 +190,8 @@ func MockSnapdenvTesting(testing bool) (restore func()) { } } -func NewRootVarReader(host HostEnvironment) *rootVarReader { - return &rootVarReader{ +func NewInitialVarReader(host HostEnvironment) *initialVarReader { + return &initialVarReader{ host: host, overrides: make(map[efi.VariableDescriptor]varContents)} } @@ -224,12 +204,13 @@ func NewVarUpdate(prev *varUpdate, name efi.VariableDescriptor, attrs efi.Variab data: data} } -type mockRootVarsModifierOption rootVarsModifier +type mockInitialVariablesModifierOption internal.InitialVariablesModifier -func (o mockRootVarsModifierOption) applyOptionTo(gen *pcrProfileGenerator) { - gen.varModifiers = append(gen.varModifiers, rootVarsModifier(o)) +func (o mockInitialVariablesModifierOption) ApplyOptionTo(visitor internal.PCRProfileOptionVisitor) error { + visitor.AddInitialVariablesModifier(internal.InitialVariablesModifier(o)) + return nil } -func WithMockRootVarsModifierOption(fn func(vars *RootVarsCollector) error) PCRProfileOption { - return mockRootVarsModifierOption(fn) +func WithMockInitialVariablesModifierOption(fn func(internal.VariableSet) error) PCRProfileOption { + return mockInitialVariablesModifierOption(fn) } diff --git a/efi/fw_load_handler.go b/efi/fw_load_handler.go index a43f593d..dcf31ebb 100644 --- a/efi/fw_load_handler.go +++ b/efi/fw_load_handler.go @@ -53,7 +53,7 @@ func (h *fwLoadHandler) measureSeparator(ctx pcrBranchContext, pcr tpm2.Handle, data, ok := event.Data.(*tcglog.SeparatorEventData) if !ok { - // if decoding fails, the resulting type is guaranteed to implement error. + // if the event data failed to decode, the resulting implementation is guaranteed to implement error. return fmt.Errorf("cannot measure invalid separator event: %w", event.Data.(error)) } if data.IsError() { @@ -69,7 +69,7 @@ func (h *fwLoadHandler) readAndMeasureSignatureDb(ctx pcrBranchContext, name efi return nil, xerrors.Errorf("cannot read current variable: %w", err) } - ctx.MeasureVariable(secureBootPolicyPCR, name.GUID, name.Name, db) + ctx.MeasureVariable(internal.SecureBootPolicyPCR, name.GUID, name.Name, db) return db, nil } @@ -91,7 +91,7 @@ func (h *fwLoadHandler) measureSecureBootPolicyPreOS(ctx pcrBranchContext) error // This hard-codes a profile that will only work on devices with secure boot enabled, // deployed mode on (where UEFI >= 2.5), without a UEFI debugger enabled and which // measure events in the correct order. - ctx.MeasureVariable(secureBootPolicyPCR, efi.GlobalVariable, sbStateName, []byte{1}) + ctx.MeasureVariable(internal.SecureBootPolicyPCR, efi.GlobalVariable, sbStateName, []byte{1}) if _, err := h.readAndMeasureSignatureDb(ctx, PK); err != nil { return xerrors.Errorf("cannot measure PK: %w", err) } @@ -118,19 +118,19 @@ func (h *fwLoadHandler) measureSecureBootPolicyPreOS(ctx pcrBranchContext) error events = events[1:] switch { - case e.PCRIndex < tcglog.PCRIndex(secureBootPolicyPCR) && e.EventType == tcglog.EventTypeSeparator: + case e.PCRIndex < tcglog.PCRIndex(internal.SecureBootPolicyPCR) && e.EventType == tcglog.EventTypeSeparator: // pre-OS to OS-present signal foundOsPresent = true - case e.PCRIndex == tcglog.PCRIndex(secureBootPolicyPCR) && e.EventType == tcglog.EventTypeSeparator: + case e.PCRIndex == tcglog.PCRIndex(internal.SecureBootPolicyPCR) && e.EventType == tcglog.EventTypeSeparator: // end of secure boot configuration signal if foundSecureBootSeparator { return errors.New("unexpected separator") } - if err := h.measureSeparator(ctx, secureBootPolicyPCR, e); err != nil { + if err := h.measureSeparator(ctx, internal.SecureBootPolicyPCR, e); err != nil { return err } foundSecureBootSeparator = true - case e.PCRIndex == tcglog.PCRIndex(secureBootPolicyPCR) && e.EventType == tcglog.EventTypeEFIVariableAuthority: + case e.PCRIndex == tcglog.PCRIndex(internal.SecureBootPolicyPCR) && e.EventType == tcglog.EventTypeEFIVariableAuthority: // secure boot verification event - shouldn't see this before the end of secure // boot configuration signal. if !foundSecureBootSeparator { @@ -138,14 +138,14 @@ func (h *fwLoadHandler) measureSecureBootPolicyPreOS(ctx pcrBranchContext) error } digest := tpm2.Digest(e.Digests[ctx.PCRAlg()]) ctx.FwContext().AppendVerificationEvent(digest) - ctx.ExtendPCR(secureBootPolicyPCR, digest) - case e.PCRIndex == tcglog.PCRIndex(secureBootPolicyPCR) && e.EventType == tcglog.EventTypeEFIVariableDriverConfig: + ctx.ExtendPCR(internal.SecureBootPolicyPCR, digest) + case e.PCRIndex == tcglog.PCRIndex(internal.SecureBootPolicyPCR) && e.EventType == tcglog.EventTypeEFIVariableDriverConfig: // ignore: part of the secure boot configuration - shouldn't see this after the // end of secure boot configuration signal. if foundSecureBootSeparator { return errors.New("unexpected configuration event") } - case e.PCRIndex == tcglog.PCRIndex(secureBootPolicyPCR): + case e.PCRIndex == tcglog.PCRIndex(internal.SecureBootPolicyPCR): return fmt.Errorf("unexpected event type (%v) found in log", e.EventType) default: // not a secure boot event @@ -166,7 +166,7 @@ func (h *fwLoadHandler) measurePlatformFirmware(ctx pcrBranchContext) error { donePcrReset := false for _, event := range h.log.Events { - if event.PCRIndex != tcglog.PCRIndex(platformFirmwarePCR) { + if event.PCRIndex != tcglog.PCRIndex(internal.PlatformFirmwarePCR) { continue } if event.EventType == tcglog.EventTypeNoAction { @@ -184,14 +184,14 @@ func (h *fwLoadHandler) measurePlatformFirmware(ctx pcrBranchContext) error { } if !donePcrReset { - ctx.ResetPCR(platformFirmwarePCR) + ctx.ResetPCR(internal.PlatformFirmwarePCR) donePcrReset = true } if event.EventType == tcglog.EventTypeSeparator { - return h.measureSeparator(ctx, platformFirmwarePCR, event) + return h.measureSeparator(ctx, internal.PlatformFirmwarePCR, event) } - ctx.ExtendPCR(platformFirmwarePCR, tpm2.Digest(event.Digests[ctx.PCRAlg()])) + ctx.ExtendPCR(internal.PlatformFirmwarePCR, tpm2.Digest(event.Digests[ctx.PCRAlg()])) } return errors.New("missing separator") @@ -199,14 +199,14 @@ func (h *fwLoadHandler) measurePlatformFirmware(ctx pcrBranchContext) error { func (h *fwLoadHandler) measureDriversAndApps(ctx pcrBranchContext) error { for _, event := range h.log.Events { - if event.PCRIndex != tcglog.PCRIndex(driversAndAppsPCR) { + if event.PCRIndex != tcglog.PCRIndex(internal.DriversAndAppsPCR) { continue } if event.EventType == tcglog.EventTypeSeparator { - return h.measureSeparator(ctx, driversAndAppsPCR, event) + return h.measureSeparator(ctx, internal.DriversAndAppsPCR, event) } - ctx.ExtendPCR(driversAndAppsPCR, tpm2.Digest(event.Digests[ctx.PCRAlg()])) + ctx.ExtendPCR(internal.DriversAndAppsPCR, tpm2.Digest(event.Digests[ctx.PCRAlg()])) } return errors.New("missing separator") @@ -252,18 +252,18 @@ func (h *fwLoadHandler) measureBootManagerCodePreOS(ctx pcrBranchContext) error event := events[0] events = events[1:] - if event.PCRIndex != tcglog.PCRIndex(bootManagerCodePCR) { + if event.PCRIndex != tcglog.PCRIndex(internal.BootManagerCodePCR) { continue } if event.EventType == tcglog.EventTypeSeparator { - if err := h.measureSeparator(ctx, bootManagerCodePCR, event); err != nil { + if err := h.measureSeparator(ctx, internal.BootManagerCodePCR, event); err != nil { return err } measuredSeparator = true break } - ctx.ExtendPCR(bootManagerCodePCR, tpm2.Digest(event.Digests[ctx.PCRAlg()])) + ctx.ExtendPCR(internal.BootManagerCodePCR, tpm2.Digest(event.Digests[ctx.PCRAlg()])) } if !measuredSeparator { @@ -279,7 +279,7 @@ func (h *fwLoadHandler) measureBootManagerCodePreOS(ctx pcrBranchContext) error event := events[0] events = events[1:] - if event.PCRIndex != tcglog.PCRIndex(bootManagerCodePCR) { + if event.PCRIndex != tcglog.PCRIndex(internal.BootManagerCodePCR) { continue } if event.EventType != tcglog.EventTypeEFIBootServicesApplication { @@ -295,7 +295,7 @@ func (h *fwLoadHandler) measureBootManagerCodePreOS(ctx pcrBranchContext) error } if isAbsolute { // copy the digest to the policy - ctx.ExtendPCR(bootManagerCodePCR, tpm2.Digest(event.Digests[ctx.PCRAlg()])) + ctx.ExtendPCR(internal.BootManagerCodePCR, tpm2.Digest(event.Digests[ctx.PCRAlg()])) } // If it's not Absolute, we assume it's related to the OS launch which we will predict // later on. If it's something else, discarding it here creates an invalid policy but this is @@ -316,28 +316,28 @@ func (h *fwLoadHandler) MeasureImageStart(ctx pcrBranchContext) error { // extends it later on. We ignore PCR0 here as a special case because it doesn't // necessarily have a zero reset value. for _, pcr := range ctx.PCRs().PCRs() { - if pcr == platformFirmwarePCR { + if pcr == internal.PlatformFirmwarePCR { continue } ctx.ResetPCR(pcr) } - if ctx.PCRs().Contains(platformFirmwarePCR) { + if ctx.PCRs().Contains(internal.PlatformFirmwarePCR) { if err := h.measurePlatformFirmware(ctx); err != nil { return fmt.Errorf("cannot measure platform firmware: %w", err) } } - if ctx.PCRs().Contains(driversAndAppsPCR) { + if ctx.PCRs().Contains(internal.DriversAndAppsPCR) { if err := h.measureDriversAndApps(ctx); err != nil { return fmt.Errorf("cannot measure drivers and apps: %w", err) } } - if ctx.PCRs().Contains(bootManagerCodePCR) { + if ctx.PCRs().Contains(internal.BootManagerCodePCR) { if err := h.measureBootManagerCodePreOS(ctx); err != nil { return fmt.Errorf("cannot measure boot manager code: %w", err) } } - if ctx.PCRs().Contains(secureBootPolicyPCR) { + if ctx.PCRs().Contains(internal.SecureBootPolicyPCR) { if err := h.measureSecureBootPolicyPreOS(ctx); err != nil { return xerrors.Errorf("cannot measure secure boot policy: %w", err) } @@ -390,7 +390,7 @@ func (m *fwImageLoadMeasurer) measureVerification() error { return nil } m.FwContext().AppendVerificationEvent(digest) - m.ExtendPCR(secureBootPolicyPCR, digest) + m.ExtendPCR(internal.SecureBootPolicyPCR, digest) return nil } @@ -399,18 +399,18 @@ func (m *fwImageLoadMeasurer) measurePEImageDigest() error { if err != nil { return xerrors.Errorf("cannot compute PE digest: %w", err) } - m.ExtendPCR(bootManagerCodePCR, digest) + m.ExtendPCR(internal.BootManagerCodePCR, digest) return nil } func (m *fwImageLoadMeasurer) measure() error { - if m.PCRs().Contains(secureBootPolicyPCR) { + if m.PCRs().Contains(internal.SecureBootPolicyPCR) { if err := m.measureVerification(); err != nil { return xerrors.Errorf("cannot measure secure boot event: %w", err) } } - if m.PCRs().Contains(bootManagerCodePCR) { + if m.PCRs().Contains(internal.BootManagerCodePCR) { if err := m.measurePEImageDigest(); err != nil { return xerrors.Errorf("cannot measure boot manager code event: %w", err) } diff --git a/efi/fw_load_handler_test.go b/efi/fw_load_handler_test.go index 5869e5bb..1eeab096 100644 --- a/efi/fw_load_handler_test.go +++ b/efi/fw_load_handler_test.go @@ -31,6 +31,7 @@ import ( "github.com/canonical/tcglog-parser" . "github.com/snapcore/secboot/efi" + "github.com/snapcore/secboot/efi/internal" "github.com/snapcore/secboot/internal/efitest" "github.com/snapcore/secboot/internal/testutil" ) @@ -54,7 +55,7 @@ type testFwMeasureImageStartData struct { } func (s *fwLoadHandlerSuite) testMeasureImageStart(c *C, data *testFwMeasureImageStartData) *FwContext { - collector := NewRootVarsCollector(efitest.NewMockHostEnvironment(data.vars, nil)) + collector := NewVariableSetCollector(efitest.NewMockHostEnvironment(data.vars, nil)) ctx := newMockPcrBranchContext(&mockPcrProfileContext{ alg: data.alg, pcrs: data.pcrs}, nil, collector.Next()) @@ -75,7 +76,7 @@ func (s *fwLoadHandlerSuite) TestMeasureImageStartSecureBootPolicyProfile(c *C) vars: vars, logOptions: &efitest.LogOptions{Algorithms: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256, tpm2.HashAlgorithmSHA1}}, alg: tpm2.HashAlgorithmSHA256, - pcrs: MakePcrFlags(SecureBootPolicyPCR), + pcrs: MakePcrFlags(internal.SecureBootPolicyPCR), expectedEvents: []*mockPcrBranchEvent{ {pcr: 7, eventType: mockPcrBranchResetEvent}, {pcr: 7, eventType: mockPcrBranchMeasureVariableEvent, varName: efi.VariableDescriptor{Name: "SecureBoot", GUID: efi.GlobalVariable}, varData: []byte{0x01}}, @@ -99,7 +100,7 @@ func (s *fwLoadHandlerSuite) TestMeasureImageStartSecureBootPolicyProfileSecureB SecureBootDisabled: true, }, alg: tpm2.HashAlgorithmSHA256, - pcrs: MakePcrFlags(SecureBootPolicyPCR), + pcrs: MakePcrFlags(internal.SecureBootPolicyPCR), expectedEvents: []*mockPcrBranchEvent{ {pcr: 7, eventType: mockPcrBranchResetEvent}, {pcr: 7, eventType: mockPcrBranchMeasureVariableEvent, varName: efi.VariableDescriptor{Name: "SecureBoot", GUID: efi.GlobalVariable}, varData: []byte{0x01}}, @@ -123,7 +124,7 @@ func (s *fwLoadHandlerSuite) TestMeasureImageStartSecureBootPolicyProfileInclude IncludeDriverLaunch: true, }, alg: tpm2.HashAlgorithmSHA256, - pcrs: MakePcrFlags(SecureBootPolicyPCR), + pcrs: MakePcrFlags(internal.SecureBootPolicyPCR), expectedEvents: []*mockPcrBranchEvent{ {pcr: 7, eventType: mockPcrBranchResetEvent}, {pcr: 7, eventType: mockPcrBranchMeasureVariableEvent, varName: efi.VariableDescriptor{Name: "SecureBoot", GUID: efi.GlobalVariable}, varData: []byte{0x01}}, @@ -144,7 +145,7 @@ func (s *fwLoadHandlerSuite) TestMeasureImageStartBootManagerCodeProfile(c *C) { vars: vars, logOptions: &efitest.LogOptions{Algorithms: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256, tpm2.HashAlgorithmSHA1}}, alg: tpm2.HashAlgorithmSHA256, - pcrs: MakePcrFlags(BootManagerCodePCR), + pcrs: MakePcrFlags(internal.BootManagerCodePCR), expectedEvents: []*mockPcrBranchEvent{ {pcr: 4, eventType: mockPcrBranchResetEvent}, {pcr: 4, eventType: mockPcrBranchExtendEvent, digest: testutil.DecodeHexString(c, "3d6772b4f84ed47595d72a2c4c5ffd15f5bb72c7507fe26f2aaee2c69d5633ba")}, @@ -164,7 +165,7 @@ func (s *fwLoadHandlerSuite) TestMeasureImageStartBootManagerCodeProfileWithoutC NoCallingEFIApplicationEvent: true, }, alg: tpm2.HashAlgorithmSHA256, - pcrs: MakePcrFlags(BootManagerCodePCR), + pcrs: MakePcrFlags(internal.BootManagerCodePCR), expectedEvents: []*mockPcrBranchEvent{ {pcr: 4, eventType: mockPcrBranchResetEvent}, {pcr: 4, eventType: mockPcrBranchExtendEvent, digest: testutil.DecodeHexString(c, "df3f619804a92fdb4057192dc43dd748ea778adc52bc498ce80524c014b81119")}, @@ -182,7 +183,7 @@ func (s *fwLoadHandlerSuite) TestMeasureImageStartBootManagerCodeProfileIncludeS IncludeSysPrepAppLaunch: true, }, alg: tpm2.HashAlgorithmSHA256, - pcrs: MakePcrFlags(BootManagerCodePCR), + pcrs: MakePcrFlags(internal.BootManagerCodePCR), expectedEvents: []*mockPcrBranchEvent{ {pcr: 4, eventType: mockPcrBranchResetEvent}, {pcr: 4, eventType: mockPcrBranchExtendEvent, digest: testutil.DecodeHexString(c, "11b68a5ce0facfa4233cb71140e3d59c686bc7a176a49a520947c57247fe86f4")}, @@ -203,7 +204,7 @@ func (s *fwLoadHandlerSuite) TestMeasureImageStartBootManagerCodeProfileIncludeA IncludeOSPresentFirmwareAppLaunch: efi.MakeGUID(0x821aca26, 0x29ea, 0x4993, 0x839f, [...]byte{0x59, 0x7f, 0xc0, 0x21, 0x70, 0x8d}), }, alg: tpm2.HashAlgorithmSHA256, - pcrs: MakePcrFlags(BootManagerCodePCR), + pcrs: MakePcrFlags(internal.BootManagerCodePCR), expectedEvents: []*mockPcrBranchEvent{ {pcr: 4, eventType: mockPcrBranchResetEvent}, {pcr: 4, eventType: mockPcrBranchExtendEvent, digest: testutil.DecodeHexString(c, "3d6772b4f84ed47595d72a2c4c5ffd15f5bb72c7507fe26f2aaee2c69d5633ba")}, @@ -224,7 +225,7 @@ func (s *fwLoadHandlerSuite) TestMeasureImageStartBootManagerCodeProfileIncludeA IncludeOSPresentFirmwareAppLaunch: efi.MakeGUID(0x8feeecf1, 0xbcfd, 0x4a78, 0x9231, [...]byte{0x48, 0x01, 0x56, 0x6b, 0x35, 0x67}), }, alg: tpm2.HashAlgorithmSHA256, - pcrs: MakePcrFlags(BootManagerCodePCR), + pcrs: MakePcrFlags(internal.BootManagerCodePCR), expectedEvents: []*mockPcrBranchEvent{ {pcr: 4, eventType: mockPcrBranchResetEvent}, {pcr: 4, eventType: mockPcrBranchExtendEvent, digest: testutil.DecodeHexString(c, "3d6772b4f84ed47595d72a2c4c5ffd15f5bb72c7507fe26f2aaee2c69d5633ba")}, @@ -246,7 +247,7 @@ func (s *fwLoadHandlerSuite) TestMeasureImageStartBootManagerCodeProfileIgnoreUn IncludeOSPresentFirmwareAppLaunch: efi.MakeGUID(0xee993080, 0x5197, 0x4d4e, 0xb63c, [...]byte{0xf1, 0xf7, 0x41, 0x3e, 0x33, 0xce}), }, alg: tpm2.HashAlgorithmSHA256, - pcrs: MakePcrFlags(BootManagerCodePCR), + pcrs: MakePcrFlags(internal.BootManagerCodePCR), expectedEvents: []*mockPcrBranchEvent{ {pcr: 4, eventType: mockPcrBranchResetEvent}, {pcr: 4, eventType: mockPcrBranchExtendEvent, digest: testutil.DecodeHexString(c, "3d6772b4f84ed47595d72a2c4c5ffd15f5bb72c7507fe26f2aaee2c69d5633ba")}, @@ -261,7 +262,7 @@ func (s *fwLoadHandlerSuite) TestMeasureImageStartSecureBootPolicyAndBootManager vars: vars, logOptions: &efitest.LogOptions{Algorithms: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256, tpm2.HashAlgorithmSHA1}}, alg: tpm2.HashAlgorithmSHA256, - pcrs: MakePcrFlags(BootManagerCodePCR, SecureBootPolicyPCR), + pcrs: MakePcrFlags(internal.BootManagerCodePCR, internal.SecureBootPolicyPCR), expectedEvents: []*mockPcrBranchEvent{ {pcr: 4, eventType: mockPcrBranchResetEvent}, {pcr: 7, eventType: mockPcrBranchResetEvent}, @@ -281,7 +282,7 @@ func (s *fwLoadHandlerSuite) TestMeasureImageStartPlatformFirmwareProfile(c *C) s.testMeasureImageStart(c, &testFwMeasureImageStartData{ logOptions: &efitest.LogOptions{Algorithms: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256, tpm2.HashAlgorithmSHA1}}, alg: tpm2.HashAlgorithmSHA256, - pcrs: MakePcrFlags(PlatformFirmwarePCR), + pcrs: MakePcrFlags(internal.PlatformFirmwarePCR), expectedEvents: []*mockPcrBranchEvent{ {pcr: 0, eventType: mockPcrBranchResetEvent}, {pcr: 0, eventType: mockPcrBranchExtendEvent, digest: testutil.DecodeHexString(c, "d0ff5974b6aa52cf562bea5921840c032a860a91a3512f7fe8f768f6bbe005f6")}, @@ -296,7 +297,7 @@ func (s *fwLoadHandlerSuite) TestMeasureImageStartPlatformFirmwareProfileSL3(c * s.testMeasureImageStart(c, &testFwMeasureImageStartData{ logOptions: &efitest.LogOptions{Algorithms: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256, tpm2.HashAlgorithmSHA1}, StartupLocality: 3}, alg: tpm2.HashAlgorithmSHA256, - pcrs: MakePcrFlags(PlatformFirmwarePCR), + pcrs: MakePcrFlags(internal.PlatformFirmwarePCR), expectedEvents: []*mockPcrBranchEvent{ {pcr: 0, eventType: mockPcrBranchResetCRTMPCREvent, locality: 3}, {pcr: 0, eventType: mockPcrBranchExtendEvent, digest: testutil.DecodeHexString(c, "d0ff5974b6aa52cf562bea5921840c032a860a91a3512f7fe8f768f6bbe005f6")}, @@ -311,7 +312,7 @@ func (s *fwLoadHandlerSuite) TestMeasureImageStartDriversAndAppsProfile(c *C) { s.testMeasureImageStart(c, &testFwMeasureImageStartData{ logOptions: &efitest.LogOptions{Algorithms: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256, tpm2.HashAlgorithmSHA1}}, alg: tpm2.HashAlgorithmSHA256, - pcrs: MakePcrFlags(DriversAndAppsPCR), + pcrs: MakePcrFlags(internal.DriversAndAppsPCR), expectedEvents: []*mockPcrBranchEvent{ {pcr: 2, eventType: mockPcrBranchResetEvent}, {pcr: 2, eventType: mockPcrBranchExtendEvent, digest: testutil.DecodeHexString(c, "df3f619804a92fdb4057192dc43dd748ea778adc52bc498ce80524c014b81119")}, @@ -323,7 +324,7 @@ 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, - pcrs: MakePcrFlags(DriversAndAppsPCR), + pcrs: MakePcrFlags(internal.DriversAndAppsPCR), expectedEvents: []*mockPcrBranchEvent{ {pcr: 2, eventType: mockPcrBranchResetEvent}, {pcr: 2, eventType: mockPcrBranchExtendEvent, digest: testutil.DecodeHexString(c, "1e94aaed2ad59a4409f3230dca2ad8c03ef8e3fde77cc47dc7b81bb8b242f3e6")}, @@ -334,10 +335,10 @@ func (s *fwLoadHandlerSuite) TestMeasureImageStartDriversAndAppsProfile2(c *C) { func (s *fwLoadHandlerSuite) TestMeasureImageStartErrBadLogPCR7_1(c *C) { // Insert a second EV_SEPARATOR event into PCR7 - collector := NewRootVarsCollector(efitest.NewMockHostEnvironment(makeMockVars(c, withMsSecureBootConfig()), nil)) + collector := NewVariableSetCollector(efitest.NewMockHostEnvironment(makeMockVars(c, withMsSecureBootConfig()), nil)) ctx := newMockPcrBranchContext(&mockPcrProfileContext{ alg: tpm2.HashAlgorithmSHA256, - pcrs: MakePcrFlags(SecureBootPolicyPCR)}, nil, collector.Next()) + pcrs: MakePcrFlags(internal.SecureBootPolicyPCR)}, nil, collector.Next()) log := efitest.NewLog(c, &efitest.LogOptions{Algorithms: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256, tpm2.HashAlgorithmSHA1}}) for i, event := range log.Events { @@ -358,10 +359,10 @@ func (s *fwLoadHandlerSuite) TestMeasureImageStartErrBadLogPCR7_1(c *C) { func (s *fwLoadHandlerSuite) TestMeasureImageStartErrBadLogPCR7_2(c *C) { // Prepend a verification event into PCR7 before the EV_SEPARATOR - collector := NewRootVarsCollector(efitest.NewMockHostEnvironment(makeMockVars(c, withMsSecureBootConfig()), nil)) + collector := NewVariableSetCollector(efitest.NewMockHostEnvironment(makeMockVars(c, withMsSecureBootConfig()), nil)) ctx := newMockPcrBranchContext(&mockPcrProfileContext{ alg: tpm2.HashAlgorithmSHA256, - pcrs: MakePcrFlags(SecureBootPolicyPCR)}, nil, collector.Next()) + pcrs: MakePcrFlags(internal.SecureBootPolicyPCR)}, nil, collector.Next()) log := efitest.NewLog(c, &efitest.LogOptions{Algorithms: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256, tpm2.HashAlgorithmSHA1}}) for i, event := range log.Events { @@ -385,10 +386,10 @@ func (s *fwLoadHandlerSuite) TestMeasureImageStartErrBadLogPCR7_2(c *C) { func (s *fwLoadHandlerSuite) TestMeasureImageStartErrBadLogPCR7_3(c *C) { // Append a configuration event into PCR7 after the EV_SEPARATOR - collector := NewRootVarsCollector(efitest.NewMockHostEnvironment(makeMockVars(c, withMsSecureBootConfig()), nil)) + collector := NewVariableSetCollector(efitest.NewMockHostEnvironment(makeMockVars(c, withMsSecureBootConfig()), nil)) ctx := newMockPcrBranchContext(&mockPcrProfileContext{ alg: tpm2.HashAlgorithmSHA256, - pcrs: MakePcrFlags(SecureBootPolicyPCR)}, nil, collector.Next()) + pcrs: MakePcrFlags(internal.SecureBootPolicyPCR)}, nil, collector.Next()) log := efitest.NewLog(c, &efitest.LogOptions{Algorithms: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256, tpm2.HashAlgorithmSHA1}}) for i, event := range log.Events { @@ -412,10 +413,10 @@ func (s *fwLoadHandlerSuite) TestMeasureImageStartErrBadLogPCR7_3(c *C) { func (s *fwLoadHandlerSuite) TestMeasureImageStartErrBadLogPCR7_4(c *C) { // Insert an unexpected event type into PCR7 - collector := NewRootVarsCollector(efitest.NewMockHostEnvironment(makeMockVars(c, withMsSecureBootConfig()), nil)) + collector := NewVariableSetCollector(efitest.NewMockHostEnvironment(makeMockVars(c, withMsSecureBootConfig()), nil)) ctx := newMockPcrBranchContext(&mockPcrProfileContext{ alg: tpm2.HashAlgorithmSHA256, - pcrs: MakePcrFlags(SecureBootPolicyPCR)}, nil, collector.Next()) + pcrs: MakePcrFlags(internal.SecureBootPolicyPCR)}, nil, collector.Next()) log := efitest.NewLog(c, &efitest.LogOptions{Algorithms: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256, tpm2.HashAlgorithmSHA1}}) for i, event := range log.Events { @@ -439,10 +440,10 @@ func (s *fwLoadHandlerSuite) TestMeasureImageStartErrBadLogPCR7_4(c *C) { func (s *fwLoadHandlerSuite) TestMeasureImageStartErrBadLogPCR0_1(c *C) { // Insert an invalid StartupLocality event data into the log - collector := NewRootVarsCollector(efitest.NewMockHostEnvironment(nil, nil)) + collector := NewVariableSetCollector(efitest.NewMockHostEnvironment(nil, nil)) ctx := newMockPcrBranchContext(&mockPcrProfileContext{ alg: tpm2.HashAlgorithmSHA256, - pcrs: MakePcrFlags(PlatformFirmwarePCR)}, nil, collector.Next()) + pcrs: MakePcrFlags(internal.PlatformFirmwarePCR)}, nil, collector.Next()) log := efitest.NewLog(c, &efitest.LogOptions{ Algorithms: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256, tpm2.HashAlgorithmSHA1}, @@ -464,10 +465,10 @@ func (s *fwLoadHandlerSuite) TestMeasureImageStartErrBadLogPCR0_1(c *C) { func (s *fwLoadHandlerSuite) TestMeasureImageStartErrBadLogPCR0_2(c *C) { // Insert an extra StartupLocality event data into the log - collector := NewRootVarsCollector(efitest.NewMockHostEnvironment(nil, nil)) + collector := NewVariableSetCollector(efitest.NewMockHostEnvironment(nil, nil)) ctx := newMockPcrBranchContext(&mockPcrProfileContext{ alg: tpm2.HashAlgorithmSHA256, - pcrs: MakePcrFlags(PlatformFirmwarePCR)}, nil, collector.Next()) + pcrs: MakePcrFlags(internal.PlatformFirmwarePCR)}, nil, collector.Next()) log := efitest.NewLog(c, &efitest.LogOptions{ Algorithms: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256, tpm2.HashAlgorithmSHA1}, @@ -493,10 +494,10 @@ func (s *fwLoadHandlerSuite) TestMeasureImageStartErrBadLogPCR0_2(c *C) { func (s *fwLoadHandlerSuite) TestMeasureImageStartErrBadLogPCR4_1(c *C) { // Insert an unexpected event type in the OS-present phase - collector := NewRootVarsCollector(efitest.NewMockHostEnvironment(nil, nil)) + collector := NewVariableSetCollector(efitest.NewMockHostEnvironment(nil, nil)) ctx := newMockPcrBranchContext(&mockPcrProfileContext{ alg: tpm2.HashAlgorithmSHA256, - pcrs: MakePcrFlags(BootManagerCodePCR)}, nil, collector.Next()) + pcrs: MakePcrFlags(internal.BootManagerCodePCR)}, nil, collector.Next()) log := efitest.NewLog(c, &efitest.LogOptions{ Algorithms: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256, tpm2.HashAlgorithmSHA1}, @@ -514,10 +515,10 @@ func (s *fwLoadHandlerSuite) TestMeasureImageStartErrBadLogPCR4_1(c *C) { func (s *fwLoadHandlerSuite) TestMeasureImageStartErrBadLogPCR4_2(c *C) { // Insert invalid event data in the OS-present phase so that internal.IsAbsoluteAgentLaunch returns an error - collector := NewRootVarsCollector(efitest.NewMockHostEnvironment(nil, nil)) + collector := NewVariableSetCollector(efitest.NewMockHostEnvironment(nil, nil)) ctx := newMockPcrBranchContext(&mockPcrProfileContext{ alg: tpm2.HashAlgorithmSHA256, - pcrs: MakePcrFlags(BootManagerCodePCR)}, nil, collector.Next()) + pcrs: MakePcrFlags(internal.BootManagerCodePCR)}, nil, collector.Next()) log := efitest.NewLog(c, &efitest.LogOptions{ Algorithms: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256, tpm2.HashAlgorithmSHA1}, @@ -538,7 +539,7 @@ func (s *fwLoadHandlerSuite) TestMeasureImageStartErrBadLogPCR4_2(c *C) { func (s *fwLoadHandlerSuite) testMeasureImageStartErrBadLogSeparatorError(c *C, pcr tpm2.Handle) error { // Insert an invalid error separator event into the log for the specified pcr - collector := NewRootVarsCollector(efitest.NewMockHostEnvironment(nil, nil)) + collector := NewVariableSetCollector(efitest.NewMockHostEnvironment(nil, nil)) ctx := newMockPcrBranchContext(&mockPcrProfileContext{ alg: tpm2.HashAlgorithmSHA256, pcrs: MakePcrFlags(pcr)}, nil, collector.Next()) @@ -579,7 +580,7 @@ func (s *fwLoadHandlerSuite) TestMeasureImageStartErrBadLogSeparatorErrorPCR7(c func (s *fwLoadHandlerSuite) testMeasureImageStartErrBadLogInvalidSeparator(c *C, pcr tpm2.Handle) error { // Insert an invalid separator event into the log for the specified PCR - collector := NewRootVarsCollector(efitest.NewMockHostEnvironment(nil, nil)) + collector := NewVariableSetCollector(efitest.NewMockHostEnvironment(nil, nil)) ctx := newMockPcrBranchContext(&mockPcrProfileContext{ alg: tpm2.HashAlgorithmSHA256, pcrs: MakePcrFlags(pcr)}, nil, collector.Next()) @@ -620,7 +621,7 @@ func (s *fwLoadHandlerSuite) TestMeasureImageStartErrBadLogInvalidSeparatorPCR7( func (s *fwLoadHandlerSuite) testMeasureImageStartErrBadLogMissingSeparator(c *C, pcr tpm2.Handle) error { // Remove the separator from the specified PCR - collector := NewRootVarsCollector(efitest.NewMockHostEnvironment(nil, nil)) + collector := NewVariableSetCollector(efitest.NewMockHostEnvironment(nil, nil)) ctx := newMockPcrBranchContext(&mockPcrProfileContext{ alg: tpm2.HashAlgorithmSHA256, pcrs: MakePcrFlags(pcr)}, nil, collector.Next()) @@ -703,7 +704,7 @@ func (s *fwLoadHandlerSuite) TestMeasureImageLoadSecureBootPolicyProfile(c *C) { s.testMeasureImageLoad(c, &testFwMeasureImageLoadData{ alg: tpm2.HashAlgorithmSHA256, - pcrs: MakePcrFlags(SecureBootPolicyPCR), + pcrs: MakePcrFlags(internal.SecureBootPolicyPCR), db: msDb(c), image: newMockImage().appendSignatures(efitest.ReadWinCertificateAuthenticodeDetached(c, shimUbuntuSig4)), expectedEvents: []*mockPcrBranchEvent{ @@ -721,7 +722,7 @@ func (s *fwLoadHandlerSuite) TestMeasureImageLoadSecureBootPolicyProfileExisting s.testMeasureImageLoad(c, &testFwMeasureImageLoadData{ alg: tpm2.HashAlgorithmSHA256, - pcrs: MakePcrFlags(SecureBootPolicyPCR), + pcrs: MakePcrFlags(internal.SecureBootPolicyPCR), db: msDb(c), fc: fc, image: newMockImage().appendSignatures(efitest.ReadWinCertificateAuthenticodeDetached(c, shimUbuntuSig4)), @@ -731,7 +732,7 @@ func (s *fwLoadHandlerSuite) TestMeasureImageLoadSecureBootPolicyProfileExisting func (s *fwLoadHandlerSuite) TestMeasureImageLoadBootManagerCodeProfile1(c *C) { s.testMeasureImageLoad(c, &testFwMeasureImageLoadData{ alg: tpm2.HashAlgorithmSHA256, - pcrs: MakePcrFlags(BootManagerCodePCR), + pcrs: MakePcrFlags(internal.BootManagerCodePCR), image: newMockImage().appendSignatures(efitest.ReadWinCertificateAuthenticodeDetached(c, shimUbuntuSig4)), expectedEvents: []*mockPcrBranchEvent{ {pcr: 4, eventType: mockPcrBranchExtendEvent, digest: testutil.DecodeHexString(c, "bf6b6dfdb1f6435a81e4808db7f846d86d170566e4753d4384fdab6504be4fb9")}, @@ -742,7 +743,7 @@ func (s *fwLoadHandlerSuite) TestMeasureImageLoadBootManagerCodeProfile1(c *C) { func (s *fwLoadHandlerSuite) TestMeasureImageLoadBootManagerCodeProfile2(c *C) { s.testMeasureImageLoad(c, &testFwMeasureImageLoadData{ alg: tpm2.HashAlgorithmSHA256, - pcrs: MakePcrFlags(BootManagerCodePCR), + pcrs: MakePcrFlags(internal.BootManagerCodePCR), image: newMockImage().appendSignatures(efitest.ReadWinCertificateAuthenticodeDetached(c, shimUbuntuSig3)), expectedEvents: []*mockPcrBranchEvent{ {pcr: 4, eventType: mockPcrBranchExtendEvent, digest: testutil.DecodeHexString(c, "dbffd70a2c43fd2c1931f18b8f8c08c5181db15f996f747dfed34def52fad036")}, @@ -755,7 +756,7 @@ func (s *fwLoadHandlerSuite) TestMeasureImageLoadSecureBootPolicyAndBootManagerC s.testMeasureImageLoad(c, &testFwMeasureImageLoadData{ alg: tpm2.HashAlgorithmSHA256, - pcrs: MakePcrFlags(BootManagerCodePCR, SecureBootPolicyPCR), + pcrs: MakePcrFlags(internal.BootManagerCodePCR, internal.SecureBootPolicyPCR), db: msDb(c), image: newMockImage().appendSignatures(efitest.ReadWinCertificateAuthenticodeDetached(c, shimUbuntuSig4)), expectedEvents: []*mockPcrBranchEvent{ diff --git a/efi/grub_load_handler_test.go b/efi/grub_load_handler_test.go index 5af1f4fc..a90d73ff 100644 --- a/efi/grub_load_handler_test.go +++ b/efi/grub_load_handler_test.go @@ -25,6 +25,7 @@ import ( efi "github.com/canonical/go-efilib" "github.com/canonical/go-tpm2" . "github.com/snapcore/secboot/efi" + "github.com/snapcore/secboot/efi/internal" "github.com/snapcore/secboot/internal/efitest" "github.com/snapcore/secboot/internal/testutil" ) @@ -42,7 +43,7 @@ var _ = Suite(&grubLoadHandlerSuite{}) func (s *grubLoadHandlerSuite) TestMeasureImageLoadUbuntuUsesShim15_7(c *C) { ctx := newMockPcrBranchContext(&mockPcrProfileContext{ alg: tpm2.HashAlgorithmSHA256, - pcrs: MakePcrFlags(SecureBootPolicyPCR), + pcrs: MakePcrFlags(internal.SecureBootPolicyPCR), handlers: s, }, nil, nil) ctx.FwContext().Db = &SecureBootDB{ @@ -71,7 +72,7 @@ func (s *grubLoadHandlerSuite) TestMeasureImageLoadUbuntuUsesShim15_7(c *C) { func (s *grubLoadHandlerSuite) TestMeasureImageLoadUbuntuUsesShim15_6(c *C) { ctx := newMockPcrBranchContext(&mockPcrProfileContext{ alg: tpm2.HashAlgorithmSHA256, - pcrs: MakePcrFlags(SecureBootPolicyPCR), + pcrs: MakePcrFlags(internal.SecureBootPolicyPCR), handlers: s, }, nil, nil) ctx.FwContext().Db = &SecureBootDB{ @@ -100,7 +101,7 @@ func (s *grubLoadHandlerSuite) TestMeasureImageLoadUbuntuUsesShim15_6(c *C) { func (s *grubLoadHandlerSuite) TestMeasureImageLoadNoShim(c *C) { ctx := newMockPcrBranchContext(&mockPcrProfileContext{ alg: tpm2.HashAlgorithmSHA256, - pcrs: MakePcrFlags(SecureBootPolicyPCR), + pcrs: MakePcrFlags(internal.SecureBootPolicyPCR), handlers: s, }, nil, nil) ctx.FwContext().Db = &SecureBootDB{ @@ -129,7 +130,7 @@ func (s *grubLoadHandlerSuite) TestMeasureImageLoadNoShim(c *C) { func (s *grubLoadHandlerSuite) TestMeasureImageLoadNoShimError(c *C) { ctx := newMockPcrBranchContext(&mockPcrProfileContext{ alg: tpm2.HashAlgorithmSHA256, - pcrs: MakePcrFlags(SecureBootPolicyPCR), + pcrs: MakePcrFlags(internal.SecureBootPolicyPCR), handlers: s, }, nil, nil) ctx.FwContext().Db = &SecureBootDB{ diff --git a/efi/image_rules_defs.go b/efi/image_rules_defs.go index 77845088..69c95baf 100644 --- a/efi/image_rules_defs.go +++ b/efi/image_rules_defs.go @@ -22,58 +22,25 @@ package efi import ( "crypto" "crypto/x509" + + "github.com/snapcore/secboot/efi/internal" ) func makeMicrosoftUEFICASecureBootNamespaceRules() *secureBootNamespaceRules { return newSecureBootNamespaceRules( "Microsoft UEFI CA", withAuthority( - // CN=Microsoft Corporation UEFI CA 2011,O=Microsoft Corporation,L=Redmond,ST=Washington,C=US - []byte{ - 0x30, 0x81, 0x81, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, - 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, - 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x57, 0x61, 0x73, - 0x68, 0x69, 0x6e, 0x67, 0x74, 0x6f, 0x6e, 0x31, 0x10, 0x30, - 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x07, 0x52, 0x65, - 0x64, 0x6d, 0x6f, 0x6e, 0x64, 0x31, 0x1e, 0x30, 0x1c, 0x06, - 0x03, 0x55, 0x04, 0x0a, 0x13, 0x15, 0x4d, 0x69, 0x63, 0x72, - 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x43, 0x6f, 0x72, 0x70, - 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x2b, 0x30, - 0x29, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x22, 0x4d, 0x69, - 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x43, 0x6f, - 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, - 0x55, 0x45, 0x46, 0x49, 0x20, 0x43, 0x41, 0x20, 0x32, 0x30, - 0x31, 0x31, - }, - // SKID - []byte{ - 0x13, 0xad, 0xbf, 0x43, 0x09, 0xbd, 0x82, 0x70, 0x9c, 0x8c, - 0xd5, 0x4f, 0x31, 0x6e, 0xd5, 0x22, 0x98, 0x8a, 0x1b, 0xd4, - }, - // pubkey alg - x509.RSA, + internal.MSUefiCA2011.Subject, + internal.MSUefiCA2011.SubjectKeyId, + internal.MSUefiCA2011.PublicKeyAlgorithm, ), // TODO(chrisccoulson): add tests for this when we find something that it's // been used to sign and we have a signing certificate in the wild that we // can add to embeds_test.go in order to create a mock shim with it withAuthority( - // CN=Microsoft UEFI CA 2023,O=Microsoft Corporation,C=US - []byte{ - 0x30, 0x4e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, - 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x1e, 0x30, 0x1c, 0x06, - 0x03, 0x55, 0x04, 0x0a, 0x13, 0x15, 0x4d, 0x69, 0x63, 0x72, - 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x43, 0x6f, 0x72, 0x70, - 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x1f, 0x30, - 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x16, 0x4d, 0x69, - 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x55, 0x45, - 0x46, 0x49, 0x20, 0x43, 0x41, 0x20, 0x32, 0x30, 0x32, 0x33, - }, - []byte{ - 0x81, 0xaa, 0x6b, 0x32, 0x44, 0xc9, 0x35, 0xbc, 0xe0, 0xd6, - 0x62, 0x8a, 0xf3, 0x98, 0x27, 0x42, 0x1e, 0x32, 0x49, 0x7d, - }, - // pubkey alg - x509.RSA, + internal.MSUefiCA2023.Subject, + internal.MSUefiCA2023.SubjectKeyId, + internal.MSUefiCA2023.PublicKeyAlgorithm, ), withSelfSignedSignerOnlyForTesting( // O = Snake Oil diff --git a/efi/internal/MicrosoftKEK.crt b/efi/internal/MicrosoftKEK.crt new file mode 100644 index 00000000..37c814a7 --- /dev/null +++ b/efi/internal/MicrosoftKEK.crt @@ -0,0 +1,34 @@ +-----BEGIN CERTIFICATE----- +MIIF6DCCA9CgAwIBAgIKYQrRiAAAAAAAAzANBgkqhkiG9w0BAQsFADCBkTELMAkG +A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQx +HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjE7MDkGA1UEAxMyTWljcm9z +b2Z0IENvcnBvcmF0aW9uIFRoaXJkIFBhcnR5IE1hcmtldHBsYWNlIFJvb3QwHhcN +MTEwNjI0MjA0MTI5WhcNMjYwNjI0MjA1MTI5WjCBgDELMAkGA1UEBhMCVVMxEzAR +BgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1p +Y3Jvc29mdCBDb3Jwb3JhdGlvbjEqMCgGA1UEAxMhTWljcm9zb2Z0IENvcnBvcmF0 +aW9uIEtFSyBDQSAyMDExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA +xOi1ir+tVyawJsPq5/tXekQCXQcN2krldCrmsA/sbevsf7njWmMyfBEXTw7jC6c4 +FZOOxvXghLGamyzn9beR1gnh4sAEqKwwHN9I8wZQmmSnUX/IhU+PIIbO/i/hn/+C +wO3pzc70U2piOgtDueIl/f4F+dTEFKsR4iOJjXC3pB1N7K7lnPoWwtfBy9ToxC/l +me4kiwPsjfKL6sNK+0MREgt+tUeSbNzmBInr9TME6xABKnHl+YMTPP8lCS9odkb/ +uk++3K1xKliq+w7SeT3km2U7zCkqn/xyWaLrrpLv9jUTgMYC7ORfzJ12ze9jksGv +eUCEeYd/41Ko6J17B2mPFQIDAQABo4IBTzCCAUswEAYJKwYBBAGCNxUBBAMCAQAw +HQYDVR0OBBYEFGL8Q82gPqTLZxLSW9lVrHvMtopfMBkGCSsGAQQBgjcUAgQMHgoA +UwB1AGIAQwBBMAsGA1UdDwQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQY +MBaAFEVmUkPhflgRv9ZOniNVCDs6ImqoMFwGA1UdHwRVMFMwUaBPoE2GS2h0dHA6 +Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY0NvclRoaVBh +ck1hclJvb18yMDEwLTEwLTA1LmNybDBgBggrBgEFBQcBAQRUMFIwUAYIKwYBBQUH +MAKGRGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljQ29yVGhp +UGFyTWFyUm9vXzIwMTAtMTAtMDUuY3J0MA0GCSqGSIb3DQEBCwUAA4ICAQDUhIj1 +FJQYAsoqPPsqkhwM16DR8ehSZqjuorV1epAAqi2kdlrqebe5N2pRexBk9uFk8gJn +vveoG3i9us6IWGQM1lfIGaNfBdbbxtBpzkhLMrfrXdIw9cD1uLp4B6Mr/pvbNFaE +7ILKrkElcJxr6f6QD9eWH+XnlB+yKgyNS/8oKRB799d8pdF2uQXIee0PkJKcwv7f +b35sD3vUwUXdNFGWOQ/lXlbYGAWW9AemQrOgd/0IGfJxVsyfhiOkh8um/Vh+1Gln +FZF+gfJ/E+UNi4o8h4Tr4869Q+WtLYSTjmorWnxE+lKqgcgtHLvgUt8AEfiaPcFg +sOEztaOI0WUZChrnrHykwYKHTjixLw3FFIdv/Y0uvDm25+bD4OTNJ4TvlELvKYuQ +RkE7gRtn2PlDWWXLDbz9AJJP9HU7p6kk/FBBQHngLU8Kaid2blLtlml7rw/3hwXQ +RcKtUxSBH/swBKo3NmHaSmkbNNho7dYCz2yUDNPPbCJ5rbHwvAOiRmCpxAfCIYLx +/fLoeTJgv9ispSIUS8rB2EvrfT9XNbLmT3W0sGADIlOukXkd1ptBHxWGVHCy3g01 +D3ywNHK6l2A78HnrorIcXaIWuIfF6Rv2tZclbzif45H6inmYw2kOt6McIAWX+MoU +rgDXxPPAFBB1azSgG7WZYPNcsMVXTjbSMoS/ng== +-----END CERTIFICATE----- diff --git a/efi/default_env.go b/efi/internal/default_env.go similarity index 90% rename from efi/default_env.go rename to efi/internal/default_env.go index 692a283f..e792cfde 100644 --- a/efi/default_env.go +++ b/efi/internal/default_env.go @@ -17,7 +17,7 @@ * */ -package efi +package internal import ( "os" @@ -47,4 +47,6 @@ func (e defaultEnvImpl) ReadEventLog() (*tcglog.Log, error) { return tcglog.ReadLog(f, &tcglog.LogOptions{}) } -var defaultEnv = defaultEnvImpl{} +// DefaultEnv corresponds to the environment associated with the host +// machine. +var DefaultEnv = defaultEnvImpl{} diff --git a/efi/default_env_test.go b/efi/internal/default_env_test.go similarity index 80% rename from efi/default_env_test.go rename to efi/internal/default_env_test.go index 777a1a9b..0fbc2215 100644 --- a/efi/default_env_test.go +++ b/efi/internal/default_env_test.go @@ -17,9 +17,10 @@ * */ -package efi_test +package internal_test import ( + _ "embed" "io" "os" "path/filepath" @@ -27,12 +28,24 @@ import ( efi "github.com/canonical/go-efilib" "github.com/canonical/go-tpm2" "github.com/canonical/tcglog-parser" - . "github.com/snapcore/secboot/efi" + . "github.com/snapcore/secboot/efi/internal" "github.com/snapcore/secboot/internal/efitest" + "github.com/snapcore/secboot/internal/testutil" . "gopkg.in/check.v1" ) +var ( + //go:embed MicrosoftKEK.crt + msKEKCertPEM []byte + + msKEKCert []byte +) + +func init() { + msKEKCert = testutil.MustDecodePEMType("CERTIFICATE", msKEKCertPEM) +} + type defaultEnvSuite struct{} var _ = Suite(&defaultEnvSuite{}) @@ -43,7 +56,22 @@ type testReadVarData struct { } func (s *defaultEnvSuite) testReadVar(c *C, data *testReadVarData) { - vars := makeMockVars(c, withMsSecureBootConfig()) + ownerGuid := efi.MakeGUID(0x77fa9abd, 0x0359, 0x4d32, 0xbd60, [...]uint8{0x28, 0xf4, 0xe7, 0x8f, 0x78, 0x4b}) + kek := &efi.SignatureList{ + Type: efi.CertX509Guid, + Signatures: []*efi.SignatureData{ + { + Owner: ownerGuid, + Data: msKEKCert, + }, + }, + } + dbx := efitest.NewSignatureListNullSHA256(ownerGuid) + vars := efitest.MakeMockVars() + vars.SetSecureBoot(true) + vars.SetKEK(c, efi.SignatureDatabase{kek}) + vars.SetDbx(c, efi.SignatureDatabase{dbx}) + restore := MockReadVar(func(name string, guid efi.GUID) ([]byte, efi.VariableAttributes, error) { entry, exists := vars[efi.VariableDescriptor{Name: name, GUID: guid}] if !exists { @@ -73,7 +101,7 @@ func (s *defaultEnvSuite) TestReadVar1(c *C) { func (s *defaultEnvSuite) TestReadVar2(c *C) { s.testReadVar(c, &testReadVarData{ - name: "PK", + name: "KEK", guid: efi.GlobalVariable}) } diff --git a/efi/internal/export_test.go b/efi/internal/export_test.go new file mode 100644 index 00000000..f2191a36 --- /dev/null +++ b/efi/internal/export_test.go @@ -0,0 +1,38 @@ +// -*- Mode: Go; indent-tabs-mode: t -*- + +/* + * Copyright (C) 2019-2024 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package internal + +import efi "github.com/canonical/go-efilib" + +func MockEventLogPath(path string) (restore func()) { + origPath := eventLogPath + eventLogPath = path + return func() { + eventLogPath = origPath + } +} + +func MockReadVar(fn func(string, efi.GUID) ([]byte, efi.VariableAttributes, error)) (restore func()) { + origReadVar := readVar + readVar = fn + return func() { + readVar = origReadVar + } +} diff --git a/efi/internal/known_secureboot_cas.go b/efi/internal/known_secureboot_cas.go new file mode 100644 index 00000000..a3a77587 --- /dev/null +++ b/efi/internal/known_secureboot_cas.go @@ -0,0 +1,83 @@ +// -*- Mode: Go; indent-tabs-mode: t -*- + +/* + * Copyright (C) 2024 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package internal + +import "crypto/x509" + +// SecureBootAuthorityIdentity corresponds to the identify of a secure boot +// authority. +type SecureBootAuthorityIdentity struct { + Subject []byte + SubjectKeyId []byte + PublicKeyAlgorithm x509.PublicKeyAlgorithm + + Issuer []byte + AuthorityKeyId []byte + SignatureAlgorithm x509.SignatureAlgorithm +} + +var ( + // MSUefiCA2011 corresponds to the 2011 Microsoft UEFI CA + MSUefiCA2011 = &SecureBootAuthorityIdentity{ + // CN=Microsoft Corporation UEFI CA 2011,O=Microsoft Corporation,L=Redmond,ST=Washington,C=US + Subject: []byte{ + 0x30, 0x81, 0x81, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, + 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, + 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x57, 0x61, 0x73, + 0x68, 0x69, 0x6e, 0x67, 0x74, 0x6f, 0x6e, 0x31, 0x10, 0x30, + 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x07, 0x52, 0x65, + 0x64, 0x6d, 0x6f, 0x6e, 0x64, 0x31, 0x1e, 0x30, 0x1c, 0x06, + 0x03, 0x55, 0x04, 0x0a, 0x13, 0x15, 0x4d, 0x69, 0x63, 0x72, + 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x43, 0x6f, 0x72, 0x70, + 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x2b, 0x30, + 0x29, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x22, 0x4d, 0x69, + 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x43, 0x6f, + 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, + 0x55, 0x45, 0x46, 0x49, 0x20, 0x43, 0x41, 0x20, 0x32, 0x30, + 0x31, 0x31, + }, + SubjectKeyId: []byte{ + 0x13, 0xad, 0xbf, 0x43, 0x09, 0xbd, 0x82, 0x70, 0x9c, 0x8c, + 0xd5, 0x4f, 0x31, 0x6e, 0xd5, 0x22, 0x98, 0x8a, 0x1b, 0xd4, + }, + PublicKeyAlgorithm: x509.RSA, + } + + // MSUefiCA2023 corresponds to the 2023 Microsoft UEFI CA, which will eventually + // replace the 2011 CA. + MSUefiCA2023 = &SecureBootAuthorityIdentity{ + // CN=Microsoft UEFI CA 2023,O=Microsoft Corporation,C=US + Subject: []byte{ + 0x30, 0x4e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, + 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x1e, 0x30, 0x1c, 0x06, + 0x03, 0x55, 0x04, 0x0a, 0x13, 0x15, 0x4d, 0x69, 0x63, 0x72, + 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x43, 0x6f, 0x72, 0x70, + 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x1f, 0x30, + 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x16, 0x4d, 0x69, + 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x55, 0x45, + 0x46, 0x49, 0x20, 0x43, 0x41, 0x20, 0x32, 0x30, 0x32, 0x33, + }, + SubjectKeyId: []byte{ + 0x81, 0xaa, 0x6b, 0x32, 0x44, 0xc9, 0x35, 0xbc, 0xe0, 0xd6, + 0x62, 0x8a, 0xf3, 0x98, 0x27, 0x42, 0x1e, 0x32, 0x49, 0x7d, + }, + PublicKeyAlgorithm: x509.RSA, + } +) diff --git a/efi/internal/options.go b/efi/internal/options.go new file mode 100644 index 00000000..3402dac4 --- /dev/null +++ b/efi/internal/options.go @@ -0,0 +1,67 @@ +// -*- Mode: Go; indent-tabs-mode: t -*- + +/* + * Copyright (C) 2024 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package internal + +import ( + efi "github.com/canonical/go-efilib" + "github.com/canonical/go-tpm2" + "github.com/canonical/tcglog-parser" +) + +type InitialVariablesModifier func(VariableSet) error + +type PCRProfileOptionVisitor interface { + // AddPCRs adds the supplied PCRs to the profile. + AddPCRs(pcrs ...tpm2.Handle) + + // SetEnvironment overrides the host environment to the supplied environment. + SetEnvironment(env HostEnvironment) + + // AddInitialVariablesModifier adds a function that will be called to allow + // the initial variable set for profile generation to be modified. + AddInitialVariablesModifier(fn InitialVariablesModifier) +} + +// HostEnvironment is an interface that abstracts out an EFI environment, so that +// consumers of the API can provide a custom mechanism to read EFI variables or parse +// the TCG event log. This needs to be kept in sync with [efi.HostEnvironment]. +type HostEnvironment interface { + // ReadVar reads the specified EFI variable + ReadVar(name string, guid efi.GUID) ([]byte, efi.VariableAttributes, error) + + // ReadEventLog reads the TCG event log + ReadEventLog() (*tcglog.Log, error) +} + +// VariableSet corresponds to a set of EFI variables. +type VariableSet interface { + // ReadVar reads the specified EFI variable for this set. + ReadVar(name string, guid efi.GUID) ([]byte, efi.VariableAttributes, error) + + // WriteVar updates the specified EFI variable for this set, for + // boot components that update variables. Each individual write + // creates a new intitial set of variables for which a profile will be + // generated against to accommodate interrupted sequences of writes. + WriteVar(name string, guid efi.GUID, attrs efi.VariableAttributes, data []byte) error + + // Clone creates a copy of this variable set to make it possible to create + // branches by setting variables to different values in each returned set. + Clone() VariableSet +} diff --git a/efi/internal/tcg_pcrs.go b/efi/internal/tcg_pcrs.go new file mode 100644 index 00000000..16e786f6 --- /dev/null +++ b/efi/internal/tcg_pcrs.go @@ -0,0 +1,39 @@ +// -*- Mode: Go; indent-tabs-mode: t -*- + +/* + * Copyright (C) 2019 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package internal + +import "github.com/canonical/go-tpm2" + +const ( + // PlatformFirmarePCR is the SRTM, POST BIOS, and Embedded Drivers PCR + PlatformFirmwarePCR tpm2.Handle = 0 + + // HostPlatformConfigPCR is the Host Platform Configuration PCR + HostPlatformConfigPCR tpm2.Handle = 1 + + // DriversAndAppsPCR is the UEFI Drivers and UEFI Applications PCR + DriversAndAppsPCR tpm2.Handle = 2 + + // BootManagerCodePCR is the Boot Manager Code and Boot Attempts PCR + BootManagerCodePCR tpm2.Handle = 4 + + // SecureBootPolicyPCR is the Secure Boot Policy Measurements PCR + SecureBootPolicyPCR tpm2.Handle = 7 +) diff --git a/efi/pcr_branch_context.go b/efi/pcr_branch_context.go index c993efec..24697241 100644 --- a/efi/pcr_branch_context.go +++ b/efi/pcr_branch_context.go @@ -24,6 +24,7 @@ import ( "github.com/canonical/go-tpm2" "github.com/canonical/tcglog-parser" + "github.com/snapcore/secboot/efi/internal" secboot_tpm2 "github.com/snapcore/secboot/tpm2" ) @@ -97,7 +98,7 @@ func (c *pcrBranchCtx) ResetPCR(pcr tpm2.Handle) { func (c *pcrBranchCtx) ResetCRTMPCR(locality uint8) { value := make([]byte, c.PCRAlg().Size()) value[len(value)-1] = locality - c.branch.AddPCRValue(c.PCRAlg(), int(platformFirmwarePCR), value) + c.branch.AddPCRValue(c.PCRAlg(), int(internal.PlatformFirmwarePCR), value) } func (c *pcrBranchCtx) ExtendPCR(pcr tpm2.Handle, digest tpm2.Digest) { diff --git a/efi/pcr_branch_context_test.go b/efi/pcr_branch_context_test.go index 8913cb4c..71eb824e 100644 --- a/efi/pcr_branch_context_test.go +++ b/efi/pcr_branch_context_test.go @@ -76,7 +76,7 @@ func (s *pcrBranchContextSuite) TestPcrBranchCtxParamsSubBranch(c *C) { } func (s *pcrBranchContextSuite) TestPcrBranchCtxVars(c *C) { - vars := NewRootVarsCollector(efitest.NewMockHostEnvironment(efitest.MockVars{ + vars := NewVariableSetCollector(efitest.NewMockHostEnvironment(efitest.MockVars{ {Name: "foo", GUID: efi.GlobalVariable}: {Payload: []byte{1}, Attrs: efi.AttributeNonVolatile | efi.AttributeBootserviceAccess}, }, nil)).Next() bc := NewRootPcrBranchCtx(&mockPcrProfileContext{alg: tpm2.HashAlgorithmSHA256}, nil, new(LoadParams), vars) @@ -96,7 +96,7 @@ func (s *pcrBranchContextSuite) TestPcrBranchCtxVars(c *C) { } func (s *pcrBranchContextSuite) TestPcrBranchCtxVarsSubBranch(c *C) { - vars := NewRootVarsCollector(efitest.NewMockHostEnvironment(efitest.MockVars{ + vars := NewVariableSetCollector(efitest.NewMockHostEnvironment(efitest.MockVars{ {Name: "foo", GUID: efi.GlobalVariable}: {Payload: []byte{1}, Attrs: efi.AttributeNonVolatile | efi.AttributeBootserviceAccess}, }, nil)).Next() bc := NewRootPcrBranchCtx(&mockPcrProfileContext{alg: tpm2.HashAlgorithmSHA256}, secboot_tpm2.NewPCRProtectionProfile().RootBranch(), new(LoadParams), vars) diff --git a/efi/pcr_images_measurer_test.go b/efi/pcr_images_measurer_test.go index f4bafe75..26de687a 100644 --- a/efi/pcr_images_measurer_test.go +++ b/efi/pcr_images_measurer_test.go @@ -45,7 +45,7 @@ func (s *pcrImagesMeasurerSuite) TestPcrImagesMeasurerMeasureOneLeaf(c *C) { profile := secboot_tpm2.NewPCRProtectionProfile() params := new(LoadParams) - vars := NewRootVarsCollector(efitest.NewMockHostEnvironment(efitest.MockVars{}, nil)).Next() + vars := NewVariableSetCollector(efitest.NewMockHostEnvironment(efitest.MockVars{}, nil)).Next() h := crypto.SHA256.New() io.WriteString(h, "foo") @@ -94,7 +94,7 @@ func (s *pcrImagesMeasurerSuite) TestPcrImagesMeasurerTwoLeaf(c *C) { profile := secboot_tpm2.NewPCRProtectionProfile() params := new(LoadParams) - vars := NewRootVarsCollector(efitest.NewMockHostEnvironment(efitest.MockVars{}, nil)).Next() + vars := NewVariableSetCollector(efitest.NewMockHostEnvironment(efitest.MockVars{}, nil)).Next() h := crypto.SHA256.New() io.WriteString(h, "foo") @@ -146,7 +146,7 @@ func (s *pcrImagesMeasurerSuite) TestPcrImagesMeasurerNonLeaf(c *C) { profile := secboot_tpm2.NewPCRProtectionProfile() params := new(LoadParams) - vars := NewRootVarsCollector(efitest.NewMockHostEnvironment(efitest.MockVars{}, nil)).Next() + vars := NewVariableSetCollector(efitest.NewMockHostEnvironment(efitest.MockVars{}, nil)).Next() h := crypto.SHA256.New() io.WriteString(h, "foo") @@ -203,7 +203,7 @@ func (s *pcrImagesMeasurerSuite) TestPcrImagesMeasurerTwoNonLeaf(c *C) { profile := secboot_tpm2.NewPCRProtectionProfile() params := new(LoadParams) - vars := NewRootVarsCollector(efitest.NewMockHostEnvironment(efitest.MockVars{}, nil)).Next() + vars := NewVariableSetCollector(efitest.NewMockHostEnvironment(efitest.MockVars{}, nil)).Next() h := crypto.SHA256.New() io.WriteString(h, "foo1") @@ -279,7 +279,7 @@ func (s *pcrImagesMeasurerSuite) TestPcrImagesMeasurerMeasureWithParams(c *C) { profile := secboot_tpm2.NewPCRProtectionProfile() params := new(LoadParams) - vars := NewRootVarsCollector(efitest.NewMockHostEnvironment(efitest.MockVars{}, nil)).Next() + vars := NewVariableSetCollector(efitest.NewMockHostEnvironment(efitest.MockVars{}, nil)).Next() h := crypto.SHA256.New() io.WriteString(h, "foo") @@ -341,7 +341,7 @@ func (s *pcrImagesMeasurerSuite) TestPcrImagesMeasurerMeasureWithInheritedParams profile := secboot_tpm2.NewPCRProtectionProfile() params := &LoadParams{SnapModel: model} - vars := NewRootVarsCollector(efitest.NewMockHostEnvironment(efitest.MockVars{}, nil)).Next() + vars := NewVariableSetCollector(efitest.NewMockHostEnvironment(efitest.MockVars{}, nil)).Next() h := crypto.SHA256.New() io.WriteString(h, "foo") @@ -395,7 +395,7 @@ func (s *pcrImagesMeasurerSuite) TestPcrImagesMeasurerMeasureWithVars(c *C) { profile := secboot_tpm2.NewPCRProtectionProfile() params := new(LoadParams) - vars := NewRootVarsCollector(efitest.NewMockHostEnvironment(efitest.MockVars{ + vars := NewVariableSetCollector(efitest.NewMockHostEnvironment(efitest.MockVars{ {Name: "foo", GUID: testGuid1}: {Payload: []byte{1}, Attrs: efi.AttributeNonVolatile | efi.AttributeBootserviceAccess}, }, nil)).Next() @@ -447,7 +447,7 @@ func (s *pcrImagesMeasurerSuite) TestPcrImagesMeasurerMeasureEnsureVarsAreCopied profile := secboot_tpm2.NewPCRProtectionProfile() params := new(LoadParams) - vars := NewRootVarsCollector(efitest.NewMockHostEnvironment(efitest.MockVars{ + vars := NewVariableSetCollector(efitest.NewMockHostEnvironment(efitest.MockVars{ {Name: "foo", GUID: testGuid1}: {Payload: []byte{1}, Attrs: efi.AttributeNonVolatile | efi.AttributeBootserviceAccess}, }, nil)).Next() @@ -504,7 +504,7 @@ func (s *pcrImagesMeasurerSuite) TestPcrImagesMeasurerMeasureWithFwContext(c *C) profile := secboot_tpm2.NewPCRProtectionProfile() params := new(LoadParams) - vars := NewRootVarsCollector(efitest.NewMockHostEnvironment(efitest.MockVars{}, nil)).Next() + vars := NewVariableSetCollector(efitest.NewMockHostEnvironment(efitest.MockVars{}, nil)).Next() h := crypto.SHA256.New() io.WriteString(h, "foo") @@ -555,7 +555,7 @@ func (s *pcrImagesMeasurerSuite) TestPcrImagesMeasurerMeasureEnsureFwContextIsCo profile := secboot_tpm2.NewPCRProtectionProfile() params := new(LoadParams) - vars := NewRootVarsCollector(efitest.NewMockHostEnvironment(efitest.MockVars{}, nil)).Next() + vars := NewVariableSetCollector(efitest.NewMockHostEnvironment(efitest.MockVars{}, nil)).Next() h := crypto.SHA256.New() io.WriteString(h, "foo") @@ -612,7 +612,7 @@ func (s *pcrImagesMeasurerSuite) TestPcrImagesMeasurerMeasureWithShimContext(c * profile := secboot_tpm2.NewPCRProtectionProfile() params := new(LoadParams) - vars := NewRootVarsCollector(efitest.NewMockHostEnvironment(efitest.MockVars{}, nil)).Next() + vars := NewVariableSetCollector(efitest.NewMockHostEnvironment(efitest.MockVars{}, nil)).Next() h := crypto.SHA256.New() io.WriteString(h, "foo") @@ -663,7 +663,7 @@ func (s *pcrImagesMeasurerSuite) TestPcrImagesMeasurerMeasureEnsureShimContextIs profile := secboot_tpm2.NewPCRProtectionProfile() params := new(LoadParams) - vars := NewRootVarsCollector(efitest.NewMockHostEnvironment(efitest.MockVars{}, nil)).Next() + vars := NewVariableSetCollector(efitest.NewMockHostEnvironment(efitest.MockVars{}, nil)).Next() h := crypto.SHA256.New() io.WriteString(h, "foo") diff --git a/efi/pcr_profile.go b/efi/pcr_profile.go index 8057245a..f24b6cbf 100644 --- a/efi/pcr_profile.go +++ b/efi/pcr_profile.go @@ -21,43 +21,46 @@ package efi import ( "errors" + "fmt" "github.com/canonical/go-tpm2" "github.com/canonical/tcglog-parser" + "github.com/snapcore/secboot/efi/internal" secboot_tpm2 "github.com/snapcore/secboot/tpm2" "golang.org/x/xerrors" ) // PCRProfileOption is an option for AddPCRProfile type PCRProfileOption interface { - applyOptionTo(gen *pcrProfileGenerator) + ApplyOptionTo(visitor internal.PCRProfileOptionVisitor) error } // PCRProfileEnablePCRsOption is an option for AddPCRProfile that adds one or more PCRs. type PCRProfileEnablePCRsOption interface { PCRProfileOption - PCRs() tpm2.HandleList + PCRs() (tpm2.HandleList, error) } -type pcrProfileSetPcrsOption struct { +type pcrProfileSetPcrOption struct { PCRProfileOption - pcrs pcrFlags + pcr tpm2.Handle } -func newPcrProfileSetPcrsOption(pcrs pcrFlags) *pcrProfileSetPcrsOption { - out := &pcrProfileSetPcrsOption{ - pcrs: pcrs, +func newPcrProfileSetPcrOption(pcr tpm2.Handle) *pcrProfileSetPcrOption { + out := &pcrProfileSetPcrOption{ + pcr: pcr, } out.PCRProfileOption = out return out } -func (o *pcrProfileSetPcrsOption) applyOptionTo(gen *pcrProfileGenerator) { - gen.pcrs |= o.pcrs +func (o *pcrProfileSetPcrOption) ApplyOptionTo(visitor internal.PCRProfileOptionVisitor) error { + visitor.AddPCRs(o.pcr) + return nil } -func (o *pcrProfileSetPcrsOption) PCRs() tpm2.HandleList { - return o.pcrs.PCRs() +func (o *pcrProfileSetPcrOption) PCRs() (tpm2.HandleList, error) { + return tpm2.HandleList{o.pcr}, nil } // WithPlatformFirmwareProfile adds the SRTM, POST BIOS and Embedded Drivers @@ -68,14 +71,14 @@ func (o *pcrProfileSetPcrsOption) PCRs() tpm2.HandleList { // hardware root of trust as opposed to being verified as authentic and prevented // from running otherwise. func WithPlatformFirmwareProfile() PCRProfileEnablePCRsOption { - return newPcrProfileSetPcrsOption(makePcrFlags(platformFirmwarePCR)) + return newPcrProfileSetPcrOption(internal.PlatformFirmwarePCR) } // WithDriversAndAppsProfile adds the UEFI Drivers and UEFI Applications profile // (measured to PCR2). This is copied directly from the current host environment // configiguration. func WithDriversAndAppsProfile() PCRProfileEnablePCRsOption { - return newPcrProfileSetPcrsOption(makePcrFlags(driversAndAppsPCR)) + return newPcrProfileSetPcrOption(internal.DriversAndAppsPCR) } // WithSecureBootPolicyProfile requests that the UEFI secure boot policy profile is @@ -135,7 +138,7 @@ func WithDriversAndAppsProfile() PCRProfileEnablePCRsOption { // of these makes a policy inherently fragile because it is not possible to pre-generate // policy to accomodate updates of these components. func WithSecureBootPolicyProfile() PCRProfileEnablePCRsOption { - return newPcrProfileSetPcrsOption(makePcrFlags(secureBootPolicyPCR)) + return newPcrProfileSetPcrOption(internal.SecureBootPolicyPCR) } // WithBootManagerCodeProfile requests that the UEFI boot manager code and boot attempts @@ -171,7 +174,7 @@ func WithSecureBootPolicyProfile() PCRProfileEnablePCRsOption { // fail before performing a successful attempt, even if the images associated with the // successful attempt are included in this policy. func WithBootManagerCodeProfile() PCRProfileEnablePCRsOption { - return newPcrProfileSetPcrsOption(makePcrFlags(bootManagerCodePCR)) + return newPcrProfileSetPcrOption(internal.BootManagerCodePCR) } // WithKernelConfigProfile adds the kernel config profile. This binds a policy to a @@ -182,7 +185,7 @@ func WithBootManagerCodeProfile() PCRProfileEnablePCRsOption { // Snap models can be injected into the profile with [SnapModelParams]. Note that a model // assertion is mandatory for profiles that include a UKI for Ubuntu Core. func WithKernelConfigProfile() PCRProfileEnablePCRsOption { - return newPcrProfileSetPcrsOption(makePcrFlags(kernelConfigPCR)) + return newPcrProfileSetPcrOption(kernelConfigPCR) } // AddPCRProfile adds a profile defined by the supplied options to the supplied @@ -190,7 +193,10 @@ func WithKernelConfigProfile() PCRProfileEnablePCRsOption { // for the PCR digest. The generated profile is defined by the supplied load // sequences and options. func AddPCRProfile(pcrAlg tpm2.HashAlgorithmId, branch *secboot_tpm2.PCRProtectionProfileBranch, loadSequences *ImageLoadSequences, options ...PCRProfileOption) error { - gen := newPcrProfileGenerator(pcrAlg, loadSequences, options...) + gen, err := newPcrProfileGenerator(pcrAlg, loadSequences, options...) + if err != nil { + return err + } if gen.pcrs == 0 { return errors.New("must specify a profile to add") @@ -224,23 +230,25 @@ type pcrProfileGenerator struct { // of every possible EFI variable starting state, and is used for generating // profiles that incorporate signature database updates and changest to // SbatPolicy. - varModifiers []rootVarsModifier + varModifiers []internal.InitialVariablesModifier // log is the host TCG log, which is read from the associated env. log *tcglog.Log } -func newPcrProfileGenerator(pcrAlg tpm2.HashAlgorithmId, loadSequences *ImageLoadSequences, options ...PCRProfileOption) *pcrProfileGenerator { +func newPcrProfileGenerator(pcrAlg tpm2.HashAlgorithmId, loadSequences *ImageLoadSequences, options ...PCRProfileOption) (*pcrProfileGenerator, error) { gen := &pcrProfileGenerator{ pcrAlg: pcrAlg, loadSequences: loadSequences, - env: defaultEnv, + env: internal.DefaultEnv, handlers: makeImageLoadHandlerMap(), } for _, opt := range options { - opt.applyOptionTo(gen) + if err := opt.ApplyOptionTo(gen); err != nil { + return nil, err + } } - return gen + return gen, nil } func (g *pcrProfileGenerator) addPCRProfile(branch *secboot_tpm2.PCRProtectionProfileBranch) error { @@ -255,12 +263,14 @@ func (g *pcrProfileGenerator) addPCRProfile(branch *secboot_tpm2.PCRProtectionPr // Collect all of the starting EFI variable states that we need to // generate branches for. - collector := newRootVarsCollector(g.env) + collector := newVariableSetCollector(g.env) // Collect the starting EFI variable states from the supplied options for i, mod := range g.varModifiers { - if err := mod(collector); err != nil { - return xerrors.Errorf("cannot process host variable modifier %d: %w", i, err) + for j, branch := range collector.PeekAll() { + if err := mod(branch); err != nil { + return fmt.Errorf("cannot process host variable modifier %d for initial branch %d: %w", i, j, err) + } } } @@ -311,6 +321,20 @@ func (g *pcrProfileGenerator) addOnePCRProfileBranch(bp *secboot_tpm2.PCRProtect return nil } +// AddPCRs implements [internal.PCRProfileOptionVisitor.AddPCRs] +func (g *pcrProfileGenerator) AddPCRs(pcrs ...tpm2.Handle) { + g.pcrs |= makePcrFlags(pcrs...) +} + +// SetEnvironment implements [internal.PCRProfileOptionVisitor.SetEnvironment] +func (g *pcrProfileGenerator) SetEnvironment(env internal.HostEnvironment) { + g.env = env +} + +func (g *pcrProfileGenerator) AddInitialVariablesModifier(fn internal.InitialVariablesModifier) { + g.varModifiers = append(g.varModifiers, fn) +} + // PCRAlg implements pcrProfileContext.PCRAlg. func (g *pcrProfileGenerator) PCRAlg() tpm2.HashAlgorithmId { return g.pcrAlg diff --git a/efi/pcr_profile_test.go b/efi/pcr_profile_test.go index 9ec6f5e2..b2f578ac 100644 --- a/efi/pcr_profile_test.go +++ b/efi/pcr_profile_test.go @@ -34,6 +34,7 @@ import ( . "gopkg.in/check.v1" . "github.com/snapcore/secboot/efi" + "github.com/snapcore/secboot/efi/internal" "github.com/snapcore/secboot/internal/efitest" "github.com/snapcore/secboot/internal/testutil" "github.com/snapcore/secboot/internal/tpm2test" @@ -75,27 +76,27 @@ func (s *pcrProfileMockedSuite) TearDownSuite(c *C) { var _ = Suite(&pcrProfileMockedSuite{}) func (s *pcrProfileMockedSuite) TestPcrProfileGeneratorPCRAlg(c *C) { - gen := NewPcrProfileGenerator(tpm2.HashAlgorithmSHA256, NewImageLoadSequences()) + gen, _ := NewPcrProfileGenerator(tpm2.HashAlgorithmSHA256, NewImageLoadSequences()) c.Check(gen.PCRAlg(), Equals, tpm2.HashAlgorithmSHA256) } func (s *pcrProfileMockedSuite) TestPcrProfileGeneratorPCRAlgSHA1(c *C) { - gen := NewPcrProfileGenerator(tpm2.HashAlgorithmSHA1, NewImageLoadSequences()) + gen, _ := NewPcrProfileGenerator(tpm2.HashAlgorithmSHA1, NewImageLoadSequences()) c.Check(gen.PCRAlg(), Equals, tpm2.HashAlgorithmSHA1) } func (s *pcrProfileMockedSuite) TestWithSecureBootPolicyProfile(c *C) { - gen := NewPcrProfileGenerator(tpm2.HashAlgorithmSHA256, NewImageLoadSequences(), WithSecureBootPolicyProfile()) - c.Check(gen.PCRs(), Equals, PcrFlags(1<