From e49aa0cea845264b383937b6ed4a6e7f5925e42a Mon Sep 17 00:00:00 2001 From: Chris Coulson Date: Wed, 13 Nov 2024 17:34:08 +0000 Subject: [PATCH] preinstall: Add explicit checks for empty PCR banks Whilst this has no consequence for FDE because we seal against a good bank, it breaks measured boot as required by remove verifiers, as an empty PCR bank provides a means for an adversary to spoof any host platform of their choosing. We reject systems with empty PCR banks by default, but with an opt-in to permit it. --- efi/preinstall/check_tcglog.go | 32 ++- efi/preinstall/check_tcglog_test.go | 156 ++++++++++--- efi/preinstall/checks.go | 16 +- efi/preinstall/checks_test.go | 325 +++++++++++++++++----------- efi/preinstall/errors.go | 98 ++++----- efi/preinstall/result.go | 9 +- 6 files changed, 416 insertions(+), 220 deletions(-) diff --git a/efi/preinstall/check_tcglog.go b/efi/preinstall/check_tcglog.go index 70c8b1b6..a4106e10 100644 --- a/efi/preinstall/check_tcglog.go +++ b/efi/preinstall/check_tcglog.go @@ -84,11 +84,14 @@ func (r *pcrResults) Err() error { } if !r.extended() { // Return an error if the PCR hasn't been extended. + // This generally shouldn't happen because there should at + // least be a EV_SEPARATOR event, and if there isn't one, we + // trigger errors elsewhere related to the structure of the log. 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 &PCRValueMismatchError{PCRValue: r.pcrValue, LogValue: r.logValue} } return nil } @@ -257,8 +260,7 @@ func checkFirmwareLogAgainstTPMForAlg(tpm *tpm2.TPMContext, log *tcglog.Log, alg break } if !supported { - // The log doesn't contain the specified algorithm - return nil, errors.New("digest algorithm not present in log") + return nil, ErrPCRBankMissingFromLog } // Create the result tracker for PCRs 0-7 @@ -576,7 +578,7 @@ func (t *tcglogPhaseTracker) reachedOSPresent() bool { // 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) { +func checkFirmwareLogAndChoosePCRBank(tpm *tpm2.TPMContext, log *tcglog.Log, mandatoryPcrs tpm2.HandleList, permitEmptyPCRBanks bool) (results *pcrBankResults, err error) { // Make sure it's a crypto-agile log if !log.Spec.IsEFI_2() { return nil, errors.New("invalid log spec") @@ -586,7 +588,10 @@ func checkFirmwareLogAndChoosePCRBank(tpm *tpm2.TPMContext, log *tcglog.Log, man // 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) + mainErr := &NoSuitablePCRAlgorithmError{ + BankErrs: make(map[tpm2.HashAlgorithmId]error), + PCRErrs: make(map[tpm2.HashAlgorithmId]map[tpm2.Handle]error), + } var chosenResults *pcrBankResults for _, alg := range supportedAlgs { if chosenResults != nil { @@ -596,6 +601,23 @@ func checkFirmwareLogAndChoosePCRBank(tpm *tpm2.TPMContext, log *tcglog.Log, man results, err := checkFirmwareLogAgainstTPMForAlg(tpm, log, alg, mandatoryPcrs) switch { + case errors.Is(err, ErrPCRBankMissingFromLog): + if !permitEmptyPCRBanks { + // Make sure that the TPM PCR bank is not enabled + pcrs, err := tpm.GetCapabilityPCRs() + if err != nil { + return nil, fmt.Errorf("cannot obtain active PCRs: %w", err) + } + for _, selection := range pcrs { + if selection.Hash == alg && len(selection.Select) > 0 { + // This bank is missing from the log but enabled on the TPM. + // This is very bad for remote attestation (not so bad for FDE), but treat + // this as a serious error nonetheless. + return nil, &EmptyPCRBankError{alg} + } + } + } + fallthrough case err != nil: // This entire bank is bad mainErr.setBankErr(alg, err) diff --git a/efi/preinstall/check_tcglog_test.go b/efi/preinstall/check_tcglog_test.go index 3447fb3f..fe54a6f9 100644 --- a/efi/preinstall/check_tcglog_test.go +++ b/efi/preinstall/check_tcglog_test.go @@ -176,6 +176,7 @@ type testCheckFirmwareLogAndChoosePCRBankParams struct { startupLocality uint8 disallowPreOSVerification bool mandatoryPcrs tpm2.HandleList + permitEmptyPCRBanks bool expectedAlg tpm2.HashAlgorithmId } @@ -189,7 +190,7 @@ func (s *tcglogSuite) testCheckFirmwareLogAndChoosePCRBank(c *C, params *testChe DisallowPreOSVerification: params.disallowPreOSVerification, }) s.resetTPMAndReplayLog(c, log, params.logAlgs...) - result, err := CheckFirmwareLogAndChoosePCRBank(s.TPM, log, params.mandatoryPcrs) + result, err := CheckFirmwareLogAndChoosePCRBank(s.TPM, log, params.mandatoryPcrs, params.permitEmptyPCRBanks) c.Assert(err, IsNil) c.Check(result.Alg, Equals, params.expectedAlg) c.Check(result.StartupLocality, Equals, params.startupLocality) @@ -285,7 +286,8 @@ func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankSHA256WithEmptySHA384B internal_efi.PlatformManufacturerPCR, internal_efi.SecureBootPolicyPCR, }, - expectedAlg: tpm2.HashAlgorithmSHA256, + permitEmptyPCRBanks: true, + expectedAlg: tpm2.HashAlgorithmSHA256, }) } @@ -405,10 +407,10 @@ func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankUnexpectedStartupLocal _, err := CheckFirmwareLogAndChoosePCRBank(s.TPM, log, tpm2.HandleList{ internal_efi.PlatformFirmwarePCR, - }) + }, false) 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_SHA512: the PCR bank is missing from the TCG log. +- TPM_ALG_SHA384: the PCR bank is missing from the TCG 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\). `) @@ -416,13 +418,16 @@ func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankUnexpectedStartupLocal 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.PlatformConfigPCR), ErrorMatches, `unexpected StartupLocality event \(should be in PCR0\)`) - c.Check(e.UnwrapPCRError(tpm2.HashAlgorithmSHA256, internal_efi.DriversAndAppsPCR), IsNil) + c.Check(e.BankErrs[tpm2.HashAlgorithmSHA512], Equals, ErrPCRBankMissingFromLog) + c.Check(e.BankErrs[tpm2.HashAlgorithmSHA384], Equals, ErrPCRBankMissingFromLog) + c.Check(e.PCRErrs[tpm2.HashAlgorithmSHA384][internal_efi.PlatformFirmwarePCR], IsNil) + c.Check(e.BankErrs[tpm2.HashAlgorithmSHA256], IsNil) + + var mismatchErr *PCRValueMismatchError + c.Check(e.PCRErrs[tpm2.HashAlgorithmSHA256][internal_efi.PlatformFirmwarePCR], ErrorMatches, `PCR value mismatch \(actual from TPM 0xb0d6d5f50852be1524306ad88b928605c14338e56a1b8c0dc211a144524df2ef, reconstructed from log 0xa6602a7a403068b5556e78cc3f5b00c9c76d33d514093ca9b584dce7590e6c69\)`) + c.Check(errors.As(e.PCRErrs[tpm2.HashAlgorithmSHA256][internal_efi.PlatformFirmwarePCR], &mismatchErr), testutil.IsTrue) + c.Check(e.PCRErrs[tpm2.HashAlgorithmSHA256][internal_efi.PlatformConfigPCR], ErrorMatches, `unexpected StartupLocality event \(should be in PCR0\)`) + c.Check(e.PCRErrs[tpm2.HashAlgorithmSHA256][internal_efi.DriversAndAppsPCR], IsNil) } func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankOutOfPlaceStartupLocality(c *C) { @@ -481,10 +486,10 @@ func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankOutOfPlaceStartupLocal _, err := CheckFirmwareLogAndChoosePCRBank(s.TPM, log, tpm2.HandleList{ internal_efi.PlatformFirmwarePCR, - }) + }, false) 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_SHA512: the PCR bank is missing from the TCG log. +- TPM_ALG_SHA384: the PCR bank is missing from the TCG log. - TPM_ALG_SHA256\(PCR0\): unexpected StartupLocality event after measurements already made. `) var e *NoSuitablePCRAlgorithmError @@ -524,10 +529,10 @@ func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankInvalidStartupLocality _, err := CheckFirmwareLogAndChoosePCRBank(s.TPM, log, tpm2.HandleList{ internal_efi.PlatformFirmwarePCR, - }) + }, false) 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_SHA512: the PCR bank is missing from the TCG log. +- TPM_ALG_SHA384: the PCR bank is missing from the TCG 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 @@ -550,10 +555,10 @@ func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankPCRMismatchMandatory(c }) _, err := CheckFirmwareLogAndChoosePCRBank(s.TPM, log, tpm2.HandleList{ internal_efi.PlatformFirmwarePCR, - }) + }, false) 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_SHA512: the PCR bank is missing from the TCG log. +- TPM_ALG_SHA384: the PCR bank is missing from the TCG log. - TPM_ALG_SHA256\(PCR0\): PCR value mismatch \(actual from TPM 0xb0d6d5f50852be1524306ad88b928605c14338e56a1b8c0dc211a144524df2ef, reconstructed from log 0xa6602a7a403068b5556e78cc3f5b00c9c76d33d514093ca9b584dce7590e6c69\). `) var e *NoSuitablePCRAlgorithmError @@ -584,6 +589,7 @@ func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankPCRMismatchNonMandator internal_efi.PlatformManufacturerPCR, internal_efi.SecureBootPolicyPCR, }, + false, ) c.Assert(err, IsNil) c.Check(results.Alg, Equals, tpm2.HashAlgorithmSHA256) @@ -623,6 +629,7 @@ func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankPCRMismatchMandatoryIn internal_efi.PlatformManufacturerPCR, internal_efi.SecureBootPolicyPCR, }, + false, ) c.Assert(err, IsNil) c.Check(results.Alg, Equals, tpm2.HashAlgorithmSHA256) @@ -658,6 +665,7 @@ func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankPCRMismatchNonMandator internal_efi.PlatformManufacturerPCR, internal_efi.SecureBootPolicyPCR, }, + false, ) c.Assert(err, IsNil) c.Check(results.Alg, Equals, tpm2.HashAlgorithmSHA384) @@ -716,6 +724,7 @@ func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankSecureBootConfigJumpsT internal_efi.PlatformManufacturerPCR, internal_efi.SecureBootPolicyPCR, }, + false, ) c.Assert(err, IsNil) c.Check(results.Alg, Equals, tpm2.HashAlgorithmSHA256) @@ -732,7 +741,7 @@ func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankBadSpec(c *C) { Minor: 2, Errata: 0, } - _, err := CheckFirmwareLogAndChoosePCRBank(s.TPM, log, nil) + _, err := CheckFirmwareLogAndChoosePCRBank(s.TPM, log, nil, false) c.Check(err, ErrorMatches, `invalid log spec`) } @@ -765,7 +774,7 @@ func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankPreOSMeasurementToNonT log.Events = eventsCopy s.resetTPMAndReplayLog(c, log, tpm2.HashAlgorithmSHA256) - _, err := CheckFirmwareLogAndChoosePCRBank(s.TPM, log, nil) + _, err := CheckFirmwareLogAndChoosePCRBank(s.TPM, log, nil, false) c.Check(err, ErrorMatches, `measurements were made by firmware from pre-OS environment to non-TCG defined PCR 8`) } @@ -789,7 +798,7 @@ func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankSeparatorDecodeError(c } s.resetTPMAndReplayLog(c, log, tpm2.HashAlgorithmSHA256) - _, err := CheckFirmwareLogAndChoosePCRBank(s.TPM, log, nil) + _, err := CheckFirmwareLogAndChoosePCRBank(s.TPM, log, nil, false) c.Check(err, ErrorMatches, `invalid event data for EV_SEPARATOR event in PCR 7: some error`) } @@ -813,7 +822,7 @@ func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankSeparatorError(c *C) { } s.resetTPMAndReplayLog(c, log, tpm2.HashAlgorithmSHA256) - _, err := CheckFirmwareLogAndChoosePCRBank(s.TPM, log, nil) + _, err := CheckFirmwareLogAndChoosePCRBank(s.TPM, log, nil, false) c.Check(err, ErrorMatches, `EV_SEPARATOR event for PCR 7 indicates an error occurred \(error code in log: 67305985\)`) } @@ -849,7 +858,7 @@ func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankUnexpectedSuccessfulSe s.resetTPMAndReplayLog(c, log, tpm2.HashAlgorithmSHA256) - _, err := CheckFirmwareLogAndChoosePCRBank(s.TPM, log, nil) + _, err := CheckFirmwareLogAndChoosePCRBank(s.TPM, log, nil, false) c.Check(err, ErrorMatches, `unexpected normal EV_SEPARATOR event in PCR 0`) } @@ -878,7 +887,7 @@ func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankMissingSeparators(c *C log.Events = eventsCopy s.resetTPMAndReplayLog(c, log, tpm2.HashAlgorithmSHA256) - _, err := CheckFirmwareLogAndChoosePCRBank(s.TPM, log, nil) + _, err := CheckFirmwareLogAndChoosePCRBank(s.TPM, log, nil, false) c.Check(err, ErrorMatches, `unexpected EV_EFI_VARIABLE_AUTHORITY event in PCR 7 whilst transitioning to OS-present \(expected EV_SEPARATOR\)`) } @@ -904,7 +913,7 @@ func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankMultipleSeparatorsForS log.Events = eventsCopy s.resetTPMAndReplayLog(c, log, tpm2.HashAlgorithmSHA256) - _, err := CheckFirmwareLogAndChoosePCRBank(s.TPM, log, nil) + _, err := CheckFirmwareLogAndChoosePCRBank(s.TPM, log, nil, false) c.Check(err, ErrorMatches, `more than one EV_SEPARATOR event exists for PCR 7`) } @@ -928,6 +937,95 @@ func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankTruncatedLog(c *C) { log.Events = eventsCopy s.resetTPMAndReplayLog(c, log, tpm2.HashAlgorithmSHA256) - _, err := CheckFirmwareLogAndChoosePCRBank(s.TPM, log, nil) + _, err := CheckFirmwareLogAndChoosePCRBank(s.TPM, log, nil, false) c.Check(err, ErrorMatches, `reached the end of the log without seeing EV_SEPARATOR events in all TCG defined PCRs`) } + +func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankEmptyPCRBankNotAllowed(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}, + 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.PlatformConfigPCR, + internal_efi.DriversAndAppsPCR, + internal_efi.DriversAndAppsConfigPCR, + internal_efi.BootManagerCodePCR, + internal_efi.BootManagerConfigPCR, + internal_efi.PlatformManufacturerPCR, + internal_efi.SecureBootPolicyPCR, + }, + false, + ) + c.Check(err, ErrorMatches, `the PCR bank for TPM_ALG_SHA384 is missing from the TCG log but is active on the TPM`) + + var emptyPCRErr *EmptyPCRBankError + c.Check(errors.As(err, &emptyPCRErr), testutil.IsTrue) +} + +func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankEmptyPCRBankAllowed(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}, + 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.PlatformConfigPCR, + internal_efi.DriversAndAppsPCR, + internal_efi.DriversAndAppsConfigPCR, + internal_efi.BootManagerCodePCR, + internal_efi.BootManagerConfigPCR, + internal_efi.PlatformManufacturerPCR, + internal_efi.SecureBootPolicyPCR, + }, + true, + ) + c.Assert(err, IsNil) +} + +func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankSHA256WithEmptySHA384BankBad(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}, + StartupLocality: 3, + }) + s.resetTPMAndReplayLog(c, log, tpm2.HashAlgorithmSHA256) + + _, err := CheckFirmwareLogAndChoosePCRBank(s.TPM, log, + tpm2.HandleList{ + internal_efi.PlatformConfigPCR, + internal_efi.DriversAndAppsPCR, + internal_efi.DriversAndAppsConfigPCR, + internal_efi.BootManagerCodePCR, + internal_efi.BootManagerConfigPCR, + internal_efi.PlatformManufacturerPCR, + internal_efi.SecureBootPolicyPCR, + }, + false, + ) + c.Check(err, ErrorMatches, `the PCR bank for TPM_ALG_SHA384 is missing from the TCG log but is active on the TPM`) + + var bankErr *EmptyPCRBankError + c.Check(errors.As(err, &bankErr), testutil.IsTrue) +} diff --git a/efi/preinstall/checks.go b/efi/preinstall/checks.go index 4e70741d..8035ab82 100644 --- a/efi/preinstall/checks.go +++ b/efi/preinstall/checks.go @@ -142,6 +142,12 @@ const ( // regards to firmware updates because db has to be changed accordingly each time, so this is not // advisable. PermitPreOSVerificationUsingDigests + + // PermitEmptyPCRBanks will prevent RunChecks from returning an error if there are any PCR banks + // (those are PCR banks that are enabled but which firmware doesn't perform measurements to). This + // is generally ok for full-disk encryption, but completely breaks the remote attestation model + // because it allows an adversary to trivially spoof an entire trusted platform from software. + PermitEmptyPCRBanks ) var ( @@ -236,11 +242,17 @@ func RunChecks(ctx context.Context, flags CheckFlags, loadedImages []secboot_efi mandatoryPcrs = append(mandatoryPcrs, internal_efi.SecureBootPolicyPCR) } - logResults, err := checkFirmwareLogAndChoosePCRBank(tpm, log, mandatoryPcrs) + permitEmptyPCRBanks := flags&PermitEmptyPCRBanks > 0 + logResults, err := checkFirmwareLogAndChoosePCRBank(tpm, log, mandatoryPcrs, permitEmptyPCRBanks) switch { case tpm2.IsTPMError(err, tpm2.AnyErrorCode, tpm2.AnyCommandCode): return nil, &TPM2DeviceError{err} case err != nil: + var pcrBankErr *EmptyPCRBankError + if errors.As(err, &pcrBankErr) { + // return this one unwrapped + return nil, err + } return nil, &TCGLogError{err} } @@ -436,7 +448,7 @@ func RunChecks(ctx context.Context, flags CheckFlags, loadedImages []secboot_efi } } - if mainErr.NumErrors() > 0 { + if len(mainErr.Errs) > 0 { return nil, mainErr } return result, nil diff --git a/efi/preinstall/checks_test.go b/efi/preinstall/checks_test.go index c651f9a2..44ff818c 100644 --- a/efi/preinstall/checks_test.go +++ b/efi/preinstall/checks_test.go @@ -185,19 +185,19 @@ C7E003CB expectedFlags: NoPlatformConfigProfileSupport | NoDriversAndAppsConfigProfileSupport | NoBootManagerConfigProfileSupport, }) c.Assert(err, IsNil) - c.Assert(warnings.NumErrors(), Equals, 3) + c.Assert(warnings.Errs, HasLen, 3) - warning := warnings.UnwrapError(0) + warning := warnings.Errs[0] c.Check(warning, ErrorMatches, `error with platform config \(PCR1\) measurements: generating profiles for PCR 1 is not supported yet`) var pce *PlatformConfigPCRError c.Check(errors.As(warning, &pce), testutil.IsTrue) - warning = warnings.UnwrapError(1) + warning = warnings.Errs[1] c.Check(warning, ErrorMatches, `error with drivers and apps config \(PCR3\) measurements: generating profiles for PCR 3 is not supported yet`) var dce *DriversAndAppsConfigPCRError c.Check(errors.As(warning, &dce), testutil.IsTrue) - warning = warnings.UnwrapError(2) + warning = warnings.Errs[2] c.Check(warning, ErrorMatches, `error with boot manager config \(PCR5\) measurements: generating profiles for PCR 5 is not supported yet`) var bmce *BootManagerConfigPCRError c.Check(errors.As(warning, &bmce), testutil.IsTrue) @@ -269,19 +269,19 @@ C7E003CB expectedFlags: NoPlatformConfigProfileSupport | NoDriversAndAppsConfigProfileSupport | NoBootManagerConfigProfileSupport, }) c.Assert(err, IsNil) - c.Assert(warnings.NumErrors(), Equals, 3) + c.Assert(warnings.Errs, HasLen, 3) - warning := warnings.UnwrapError(0) + warning := warnings.Errs[0] c.Check(warning, ErrorMatches, `error with platform config \(PCR1\) measurements: generating profiles for PCR 1 is not supported yet`) var pce *PlatformConfigPCRError c.Check(errors.As(warning, &pce), testutil.IsTrue) - warning = warnings.UnwrapError(1) + warning = warnings.Errs[1] c.Check(warning, ErrorMatches, `error with drivers and apps config \(PCR3\) measurements: generating profiles for PCR 3 is not supported yet`) var dce *DriversAndAppsConfigPCRError c.Check(errors.As(warning, &dce), testutil.IsTrue) - warning = warnings.UnwrapError(2) + warning = warnings.Errs[2] c.Check(warning, ErrorMatches, `error with boot manager config \(PCR5\) measurements: generating profiles for PCR 5 is not supported yet`) var bmce *BootManagerConfigPCRError c.Check(errors.As(warning, &bmce), testutil.IsTrue) @@ -344,24 +344,25 @@ C7E003CB &mockImage{contents: []byte("mock grub executable"), digest: testutil.DecodeHexString(c, "d5a9780e9f6a43c2e53fe9fda547be77f7783f31aea8013783242b040ff21dc0")}, &mockImage{contents: []byte("mock kernel executable"), digest: testutil.DecodeHexString(c, "2ddfbd91fa1698b0d133c38ba90dbba76c9e08371ff83d03b5fb4c2e56d7e81f")}, }, + flags: PermitEmptyPCRBanks, expectedPcrAlg: tpm2.HashAlgorithmSHA256, expectedUsedSecureBootCAs: []*X509CertificateID{NewX509CertificateID(testutil.ParseCertificate(c, msUefiCACert))}, expectedFlags: NoPlatformConfigProfileSupport | NoDriversAndAppsConfigProfileSupport | NoBootManagerConfigProfileSupport, }) c.Assert(err, IsNil) - c.Assert(warnings.NumErrors(), Equals, 3) + c.Assert(warnings.Errs, HasLen, 3) - warning := warnings.UnwrapError(0) + warning := warnings.Errs[0] c.Check(warning, ErrorMatches, `error with platform config \(PCR1\) measurements: generating profiles for PCR 1 is not supported yet`) var pce *PlatformConfigPCRError c.Check(errors.As(warning, &pce), testutil.IsTrue) - warning = warnings.UnwrapError(1) + warning = warnings.Errs[1] c.Check(warning, ErrorMatches, `error with drivers and apps config \(PCR3\) measurements: generating profiles for PCR 3 is not supported yet`) var dce *DriversAndAppsConfigPCRError c.Check(errors.As(warning, &dce), testutil.IsTrue) - warning = warnings.UnwrapError(2) + warning = warnings.Errs[2] c.Check(warning, ErrorMatches, `error with boot manager config \(PCR5\) measurements: generating profiles for PCR 5 is not supported yet`) var bmce *BootManagerConfigPCRError c.Check(errors.As(warning, &bmce), testutil.IsTrue) @@ -431,19 +432,19 @@ C7E003CB expectedFlags: NoPlatformConfigProfileSupport | NoDriversAndAppsConfigProfileSupport | NoBootManagerConfigProfileSupport, }) c.Assert(err, IsNil) - c.Assert(warnings.NumErrors(), Equals, 3) + c.Assert(warnings.Errs, HasLen, 3) - warning := warnings.UnwrapError(0) + warning := warnings.Errs[0] c.Check(warning, ErrorMatches, `error with platform config \(PCR1\) measurements: generating profiles for PCR 1 is not supported yet`) var pce *PlatformConfigPCRError c.Check(errors.As(warning, &pce), testutil.IsTrue) - warning = warnings.UnwrapError(1) + warning = warnings.Errs[1] c.Check(warning, ErrorMatches, `error with drivers and apps config \(PCR3\) measurements: generating profiles for PCR 3 is not supported yet`) var dce *DriversAndAppsConfigPCRError c.Check(errors.As(warning, &dce), testutil.IsTrue) - warning = warnings.UnwrapError(2) + warning = warnings.Errs[2] c.Check(warning, ErrorMatches, `error with boot manager config \(PCR5\) measurements: generating profiles for PCR 5 is not supported yet`) var bmce *BootManagerConfigPCRError c.Check(errors.As(warning, &bmce), testutil.IsTrue) @@ -487,19 +488,19 @@ func (s *runChecksSuite) TestRunChecksGoodVirtualMachine1(c *C) { expectedFlags: NoPlatformConfigProfileSupport | NoDriversAndAppsConfigProfileSupport | NoBootManagerConfigProfileSupport | RunningInVirtualMachine, }) c.Assert(err, IsNil) - c.Assert(warnings.NumErrors(), Equals, 3) + c.Assert(warnings.Errs, HasLen, 3) - warning := warnings.UnwrapError(0) + warning := warnings.Errs[0] c.Check(warning, ErrorMatches, `error with platform config \(PCR1\) measurements: generating profiles for PCR 1 is not supported yet`) var pce *PlatformConfigPCRError c.Check(errors.As(warning, &pce), testutil.IsTrue) - warning = warnings.UnwrapError(1) + warning = warnings.Errs[1] c.Check(warning, ErrorMatches, `error with drivers and apps config \(PCR3\) measurements: generating profiles for PCR 3 is not supported yet`) var dce *DriversAndAppsConfigPCRError c.Check(errors.As(warning, &dce), testutil.IsTrue) - warning = warnings.UnwrapError(2) + warning = warnings.Errs[2] c.Check(warning, ErrorMatches, `error with boot manager config \(PCR5\) measurements: generating profiles for PCR 5 is not supported yet`) var bmce *BootManagerConfigPCRError c.Check(errors.As(warning, &bmce), testutil.IsTrue) @@ -546,19 +547,19 @@ func (s *runChecksSuite) TestRunChecksGoodVirtualMachine2(c *C) { expectedFlags: NoPlatformConfigProfileSupport | NoDriversAndAppsConfigProfileSupport | NoBootManagerConfigProfileSupport | RunningInVirtualMachine, }) c.Assert(err, IsNil) - c.Assert(warnings.NumErrors(), Equals, 3) + c.Assert(warnings.Errs, HasLen, 3) - warning := warnings.UnwrapError(0) + warning := warnings.Errs[0] c.Check(warning, ErrorMatches, `error with platform config \(PCR1\) measurements: generating profiles for PCR 1 is not supported yet`) var pce *PlatformConfigPCRError c.Check(errors.As(warning, &pce), testutil.IsTrue) - warning = warnings.UnwrapError(1) + warning = warnings.Errs[1] c.Check(warning, ErrorMatches, `error with drivers and apps config \(PCR3\) measurements: generating profiles for PCR 3 is not supported yet`) var dce *DriversAndAppsConfigPCRError c.Check(errors.As(warning, &dce), testutil.IsTrue) - warning = warnings.UnwrapError(2) + warning = warnings.Errs[2] c.Check(warning, ErrorMatches, `error with boot manager config \(PCR5\) measurements: generating profiles for PCR 5 is not supported yet`) var bmce *BootManagerConfigPCRError c.Check(errors.As(warning, &bmce), testutil.IsTrue) @@ -627,19 +628,19 @@ C7E003CB expectedFlags: NoPlatformConfigProfileSupport | NoDriversAndAppsConfigProfileSupport | NoBootManagerConfigProfileSupport | DiscreteTPMDetected | StartupLocalityNotProtected, }) c.Assert(err, IsNil) - c.Assert(warnings.NumErrors(), Equals, 3) + c.Assert(warnings.Errs, HasLen, 3) - warning := warnings.UnwrapError(0) + warning := warnings.Errs[0] c.Check(warning, ErrorMatches, `error with platform config \(PCR1\) measurements: generating profiles for PCR 1 is not supported yet`) var pce *PlatformConfigPCRError c.Check(errors.As(warning, &pce), testutil.IsTrue) - warning = warnings.UnwrapError(1) + warning = warnings.Errs[1] c.Check(warning, ErrorMatches, `error with drivers and apps config \(PCR3\) measurements: generating profiles for PCR 3 is not supported yet`) var dce *DriversAndAppsConfigPCRError c.Check(errors.As(warning, &dce), testutil.IsTrue) - warning = warnings.UnwrapError(2) + warning = warnings.Errs[2] c.Check(warning, ErrorMatches, `error with boot manager config \(PCR5\) measurements: generating profiles for PCR 5 is not supported yet`) var bmce *BootManagerConfigPCRError c.Check(errors.As(warning, &bmce), testutil.IsTrue) @@ -710,19 +711,19 @@ C7E003CB expectedFlags: NoPlatformConfigProfileSupport | NoDriversAndAppsConfigProfileSupport | NoBootManagerConfigProfileSupport | DiscreteTPMDetected, }) c.Assert(err, IsNil) - c.Assert(warnings.NumErrors(), Equals, 3) + c.Assert(warnings.Errs, HasLen, 3) - warning := warnings.UnwrapError(0) + warning := warnings.Errs[0] c.Check(warning, ErrorMatches, `error with platform config \(PCR1\) measurements: generating profiles for PCR 1 is not supported yet`) var pce *PlatformConfigPCRError c.Check(errors.As(warning, &pce), testutil.IsTrue) - warning = warnings.UnwrapError(1) + warning = warnings.Errs[1] c.Check(warning, ErrorMatches, `error with drivers and apps config \(PCR3\) measurements: generating profiles for PCR 3 is not supported yet`) var dce *DriversAndAppsConfigPCRError c.Check(errors.As(warning, &dce), testutil.IsTrue) - warning = warnings.UnwrapError(2) + warning = warnings.Errs[2] c.Check(warning, ErrorMatches, `error with boot manager config \(PCR5\) measurements: generating profiles for PCR 5 is not supported yet`) var bmce *BootManagerConfigPCRError c.Check(errors.As(warning, &bmce), testutil.IsTrue) @@ -794,19 +795,19 @@ C7E003CB expectedFlags: NoPlatformConfigProfileSupport | NoDriversAndAppsConfigProfileSupport | NoBootManagerConfigProfileSupport | DiscreteTPMDetected | StartupLocalityNotProtected, }) c.Assert(err, IsNil) - c.Assert(warnings.NumErrors(), Equals, 3) + c.Assert(warnings.Errs, HasLen, 3) - warning := warnings.UnwrapError(0) + warning := warnings.Errs[0] c.Check(warning, ErrorMatches, `error with platform config \(PCR1\) measurements: generating profiles for PCR 1 is not supported yet`) var pce *PlatformConfigPCRError c.Check(errors.As(warning, &pce), testutil.IsTrue) - warning = warnings.UnwrapError(1) + warning = warnings.Errs[1] c.Check(warning, ErrorMatches, `error with drivers and apps config \(PCR3\) measurements: generating profiles for PCR 3 is not supported yet`) var dce *DriversAndAppsConfigPCRError c.Check(errors.As(warning, &dce), testutil.IsTrue) - warning = warnings.UnwrapError(2) + warning = warnings.Errs[2] c.Check(warning, ErrorMatches, `error with boot manager config \(PCR5\) measurements: generating profiles for PCR 5 is not supported yet`) var bmce *BootManagerConfigPCRError c.Check(errors.As(warning, &bmce), testutil.IsTrue) @@ -878,24 +879,24 @@ C7E003CB expectedFlags: NoPlatformFirmwareProfileSupport | NoPlatformConfigProfileSupport | NoDriversAndAppsConfigProfileSupport | NoBootManagerConfigProfileSupport, }) c.Assert(err, IsNil) - c.Assert(warnings.NumErrors(), Equals, 4) + c.Assert(warnings.Errs, HasLen, 4) - warning := warnings.UnwrapError(0) + warning := warnings.Errs[0] c.Check(warning, ErrorMatches, `error with platform firmware \(PCR0\) measurements: PCR value mismatch \(actual from TPM 0xe9995745ca25279ec699688b70488116fe4d9f053cb0991dd71e82e7edfa66b5, reconstructed from log 0xa6602a7a403068b5556e78cc3f5b00c9c76d33d514093ca9b584dce7590e6c69\)`) var pfe *PlatformFirmwarePCRError c.Check(errors.As(warning, &pfe), testutil.IsTrue) - warning = warnings.UnwrapError(1) + warning = warnings.Errs[1] c.Check(warning, ErrorMatches, `error with platform config \(PCR1\) measurements: generating profiles for PCR 1 is not supported yet`) var pce *PlatformConfigPCRError c.Check(errors.As(warning, &pce), testutil.IsTrue) - warning = warnings.UnwrapError(2) + warning = warnings.Errs[2] c.Check(warning, ErrorMatches, `error with drivers and apps config \(PCR3\) measurements: generating profiles for PCR 3 is not supported yet`) var dce *DriversAndAppsConfigPCRError c.Check(errors.As(warning, &dce), testutil.IsTrue) - warning = warnings.UnwrapError(3) + warning = warnings.Errs[3] c.Check(warning, ErrorMatches, `error with boot manager config \(PCR5\) measurements: generating profiles for PCR 5 is not supported yet`) var bmce *BootManagerConfigPCRError c.Check(errors.As(warning, &bmce), testutil.IsTrue) @@ -967,24 +968,24 @@ C7E003CB expectedFlags: NoPlatformConfigProfileSupport | NoDriversAndAppsProfileSupport | NoDriversAndAppsConfigProfileSupport | NoBootManagerConfigProfileSupport, }) c.Assert(err, IsNil) - c.Assert(warnings.NumErrors(), Equals, 4) + c.Assert(warnings.Errs, HasLen, 4) - warning := warnings.UnwrapError(0) + warning := warnings.Errs[0] c.Check(warning, ErrorMatches, `error with drivers and apps \(PCR2\) measurements: PCR value mismatch \(actual from TPM 0xfa734a6a4d262d7405d47d48c0a1b127229ca808032555ad919ed5dd7c1f6519, reconstructed from log 0x3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969\)`) var de *DriversAndAppsPCRError c.Check(errors.As(warning, &de), testutil.IsTrue) - warning = warnings.UnwrapError(1) + warning = warnings.Errs[1] c.Check(warning, ErrorMatches, `error with platform config \(PCR1\) measurements: generating profiles for PCR 1 is not supported yet`) var pce *PlatformConfigPCRError c.Check(errors.As(warning, &pce), testutil.IsTrue) - warning = warnings.UnwrapError(2) + warning = warnings.Errs[2] c.Check(warning, ErrorMatches, `error with drivers and apps config \(PCR3\) measurements: generating profiles for PCR 3 is not supported yet`) var dce *DriversAndAppsConfigPCRError c.Check(errors.As(warning, &dce), testutil.IsTrue) - warning = warnings.UnwrapError(3) + warning = warnings.Errs[3] c.Check(warning, ErrorMatches, `error with boot manager config \(PCR5\) measurements: generating profiles for PCR 5 is not supported yet`) var bmce *BootManagerConfigPCRError c.Check(errors.As(warning, &bmce), testutil.IsTrue) @@ -1056,24 +1057,24 @@ C7E003CB expectedFlags: NoPlatformConfigProfileSupport | NoDriversAndAppsConfigProfileSupport | NoBootManagerCodeProfileSupport | NoBootManagerConfigProfileSupport, }) c.Assert(err, IsNil) - c.Assert(warnings.NumErrors(), Equals, 4) + c.Assert(warnings.Errs, HasLen, 4) - warning := warnings.UnwrapError(0) + warning := warnings.Errs[0] c.Check(warning, ErrorMatches, `error with boot manager code \(PCR4\) measurements: PCR value mismatch \(actual from TPM 0x1c93930d6b26232e061eaa33ecf6341fae63ce598a0c6a26ee96a0828639c044, reconstructed from log 0x4bc74f3ffe49b4dd275c9f475887b68193e2db8348d72e1c3c9099c2dcfa85b0\)`) var bme *BootManagerCodePCRError c.Check(errors.As(warning, &bme), testutil.IsTrue) - warning = warnings.UnwrapError(1) + warning = warnings.Errs[1] c.Check(warning, ErrorMatches, `error with platform config \(PCR1\) measurements: generating profiles for PCR 1 is not supported yet`) var pce *PlatformConfigPCRError c.Check(errors.As(warning, &pce), testutil.IsTrue) - warning = warnings.UnwrapError(2) + warning = warnings.Errs[2] c.Check(warning, ErrorMatches, `error with drivers and apps config \(PCR3\) measurements: generating profiles for PCR 3 is not supported yet`) var dce *DriversAndAppsConfigPCRError c.Check(errors.As(warning, &dce), testutil.IsTrue) - warning = warnings.UnwrapError(3) + warning = warnings.Errs[3] c.Check(warning, ErrorMatches, `error with boot manager config \(PCR5\) measurements: generating profiles for PCR 5 is not supported yet`) var bmce *BootManagerConfigPCRError c.Check(errors.As(warning, &bmce), testutil.IsTrue) @@ -1144,24 +1145,24 @@ C7E003CB expectedFlags: NoPlatformConfigProfileSupport | NoDriversAndAppsConfigProfileSupport | NoBootManagerConfigProfileSupport | NoSecureBootPolicyProfileSupport, }) c.Assert(err, IsNil) - c.Assert(warnings.NumErrors(), Equals, 4) + c.Assert(warnings.Errs, HasLen, 4) - warning := warnings.UnwrapError(0) + warning := warnings.Errs[0] c.Check(warning, ErrorMatches, `error with secure boot policy \(PCR7\) measurements: PCR value mismatch \(actual from TPM 0xdf7b5d709755f1bd7142dd2f8c2d1195fc6b4dab5c78d41daf5c795da55db5f2, reconstructed from log 0xafc99bd8b298ea9b70d2796cb0ca22fe2b70d784691a1cae2aa3ba55edc365dc\)`) var sbe *SecureBootPolicyPCRError c.Check(errors.As(warning, &sbe), testutil.IsTrue) - warning = warnings.UnwrapError(1) + warning = warnings.Errs[1] c.Check(warning, ErrorMatches, `error with platform config \(PCR1\) measurements: generating profiles for PCR 1 is not supported yet`) var pce *PlatformConfigPCRError c.Check(errors.As(warning, &pce), testutil.IsTrue) - warning = warnings.UnwrapError(2) + warning = warnings.Errs[2] c.Check(warning, ErrorMatches, `error with drivers and apps config \(PCR3\) measurements: generating profiles for PCR 3 is not supported yet`) var dce *DriversAndAppsConfigPCRError c.Check(errors.As(warning, &dce), testutil.IsTrue) - warning = warnings.UnwrapError(3) + warning = warnings.Errs[3] c.Check(warning, ErrorMatches, `error with boot manager config \(PCR5\) measurements: generating profiles for PCR 5 is not supported yet`) var bmce *BootManagerConfigPCRError c.Check(errors.As(warning, &bmce), testutil.IsTrue) @@ -1233,19 +1234,19 @@ C7E003CB expectedFlags: NoPlatformConfigProfileSupport | NoDriversAndAppsConfigProfileSupport | NoBootManagerConfigProfileSupport | VARDriversPresent, }) c.Assert(err, IsNil) - c.Assert(warnings.NumErrors(), Equals, 3) + c.Assert(warnings.Errs, HasLen, 3) - warning := warnings.UnwrapError(0) + warning := warnings.Errs[0] c.Check(warning, ErrorMatches, `error with platform config \(PCR1\) measurements: generating profiles for PCR 1 is not supported yet`) var pce *PlatformConfigPCRError c.Check(errors.As(warning, &pce), testutil.IsTrue) - warning = warnings.UnwrapError(1) + warning = warnings.Errs[1] c.Check(warning, ErrorMatches, `error with drivers and apps config \(PCR3\) measurements: generating profiles for PCR 3 is not supported yet`) var dce *DriversAndAppsConfigPCRError c.Check(errors.As(warning, &dce), testutil.IsTrue) - warning = warnings.UnwrapError(2) + warning = warnings.Errs[2] c.Check(warning, ErrorMatches, `error with boot manager config \(PCR5\) measurements: generating profiles for PCR 5 is not supported yet`) var bmce *BootManagerConfigPCRError c.Check(errors.As(warning, &bmce), testutil.IsTrue) @@ -1317,19 +1318,19 @@ C7E003CB expectedFlags: NoPlatformConfigProfileSupport | NoDriversAndAppsConfigProfileSupport | NoBootManagerConfigProfileSupport | SysPrepApplicationsPresent, }) c.Assert(err, IsNil) - c.Assert(warnings.NumErrors(), Equals, 3) + c.Assert(warnings.Errs, HasLen, 3) - warning := warnings.UnwrapError(0) + warning := warnings.Errs[0] c.Check(warning, ErrorMatches, `error with platform config \(PCR1\) measurements: generating profiles for PCR 1 is not supported yet`) var pce *PlatformConfigPCRError c.Check(errors.As(warning, &pce), testutil.IsTrue) - warning = warnings.UnwrapError(1) + warning = warnings.Errs[1] c.Check(warning, ErrorMatches, `error with drivers and apps config \(PCR3\) measurements: generating profiles for PCR 3 is not supported yet`) var dce *DriversAndAppsConfigPCRError c.Check(errors.As(warning, &dce), testutil.IsTrue) - warning = warnings.UnwrapError(2) + warning = warnings.Errs[2] c.Check(warning, ErrorMatches, `error with boot manager config \(PCR5\) measurements: generating profiles for PCR 5 is not supported yet`) var bmce *BootManagerConfigPCRError c.Check(errors.As(warning, &bmce), testutil.IsTrue) @@ -1401,19 +1402,19 @@ C7E003CB expectedFlags: NoPlatformConfigProfileSupport | NoDriversAndAppsConfigProfileSupport | NoBootManagerConfigProfileSupport | AbsoluteComputraceActive, }) c.Assert(err, IsNil) - c.Assert(warnings.NumErrors(), Equals, 3) + c.Assert(warnings.Errs, HasLen, 3) - warning := warnings.UnwrapError(0) + warning := warnings.Errs[0] c.Check(warning, ErrorMatches, `error with platform config \(PCR1\) measurements: generating profiles for PCR 1 is not supported yet`) var pce *PlatformConfigPCRError c.Check(errors.As(warning, &pce), testutil.IsTrue) - warning = warnings.UnwrapError(1) + warning = warnings.Errs[1] c.Check(warning, ErrorMatches, `error with drivers and apps config \(PCR3\) measurements: generating profiles for PCR 3 is not supported yet`) var dce *DriversAndAppsConfigPCRError c.Check(errors.As(warning, &dce), testutil.IsTrue) - warning = warnings.UnwrapError(2) + warning = warnings.Errs[2] c.Check(warning, ErrorMatches, `error with boot manager config \(PCR5\) measurements: generating profiles for PCR 5 is not supported yet`) var bmce *BootManagerConfigPCRError c.Check(errors.As(warning, &bmce), testutil.IsTrue) @@ -1483,19 +1484,19 @@ C7E003CB expectedFlags: NoPlatformConfigProfileSupport | NoDriversAndAppsConfigProfileSupport | NoBootManagerConfigProfileSupport | NotAllBootManagerCodeDigestsVerified, }) c.Assert(err, IsNil) - c.Assert(warnings.NumErrors(), Equals, 3) + c.Assert(warnings.Errs, HasLen, 3) - warning := warnings.UnwrapError(0) + warning := warnings.Errs[0] c.Check(warning, ErrorMatches, `error with platform config \(PCR1\) measurements: generating profiles for PCR 1 is not supported yet`) var pce *PlatformConfigPCRError c.Check(errors.As(warning, &pce), testutil.IsTrue) - warning = warnings.UnwrapError(1) + warning = warnings.Errs[1] c.Check(warning, ErrorMatches, `error with drivers and apps config \(PCR3\) measurements: generating profiles for PCR 3 is not supported yet`) var dce *DriversAndAppsConfigPCRError c.Check(errors.As(warning, &dce), testutil.IsTrue) - warning = warnings.UnwrapError(2) + warning = warnings.Errs[2] c.Check(warning, ErrorMatches, `error with boot manager config \(PCR5\) measurements: generating profiles for PCR 5 is not supported yet`) var bmce *BootManagerConfigPCRError c.Check(errors.As(warning, &bmce), testutil.IsTrue) @@ -1568,24 +1569,24 @@ C7E003CB expectedFlags: NoPlatformConfigProfileSupport | NoDriversAndAppsConfigProfileSupport | NoBootManagerCodeProfileSupport | NoBootManagerConfigProfileSupport, }) c.Assert(err, IsNil) - c.Assert(warnings.NumErrors(), Equals, 4) + c.Assert(warnings.Errs, HasLen, 4) - warning := warnings.UnwrapError(0) + warning := warnings.Errs[0] c.Check(warning, ErrorMatches, `error with platform config \(PCR1\) measurements: generating profiles for PCR 1 is not supported yet`) var pce *PlatformConfigPCRError c.Check(errors.As(warning, &pce), testutil.IsTrue) - warning = warnings.UnwrapError(1) + warning = warnings.Errs[1] c.Check(warning, ErrorMatches, `error with drivers and apps config \(PCR3\) measurements: generating profiles for PCR 3 is not supported yet`) var dce *DriversAndAppsConfigPCRError c.Check(errors.As(warning, &dce), testutil.IsTrue) - warning = warnings.UnwrapError(2) - c.Check(warning, ErrorMatches, `error with boot manager code \(PCR4\) measurements: log contains unexpected EV_EFI_BOOT_SERVICES_APPLICATION digest for OS-present application mock image: log digest matches flat file digest \(0xd5a9780e9f6a43c2e53fe9fda547be77f7783f31aea8013783242b040ff21dc0\) which suggests an image loaded outside of the LoadImage API and firmware lacking support for the EFI_TCG2_PROTOCOL and/or the PE_COFF_IMAGE flag`) - var bce *BootManagerCodePCRError - c.Check(errors.As(warning, &bce), testutil.IsTrue) + warning = warnings.Errs[2] + c.Check(warning, ErrorMatches, `error with boot manager code \(PCR4\) measurements: log contains unexpected EV_EFI_BOOT_SERVICES_APPLICATION digest for OS-present application mock image: log digest matches flat file digest \(0xd5a9780e9f6a43c2e53fe9fda547be77f7783f31aea8013783242b040ff21dc0\) which suggests an image loaded outside of the LoadImage API and firmware lacking support for the EFI_TCG2_PROTOCOL and\/or the PE_COFF_IMAGE flag`) + var bme *BootManagerCodePCRError + c.Check(errors.As(warning, &bme), testutil.IsTrue) - warning = warnings.UnwrapError(3) + warning = warnings.Errs[3] c.Check(warning, ErrorMatches, `error with boot manager config \(PCR5\) measurements: generating profiles for PCR 5 is not supported yet`) var bmce *BootManagerConfigPCRError c.Check(errors.As(warning, &bmce), testutil.IsTrue) @@ -1658,19 +1659,19 @@ C7E003CB expectedFlags: NoPlatformConfigProfileSupport | NoDriversAndAppsConfigProfileSupport | NoBootManagerConfigProfileSupport | VARDriversPresent | PreOSVerificationUsingDigestsDetected, }) c.Assert(err, IsNil) - c.Assert(warnings.NumErrors(), Equals, 3) + c.Assert(warnings.Errs, HasLen, 3) - warning := warnings.UnwrapError(0) + warning := warnings.Errs[0] c.Check(warning, ErrorMatches, `error with platform config \(PCR1\) measurements: generating profiles for PCR 1 is not supported yet`) var pce *PlatformConfigPCRError c.Check(errors.As(warning, &pce), testutil.IsTrue) - warning = warnings.UnwrapError(1) + warning = warnings.Errs[1] c.Check(warning, ErrorMatches, `error with drivers and apps config \(PCR3\) measurements: generating profiles for PCR 3 is not supported yet`) var dce *DriversAndAppsConfigPCRError c.Check(errors.As(warning, &dce), testutil.IsTrue) - warning = warnings.UnwrapError(2) + warning = warnings.Errs[2] c.Check(warning, ErrorMatches, `error with boot manager config \(PCR5\) measurements: generating profiles for PCR 5 is not supported yet`) var bmce *BootManagerConfigPCRError c.Check(errors.As(warning, &bmce), testutil.IsTrue) @@ -1743,19 +1744,19 @@ C7E003CB expectedFlags: NoPlatformConfigProfileSupport | NoDriversAndAppsConfigProfileSupport | NoBootManagerConfigProfileSupport | VARDriversPresent | PreOSVerificationUsingDigestsDetected | WeakSecureBootAlgorithmsDetected, }) c.Assert(err, IsNil) - c.Assert(warnings.NumErrors(), Equals, 3) + c.Assert(warnings.Errs, HasLen, 3) - warning := warnings.UnwrapError(0) + warning := warnings.Errs[0] c.Check(warning, ErrorMatches, `error with platform config \(PCR1\) measurements: generating profiles for PCR 1 is not supported yet`) var pce *PlatformConfigPCRError c.Check(errors.As(warning, &pce), testutil.IsTrue) - warning = warnings.UnwrapError(1) + warning = warnings.Errs[1] c.Check(warning, ErrorMatches, `error with drivers and apps config \(PCR3\) measurements: generating profiles for PCR 3 is not supported yet`) var dce *DriversAndAppsConfigPCRError c.Check(errors.As(warning, &dce), testutil.IsTrue) - warning = warnings.UnwrapError(2) + warning = warnings.Errs[2] c.Check(warning, ErrorMatches, `error with boot manager config \(PCR5\) measurements: generating profiles for PCR 5 is not supported yet`) var bmce *BootManagerConfigPCRError c.Check(errors.As(warning, &bmce), testutil.IsTrue) @@ -1822,24 +1823,24 @@ C7E003CB expectedFlags: NoPlatformConfigProfileSupport | NoDriversAndAppsConfigProfileSupport | NoBootManagerConfigProfileSupport | NoSecureBootPolicyProfileSupport, }) c.Assert(err, IsNil) - c.Assert(warnings.NumErrors(), Equals, 4) + c.Assert(warnings.Errs, HasLen, 4) - warning := warnings.UnwrapError(0) + warning := warnings.Errs[0] c.Check(warning, ErrorMatches, `error with platform config \(PCR1\) measurements: generating profiles for PCR 1 is not supported yet`) var pce *PlatformConfigPCRError c.Check(errors.As(warning, &pce), testutil.IsTrue) - warning = warnings.UnwrapError(1) + warning = warnings.Errs[1] c.Check(warning, ErrorMatches, `error with drivers and apps config \(PCR3\) measurements: generating profiles for PCR 3 is not supported yet`) var dce *DriversAndAppsConfigPCRError c.Check(errors.As(warning, &dce), testutil.IsTrue) - warning = warnings.UnwrapError(2) + warning = warnings.Errs[2] c.Check(warning, ErrorMatches, `error with boot manager config \(PCR5\) measurements: generating profiles for PCR 5 is not supported yet`) var bmce *BootManagerConfigPCRError c.Check(errors.As(warning, &bmce), testutil.IsTrue) - warning = warnings.UnwrapError(3) + warning = warnings.Errs[3] c.Check(warning, ErrorMatches, `error with secure boot policy \(PCR7\) measurements: deployed mode should be enabled in order to generate secure boot profiles`) c.Check(errors.Is(warning, ErrNoDeployedMode), testutil.IsTrue) } @@ -1909,8 +1910,8 @@ func (s *runChecksSuite) TestRunChecksBadInvalidPCR0Value(c *C) { flags: PlatformFirmwareProfileSupportRequired, }) c.Check(err, ErrorMatches, `error with TCG log: 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_SHA512: the PCR bank is missing from the TCG log. +- TPM_ALG_SHA384: the PCR bank is missing from the TCG log. - TPM_ALG_SHA256\(PCR0\): PCR value mismatch \(actual from TPM 0xe9995745ca25279ec699688b70488116fe4d9f053cb0991dd71e82e7edfa66b5, reconstructed from log 0xa6602a7a403068b5556e78cc3f5b00c9c76d33d514093ca9b584dce7590e6c69\). `) var te *TCGLogError @@ -1939,8 +1940,8 @@ func (s *runChecksSuite) TestRunChecksBadInvalidPCR2Value(c *C) { flags: DriversAndAppsProfileSupportRequired, }) c.Check(err, ErrorMatches, `error with TCG log: 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_SHA512: the PCR bank is missing from the TCG log. +- TPM_ALG_SHA384: the PCR bank is missing from the TCG log. - TPM_ALG_SHA256\(PCR2\): PCR value mismatch \(actual from TPM 0xfa734a6a4d262d7405d47d48c0a1b127229ca808032555ad919ed5dd7c1f6519, reconstructed from log 0x3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969\). `) var te *TCGLogError @@ -1969,8 +1970,8 @@ func (s *runChecksSuite) TestRunChecksBadInvalidPCR4Value(c *C) { flags: BootManagerCodeProfileSupportRequired, }) c.Check(err, ErrorMatches, `error with TCG log: 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_SHA512: the PCR bank is missing from the TCG log. +- TPM_ALG_SHA384: the PCR bank is missing from the TCG log. - TPM_ALG_SHA256\(PCR4\): PCR value mismatch \(actual from TPM 0x1c93930d6b26232e061eaa33ecf6341fae63ce598a0c6a26ee96a0828639c044, reconstructed from log 0x4bc74f3ffe49b4dd275c9f475887b68193e2db8348d72e1c3c9099c2dcfa85b0\). `) var te *TCGLogError @@ -1999,8 +2000,8 @@ func (s *runChecksSuite) TestRunChecksBadInvalidPCR7Value(c *C) { flags: SecureBootPolicyProfileSupportRequired, }) c.Check(err, ErrorMatches, `error with TCG log: 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_SHA512: the PCR bank is missing from the TCG log. +- TPM_ALG_SHA384: the PCR bank is missing from the TCG log. - TPM_ALG_SHA256\(PCR7\): PCR value mismatch \(actual from TPM 0xdf7b5d709755f1bd7142dd2f8c2d1195fc6b4dab5c78d41daf5c795da55db5f2, reconstructed from log 0xafc99bd8b298ea9b70d2796cb0ca22fe2b70d784691a1cae2aa3ba55edc365dc\). `) var te *TCGLogError @@ -2053,9 +2054,9 @@ C7E003CB `) var rce *RunChecksErrors c.Assert(errors.As(err, &rce), testutil.IsTrue) - c.Assert(rce.NumErrors(), Equals, 1) + c.Assert(rce.Errs, HasLen, 1) - err = rce.UnwrapError(0) + err = rce.Errs[0] var pfe *PlatformFirmwareProtectionError c.Check(errors.As(err, &pfe), testutil.IsTrue) } @@ -2126,9 +2127,9 @@ C7E003CB var rce *RunChecksErrors c.Assert(errors.As(err, &rce), testutil.IsTrue) - c.Assert(rce.NumErrors(), Equals, 1) + c.Assert(rce.Errs, HasLen, 1) - err = rce.UnwrapError(0) + err = rce.Errs[0] var pce *PlatformConfigPCRError c.Check(errors.As(err, &pce), testutil.IsTrue) } @@ -2199,9 +2200,9 @@ C7E003CB var rce *RunChecksErrors c.Assert(errors.As(err, &rce), testutil.IsTrue) - c.Assert(rce.NumErrors(), Equals, 1) + c.Assert(rce.Errs, HasLen, 1) - err = rce.UnwrapError(0) + err = rce.Errs[0] var dce *DriversAndAppsConfigPCRError c.Check(errors.As(err, &dce), testutil.IsTrue) } @@ -2272,9 +2273,9 @@ C7E003CB var rce *RunChecksErrors c.Assert(errors.As(err, &rce), testutil.IsTrue) - c.Assert(rce.NumErrors(), Equals, 1) + c.Assert(rce.Errs, HasLen, 1) - err = rce.UnwrapError(0) + err = rce.Errs[0] var bmce *BootManagerConfigPCRError c.Check(errors.As(err, &bmce), testutil.IsTrue) } @@ -2347,9 +2348,9 @@ C7E003CB var rce *RunChecksErrors c.Assert(errors.As(err, &rce), testutil.IsTrue) - c.Assert(rce.NumErrors(), Equals, 1) + c.Assert(rce.Errs, HasLen, 1) - err = rce.UnwrapError(0) + err = rce.Errs[0] c.Check(errors.Is(err, ErrVARSuppliedDriversPresent), testutil.IsTrue) } @@ -2421,9 +2422,9 @@ C7E003CB var rce *RunChecksErrors c.Assert(errors.As(err, &rce), testutil.IsTrue) - c.Assert(rce.NumErrors(), Equals, 1) + c.Assert(rce.Errs, HasLen, 1) - err = rce.UnwrapError(0) + err = rce.Errs[0] c.Check(errors.Is(err, ErrSysPrepApplicationsPresent), testutil.IsTrue) } @@ -2495,9 +2496,9 @@ C7E003CB var rce *RunChecksErrors c.Assert(errors.As(err, &rce), testutil.IsTrue) - c.Assert(rce.NumErrors(), Equals, 1) + c.Assert(rce.Errs, HasLen, 1) - err = rce.UnwrapError(0) + err = rce.Errs[0] c.Check(errors.Is(err, ErrAbsoluteComputraceActive), testutil.IsTrue) } @@ -2567,9 +2568,9 @@ C7E003CB var rce *RunChecksErrors c.Assert(errors.As(err, &rce), testutil.IsTrue) - c.Assert(rce.NumErrors(), Equals, 1) + c.Assert(rce.Errs, HasLen, 1) - err = rce.UnwrapError(0) + err = rce.Errs[0] c.Check(errors.Is(err, ErrNotAllBootManagerCodeDigestsVerified), testutil.IsTrue) } @@ -2644,10 +2645,10 @@ C7E003CB var rce *RunChecksErrors c.Assert(errors.As(err, &rce), testutil.IsTrue) - c.Assert(rce.NumErrors(), Equals, 2) + c.Assert(rce.Errs, HasLen, 2) - c.Check(errors.Is(rce.UnwrapError(0), ErrWeakSecureBootAlgorithmDetected), testutil.IsTrue) - c.Check(errors.Is(rce.UnwrapError(1), ErrPreOSVerificationUsingDigests), testutil.IsTrue) + c.Check(errors.Is(rce.Errs[0], ErrWeakSecureBootAlgorithmDetected), testutil.IsTrue) + c.Check(errors.Is(rce.Errs[1], ErrPreOSVerificationUsingDigests), testutil.IsTrue) } func (s *runChecksSuite) TestRunChecksBadPreOSVerificationUsingDigests(c *C) { @@ -2720,9 +2721,9 @@ C7E003CB var rce *RunChecksErrors c.Assert(errors.As(err, &rce), testutil.IsTrue) - c.Assert(rce.NumErrors(), Equals, 1) + c.Assert(rce.Errs, HasLen, 1) - c.Check(errors.Is(rce.UnwrapError(0), ErrPreOSVerificationUsingDigests), testutil.IsTrue) + c.Check(errors.Is(rce.Errs[0], ErrPreOSVerificationUsingDigests), testutil.IsTrue) } func (s *runChecksSuite) TestRunChecksBadNoBootManagerCodeProfileSupport(c *C) { @@ -2796,9 +2797,9 @@ C7E003CB var rce *RunChecksErrors c.Assert(errors.As(err, &rce), testutil.IsTrue) - c.Assert(rce.NumErrors(), Equals, 1) + c.Assert(rce.Errs, HasLen, 1) - err = rce.UnwrapError(0) + err = rce.Errs[0] var bce *BootManagerCodePCRError c.Check(errors.As(err, &bce), testutil.IsTrue) } @@ -2869,9 +2870,9 @@ C7E003CB var rce *RunChecksErrors c.Assert(errors.As(err, &rce), testutil.IsTrue) - c.Assert(rce.NumErrors(), Equals, 1) + c.Assert(rce.Errs, HasLen, 1) - err = rce.UnwrapError(0) + err = rce.Errs[0] var sbe *SecureBootPolicyPCRError c.Check(errors.As(err, &sbe), testutil.IsTrue) c.Check(errors.Is(sbe, ErrNoDeployedMode), testutil.IsTrue) @@ -2939,15 +2940,81 @@ C7E003CB }, expectedPcrAlg: tpm2.HashAlgorithmSHA256, }) - c.Logf("%v", err) c.Check(err, ErrorMatches, `one or more errors detected: - access to the discrete TPM's startup locality is available to platform firmware and privileged OS code, preventing any mitigation against reset attacks `) var rce *RunChecksErrors c.Assert(errors.As(err, &rce), testutil.IsTrue) - c.Assert(rce.NumErrors(), Equals, 1) + c.Assert(rce.Errs, HasLen, 1) - err = rce.UnwrapError(0) + err = rce.Errs[0] c.Check(errors.Is(err, ErrTPMStartupLocalityNotProtected), testutil.IsTrue) } + +func (s *runChecksSuite) TestRunChecksBadEmptySHA384(c *C) { + meiAttrs := map[string][]byte{ + "fw_ver": []byte(`0:16.1.27.2176 +0:16.1.27.2176 +0:16.0.15.1624 +`), + "fw_status": []byte(`94000245 +09F10506 +00000020 +00004000 +00041F03 +C7E003CB +`), + } + devices := map[string][]internal_efi.SysfsDevice{ + "iommu": []internal_efi.SysfsDevice{ + efitest.NewMockSysfsDevice("dmar0", "/sys/devices/virtual/iommu/dmar0", "iommu", nil), + efitest.NewMockSysfsDevice("dmar1", "/sys/devices/virtual/iommu/dmar1", "iommu", nil), + }, + "mei": []internal_efi.SysfsDevice{ + efitest.NewMockSysfsDevice("mei0", "/sys/devices/pci0000:00/0000:00:16.0/mei/mei0", "mei", meiAttrs), + }, + } + + _, err := s.testRunChecks(c, &testRunChecksParams{ + env: efitest.NewMockHostEnvironmentWithOpts( + efitest.WithVirtMode(internal_efi.VirtModeNone, internal_efi.DetectVirtModeAll), + efitest.WithTPMDevice(tpm2_testutil.NewTransportBackedDevice(s.Transport, false)), + efitest.WithLog(efitest.NewLog(c, &efitest.LogOptions{Algorithms: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256}})), + efitest.WithAMD64Environment("GenuineIntel", []uint64{cpuid.SDBG, cpuid.SMX}, 4, map[uint32]uint64{0xc80: 0x40000000}), + efitest.WithSysfsDevices(devices), + efitest.WithMockVars(efitest.MockVars{ + {Name: "AuditMode", GUID: efi.GlobalVariable}: &efitest.VarEntry{Attrs: efi.AttributeNonVolatile | efi.AttributeBootserviceAccess | efi.AttributeRuntimeAccess, Payload: []byte{0x0}}, + {Name: "BootCurrent", GUID: efi.GlobalVariable}: &efitest.VarEntry{Attrs: efi.AttributeBootserviceAccess | efi.AttributeRuntimeAccess, Payload: []byte{0x3, 0x0}}, + {Name: "BootOptionSupport", GUID: efi.GlobalVariable}: &efitest.VarEntry{Attrs: efi.AttributeBootserviceAccess | efi.AttributeRuntimeAccess, Payload: []byte{0x13, 0x03, 0x00, 0x00}}, + {Name: "DeployedMode", GUID: efi.GlobalVariable}: &efitest.VarEntry{Attrs: efi.AttributeNonVolatile | efi.AttributeBootserviceAccess | efi.AttributeRuntimeAccess, Payload: []byte{0x1}}, + {Name: "SetupMode", GUID: efi.GlobalVariable}: &efitest.VarEntry{Attrs: efi.AttributeBootserviceAccess | efi.AttributeRuntimeAccess, Payload: []byte{0x0}}, + {Name: "OsIndicationsSupported", GUID: efi.GlobalVariable}: &efitest.VarEntry{Attrs: efi.AttributeBootserviceAccess | efi.AttributeRuntimeAccess, Payload: []byte{0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + }.SetSecureBoot(true).SetPK(c, efitest.NewSignatureListX509(c, snakeoilCert, efi.MakeGUID(0x03f66fa4, 0x5eee, 0x479c, 0xa408, [...]uint8{0xc4, 0xdc, 0x0a, 0x33, 0xfc, 0xde})))), + ), + tpmPropertyModifiers: map[tpm2.Property]uint32{ + tpm2.PropertyNVCountersMax: 0, + tpm2.PropertyPSFamilyIndicator: 1, + tpm2.PropertyManufacturer: uint32(tpm2.TPMManufacturerINTC), + }, + enabledBanks: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256, tpm2.HashAlgorithmSHA384}, + loadedImages: []secboot_efi.Image{ + &mockImage{ + contents: []byte("mock shim executable"), + digest: testutil.DecodeHexString(c, "25e1b08db2f31ff5f5d2ea53e1a1e8fda6e1d81af4f26a7908071f1dec8611b7"), + signatures: []*efi.WinCertificateAuthenticode{ + efitest.ReadWinCertificateAuthenticodeDetached(c, shimUbuntuSig4), + }, + }, + &mockImage{contents: []byte("mock grub executable"), digest: testutil.DecodeHexString(c, "d5a9780e9f6a43c2e53fe9fda547be77f7783f31aea8013783242b040ff21dc0")}, + &mockImage{contents: []byte("mock kernel executable"), digest: testutil.DecodeHexString(c, "2ddfbd91fa1698b0d133c38ba90dbba76c9e08371ff83d03b5fb4c2e56d7e81f")}, + }, + expectedPcrAlg: tpm2.HashAlgorithmSHA256, + expectedUsedSecureBootCAs: []*X509CertificateID{NewX509CertificateID(testutil.ParseCertificate(c, msUefiCACert))}, + expectedFlags: NoPlatformConfigProfileSupport | NoDriversAndAppsConfigProfileSupport | NoBootManagerConfigProfileSupport, + }) + c.Assert(err, ErrorMatches, `the PCR bank for TPM_ALG_SHA384 is missing from the TCG log but is active on the TPM`) + + var be *EmptyPCRBankError + c.Check(errors.As(err, &be), testutil.IsTrue) +} diff --git a/efi/preinstall/errors.go b/efi/preinstall/errors.go index 3f1906e2..ffdb63ad 100644 --- a/efi/preinstall/errors.go +++ b/efi/preinstall/errors.go @@ -50,40 +50,23 @@ func indentLines(n int, str string) string { // RunChecksErrors may be returned unwrapped from [RunChecks] containing a collection // of errors found during the process of running various tests on the platform. -// It provides a mechanism to access each individual error. +// It provides a mechanism to access each individual error. This is used as an alternative +// to aborting early, in order for the caller to gather as much information as possible. type RunChecksErrors struct { - errs []error + Errs []error // All of the errors collected during the execution of RunChecks. } func (e *RunChecksErrors) Error() string { w := new(bytes.Buffer) fmt.Fprintf(w, "one or more errors detected:\n") - for _, err := range e.errs { + for _, err := range e.Errs { fmt.Fprintf(w, "%s\n", indentLines(2, "- "+err.Error())) } return w.String() } -// NumErrors returns the number of errors. -func (e *RunChecksErrors) NumErrors() int { - return len(e.errs) -} - -// UnwrapError unwraps the specific error at the specified index (zero-indexed). -func (e *RunChecksErrors) UnwrapError(n int) error { - if n > len(e.errs)-1 { - return errors.New("error index out of range") - } - return e.errs[n] -} - -// Errors returns all errors. -func (e *RunChecksErrors) Errors() []error { - return e.errs -} - func (e *RunChecksErrors) addErr(err error) { - e.errs = append(e.errs, err) + e.Errs = append(e.Errs, err) } var ( @@ -225,7 +208,7 @@ var ( ErrTPMDisabled = errors.New("TPM2 device is present but is currently disabled by the platform firmware") ) -// TPMHierarchyOwnedError is returned wrapped in TPM2DeviceError if the authorization value +// TPMHierarchyOwnedError is returned wrapped in [TPM2DeviceError] if the authorization value // for the specified hierarchy is set, but the PostInstallChecks flag isn't set. If a // hierarchy is owned during pre-install, the TPM will most likely need to be cleared. type TPM2HierarchyOwnedError struct { @@ -264,13 +247,48 @@ func (e *TCGLogError) Unwrap() error { return e.err } +var ( + // ErrPCRBankMissingFromLog may be returned wrapped by NoSuitablePCRAlgorithmError + // in the event where a PCR bank does not exist in the TCG log. It may be obtained from + // the BankErrs field. + ErrPCRBankMissingFromLog = errors.New("the PCR bank is missing from the TCG log") +) + +// EmptyPCRBankError may be returned unwrapped in the event where a PCR bank seems +// to be active but not extended by firmware and not present in the log. This doesn't matter so +// much for FDE because we can select a good bank, but is a serious firmware bug for any scenario +// that requires remote attestation, because it permits an entire trusted computing environment to +// be spoofed by an adversary in software. +// +// This error can be ignored by passing the PermitEmptyPCRBanks flag to [RunChecks]. This is +// generally ok, as long as the device is not going to be used for any kind of remote attestation. +type EmptyPCRBankError struct { + Alg tpm2.HashAlgorithmId +} + +func (e *EmptyPCRBankError) Error() string { + return fmt.Sprintf("the PCR bank for %v is missing from the TCG log but is active on the TPM", e.Alg) +} + +// PCRValueMismatchError may be returned wrapped by NoSuitablePCRAlgorithmError for a specific +// PCR in the event where there is a mismatch between the actual PCR value and the value reconstructed +// from the TCG log. It may be obtained from the PCRErrs field. +type PCRValueMismatchError struct { + PCRValue tpm2.Digest // The PCR value obtained from the TPM. + LogValue tpm2.Digest // The expected value reconstructed from the TCG log. +} + +func (e *PCRValueMismatchError) Error() string { + return fmt.Sprintf("PCR value mismatch (actual from TPM %#x, reconstructed from log %#x)", e.PCRValue, e.LogValue) +} + // NoSuitablePCRAlgorithmError is returned wrapped in [TCGLogError] 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 wraps each individual error // that occurred and provides access to them. type NoSuitablePCRAlgorithmError struct { - bankErrs map[tpm2.HashAlgorithmId]error // bankErrs apply to an entire PCR bank - pcrErrs map[tpm2.HashAlgorithmId]map[tpm2.Handle]error // pcrErrs apply to a single PCR in a single bank + BankErrs map[tpm2.HashAlgorithmId]error // BankErrs apply to an entire PCR bank + PCRErrs map[tpm2.HashAlgorithmId]map[tpm2.Handle]error // PCRErrs apply to a single PCR in a single bank } func (e *NoSuitablePCRAlgorithmError) Error() string { @@ -282,13 +300,13 @@ func (e *NoSuitablePCRAlgorithmError) Error() string { // go maps don't guarantee when iterating over keys). for _, alg := range supportedAlgs { // Print error for this PCR bank first, if there is one. - if err, isErr := e.bankErrs[alg]; isErr { + if err, isErr := e.BankErrs[alg]; isErr { // We have a general error for this PCR bank fmt.Fprintf(w, "- %v: %v.\n", alg, err) } // Then print errors associated with individual PCRs in this bank. - pcrErrs, hasPcrErrs := e.pcrErrs[alg] + pcrErrs, hasPcrErrs := e.PCRErrs[alg] if !hasPcrErrs { // We have no individual PCR errors for this bank continue @@ -303,36 +321,14 @@ func (e *NoSuitablePCRAlgorithmError) Error() string { 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 + 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() + e.PCRErrs[results.Alg] = results.pcrErrs() } // Errors related to platform firmware PCR checks diff --git a/efi/preinstall/result.go b/efi/preinstall/result.go index bbc04bd8..78a62704 100644 --- a/efi/preinstall/result.go +++ b/efi/preinstall/result.go @@ -486,7 +486,8 @@ type CheckResult struct { Flags CheckResultFlags // Warnings contains any non-fatal errors that were detected when running the tests - // on the platform. Note that this field is not serialized. + // on the current platform with the specified configuration. Note that this field is + // not serialized. Warnings *RunChecksErrors } @@ -514,10 +515,10 @@ func (r CheckResult) String() string { } } fmt.Fprintf(w, "- Flags: %s\n", strings.Join(flags, ",")) - if r.Warnings != nil && r.Warnings.NumErrors() > 0 { + if r.Warnings != nil && len(r.Warnings.Errs) > 0 { fmt.Fprintf(w, "- Warnings:\n") - for i := 0; i < r.Warnings.NumErrors(); i++ { - fmt.Fprintf(w, "%s\n", indentLines(2, "- "+r.Warnings.UnwrapError(i).Error())) + for i := 0; i < len(r.Warnings.Errs); i++ { + fmt.Fprintf(w, "%s\n", indentLines(2, "- "+r.Warnings.Errs[i].Error())) } } return w.String()