diff --git a/efi/fw_load_handler_test.go b/efi/fw_load_handler_test.go
index 2adfe999..196e420d 100644
--- a/efi/fw_load_handler_test.go
+++ b/efi/fw_load_handler_test.go
@@ -285,7 +285,8 @@ func (s *fwLoadHandlerSuite) TestMeasureImageStartPlatformFirmwareProfile(c *C)
pcrs: MakePcrFlags(internal_efi.PlatformFirmwarePCR),
expectedEvents: []*mockPcrBranchEvent{
{pcr: 0, eventType: mockPcrBranchResetEvent},
- {pcr: 0, eventType: mockPcrBranchExtendEvent, digest: testutil.DecodeHexString(c, "d0ff5974b6aa52cf562bea5921840c032a860a91a3512f7fe8f768f6bbe005f6")},
+ {pcr: 0, eventType: mockPcrBranchExtendEvent, digest: testutil.DecodeHexString(c, "cd1137dfa2bfba51973100d73d78d9f496e089fd246fe980fadc668b4efc9443")},
+ {pcr: 0, eventType: mockPcrBranchExtendEvent, digest: testutil.DecodeHexString(c, "5ca5e6acb83d626a42b53ddc5a2fe04d6a4b2f045bb07f6d9baf0e82900d7bbe")},
{pcr: 0, eventType: mockPcrBranchExtendEvent, digest: testutil.DecodeHexString(c, "aef237d4703e8936530141636186a9f249fa39e194f02f668cd328bd5902cf03")},
{pcr: 0, eventType: mockPcrBranchExtendEvent, digest: testutil.DecodeHexString(c, "8b0eec99d3cccc081edb98c3a2aa74b99a02b785bd74513e1cf7401e99121e80")},
{pcr: 0, eventType: mockPcrBranchExtendEvent, digest: testutil.DecodeHexString(c, "df3f619804a92fdb4057192dc43dd748ea778adc52bc498ce80524c014b81119")},
@@ -300,7 +301,8 @@ func (s *fwLoadHandlerSuite) TestMeasureImageStartPlatformFirmwareProfileSL3(c *
pcrs: MakePcrFlags(internal_efi.PlatformFirmwarePCR),
expectedEvents: []*mockPcrBranchEvent{
{pcr: 0, eventType: mockPcrBranchResetCRTMPCREvent, locality: 3},
- {pcr: 0, eventType: mockPcrBranchExtendEvent, digest: testutil.DecodeHexString(c, "d0ff5974b6aa52cf562bea5921840c032a860a91a3512f7fe8f768f6bbe005f6")},
+ {pcr: 0, eventType: mockPcrBranchExtendEvent, digest: testutil.DecodeHexString(c, "cd1137dfa2bfba51973100d73d78d9f496e089fd246fe980fadc668b4efc9443")},
+ {pcr: 0, eventType: mockPcrBranchExtendEvent, digest: testutil.DecodeHexString(c, "5ca5e6acb83d626a42b53ddc5a2fe04d6a4b2f045bb07f6d9baf0e82900d7bbe")},
{pcr: 0, eventType: mockPcrBranchExtendEvent, digest: testutil.DecodeHexString(c, "aef237d4703e8936530141636186a9f249fa39e194f02f668cd328bd5902cf03")},
{pcr: 0, eventType: mockPcrBranchExtendEvent, digest: testutil.DecodeHexString(c, "8b0eec99d3cccc081edb98c3a2aa74b99a02b785bd74513e1cf7401e99121e80")},
{pcr: 0, eventType: mockPcrBranchExtendEvent, digest: testutil.DecodeHexString(c, "df3f619804a92fdb4057192dc43dd748ea778adc52bc498ce80524c014b81119")},
diff --git a/efi/pcr_profile_test.go b/efi/pcr_profile_test.go
index cbb76685..9f3e2956 100644
--- a/efi/pcr_profile_test.go
+++ b/efi/pcr_profile_test.go
@@ -745,7 +745,7 @@ func (s *pcrProfileSuite) TestAddPCRProfileUC20WithExtraProfiles(c *C) {
expected: []tpm2.PCRValues{
{
tpm2.HashAlgorithmSHA256: {
- 0: testutil.DecodeHexString(c, "3d2b11b4c5cb623acbde6d14205217e47ebd368eab861e4fed782bb99be4598a"),
+ 0: testutil.DecodeHexString(c, "a6602a7a403068b5556e78cc3f5b00c9c76d33d514093ca9b584dce7590e6c69"),
2: testutil.DecodeHexString(c, "3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969"),
4: testutil.DecodeHexString(c, "bec6121586508581e08a41244944292ef452879f8e19c7f93d166e912c6aac5e"),
7: testutil.DecodeHexString(c, "3d65dbe406e9427d402488ea4f87e07e8b584c79c578a735d48d21a6405fc8bb"),
@@ -754,7 +754,7 @@ func (s *pcrProfileSuite) TestAddPCRProfileUC20WithExtraProfiles(c *C) {
},
{
tpm2.HashAlgorithmSHA256: {
- 0: testutil.DecodeHexString(c, "3d2b11b4c5cb623acbde6d14205217e47ebd368eab861e4fed782bb99be4598a"),
+ 0: testutil.DecodeHexString(c, "a6602a7a403068b5556e78cc3f5b00c9c76d33d514093ca9b584dce7590e6c69"),
2: testutil.DecodeHexString(c, "3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969"),
4: testutil.DecodeHexString(c, "c731a39b7fc6475c7d8a9264e704902157c7cee40c22f59fa1690ea99ff70c67"),
7: testutil.DecodeHexString(c, "3d65dbe406e9427d402488ea4f87e07e8b584c79c578a735d48d21a6405fc8bb"),
@@ -801,7 +801,7 @@ func (s *pcrProfileSuite) TestAddPCRProfileUC20WithPlatformFirmwareProfileSL3(c
expected: []tpm2.PCRValues{
{
tpm2.HashAlgorithmSHA256: {
- 0: testutil.DecodeHexString(c, "25a58800ba22dff433a8bb1b5084a53ddf02dc71f204053b38036fe1c0f146e2"),
+ 0: testutil.DecodeHexString(c, "b0d6d5f50852be1524306ad88b928605c14338e56a1b8c0dc211a144524df2ef"),
2: testutil.DecodeHexString(c, "3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969"),
4: testutil.DecodeHexString(c, "bec6121586508581e08a41244944292ef452879f8e19c7f93d166e912c6aac5e"),
7: testutil.DecodeHexString(c, "3d65dbe406e9427d402488ea4f87e07e8b584c79c578a735d48d21a6405fc8bb"),
@@ -810,7 +810,7 @@ func (s *pcrProfileSuite) TestAddPCRProfileUC20WithPlatformFirmwareProfileSL3(c
},
{
tpm2.HashAlgorithmSHA256: {
- 0: testutil.DecodeHexString(c, "25a58800ba22dff433a8bb1b5084a53ddf02dc71f204053b38036fe1c0f146e2"),
+ 0: testutil.DecodeHexString(c, "b0d6d5f50852be1524306ad88b928605c14338e56a1b8c0dc211a144524df2ef"),
2: testutil.DecodeHexString(c, "3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969"),
4: testutil.DecodeHexString(c, "c731a39b7fc6475c7d8a9264e704902157c7cee40c22f59fa1690ea99ff70c67"),
7: testutil.DecodeHexString(c, "3d65dbe406e9427d402488ea4f87e07e8b584c79c578a735d48d21a6405fc8bb"),
diff --git a/efi/preinstall/check_tcglog.go b/efi/preinstall/check_tcglog.go
new file mode 100644
index 00000000..6d291a12
--- /dev/null
+++ b/efi/preinstall/check_tcglog.go
@@ -0,0 +1,501 @@
+// -*- 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 preinstall
+
+import (
+ "bytes"
+ _ "crypto/sha256"
+ _ "crypto/sha512"
+ "encoding/binary"
+ "errors"
+ "fmt"
+
+ "github.com/canonical/go-tpm2"
+ "github.com/canonical/tcglog-parser"
+ internal_efi "github.com/snapcore/secboot/internal/efi"
+)
+
+var (
+ // supportedAlgs specifies the supported PCR banks, in order of preference.
+ // XXX: We disallow SHA-1 here - perhaps this should be optionally permitted?
+ supportedAlgs = []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA512, tpm2.HashAlgorithmSHA384, tpm2.HashAlgorithmSHA256}
+
+ // supportedPcrs specifies all of the TCG defined PCRs, although we don't actually
+ // support generating profiles for all of them at the moment, nor are we likely to
+ // for some of them in the future.
+ supportedPcrs = []tpm2.Handle{
+ internal_efi.PlatformFirmwarePCR,
+ internal_efi.PlatformFirmwareConfigPCR,
+ internal_efi.DriversAndAppsPCR,
+ internal_efi.DriversAndAppsConfigPCR,
+ internal_efi.BootManagerCodePCR,
+ internal_efi.BootManagerCodeConfigPCR,
+ internal_efi.PlatformManufacturerPCR,
+ internal_efi.SecureBootPolicyPCR,
+ }
+)
+
+// NoSuitablePCRAlgorithmError is returned wrapped from [RunChecks] if there is no suitable PCR bank
+// where the log matches the TPM values when reconstructed. As multiple errors can occur during
+// testing (multiple banks and multiple PCRs), this error tries to keep as much information as
+// possible
+type NoSuitablePCRAlgorithmError struct {
+ bankErrs map[tpm2.HashAlgorithmId]error
+ pcrErrs map[tpm2.HashAlgorithmId]map[tpm2.Handle]error
+}
+
+func (e *NoSuitablePCRAlgorithmError) Error() string {
+ w := new(bytes.Buffer)
+ fmt.Fprintf(w, "no suitable PCR algorithm available:\n")
+ for _, alg := range supportedAlgs {
+ if err, isErr := e.bankErrs[alg]; isErr {
+ // We have a general error for this PCR bank
+ fmt.Fprintf(w, "- %v: %v.\n", alg, err)
+ }
+ pcrErrs, hasPcrErrs := e.pcrErrs[alg]
+ if !hasPcrErrs {
+ // WE have no individual PCR errors for this bank
+ continue
+ }
+ for _, pcr := range supportedPcrs {
+ if err, isErr := pcrErrs[pcr]; isErr {
+ // We have an error for this PCR
+ fmt.Fprintf(w, "- %v(PCR%d): %v.\n", alg, pcr, err)
+ }
+ }
+ }
+ return w.String()
+}
+
+// UNwrapBankError returns the error associated with the specified PCR bank if one
+// occurred, or nil if none occurred.
+func (e *NoSuitablePCRAlgorithmError) UnwrapBankError(alg tpm2.HashAlgorithmId) error {
+ return e.bankErrs[alg]
+}
+
+// UnwrapPCRError returns the error associated with the specified PCR in the specified
+// bank if one occurred, or nil if none occurred.
+func (e *NoSuitablePCRAlgorithmError) UnwrapPCRError(alg tpm2.HashAlgorithmId, pcr tpm2.Handle) error {
+ pcrErrs, exists := e.pcrErrs[alg]
+ if !exists {
+ return nil
+ }
+ return pcrErrs[pcr]
+}
+
+// setBankErr sets an error for an entire PCR bank
+func (e *NoSuitablePCRAlgorithmError) setBankErr(alg tpm2.HashAlgorithmId, err error) {
+ if e.bankErrs == nil {
+ e.bankErrs = make(map[tpm2.HashAlgorithmId]error)
+ }
+ e.bankErrs[alg] = err
+}
+
+// setPcrErrs sets errors for individual PCRs associated with a bank
+func (e *NoSuitablePCRAlgorithmError) setPcrErrs(results *pcrBankResults) {
+ if e.pcrErrs == nil {
+ e.pcrErrs = make(map[tpm2.HashAlgorithmId]map[tpm2.Handle]error)
+ }
+ e.pcrErrs[results.Alg] = results.pcrErrs()
+}
+
+// pcrResult represents the result of reconstructing the log for a single PCR in a single bank
+type pcrResults struct {
+ mandatory bool // Errors from testing this PCR can't be ignored
+ initialValue tpm2.Digest // The initial value for the PCR. Initialized to the size of the digest of the bank during construction.
+ logValue tpm2.Digest // The expected TPM PCR value from the reconstructed log. Initialized to the same value as initialValue during construction.
+ pcrValue tpm2.Digest // The actual TPM PCR value. Will be empty until set by setPcrValue
+
+ err error // This is set for any error that occurred.
+}
+
+// Ok indicates that the reconstructed log is consistent with the TPM PCR value.
+func (r *pcrResults) Ok() bool {
+ return r.Err() == nil
+}
+
+// Error returns any error that occurred when checking the log consistency with the
+// associated TPM PCR value.
+func (r *pcrResults) Err() error {
+ if r.err != nil {
+ // Return the first explicitly set error.
+ return r.err
+ }
+ if len(r.pcrValue) == 0 {
+ return errors.New("PCR value has not been obtained from TPM yet")
+ }
+ if bytes.Equal(r.pcrValue, r.initialValue) {
+ // Return an error if the PCR hasn't been extended.
+ return errors.New("PCR has not been extended by platform firmware")
+ }
+ if !bytes.Equal(r.pcrValue, r.logValue) {
+ // The PCR value is inconsistent with the log value.
+ return fmt.Errorf("PCR value mismatch (actual from TPM %#x, reconstructed from log %#x)", r.pcrValue, r.logValue)
+ }
+ return nil
+}
+
+// setInitialValue sets the initial value for the associated PCR in the associated bank.
+// This will panic if extend has already been called, so the caller should check this. It
+// will also panic if the supplied digest has the wrong size
+func (r *pcrResults) setInitialValue(digest tpm2.Digest) {
+ if !bytes.Equal(r.initialValue, r.logValue) {
+ panic("cannot set initial log value for PCR once extend has been called")
+ }
+ if len(digest) != len(r.initialValue) {
+ panic("invalid initial digest length")
+ }
+ copy(r.initialValue, digest)
+ copy(r.logValue, digest)
+}
+
+// extend performs a hash extend of the logValue field with the supplied digest using the
+// specified algorithm. This will return an error if the supplied digest has the wrong
+// length.
+func (r *pcrResults) extend(alg tpm2.HashAlgorithmId, digest tpm2.Digest) error {
+ if alg.Size() != len(r.logValue) {
+ panic("invalid algorithm supplied")
+ }
+ if alg.Size() != len(digest) {
+ // Don't panic here because digest comes from the log and perhaps the log
+ // defines the wrong size for the algorithm
+ return errors.New("invalid digest length")
+ }
+ h := alg.NewHash()
+ h.Write(r.logValue)
+ h.Write(digest)
+ r.logValue = h.Sum(nil)
+ return nil
+}
+
+// setPcrValue records the PCR value from the TPM. This will panic if it's called more than
+// once. It will return an error if the value length doesn't match the log value length.
+func (r *pcrResults) setPcrValue(value tpm2.Digest) error {
+ if len(r.pcrValue) > 0 {
+ panic("cannot set PCR value more than once")
+ }
+ if len(value) != len(r.logValue) {
+ // Don't panic here because the digest is returned directly
+ // from the TPM
+ return errors.New("invalid digest length")
+ }
+ r.pcrValue = value
+ return nil
+}
+
+// setErr sets an error for the associated PCR in the associated bank. This doesn't
+// overwrite previously set errors (ie, [Error] will return the first set error).
+func (r *pcrResults) setErr(err error) {
+ if r.err != nil {
+ return
+ }
+ r.err = err
+}
+
+// pcrBankResults represents the result of reconstructing the log for an entire
+// PCR bank.
+type pcrBankResults struct {
+ Alg tpm2.HashAlgorithmId // the digest algorithm of the PCR bank
+ StartupLocality uint8 // the startup locality
+ pcrs [8]pcrResults // individual PCR results
+}
+
+func newPcrBankResults(alg tpm2.HashAlgorithmId, mandatoryPcrs tpm2.HandleList) (out *pcrBankResults) {
+ out = &pcrBankResults{
+ Alg: alg,
+ StartupLocality: 0,
+ }
+ for pcr := range out.pcrs {
+ result := out.Lookup(tpm2.Handle(pcr))
+ for _, mandatoryPcr := range mandatoryPcrs {
+ if mandatoryPcr == tpm2.Handle(pcr) {
+ result.mandatory = true
+ break
+ }
+ }
+ result.initialValue = make(tpm2.Digest, alg.Size())
+ result.logValue = make(tpm2.Digest, alg.Size())
+ // leave the pcrValue field uninitialized for now
+ }
+ return out
+}
+
+// Ok indicates that the log was reconstructed ok for all mandatory PCRs for the associated PCR bank.
+func (r *pcrBankResults) Ok() bool {
+ for _, result := range r.pcrs {
+ if !result.Ok() && result.mandatory {
+ return false
+ }
+ }
+ return true
+}
+
+// Lookup looks up the result for the specified PCR. This will panic if the supplied
+// PCR is out of range (ie, not 0-7).
+func (r *pcrBankResults) Lookup(pcr tpm2.Handle) *pcrResults {
+ if !internal_efi.IsTCGDefinedPCR(pcr) {
+ panic("invalid PCR index")
+ }
+ return &r.pcrs[pcr]
+}
+
+// extend performs a hash extend of the logValue field of the pcrResult struct
+// associated with the specified pcr, using the supplied digest. It will panic
+// if the specified PCR is out of range. It will return an error if the supplied
+// digest has the wrong size.
+func (r *pcrBankResults) extend(pcr tpm2.Handle, digest tpm2.Digest) error {
+ return r.Lookup(pcr).extend(r.Alg, digest)
+}
+
+// setPcrValues records the PCR values obtained from the TPM. It will panic
+// if this is called more than once. It will return an error if any value returned
+// from the TPM has the wrong size.
+func (r *pcrBankResults) setPcrValues(values tpm2.PCRValues) error {
+ for pcr, digest := range values[r.Alg] {
+ if !internal_efi.IsTCGDefinedPCR(tpm2.Handle(pcr)) {
+ continue
+ }
+ if err := r.Lookup(tpm2.Handle(pcr)).setPcrValue(digest); err != nil {
+ return fmt.Errorf("cannot record value for PCR %d: %w", pcr, err)
+ }
+ }
+ return nil
+}
+
+// pcrErrs returns a map of PCRs to errors for individual PCRs associated with this bank.
+func (r *pcrBankResults) pcrErrs() (out map[tpm2.Handle]error) {
+ out = make(map[tpm2.Handle]error)
+ for pcr, result := range r.pcrs {
+ err := result.Err()
+ if err == nil {
+ continue
+ }
+ out[tpm2.Handle(pcr)] = err
+ }
+ return out
+}
+
+// checkFirmwareLogAgainstTPMForAlg checks the supplied TCG log consistency, reconstructed against the
+// TPM PCRs for the specified algorithm. This only checks TCG defined PCRs (0-7).
+func checkFirmwareLogAgainstTPMForAlg(tpm *tpm2.TPMContext, log *tcglog.Log, alg tpm2.HashAlgorithmId, mandatoryPcrs tpm2.HandleList) (results *pcrBankResults, err error) {
+ // Check that the TCG log contains the specified algorithm
+ supported := false
+ for _, logAlg := range log.Algorithms {
+ if logAlg != alg {
+ continue
+ }
+ // It does, so that's a good start.
+ supported = true
+ break
+ }
+ if !supported {
+ // The log doesn't contain the specified algorithm
+ return nil, errors.New("digest algorithm not present in log")
+ }
+
+ // Create the result tracker for PCRs 0-7
+ results = newPcrBankResults(alg, mandatoryPcrs)
+
+ seenStartupLocalityEvent := false
+
+ // Iterate over the log
+ for i, ev := range log.Events {
+ if !internal_efi.IsTCGDefinedPCR(ev.PCRIndex) {
+ // Skip all events that aren't defined by the TCG
+ continue
+ }
+
+ if ev.EventType == tcglog.EventTypeNoAction {
+ // EV_NO_ACTION events are informational and not measured, so ignore most of them with the exception
+ // of StartupLocality events, which affects the initial value of PCR0.
+ startupLocalityData, isStartupLocality := ev.Data.(*tcglog.StartupLocalityEventData)
+ if !isStartupLocality {
+ // Not a StartupLocality event.
+ continue
+ }
+
+ // This is the StartupLocality event which is added to the log to indicate
+ // which locality the TPM2_Startup command was executed from. The reference
+ // TPM implementation only allows this to be executed from localities 0 and 3.
+ // Executing it from locality 3, which is generally unavailable to the host CPU,
+ // changes the reset value of PCR 0 (the least significant 2 bits are set).
+ // PCR0 can also be initialized before TPM2_Startup by a H-CRTM event sequence from
+ // locality 4, which will be reflected in this event in this case by setting the
+ // startup locality to 4, and results in PCR0 being initialized with bit 2 set and
+ // the least significant 2 bits set to zero, regardless of what locality TPM2_Startup
+ // is subsequently called from.
+ if ev.PCRIndex != internal_efi.PlatformFirmwarePCR {
+ // This event should only ever appear in PCR0
+ results.Lookup(ev.PCRIndex).setErr(errors.New("unexpected StartupLocality event (should be in PCR0)"))
+ continue
+ }
+ if !bytes.Equal(results.Lookup(0).logValue, results.Lookup(0).initialValue) {
+ // This event should not appear in the log after events that have already been measured
+ results.Lookup(0).setErr(errors.New("unexpected StartupLocality event after measurements already made"))
+ continue
+ }
+ if seenStartupLocalityEvent {
+ results.Lookup(0).setErr(errors.New("unexpected StartupLocality event - more than one appears in log"))
+ continue
+ }
+ seenStartupLocalityEvent = true
+
+ switch startupLocalityData.StartupLocality {
+ case 0, 3, 4:
+ // Valid startup locality values, with 4 meaning there was a H-CRTM event sequence.
+ results.StartupLocality = startupLocalityData.StartupLocality
+ digest := make(tpm2.Digest, alg.Size())
+ digest[alg.Size()-1] = results.StartupLocality
+ results.Lookup(0).setInitialValue(digest)
+ default:
+ // Invalid startup locality value
+ results.Lookup(0).setErr(fmt.Errorf("invalid StartupLocality value %d - "+
+ "TPM2_Startup is only permitted from locality 0 or 3, "+
+ "or PCR0 can be initialized from locality 4 by a H-CRTM event before TPM2_Startup is called", startupLocalityData.StartupLocality))
+ results.StartupLocality = 0
+ }
+ continue
+ }
+
+ // XXX: The TGC PC-Client PFP spec v1.06 is a bit vague wrt EV_S_CRTM_CONTENTS and EV_S_CRTM_VERSION events when there was a H-CRTM
+ // event sequence. Table 27 says that EV_S_CRTM_CONTENTS and EV_S_CRTM_VERSION events are always measured, but the guidelines for
+ // measuring to PCR0 separately say:
+ // - If an H-CRTM measured the SRTM version, log the SRTM version identifier measurement using an EV_S_CRTM_VERSION event.
+ // - If an H-CRTM measured the SRTM contents, log the SRTM contents measurement(s) using an EV_S_CRTM_CONTENTS event.
+ // ... which suggests that these events are added to the log just to provide information, like EV_NO_ACTION events, in order
+ // to accompany the EV_EFI_HCRTM_EVENT events from which would contain the actual measured digests.
+ //
+ // I don't know what this looks like in practise because I've never come across a device that uses H-CRTM event sequences, so
+ // we'll just not do anything special here for now. If this is wrong, we'll probably mis-predict values for PCR0, but we can
+ // fix this up if/when we come across this sequence in the wild (and perhaps this is unlikely, which might be why this is so
+ // poorly and inconsistently defined).
+
+ // This is a TCG defined event that is measured, so perform a hash extend
+ if err := results.extend(ev.PCRIndex, ev.Digests[alg]); err != nil {
+ // This should only return an error if the spec ID event at the start
+ // of the log specifies the wrong size for the algorithm, in which case
+ // all events will be wrong. Best to just bail here rather than set an
+ // error on just this PCR.
+ return nil, fmt.Errorf("cannot perform extend with event %d from PCR %d: %w", i, ev.PCRIndex, err)
+ }
+ }
+
+ // Read the actual PCR values from the TPM.
+ pcrs := tpm2.PCRSelectionList{{Hash: alg, Select: []int{0, 1, 2, 3, 4, 5, 6, 7}}}
+ _, values, err := tpm.PCRRead(pcrs)
+ if err != nil {
+ return nil, err
+ }
+
+ // Record these values on the results
+ if err := results.setPcrValues(values); err != nil {
+ return nil, fmt.Errorf("cannot process PCR values from TPM: %w", err)
+ }
+
+ return results, nil
+}
+
+// checkFirmwareLogAndChoosePCRBank verifies that the firmware TCG log is in crypto-agile form and
+// consistent with at least one supported PCR bank when reconstructed for the TCG defined PCRs (0-7). It
+// also ensures that:
+// - the TCG defined PCRs contain a EV_SEPARATOR event between the pre-OS and OS-present environment (
+// although the one in PCR7 separates secure boot policy from secure boot authentication).
+// - that none of the EV_SEPARATORs in the TCG defined PCRs indicated that an error occurred.
+// - there are no pre-OS measurements to non-TCG defined PCRs (8-).
+//
+// This won't return an error for failures in TCG defined PCRs if they aren't part of the specified mandatory
+// PCRs set, but the errors will be accessible on the returned results struct.
+//
+// The returned results struct indicates the best PCR bank to use and specifies the TPM startup locality as well.
+func checkFirmwareLogAndChoosePCRBank(tpm *tpm2.TPMContext, log *tcglog.Log, mandatoryPcrs tpm2.HandleList) (results *pcrBankResults, err error) {
+ // Make sure it's a crypto-agile log
+ if !log.Spec.IsEFI_2() {
+ return nil, errors.New("invalid log spec")
+ }
+
+ // Chose the best PCR bank, ordered from SHA-512, SHA-384 to SHA-256. We're most
+ // likely to get SHA-256 here - it's only in very recent devices that we have TPMs with
+ // SHA-384 support and corresponding firmware integration.
+ // We try to keep all errors enountered during selection here.
+ mainErr := new(NoSuitablePCRAlgorithmError)
+ var chosenResults *pcrBankResults
+ for _, alg := range supportedAlgs {
+ if chosenResults != nil {
+ // We've already got a good PCR bank, so no need to carry on.
+ break
+ }
+
+ results, err := checkFirmwareLogAgainstTPMForAlg(tpm, log, alg, mandatoryPcrs)
+ switch {
+ case err != nil:
+ // This entire bank is bad
+ mainErr.setBankErr(alg, err)
+ case results.Ok():
+ // This is a good PCR bank
+ chosenResults = results
+ default:
+ // This isn't a good PCR bank because some mandatory PCRs
+ // failed. Record the individual PCR errors.
+ mainErr.setPcrErrs(results)
+ }
+ }
+
+ if chosenResults == nil {
+ // No suitable PCR bank was found, so return an error that's hopefully useful :(
+ return nil, mainErr
+ }
+
+ // Make sure we have EV_SEPARATORS for PCRs 0-7 and that no events are measured from the pre-OS
+ // environment to PCR8 and beyond
+ var seen int
+ for _, ev := range log.Events {
+ if !internal_efi.IsTCGDefinedPCR(ev.PCRIndex) {
+ return nil, fmt.Errorf("measurements were made by firmware from pre-OS environment to non-TCG defined PCR %d", ev.PCRIndex)
+ }
+ if ev.EventType != tcglog.EventTypeSeparator {
+ continue
+ }
+ seen += 1 // we've seen another separator
+ data, ok := ev.Data.(*tcglog.SeparatorEventData)
+ if !ok {
+ // if it failed to decode then it's guaranteed to implement the error interface.
+ return nil, fmt.Errorf("invalid event data for separator in PCR %d: %w", ev.PCRIndex, ev.Data.(error))
+ }
+ if data.IsError() {
+ // The EV_SEPARATOR event indicates that an error occurred.
+ return nil, fmt.Errorf("error separator for PCR %d (error code in log: %d)", ev.PCRIndex, binary.LittleEndian.Uint32(data.Bytes()))
+ }
+ if seen >= 8 {
+ // we've seen separators for all TCG defined PCRs, so this is the point of the pre-OS to OS-present
+ // transition. None of the separators indicated an error occurred and there were no measurement from
+ // the pre-OS environment to PCRs 8-.
+ break
+ }
+ }
+
+ if seen != 8 {
+ return nil, errors.New("reached the end of the log without seeing EV_SEPARATOR events in all TCG defined PCRs")
+ }
+
+ // At this point, we've selected a PCR bank where the TCG log is consistent with the PCR values for
+ // mandatory PCRs, and the log is generally in good order, although there are more detailed PCR-specific
+ // tests to perform later on as well.
+ return chosenResults, nil
+}
diff --git a/efi/preinstall/check_tcglog_test.go b/efi/preinstall/check_tcglog_test.go
new file mode 100644
index 00000000..b1118cd0
--- /dev/null
+++ b/efi/preinstall/check_tcglog_test.go
@@ -0,0 +1,729 @@
+// -*- 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 preinstall_test
+
+import (
+ "errors"
+ "io"
+
+ "github.com/canonical/go-tpm2"
+ tpm2_testutil "github.com/canonical/go-tpm2/testutil"
+ "github.com/canonical/tcglog-parser"
+ . "github.com/snapcore/secboot/efi/preinstall"
+ internal_efi "github.com/snapcore/secboot/internal/efi"
+ "github.com/snapcore/secboot/internal/efitest"
+ "github.com/snapcore/secboot/internal/testutil"
+ . "gopkg.in/check.v1"
+)
+
+type tcglogSuite struct {
+ tpm2_testutil.TPMSimulatorTest
+}
+
+var _ = Suite(&tcglogSuite{})
+
+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.
+ // Don't immediately call TPM2_Startup in case the log indicates we need to change localities.
+ started := false
+ for _, ev := range log.Events {
+ if ev.EventType == tcglog.EventTypeNoAction {
+ // EV_NO_ACTION events are informational and not measured
+ if startupLocalityData, isStartupLocality := ev.Data.(*tcglog.StartupLocalityEventData); isStartupLocality {
+ c.Assert(ev.PCRIndex, Equals, internal_efi.PlatformFirmwarePCR)
+ c.Assert(started, testutil.IsFalse)
+
+ switch startupLocalityData.StartupLocality {
+ case 0:
+ // do nothing
+ case 3:
+ s.Mssim(c).SetLocality(3)
+ c.Assert(s.TPM.Startup(tpm2.StartupClear), IsNil)
+ s.Mssim(c).SetLocality(0)
+ started = true
+ default:
+ c.Fatal("TPM2_Startup can only be called from localities 0 or 3")
+ }
+ }
+ continue
+ }
+
+ if !started {
+ // Our first actual measurement and we haven't called TPM2_Startup yet
+ c.Assert(s.TPM.Startup(tpm2.StartupClear), IsNil)
+ started = true
+ }
+
+ var digests tpm2.TaggedHashList
+ for _, alg := range algs {
+ digest, ok := ev.Digests[alg]
+ 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)
+ }
+}
+
+func (s *tcglogSuite) allocatePCRBanks(c *C, algs ...tpm2.HashAlgorithmId) {
+ current, err := s.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}
+
+ // Iterate over the returned PCR selections first
+ for i, selection := range current {
+ found := false
+ for _, alg := range algs {
+ if selection.Hash == alg {
+ found = true // An algorithm we want to enable already appears in the TPML_PCR_SELECTION
+ break
+ }
+ }
+ switch found {
+ case true:
+ // Enable this bank
+ current[i].Select = pcrs
+ case false:
+ current[i].Select = nil // Disable this bank by clearing the selection
+ }
+ }
+
+ // We might need to enable PCR banks by adding extra TPMS_PCR_SELECTION structures
+ for _, alg := range algs {
+ found := false
+ for _, selection := range current {
+ if selection.Hash == alg {
+ // We enabled this one earlier
+ found = true
+ break
+ }
+ }
+ if found {
+ continue
+ }
+ // We haven't enabled this one yet, so append a new TPMS_PCR_SELECTION
+ current = append(current, tpm2.PCRSelection{Hash: alg, Select: pcrs})
+ }
+
+ // Set the PCR allocation
+ success, _, _, _, err := s.TPM.PCRAllocate(s.TPM.PlatformHandleContext(), current, nil)
+ c.Assert(err, IsNil)
+ c.Assert(success, testutil.IsTrue)
+
+ s.ResetTPMSimulator(c)
+}
+
+type testCheckFirmwareLogAndChoosePCRBankParams struct {
+ enabledBanks []tpm2.HashAlgorithmId
+ logAlgs []tpm2.HashAlgorithmId
+ startupLocality uint8
+ replayAlgs []tpm2.HashAlgorithmId
+ mandatoryPcrs tpm2.HandleList
+
+ expectedAlg tpm2.HashAlgorithmId
+}
+
+func (s *tcglogSuite) testCheckFirmwareLogAndChoosePCRBank(c *C, params *testCheckFirmwareLogAndChoosePCRBankParams) {
+ s.allocatePCRBanks(c, params.enabledBanks...)
+
+ log := efitest.NewLog(c, &efitest.LogOptions{
+ Algorithms: params.logAlgs,
+ StartupLocality: params.startupLocality,
+ })
+ s.resetTPMAndReplayLog(c, log, params.replayAlgs...)
+ result, err := CheckFirmwareLogAndChoosePCRBank(s.TPM, log, params.mandatoryPcrs)
+ c.Assert(err, IsNil)
+ c.Check(result.Alg, Equals, params.expectedAlg)
+ c.Check(result.StartupLocality, Equals, params.startupLocality)
+}
+
+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.PlatformFirmwareConfigPCR,
+ internal_efi.DriversAndAppsPCR,
+ internal_efi.DriversAndAppsConfigPCR,
+ internal_efi.BootManagerCodePCR,
+ internal_efi.BootManagerCodeConfigPCR,
+ internal_efi.PlatformManufacturerPCR,
+ internal_efi.SecureBootPolicyPCR,
+ },
+ expectedAlg: tpm2.HashAlgorithmSHA256,
+ })
+}
+
+func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankSHA384(c *C) {
+ s.RequireAlgorithm(c, tpm2.AlgorithmSHA384)
+ 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.PlatformFirmwareConfigPCR,
+ internal_efi.DriversAndAppsPCR,
+ internal_efi.DriversAndAppsConfigPCR,
+ internal_efi.BootManagerCodePCR,
+ internal_efi.BootManagerCodeConfigPCR,
+ internal_efi.PlatformManufacturerPCR,
+ internal_efi.SecureBootPolicyPCR,
+ },
+ expectedAlg: tpm2.HashAlgorithmSHA384,
+ })
+}
+
+func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankSHA512(c *C) {
+ s.RequireAlgorithm(c, tpm2.AlgorithmSHA512)
+ 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.PlatformFirmwareConfigPCR,
+ internal_efi.DriversAndAppsPCR,
+ internal_efi.DriversAndAppsConfigPCR,
+ internal_efi.BootManagerCodePCR,
+ internal_efi.BootManagerCodeConfigPCR,
+ internal_efi.PlatformManufacturerPCR,
+ internal_efi.SecureBootPolicyPCR,
+ },
+ expectedAlg: tpm2.HashAlgorithmSHA512,
+ })
+}
+
+func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankMultipleSHA384(c *C) {
+ s.RequireAlgorithm(c, tpm2.AlgorithmSHA384)
+ 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.PlatformFirmwareConfigPCR,
+ internal_efi.DriversAndAppsPCR,
+ internal_efi.DriversAndAppsConfigPCR,
+ internal_efi.BootManagerCodePCR,
+ internal_efi.BootManagerCodeConfigPCR,
+ internal_efi.PlatformManufacturerPCR,
+ internal_efi.SecureBootPolicyPCR,
+ },
+ expectedAlg: tpm2.HashAlgorithmSHA384,
+ })
+}
+
+func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankSHA256WithEmptySHA384Bank(c *C) {
+ s.RequireAlgorithm(c, tpm2.AlgorithmSHA384)
+ 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.PlatformFirmwareConfigPCR,
+ internal_efi.DriversAndAppsPCR,
+ internal_efi.DriversAndAppsConfigPCR,
+ internal_efi.BootManagerCodePCR,
+ internal_efi.BootManagerCodeConfigPCR,
+ internal_efi.PlatformManufacturerPCR,
+ internal_efi.SecureBootPolicyPCR,
+ },
+ expectedAlg: tpm2.HashAlgorithmSHA256,
+ })
+}
+
+func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankSHA256StartupLocality3(c *C) {
+ s.testCheckFirmwareLogAndChoosePCRBank(c, &testCheckFirmwareLogAndChoosePCRBankParams{
+ 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.PlatformFirmwareConfigPCR,
+ internal_efi.DriversAndAppsPCR,
+ internal_efi.DriversAndAppsConfigPCR,
+ internal_efi.BootManagerCodePCR,
+ internal_efi.BootManagerCodeConfigPCR,
+ internal_efi.PlatformManufacturerPCR,
+ internal_efi.SecureBootPolicyPCR,
+ },
+ expectedAlg: tpm2.HashAlgorithmSHA256,
+ })
+}
+
+// TODO(chrisccoulson): github.com/canonical/go-tpm2/mssim needs support for sending H-CRTM
+// event sequences to the simulator in order to run this test, which is relatively non-trivial
+// to add - see https://github.com/canonical/go-tpm2/issues/18
+//func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankSHA256WithHCRTM(c *C) {
+// s.testCheckFirmwareLogAndChoosePCRBank(c, &testCheckFirmwareLogAndChoosePCRBankParams{
+// 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.PlatformFirmwareConfigPCR,
+// internal_efi.DriversAndAppsPCR,
+// internal_efi.DriversAndAppsConfigPCR,
+// internal_efi.BootManagerCodePCR,
+// internal_efi.BootManagerCodeConfigPCR,
+// internal_efi.PlatformManufacturerPCR,
+// internal_efi.SecureBootPolicyPCR,
+// },
+// expectedAlg: tpm2.HashAlgorithmSHA256,
+// })
+//}
+
+func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankMultipleSHA384StartupLocality3(c *C) {
+ s.RequireAlgorithm(c, tpm2.AlgorithmSHA384)
+ s.testCheckFirmwareLogAndChoosePCRBank(c, &testCheckFirmwareLogAndChoosePCRBankParams{
+ 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.PlatformFirmwareConfigPCR,
+ internal_efi.DriversAndAppsPCR,
+ internal_efi.DriversAndAppsConfigPCR,
+ internal_efi.BootManagerCodePCR,
+ internal_efi.BootManagerCodeConfigPCR,
+ internal_efi.PlatformManufacturerPCR,
+ internal_efi.SecureBootPolicyPCR,
+ },
+ expectedAlg: tpm2.HashAlgorithmSHA384,
+ })
+}
+
+func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankUnexpectedStartupLocality(c *C) {
+ s.allocatePCRBanks(c, tpm2.HashAlgorithmSHA256)
+
+ log := efitest.NewLog(c, &efitest.LogOptions{
+ Algorithms: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256},
+ StartupLocality: 3,
+ })
+ s.resetTPMAndReplayLog(c, log, tpm2.HashAlgorithmSHA256)
+
+ // Move the startup locality event to PCR 1
+
+ events := log.Events
+ for len(events) > 0 {
+ ev := events[0]
+ events = events[1:]
+
+ if ev.PCRIndex != internal_efi.PlatformFirmwarePCR {
+ continue
+ }
+ if ev.EventType != tcglog.EventTypeNoAction {
+ continue
+ }
+ if _, isStartupLocality := ev.Data.(*tcglog.StartupLocalityEventData); !isStartupLocality {
+ continue
+ }
+
+ ev.PCRIndex = internal_efi.PlatformFirmwareConfigPCR
+ break
+ }
+
+ _, err := CheckFirmwareLogAndChoosePCRBank(s.TPM, log, tpm2.HandleList{
+ internal_efi.PlatformFirmwarePCR,
+ })
+ c.Check(err, ErrorMatches, `no suitable PCR algorithm available:
+- TPM_ALG_SHA512: digest algorithm not present in log.
+- TPM_ALG_SHA384: digest algorithm not present in log.
+- TPM_ALG_SHA256\(PCR0\): PCR value mismatch \(actual from TPM 0xb0d6d5f50852be1524306ad88b928605c14338e56a1b8c0dc211a144524df2ef, reconstructed from log 0xa6602a7a403068b5556e78cc3f5b00c9c76d33d514093ca9b584dce7590e6c69\).
+- TPM_ALG_SHA256\(PCR1\): unexpected StartupLocality event \(should be in PCR0\).
+`)
+ var e *NoSuitablePCRAlgorithmError
+ c.Check(errors.As(err, &e), testutil.IsTrue)
+
+ // Test that we can access individual errors.
+ c.Check(e.UnwrapBankError(tpm2.HashAlgorithmSHA512), ErrorMatches, `digest algorithm not present in log`)
+ c.Check(e.UnwrapBankError(tpm2.HashAlgorithmSHA384), ErrorMatches, `digest algorithm not present in log`)
+ c.Check(e.UnwrapPCRError(tpm2.HashAlgorithmSHA384, internal_efi.PlatformFirmwarePCR), IsNil)
+ c.Check(e.UnwrapBankError(tpm2.HashAlgorithmSHA256), IsNil)
+ c.Check(e.UnwrapPCRError(tpm2.HashAlgorithmSHA256, internal_efi.PlatformFirmwarePCR), ErrorMatches, `PCR value mismatch \(actual from TPM 0xb0d6d5f50852be1524306ad88b928605c14338e56a1b8c0dc211a144524df2ef, reconstructed from log 0xa6602a7a403068b5556e78cc3f5b00c9c76d33d514093ca9b584dce7590e6c69\)`)
+ c.Check(e.UnwrapPCRError(tpm2.HashAlgorithmSHA256, internal_efi.PlatformFirmwareConfigPCR), ErrorMatches, `unexpected StartupLocality event \(should be in PCR0\)`)
+ c.Check(e.UnwrapPCRError(tpm2.HashAlgorithmSHA256, internal_efi.DriversAndAppsPCR), IsNil)
+}
+
+func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankOutOfPlaceStartupLocality(c *C) {
+ s.allocatePCRBanks(c, tpm2.HashAlgorithmSHA256)
+
+ log := efitest.NewLog(c, &efitest.LogOptions{
+ Algorithms: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256},
+ StartupLocality: 3,
+ })
+ s.resetTPMAndReplayLog(c, log, tpm2.HashAlgorithmSHA256)
+
+ // Move the startup locality event after the first EV_NO_ACTION event in PCR 0
+ var slEvent *tcglog.Event // the startup locality event
+ events := log.Events // the current events
+ var eventsCopy []*tcglog.Event // a copy of the events
+
+ // Find the startup locality event, omitting it from the copy of events
+ for len(events) > 0 {
+ ev := events[0]
+ events = events[1:]
+ eventsCopy = append(eventsCopy, ev)
+
+ if ev.PCRIndex != internal_efi.PlatformFirmwarePCR {
+ continue
+ }
+ if ev.EventType != tcglog.EventTypeNoAction {
+ continue
+ }
+ if _, isStartupLocality := ev.Data.(*tcglog.StartupLocalityEventData); !isStartupLocality {
+ continue
+ }
+
+ slEvent = ev
+ eventsCopy = eventsCopy[:len(eventsCopy)-1] // truncate the copy of events by 1
+ break
+ }
+
+ c.Assert(slEvent, NotNil)
+
+ // Find the first non EV_NO_ACTION event in PCR 0 and move the startup locality event after it
+ for len(events) > 0 {
+ ev := events[0]
+ events = events[1:]
+ eventsCopy = append(eventsCopy, ev)
+
+ if ev.PCRIndex == internal_efi.PlatformFirmwarePCR &&
+ ev.EventType != tcglog.EventTypeNoAction && slEvent != nil {
+ eventsCopy = append(eventsCopy, slEvent)
+ slEvent = nil
+ }
+ }
+
+ // Swap the log over
+ log.Events = eventsCopy
+
+ _, err := CheckFirmwareLogAndChoosePCRBank(s.TPM, log, tpm2.HandleList{
+ internal_efi.PlatformFirmwarePCR,
+ })
+ c.Check(err, ErrorMatches, `no suitable PCR algorithm available:
+- TPM_ALG_SHA512: digest algorithm not present in log.
+- TPM_ALG_SHA384: digest algorithm not present in log.
+- TPM_ALG_SHA256\(PCR0\): unexpected StartupLocality event after measurements already made.
+`)
+ var e *NoSuitablePCRAlgorithmError
+ c.Check(errors.As(err, &e), testutil.IsTrue)
+}
+
+func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankInvalidStartupLocality(c *C) {
+ s.allocatePCRBanks(c, tpm2.HashAlgorithmSHA256)
+
+ log := efitest.NewLog(c, &efitest.LogOptions{
+ Algorithms: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256},
+ StartupLocality: 3,
+ })
+ s.resetTPMAndReplayLog(c, log, tpm2.HashAlgorithmSHA256)
+
+ // Change the startup locality to 2
+
+ events := log.Events
+ for len(events) > 0 {
+ ev := events[0]
+ events = events[1:]
+
+ if ev.PCRIndex != internal_efi.PlatformFirmwarePCR {
+ continue
+ }
+ if ev.EventType != tcglog.EventTypeNoAction {
+ continue
+ }
+ if _, isStartupLocality := ev.Data.(*tcglog.StartupLocalityEventData); !isStartupLocality {
+ continue
+ }
+
+ ev.Data = &tcglog.StartupLocalityEventData{StartupLocality: 2}
+ break
+ }
+
+ _, err := CheckFirmwareLogAndChoosePCRBank(s.TPM, log, tpm2.HandleList{
+ internal_efi.PlatformFirmwarePCR,
+ })
+ c.Check(err, ErrorMatches, `no suitable PCR algorithm available:
+- TPM_ALG_SHA512: digest algorithm not present in log.
+- TPM_ALG_SHA384: digest algorithm not present in log.
+- TPM_ALG_SHA256\(PCR0\): invalid StartupLocality value 2 - TPM2_Startup is only permitted from locality 0 or 3, or PCR0 can be initialized from locality 4 by a H-CRTM event before TPM2_Startup is called.
+`)
+ var e *NoSuitablePCRAlgorithmError
+ c.Check(errors.As(err, &e), testutil.IsTrue)
+}
+
+func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankPCRMismatchMandatory(c *C) {
+ s.allocatePCRBanks(c, tpm2.HashAlgorithmSHA256)
+
+ log := efitest.NewLog(c, &efitest.LogOptions{
+ Algorithms: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256},
+ StartupLocality: 3,
+ })
+ s.resetTPMAndReplayLog(c, log, tpm2.HashAlgorithmSHA256)
+
+ // This will make the PCR 0 calculation wrong
+ log = efitest.NewLog(c, &efitest.LogOptions{
+ Algorithms: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256},
+ })
+ _, err := CheckFirmwareLogAndChoosePCRBank(s.TPM, log, tpm2.HandleList{
+ internal_efi.PlatformFirmwarePCR,
+ })
+ c.Check(err, ErrorMatches, `no suitable PCR algorithm available:
+- TPM_ALG_SHA512: digest algorithm not present in log.
+- TPM_ALG_SHA384: digest algorithm not present in log.
+- TPM_ALG_SHA256\(PCR0\): PCR value mismatch \(actual from TPM 0xb0d6d5f50852be1524306ad88b928605c14338e56a1b8c0dc211a144524df2ef, reconstructed from log 0xa6602a7a403068b5556e78cc3f5b00c9c76d33d514093ca9b584dce7590e6c69\).
+`)
+ var e *NoSuitablePCRAlgorithmError
+ c.Check(errors.As(err, &e), testutil.IsTrue)
+}
+
+func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankPCRMismatchNonMandatory(c *C) {
+ s.allocatePCRBanks(c, tpm2.HashAlgorithmSHA256)
+
+ log := efitest.NewLog(c, &efitest.LogOptions{
+ Algorithms: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256},
+ StartupLocality: 3,
+ })
+ s.resetTPMAndReplayLog(c, log, tpm2.HashAlgorithmSHA256)
+
+ // This will make the PCR 0 calculation wrong
+ log = efitest.NewLog(c, &efitest.LogOptions{
+ Algorithms: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256},
+ })
+ results, err := CheckFirmwareLogAndChoosePCRBank(s.TPM, log,
+ tpm2.HandleList{
+ internal_efi.PlatformFirmwareConfigPCR,
+ internal_efi.DriversAndAppsPCR,
+ internal_efi.DriversAndAppsConfigPCR,
+ internal_efi.BootManagerCodePCR,
+ internal_efi.BootManagerCodeConfigPCR,
+ internal_efi.PlatformManufacturerPCR,
+ internal_efi.SecureBootPolicyPCR,
+ },
+ )
+ c.Assert(err, IsNil)
+ c.Check(results.Alg, Equals, tpm2.HashAlgorithmSHA256)
+ c.Check(results.Ok(), Equals, true)
+ c.Check(results.Lookup(internal_efi.PlatformFirmwarePCR).Ok(), Equals, false)
+ c.Check(results.Lookup(internal_efi.PlatformFirmwarePCR).Err(), ErrorMatches, `PCR value mismatch \(actual from TPM 0xb0d6d5f50852be1524306ad88b928605c14338e56a1b8c0dc211a144524df2ef, reconstructed from log 0xa6602a7a403068b5556e78cc3f5b00c9c76d33d514093ca9b584dce7590e6c69\)`)
+}
+
+func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankPCRMismatchMandatoryInOneBank(c *C) {
+ s.RequireAlgorithm(c, tpm2.AlgorithmSHA384)
+ s.allocatePCRBanks(c, tpm2.HashAlgorithmSHA256, tpm2.HashAlgorithmSHA384)
+
+ log := efitest.NewLog(c, &efitest.LogOptions{
+ Algorithms: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256, tpm2.HashAlgorithmSHA384},
+ StartupLocality: 3,
+ })
+ s.resetTPMAndReplayLog(c, log, tpm2.HashAlgorithmSHA256, tpm2.HashAlgorithmSHA384)
+
+ for i, ev := range log.Events {
+ if ev.PCRIndex != internal_efi.BootManagerCodePCR {
+ continue
+ }
+ if ev.EventType == tcglog.EventTypeEFIAction {
+ log.Events[i].Digests[tpm2.HashAlgorithmSHA384] = make(tpm2.Digest, tpm2.HashAlgorithmSHA384.Size())
+ }
+ }
+
+ results, err := CheckFirmwareLogAndChoosePCRBank(s.TPM, log,
+ tpm2.HandleList{
+ internal_efi.PlatformFirmwarePCR,
+ internal_efi.PlatformFirmwareConfigPCR,
+ internal_efi.DriversAndAppsPCR,
+ internal_efi.DriversAndAppsConfigPCR,
+ internal_efi.BootManagerCodePCR,
+ internal_efi.BootManagerCodeConfigPCR,
+ internal_efi.PlatformManufacturerPCR,
+ internal_efi.SecureBootPolicyPCR,
+ },
+ )
+ c.Assert(err, IsNil)
+ c.Check(results.Alg, Equals, tpm2.HashAlgorithmSHA256)
+}
+
+func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankPCRMismatchNonMandatoryInOneBank(c *C) {
+ s.RequireAlgorithm(c, tpm2.AlgorithmSHA384)
+ s.allocatePCRBanks(c, tpm2.HashAlgorithmSHA256, tpm2.HashAlgorithmSHA384)
+
+ log := efitest.NewLog(c, &efitest.LogOptions{
+ Algorithms: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256, tpm2.HashAlgorithmSHA384},
+ StartupLocality: 3,
+ })
+ s.resetTPMAndReplayLog(c, log, tpm2.HashAlgorithmSHA256, tpm2.HashAlgorithmSHA384)
+
+ for i, ev := range log.Events {
+ if ev.PCRIndex != internal_efi.BootManagerCodePCR {
+ continue
+ }
+ if ev.EventType == tcglog.EventTypeEFIAction {
+ log.Events[i].Digests[tpm2.HashAlgorithmSHA384] = make(tpm2.Digest, tpm2.HashAlgorithmSHA384.Size())
+ }
+ }
+
+ results, err := CheckFirmwareLogAndChoosePCRBank(s.TPM, log,
+ tpm2.HandleList{
+ internal_efi.PlatformFirmwarePCR,
+ internal_efi.PlatformFirmwareConfigPCR,
+ internal_efi.DriversAndAppsPCR,
+ internal_efi.DriversAndAppsConfigPCR,
+ internal_efi.BootManagerCodeConfigPCR,
+ internal_efi.PlatformManufacturerPCR,
+ internal_efi.SecureBootPolicyPCR,
+ },
+ )
+ c.Assert(err, IsNil)
+ c.Check(results.Alg, Equals, tpm2.HashAlgorithmSHA384)
+}
+
+func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankBadSpec(c *C) {
+ log := efitest.NewLog(c, &efitest.LogOptions{
+ Algorithms: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256},
+ })
+ log.Spec = tcglog.Spec{
+ PlatformType: tcglog.PlatformTypeEFI,
+ Major: 1,
+ Minor: 2,
+ Errata: 0,
+ }
+ _, err := CheckFirmwareLogAndChoosePCRBank(s.TPM, log, nil)
+ c.Check(err, ErrorMatches, `invalid log spec`)
+}
+
+func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankPreOSMeasurementToNonTCGPCR(c *C) {
+ s.allocatePCRBanks(c, tpm2.HashAlgorithmSHA256)
+ log := efitest.NewLog(c, &efitest.LogOptions{
+ Algorithms: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256},
+ })
+
+ var eventsCopy []*tcglog.Event
+ events := log.Events
+ added := false
+ for len(events) > 0 {
+ ev := events[0]
+ events = events[1:]
+
+ if ev.PCRIndex >= internal_efi.PlatformFirmwarePCR && ev.PCRIndex <= internal_efi.PlatformManufacturerPCR && ev.EventType == tcglog.EventTypeSeparator && !added {
+ eventsCopy = append(eventsCopy, &tcglog.Event{
+ PCRIndex: 8,
+ EventType: tcglog.EventTypeEventTag,
+ Data: &tcglog.TaggedEvent{EventID: 10, Data: []byte{1, 2, 3, 4}},
+ Digests: tcglog.DigestMap{tpm2.HashAlgorithmSHA256: make([]byte, 32)},
+ })
+ added = true
+ }
+
+ eventsCopy = append(eventsCopy, ev)
+ }
+ log.Events = eventsCopy
+ s.resetTPMAndReplayLog(c, log, tpm2.HashAlgorithmSHA256)
+
+ _, err := CheckFirmwareLogAndChoosePCRBank(s.TPM, log, nil)
+ c.Check(err, ErrorMatches, `measurements were made by firmware from pre-OS environment to non-TCG defined PCR 8`)
+}
+
+type invalidEventData struct {
+ err error
+}
+
+func (e *invalidEventData) String() string { return "invalid event data: " + e.err.Error() }
+func (*invalidEventData) Bytes() []byte { return nil }
+func (*invalidEventData) Write(w io.Writer) error { return errors.New("not supported") }
+func (e *invalidEventData) Error() string { return e.err.Error() }
+
+func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankSeparatorDecodeError(c *C) {
+ s.allocatePCRBanks(c, tpm2.HashAlgorithmSHA256)
+ log := efitest.NewLog(c, &efitest.LogOptions{
+ Algorithms: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256},
+ })
+ events := log.Events
+ for len(events) > 0 {
+ ev := events[0]
+ events = events[1:]
+
+ if ev.EventType != tcglog.EventTypeSeparator {
+ continue
+ }
+
+ ev.Data = &invalidEventData{errors.New("some error")}
+ break
+ }
+ s.resetTPMAndReplayLog(c, log, tpm2.HashAlgorithmSHA256)
+
+ _, err := CheckFirmwareLogAndChoosePCRBank(s.TPM, log, nil)
+ c.Check(err, ErrorMatches, `invalid event data for separator in PCR 7: some error`)
+}
+
+func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankSeparatorError(c *C) {
+ s.allocatePCRBanks(c, tpm2.HashAlgorithmSHA256)
+ log := efitest.NewLog(c, &efitest.LogOptions{
+ Algorithms: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256},
+ })
+ events := log.Events
+ for len(events) > 0 {
+ ev := events[0]
+ events = events[1:]
+
+ if ev.EventType != tcglog.EventTypeSeparator {
+ continue
+ }
+
+ ev.Data = &tcglog.SeparatorEventData{Value: tcglog.SeparatorEventErrorValue, ErrorInfo: []byte{1, 2, 3, 4}}
+ break
+ }
+ s.resetTPMAndReplayLog(c, log, tpm2.HashAlgorithmSHA256)
+
+ _, err := CheckFirmwareLogAndChoosePCRBank(s.TPM, log, nil)
+ c.Check(err, ErrorMatches, `error separator for PCR 7 \(error code in log: 67305985\)`)
+}
+
+func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankMissingSeparators(c *C) {
+ s.allocatePCRBanks(c, tpm2.HashAlgorithmSHA256)
+ log := efitest.NewLog(c, &efitest.LogOptions{
+ Algorithms: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256},
+ })
+ var eventsCopy []*tcglog.Event
+ skippedOneSeparator := false
+ events := log.Events
+ for len(events) > 0 {
+ ev := events[0]
+ events = events[1:]
+
+ if ev.EventType != tcglog.EventTypeSeparator || skippedOneSeparator {
+ eventsCopy = append(eventsCopy, ev)
+ continue
+ }
+
+ skippedOneSeparator = true
+ }
+ log.Events = eventsCopy
+ s.resetTPMAndReplayLog(c, log, tpm2.HashAlgorithmSHA256)
+
+ _, err := CheckFirmwareLogAndChoosePCRBank(s.TPM, log, nil)
+ c.Check(err, ErrorMatches, `reached the end of the log without seeing EV_SEPARATOR events in all TCG defined PCRs`)
+}
diff --git a/efi/preinstall/export_test.go b/efi/preinstall/export_test.go
index 0b8b28fa..f0607077 100644
--- a/efi/preinstall/export_test.go
+++ b/efi/preinstall/export_test.go
@@ -45,6 +45,7 @@ const (
var (
CalculateIntelMEFamily = calculateIntelMEFamily
CheckCPUDebuggingLockedMSR = checkCPUDebuggingLockedMSR
+ CheckFirmwareLogAndChoosePCRBank = checkFirmwareLogAndChoosePCRBank
CheckForKernelIOMMU = checkForKernelIOMMU
CheckPlatformFirmwareProtections = checkPlatformFirmwareProtections
CheckPlatformFirmwareProtectionsIntelMEI = checkPlatformFirmwareProtectionsIntelMEI
diff --git a/internal/efi/tcg_pcrs.go b/internal/efi/tcg_pcrs.go
index 131ffa95..da2aa804 100644
--- a/internal/efi/tcg_pcrs.go
+++ b/internal/efi/tcg_pcrs.go
@@ -26,14 +26,28 @@ const (
PlatformFirmwarePCR tpm2.Handle = 0
// HostPlatformConfigPCR is the Host Platform Configuration PCR
- HostPlatformConfigPCR tpm2.Handle = 1
+ PlatformFirmwareConfigPCR tpm2.Handle = 1
// DriversAndAppsPCR is the UEFI Drivers and UEFI Applications PCR
DriversAndAppsPCR tpm2.Handle = 2
+ // DriversAndAppsConfigPCR is the UEFI driver and application Configuration and Data PCR
+ DriversAndAppsConfigPCR tpm2.Handle = 3
+
// BootManagerCodePCR is the Boot Manager Code and Boot Attempts PCR
BootManagerCodePCR tpm2.Handle = 4
+ // BootManagerCodeConfigPCR is the Boot Manager Code Configuration and Data
+ // (for use by the Boot Manager Code) and GPT/Partition Table PCR.
+ BootManagerCodeConfigPCR tpm2.Handle = 5
+
+ // PlatformManufacturerPCR is the Host Platform Manufacturer Specific PCR
+ PlatformManufacturerPCR tpm2.Handle = 6
+
// SecureBootPolicyPCR is the Secure Boot Policy Measurements PCR
SecureBootPolicyPCR tpm2.Handle = 7
)
+
+func IsTCGDefinedPCR(pcr tpm2.Handle) bool {
+ return pcr <= SecureBootPolicyPCR
+}
diff --git a/internal/efitest/log.go b/internal/efitest/log.go
index 66c6d66f..d58ce3f7 100644
--- a/internal/efitest/log.go
+++ b/internal/efitest/log.go
@@ -100,21 +100,21 @@ const (
type LogOptions struct {
Algorithms []tpm2.HashAlgorithmId // the digest algorithms to include
+ StartupLocality uint8 // specify a startup locality other than 0
FirmwareDebugger bool // indicate a firmware debugger endpoint is enabled
DMAProtectionDisabled DMAProtectionDisabledEventType // whether DMA protection is disabled
- SecureBootDisabled bool
- IncludeDriverLaunch bool // include a driver launch in the log
- IncludeSysPrepAppLaunch bool // include a system-preparation app launch in the log
- IncludeOSPresentFirmwareAppLaunch efi.GUID // include a flash based application launch in the log as part of the OS-present phase
- NoCallingEFIApplicationEvent bool // omit the EV_EFI_ACTION "Calling EFI Application from Boot Option" event.
- NoSBAT bool // omit the SbatLevel measurement.
- StartupLocality uint8 // specify a startup locality other than 0
+ SecureBootDisabled bool // Whether secure boot is disabled
+ IncludeDriverLaunch bool // include a driver launch from a PCI device in the log
+ IncludeSysPrepAppLaunch bool // include a system-preparation app launch in the log
+ NoCallingEFIApplicationEvent bool // omit the EV_EFI_ACTION "Calling EFI Application from Boot Option" event.
+ IncludeOSPresentFirmwareAppLaunch efi.GUID // include a flash based application launch in the log as part of the OS-present phase
+ NoSBAT bool // omit the SbatLevel measurement to mimic older versions of shim
}
// NewLog creates a mock TCG log for testing. The log will look like a standard
// Linux boot (shim -> grub -> kernel) and uses hard-coded values for signature
-// databases and launch digests. The supplied options argument can be used for
-// minimal customization.
+// databases (Microsoft UEFI CA 2011 configuration, and launch digests. The
+// supplied options argument can be used for minimal customization.
func NewLog(c *C, opts *LogOptions) *tcglog.Log {
builder := &logBuilder{algs: opts.Algorithms}
@@ -139,6 +139,7 @@ func NewLog(c *C, opts *LogOptions) *tcglog.Log {
},
},
}
+
if opts.StartupLocality > 0 {
ev := &tcglog.Event{
PCRIndex: 0,
@@ -153,32 +154,67 @@ func NewLog(c *C, opts *LogOptions) *tcglog.Log {
}
// Mock S-CRTM measurements
- {
- data := tcglog.StringEventData("1.0")
- builder.hashLogExtendEvent(c, data, &logEvent{
+ if opts.StartupLocality == 4 {
+ ev := &tcglog.Event{
+ PCRIndex: 0,
+ EventType: tcglog.EventTypeNoAction,
+ Digests: make(tcglog.DigestMap),
+ Data: &tcglog.HCRTMComponentEventData{
+ ComponentDescription: "S-CRTM contents",
+ MeasurementFormatType: tcglog.HCRTMMeasurementFormatRawData,
+ ComponentMeasurement: []byte("mock S-CRTM contents"),
+ },
+ }
+ for _, alg := range opts.Algorithms {
+ ev.Digests[alg] = make(tpm2.Digest, alg.Size())
+ }
+ builder.events = append(builder.events, ev)
+
+ blob := bytesHashData("mock S-CRTM contents")
+ builder.hashLogExtendEvent(c, blob, &logEvent{
pcrIndex: 0,
- eventType: tcglog.EventTypeSCRTMVersion,
- data: data})
+ eventType: tcglog.EventTypeEFIHCRTMEvent,
+ data: tcglog.StringEventData("HCRTM")})
+ } else {
+ {
+ blob := bytesHashData("mock S-CRTM contents")
+ data := &tcglog.EFIPlatformFirmwareBlob{
+ BlobBase: 0xff000000,
+ BlobLength: 25431}
+ builder.hashLogExtendEvent(c, blob, &logEvent{
+ pcrIndex: 0,
+ eventType: tcglog.EventTypeSCRTMContents,
+ data: data})
+ }
+ {
+ data := tcglog.GUIDEventData(efi.MakeGUID(0x8beb77ea, 0x5c75, 0x4d08, 0x8e2b, [...]byte{0x96, 0x34, 0x86, 0xda, 0xe7, 0xf7}))
+ builder.hashLogExtendEvent(c, data, &logEvent{
+ pcrIndex: 0,
+ eventType: tcglog.EventTypeSCRTMVersion,
+ data: data})
+ }
}
{
blob := bytesHashData("mock platform firmware blob 1")
- var data [16]byte
- binary.LittleEndian.PutUint64(data[0:], 0x820000)
- binary.LittleEndian.PutUint64(data[8:], 0xe0000)
+ data := &tcglog.EFIPlatformFirmwareBlob{
+ BlobBase: 0xffc00000,
+ BlobLength: 0xe0000,
+ }
builder.hashLogExtendEvent(c, blob, &logEvent{
pcrIndex: 0,
eventType: tcglog.EventTypeEFIPlatformFirmwareBlob,
- data: tcglog.OpaqueEventData(data[:])})
+ data: data})
}
{
blob := bytesHashData("mock platform firmware blob 2")
- var data [16]byte
- binary.LittleEndian.PutUint64(data[0:], 0x900000)
- binary.LittleEndian.PutUint64(data[8:], 0xc00000)
+ data := &tcglog.EFIPlatformFirmwareBlob{
+ BlobBase: 0xffce0000,
+ BlobLength: 0xc00000,
+ }
builder.hashLogExtendEvent(c, blob, &logEvent{
pcrIndex: 0,
eventType: tcglog.EventTypeEFIPlatformFirmwareBlob,
- data: tcglog.OpaqueEventData(data[:])})
+ data: data})
}
sbVal := []byte{0x01}
@@ -279,8 +315,22 @@ func NewLog(c *C, opts *LogOptions) *tcglog.Log {
LocationInMemory: 0x41a2f024,
LengthInMemory: 659024,
DevicePath: efi.DevicePath{
- efi.MediaFvDevicePathNode(efi.MakeGUID(0x9b56c9db, 0x1936, 0x44a9, 0x9ed4, [...]uint8{0xb9, 0x2a, 0xef, 0xfc, 0xbb, 0x66})),
- efi.MediaFvFileDevicePathNode(efi.MakeGUID(0x15c7a296, 0xb470, 0x4b31, 0x8314, [...]uint8{0x7f, 0x6e, 0x56, 0x14, 0x37, 0xe5}))}}
+ &efi.ACPIDevicePathNode{
+ HID: 0x0a0341d0,
+ UID: 0x0,
+ },
+ &efi.PCIDevicePathNode{
+ Function: 0x1c,
+ Device: 0x2,
+ },
+ &efi.PCIDevicePathNode{
+ Function: 0x0,
+ Device: 0x0,
+ },
+ &efi.MediaRelOffsetRangeDevicePathNode{
+ StartingOffset: 0x38,
+ EndingOffset: 0x11dff,
+ }}}
builder.hashLogExtendEvent(c, pe, &logEvent{
pcrIndex: 2,
eventType: tcglog.EventTypeEFIBootServicesDriver,