Skip to content

Commit

Permalink
Merge pull request #309 from chrisccoulson/efi-prepare-pre-install-de…
Browse files Browse the repository at this point in the history
…tection

efi: Prepare to add pre-install detection.

This changes a few types, replaces pcrProfileFlags with pcrFlags
and introduces a PCRProfileEnablePCRsOption interface which is
implemented by the existing profile options and will be implemented by
a new composite option returned by the detection code.
  • Loading branch information
chrisccoulson authored Jun 11, 2024
2 parents 121a1da + ecc15ab commit 5c01e34
Show file tree
Hide file tree
Showing 15 changed files with 302 additions and 178 deletions.
50 changes: 45 additions & 5 deletions efi/efi.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,50 @@

package efi

import "github.com/canonical/go-tpm2"

const (
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
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
)

// pcrFlags corresponds to a set of PCRs. This can only represent actual PCRs, it
// cannot represent extendable NV indices (handle type 0x01) if we have a use for
// these in the future
type pcrFlags tpm2.Handle

func makePcrFlags(pcrs ...tpm2.Handle) pcrFlags {
var out pcrFlags
for _, pcr := range pcrs {
if pcr >= 32 {
panic("invalid PCR")
}
out |= 1 << pcr
}
return out
}

// PCRs returns a list of all of the PCRs represented by these flags
func (f pcrFlags) PCRs() (out tpm2.HandleList) {
for n := tpm2.Handle(0); n < 32; n++ {
if (f & (1 << n)) > 0 {
out = append(out, n)
}
}
return out
}

func (f pcrFlags) Contains(pcrs ...tpm2.Handle) bool {
for _, pcr := range pcrs {
if pcr >= 32 {
panic("invalid PCR")
}
if f&(1<<pcr) == 0 {
return false
}
}
return true
}
84 changes: 74 additions & 10 deletions efi/efi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,16 @@ func Test(t *testing.T) { TestingT(t) }

type mockPcrProfileContext struct {
alg tpm2.HashAlgorithmId
flags PcrProfileFlags
pcrs PcrFlags
handlers ImageLoadHandlerMap
}

func (c *mockPcrProfileContext) PCRAlg() tpm2.HashAlgorithmId {
return c.alg
}

func (c *mockPcrProfileContext) Flags() PcrProfileFlags {
return c.flags
func (c *mockPcrProfileContext) PCRs() PcrFlags {
return c.pcrs
}

func (c *mockPcrProfileContext) ImageLoadHandlerMap() ImageLoadHandlerMap {
Expand All @@ -67,7 +67,7 @@ const (
)

type mockPcrBranchEvent struct {
pcr int
pcr tpm2.Handle
eventType mockPcrBranchEventType

locality uint8
Expand Down Expand Up @@ -116,7 +116,7 @@ func (c *mockPcrBranchContext) ShimContext() *ShimContext {
return c.sc
}

func (c *mockPcrBranchContext) ResetPCR(pcr int) {
func (c *mockPcrBranchContext) ResetPCR(pcr tpm2.Handle) {
c.events = append(c.events, &mockPcrBranchEvent{
pcr: pcr,
eventType: mockPcrBranchResetEvent,
Expand All @@ -131,15 +131,15 @@ func (c *mockPcrBranchContext) ResetCRTMPCR(locality uint8) {
})
}

func (c *mockPcrBranchContext) ExtendPCR(pcr int, digest tpm2.Digest) {
func (c *mockPcrBranchContext) ExtendPCR(pcr tpm2.Handle, digest tpm2.Digest) {
c.events = append(c.events, &mockPcrBranchEvent{
pcr: pcr,
eventType: mockPcrBranchExtendEvent,
digest: digest,
})
}

func (c *mockPcrBranchContext) MeasureVariable(pcr int, guid efi.GUID, name string, data []byte) {
func (c *mockPcrBranchContext) MeasureVariable(pcr tpm2.Handle, guid efi.GUID, name string, data []byte) {
c.events = append(c.events, &mockPcrBranchEvent{
pcr: pcr,
eventType: mockPcrBranchMeasureVariableEvent,
Expand Down Expand Up @@ -524,15 +524,15 @@ func newMockLoadHandler(actions ...mockLoadHandlerAction) *mockLoadHandler {
return out
}

func (h *mockLoadHandler) withExtendPCROnImageStart(pcr int, digest tpm2.Digest) *mockLoadHandler {
func (h *mockLoadHandler) withExtendPCROnImageStart(pcr tpm2.Handle, digest tpm2.Digest) *mockLoadHandler {
h.startActions = append(h.startActions, func(ctx PcrBranchContext) error {
ctx.ExtendPCR(pcr, digest)
return nil
})
return h
}

func (h *mockLoadHandler) withMeasureVariableOnImageStart(pcr int, guid efi.GUID, name string) *mockLoadHandler {
func (h *mockLoadHandler) withMeasureVariableOnImageStart(pcr tpm2.Handle, guid efi.GUID, name string) *mockLoadHandler {
h.startActions = append(h.startActions, func(ctx PcrBranchContext) error {
data, _, err := ctx.Vars().ReadVar(name, guid)
switch {
Expand Down Expand Up @@ -619,7 +619,7 @@ func (h *mockLoadHandler) withAppendShimVerificationEventOnImageStart(c *C, dige
return h
}

func (h *mockLoadHandler) withExtendPCROnImageLoads(pcr int, digests ...tpm2.Digest) *mockLoadHandler {
func (h *mockLoadHandler) withExtendPCROnImageLoads(pcr tpm2.Handle, digests ...tpm2.Digest) *mockLoadHandler {
h.loadActions = append(h.loadActions, func(ctx PcrBranchContext) error {
if len(digests) == 0 {
return errors.New("no digests")
Expand Down Expand Up @@ -687,3 +687,67 @@ func (d *mockErrLogData) Error() string {
func (d *mockErrLogData) Unwrap() error {
return d.err
}

type efiSuite struct{}

var _ = Suite(&efiSuite{})

func (s *efiSuite) TestMakePcrFlags1(c *C) {
flags := MakePcrFlags(SecureBootPolicyPCR)
c.Check(flags, Equals, PcrFlags(1<<SecureBootPolicyPCR))
}

func (s *efiSuite) TestMakePcrFlags2(c *C) {
flags := MakePcrFlags(BootManagerCodePCR)
c.Check(flags, Equals, PcrFlags(1<<BootManagerCodePCR))
}

func (s *efiSuite) TestMakePcrFlags3(c *C) {
flags := MakePcrFlags(BootManagerCodePCR, SecureBootPolicyPCR)
c.Check(flags, Equals, PcrFlags(1<<BootManagerCodePCR|1<<SecureBootPolicyPCR))
}

func (e *efiSuite) TestPcrFlagsPCRs1(c *C) {
flags := PcrFlags(1 << SecureBootPolicyPCR)
c.Check(flags.PCRs(), DeepEquals, tpm2.HandleList{SecureBootPolicyPCR})
}

func (e *efiSuite) TestPcrFlagsPCRs2(c *C) {
flags := PcrFlags(1 << BootManagerCodePCR)
c.Check(flags.PCRs(), DeepEquals, tpm2.HandleList{BootManagerCodePCR})
}

func (e *efiSuite) TestPcrFlagsPCRs3(c *C) {
flags := PcrFlags((1 << BootManagerCodePCR) | (1 << SecureBootPolicyPCR))
c.Check(flags.PCRs(), DeepEquals, tpm2.HandleList{BootManagerCodePCR, SecureBootPolicyPCR})
}

func (e *efiSuite) TestPcrFlagsContains1(c *C) {
flags := PcrFlags(1 << SecureBootPolicyPCR)
c.Check(flags.Contains(SecureBootPolicyPCR), testutil.IsTrue)
}

func (e *efiSuite) TestPcrFlagsContains2(c *C) {
flags := PcrFlags(1 << BootManagerCodePCR)
c.Check(flags.Contains(BootManagerCodePCR), testutil.IsTrue)
}

func (e *efiSuite) TestPcrFlagsContains3(c *C) {
flags := PcrFlags((1 << BootManagerCodePCR) | (1 << SecureBootPolicyPCR))
c.Check(flags.Contains(BootManagerCodePCR, SecureBootPolicyPCR), testutil.IsTrue)
}

func (e *efiSuite) TestPcrFlagsContains4(c *C) {
flags := PcrFlags((1 << BootManagerCodePCR) | (1 << SecureBootPolicyPCR))
c.Check(flags.Contains(SecureBootPolicyPCR), testutil.IsTrue)
}

func (e *efiSuite) TestPcrFlagsDoesNotContain1(c *C) {
flags := PcrFlags(1 << SecureBootPolicyPCR)
c.Check(flags.Contains(PlatformFirmwarePCR), testutil.IsFalse)
}

func (e *efiSuite) TestPcrFlagsDoesNotContain2(c *C) {
flags := PcrFlags(1 << SecureBootPolicyPCR)
c.Check(flags.Contains(PlatformFirmwarePCR, SecureBootPolicyPCR), testutil.IsFalse)
}
13 changes: 7 additions & 6 deletions efi/export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ import (

// Export constants for testing
const (
BootManagerCodeProfile = bootManagerCodeProfile
DriversAndAppsProfile = driversAndAppsProfile
BootManagerCodePCR = bootManagerCodePCR
DriversAndAppsPCR = driversAndAppsPCR
GrubChainloaderUsesShimProtocol = grubChainloaderUsesShimProtocol
KernelConfigProfile = kernelConfigProfile
PlatformFirmwareProfile = platformFirmwareProfile
SecureBootPolicyProfile = secureBootPolicyProfile
KernelConfigPCR = kernelConfigPCR
PlatformFirmwarePCR = platformFirmwarePCR
SecureBootPolicyPCR = secureBootPolicyPCR
ShimFixVariableAuthorityEventsMatchSpec = shimFixVariableAuthorityEventsMatchSpec
ShimHasSbatRevocationManagement = shimHasSbatRevocationManagement
ShimHasSbatVerification = shimHasSbatVerification
Expand Down Expand Up @@ -59,6 +59,7 @@ var (
MakeImageLoadHandlerMap = makeImageLoadHandlerMap
MakeMicrosoftUEFICASecureBootNamespaceRules = makeMicrosoftUEFICASecureBootNamespaceRules
MustParseShimVersion = mustParseShimVersion
MakePcrFlags = makePcrFlags
NewestSbatLevel = newestSbatLevel
NewFwLoadHandler = newFwLoadHandler
NewGrubImageHandle = newGrubImageHandle
Expand Down Expand Up @@ -102,9 +103,9 @@ type ImageSignedByOrganization = imageSignedByOrganization
type LoadParams = loadParams
type NullLoadHandler = nullLoadHandler
type PcrBranchContext = pcrBranchContext
type PcrFlags = pcrFlags
type PcrImagesMeasurer = pcrImagesMeasurer
type PcrProfileContext = pcrProfileContext
type PcrProfileFlags = pcrProfileFlags
type PeImageHandle = peImageHandle
type RootVarReaderKey = rootVarReaderKey
type RootVarsCollector = rootVarsCollector
Expand Down
Loading

0 comments on commit 5c01e34

Please sign in to comment.