Skip to content

Commit

Permalink
preinstall: Add public RunChecks API
Browse files Browse the repository at this point in the history
RunChecks is the first main entry point for running all of the platform
tests included in this package. It is considered to be quite a low
level and a future PR is going to add a higher level API that is easier
to use (RunChecksContext)

It can be customized with the CheckFlags argument, and the caller must
supply a list of images loaded during the current boot, in the correct
order.

On failure, it will return an error. In some cases, it fails early. In
other cases, it carries on and collects individual errors which are
then returned wrapped in RunChecksError. This can be obtained with the
errors.As API in order to obtain individual errors.

On success, it will return a CheckResult. Any errors that were
encountered but are considered non-fatal based on the supplied
CheckFlags will he added to the Warnings field of CheckResult.

The intention is that CheckResult is persisted and then used by an API
(to be added in the next PR) along with some user customization flags in
order to select the most appropriate set of TCG defined PCRs to seal
against. This can still fail if an appropriately secure set of PCRs
cannot be selected, even if RunChecks succeeded. The future
higher-level RunChecksContext API will make this case easier to handle
and will also help remove the burden of deciding which set of flags
to pass to RunChecks.
  • Loading branch information
chrisccoulson committed Nov 12, 2024
1 parent 5b74975 commit f6330c4
Show file tree
Hide file tree
Showing 6 changed files with 3,793 additions and 75 deletions.
62 changes: 37 additions & 25 deletions efi/preinstall/check_tcglog_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"errors"

"github.com/canonical/go-tpm2"
"github.com/canonical/go-tpm2/mssim"
tpm2_testutil "github.com/canonical/go-tpm2/testutil"
"github.com/canonical/tcglog-parser"
. "github.com/snapcore/secboot/efi/preinstall"
Expand All @@ -33,14 +34,19 @@ import (
. "gopkg.in/check.v1"
)

type tcglogSuite struct {
tpm2_testutil.TPMSimulatorTest
type tcglogReplayMixinInterface interface {
Tpm() *tpm2.TPMContext
Mssim(*C) *mssim.Transport
ResetTPMSimulator(*C)
ResetTPMSimulatorNoStartup(*C)
}

var _ = Suite(&tcglogSuite{})
type tcglogReplayMixin struct {
impl tcglogReplayMixinInterface
}

func (s *tcglogSuite) resetTPMAndReplayLog(c *C, log *tcglog.Log, algs ...tpm2.HashAlgorithmId) {
s.ResetTPMSimulatorNoStartup(c) // Shutdown and reset the simulator to reset the PCRs back to their reset values.
func (m *tcglogReplayMixin) resetTPMAndReplayLog(c *C, log *tcglog.Log, algs ...tpm2.HashAlgorithmId) {
m.impl.ResetTPMSimulatorNoStartup(c) // Shutdown and reset the simulator to reset the PCRs back to their reset values.
// Don't immediately call TPM2_Startup in case the log indicates we need to change localities.
started := false
for _, ev := range log.Events {
Expand All @@ -54,9 +60,9 @@ func (s *tcglogSuite) resetTPMAndReplayLog(c *C, log *tcglog.Log, algs ...tpm2.H
case 0:
// do nothing
case 3:
s.Mssim(c).SetLocality(3)
c.Assert(s.TPM.Startup(tpm2.StartupClear), IsNil)
s.Mssim(c).SetLocality(0)
m.impl.Mssim(c).SetLocality(3)
c.Assert(m.impl.Tpm().Startup(tpm2.StartupClear), IsNil)
m.impl.Mssim(c).SetLocality(0)
started = true
case 4:
c.Fatal(`Handling H-CRTM event sequences is not supported yet because it requires work in
Expand All @@ -72,7 +78,7 @@ func (s *tcglogSuite) resetTPMAndReplayLog(c *C, log *tcglog.Log, algs ...tpm2.H
if !started {
// Our first actual measurement and we haven't called TPM2_Startup yet,
// so just call it from locality 0.
c.Assert(s.TPM.Startup(tpm2.StartupClear), IsNil)
c.Assert(m.impl.Tpm().Startup(tpm2.StartupClear), IsNil)
started = true
}

Expand All @@ -82,12 +88,12 @@ func (s *tcglogSuite) resetTPMAndReplayLog(c *C, log *tcglog.Log, algs ...tpm2.H
c.Assert(ok, testutil.IsTrue)
digests = append(digests, tpm2.MakeTaggedHash(alg, tpm2.Digest(digest)))
}
c.Assert(s.TPM.PCRExtend(s.TPM.PCRHandleContext(int(ev.PCRIndex)), digests, nil), IsNil)
c.Assert(m.impl.Tpm().PCRExtend(m.impl.Tpm().PCRHandleContext(int(ev.PCRIndex)), digests, nil), IsNil)
}
}

func (s *tcglogSuite) allocatePCRBanks(c *C, banks ...tpm2.HashAlgorithmId) {
current, err := s.TPM.GetCapabilityPCRs()
func (m *tcglogReplayMixin) allocatePCRBanks(c *C, banks ...tpm2.HashAlgorithmId) {
current, err := m.impl.Tpm().GetCapabilityPCRs()
c.Assert(err, IsNil)

pcrs := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23}
Expand Down Expand Up @@ -141,19 +147,34 @@ func (s *tcglogSuite) allocatePCRBanks(c *C, banks ...tpm2.HashAlgorithmId) {
}

// Set the PCR allocation
success, _, _, _, err := s.TPM.PCRAllocate(s.TPM.PlatformHandleContext(), current, nil)
success, _, _, _, err := m.impl.Tpm().PCRAllocate(m.impl.Tpm().PlatformHandleContext(), current, nil)
c.Assert(err, IsNil)
c.Assert(success, testutil.IsTrue)

s.ResetTPMSimulator(c) // This is needed for the changes to take effect. This does call TPM2_Startup.
m.impl.ResetTPMSimulator(c) // This is needed for the changes to take effect. This does call TPM2_Startup.
}

type tcglogSuite struct {
tpm2_testutil.TPMSimulatorTest
tcglogReplayMixin
}

func (s *tcglogSuite) SetUpTest(c *C) {
s.TPMSimulatorTest.SetUpTest(c)
s.tcglogReplayMixin.impl = s
}

func (s *tcglogSuite) Tpm() *tpm2.TPMContext {
return s.TPM
}

var _ = Suite(&tcglogSuite{})

type testCheckFirmwareLogAndChoosePCRBankParams struct {
enabledBanks []tpm2.HashAlgorithmId
logAlgs []tpm2.HashAlgorithmId
startupLocality uint8
disallowPreOSVerification bool
replayAlgs []tpm2.HashAlgorithmId
mandatoryPcrs tpm2.HandleList

expectedAlg tpm2.HashAlgorithmId
Expand All @@ -167,7 +188,7 @@ func (s *tcglogSuite) testCheckFirmwareLogAndChoosePCRBank(c *C, params *testChe
StartupLocality: params.startupLocality,
DisallowPreOSVerification: params.disallowPreOSVerification,
})
s.resetTPMAndReplayLog(c, log, params.replayAlgs...)
s.resetTPMAndReplayLog(c, log, params.logAlgs...)
result, err := CheckFirmwareLogAndChoosePCRBank(s.TPM, log, params.mandatoryPcrs)
c.Assert(err, IsNil)
c.Check(result.Alg, Equals, params.expectedAlg)
Expand All @@ -178,7 +199,6 @@ func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankSHA256(c *C) {
s.testCheckFirmwareLogAndChoosePCRBank(c, &testCheckFirmwareLogAndChoosePCRBankParams{
enabledBanks: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256},
logAlgs: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256},
replayAlgs: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256},
mandatoryPcrs: tpm2.HandleList{
internal_efi.PlatformFirmwarePCR,
internal_efi.PlatformConfigPCR,
Expand All @@ -198,7 +218,6 @@ func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankSHA384(c *C) {
s.testCheckFirmwareLogAndChoosePCRBank(c, &testCheckFirmwareLogAndChoosePCRBankParams{
enabledBanks: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA384},
logAlgs: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA384},
replayAlgs: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA384},
mandatoryPcrs: tpm2.HandleList{
internal_efi.PlatformFirmwarePCR,
internal_efi.PlatformConfigPCR,
Expand All @@ -218,7 +237,6 @@ func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankSHA512(c *C) {
s.testCheckFirmwareLogAndChoosePCRBank(c, &testCheckFirmwareLogAndChoosePCRBankParams{
enabledBanks: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA512},
logAlgs: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA512},
replayAlgs: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA512},
mandatoryPcrs: tpm2.HandleList{
internal_efi.PlatformFirmwarePCR,
internal_efi.PlatformConfigPCR,
Expand All @@ -238,7 +256,6 @@ func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankMultipleSHA384(c *C) {
s.testCheckFirmwareLogAndChoosePCRBank(c, &testCheckFirmwareLogAndChoosePCRBankParams{
enabledBanks: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256, tpm2.HashAlgorithmSHA384},
logAlgs: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256, tpm2.HashAlgorithmSHA384},
replayAlgs: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256, tpm2.HashAlgorithmSHA384},
mandatoryPcrs: tpm2.HandleList{
internal_efi.PlatformFirmwarePCR,
internal_efi.PlatformConfigPCR,
Expand All @@ -258,7 +275,6 @@ func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankSHA256WithEmptySHA384B
s.testCheckFirmwareLogAndChoosePCRBank(c, &testCheckFirmwareLogAndChoosePCRBankParams{
enabledBanks: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256, tpm2.HashAlgorithmSHA384},
logAlgs: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256},
replayAlgs: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256},
mandatoryPcrs: tpm2.HandleList{
internal_efi.PlatformFirmwarePCR,
internal_efi.PlatformConfigPCR,
Expand All @@ -278,7 +294,6 @@ func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankSHA256StartupLocality3
enabledBanks: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256},
logAlgs: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256},
startupLocality: 3,
replayAlgs: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256},
mandatoryPcrs: tpm2.HandleList{
internal_efi.PlatformFirmwarePCR,
internal_efi.PlatformConfigPCR,
Expand All @@ -301,7 +316,6 @@ func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankSHA256StartupLocality3
// enabledBanks: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256},
// logAlgs: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256},
// startupLocality: 4,
// replayAlgs: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256},
// mandatoryPcrs: tpm2.HandleList{
// internal_efi.PlatformFirmwarePCR,
// internal_efi.PlatformConfigPCR,
Expand All @@ -322,7 +336,6 @@ func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankMultipleSHA384StartupL
enabledBanks: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256, tpm2.HashAlgorithmSHA384},
logAlgs: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256, tpm2.HashAlgorithmSHA384},
startupLocality: 3,
replayAlgs: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256, tpm2.HashAlgorithmSHA384},
mandatoryPcrs: tpm2.HandleList{
internal_efi.PlatformFirmwarePCR,
internal_efi.PlatformConfigPCR,
Expand All @@ -346,7 +359,6 @@ func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankOldFirmware(c *C) {
enabledBanks: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256},
logAlgs: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256},
disallowPreOSVerification: true,
replayAlgs: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256},
mandatoryPcrs: tpm2.HandleList{
internal_efi.PlatformFirmwarePCR,
internal_efi.PlatformConfigPCR,
Expand Down
22 changes: 16 additions & 6 deletions efi/preinstall/check_tpm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,13 @@ import (
. "gopkg.in/check.v1"
)

type tpmSuite struct {
tpm2_testutil.TPMSimulatorTest
type tpmPropertyModifierMixin struct {
transport *tpm2_testutil.Transport
}

var _ = Suite(&tpmSuite{})

// addTPMPropertyModifiers permits the test to run with well-known property values
func (s *tpmSuite) addTPMPropertyModifiers(c *C, overrides map[tpm2.Property]uint32) {
s.Transport.ResponseIntercept = func(cmdCode tpm2.CommandCode, cmdHandles tpm2.HandleList, cmdAuthArea []tpm2.AuthCommand, cpBytes []byte, rsp *bytes.Buffer) {
func (m *tpmPropertyModifierMixin) addTPMPropertyModifiers(c *C, overrides map[tpm2.Property]uint32) {
m.transport.ResponseIntercept = func(cmdCode tpm2.CommandCode, cmdHandles tpm2.HandleList, cmdAuthArea []tpm2.AuthCommand, cpBytes []byte, rsp *bytes.Buffer) {
// Check we have the right command code
if cmdCode != tpm2.CommandGetCapability {
return
Expand Down Expand Up @@ -90,6 +88,18 @@ func (s *tpmSuite) addTPMPropertyModifiers(c *C, overrides map[tpm2.Property]uin
}
}

type tpmSuite struct {
tpm2_testutil.TPMSimulatorTest
tpmPropertyModifierMixin
}

func (s *tpmSuite) SetUpTest(c *C) {
s.TPMSimulatorTest.SetUpTest(c)
s.tpmPropertyModifierMixin.transport = s.Transport
}

var _ = Suite(&tpmSuite{})

func (s *tpmSuite) TestOpenAndCheckTPM2DeviceGoodPreInstallNoVMInfiniteCountersDiscreteTPM(c *C) {
s.addTPMPropertyModifiers(c, map[tpm2.Property]uint32{
tpm2.PropertyNVCountersMax: 0,
Expand Down
Loading

0 comments on commit f6330c4

Please sign in to comment.