Skip to content

Commit

Permalink
preinstall: Add CheckResult and WithAutoTCGPCRProfile APIs
Browse files Browse the repository at this point in the history
CheckResult is returned from RunChecks on successful completion. It is
JSON serializable and intended to be supplied later on to
WithAutoTCGPCRProfile along with some user customization flags (defined
by PCRProfileOptionsFlags) in order to generate an option that can be
supplied to secboot_efi.AddPCRProfile.

Note that some user options don't work yet because of missing PCR
support, although these limitations will be addressed later. Even so,
some options may still fail depending on the CheckResult flags.
  • Loading branch information
chrisccoulson committed Nov 13, 2024
1 parent c281620 commit 42dfed0
Show file tree
Hide file tree
Showing 16 changed files with 2,165 additions and 80 deletions.
10 changes: 5 additions & 5 deletions efi/preinstall/check_pcr7.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ var errNoSignerWithTrustAnchor = errors.New("image has no signer associated with
// signature where the signer chains to one of the supplied authorities. As with signature
// verification in EFI, it tests each of the image's signatures against each of the supplied
// authorities in turn, and will return the first signature that chains to the first authority.
func extractSignerWithTrustAnchorFromImage(authorities []*x509.Certificate, image secboot_efi.Image) (*x509.Certificate, error) {
func extractSignerWithTrustAnchorFromImage(authorities []*X509CertificateID, image secboot_efi.Image) (*x509.Certificate, error) {
r, err := image.Open()
if err != nil {
return nil, fmt.Errorf("cannot open image: %w", err)
Expand All @@ -177,7 +177,7 @@ func extractSignerWithTrustAnchorFromImage(authorities []*x509.Certificate, imag
var foundSig *efi.WinCertificateAuthenticode
for _, cert := range authorities {
for _, sig := range sigs {
if sig.CertLikelyTrustAnchor(cert) {
if sig.CertWithIDLikelyTrustAnchor(cert) {
foundSig = sig
break
}
Expand Down Expand Up @@ -295,7 +295,7 @@ const (

// secureBootPolicyResult is the result of a successful call to checkSecureBootPolicyMeasurementsAndObtainAuthorities.
type secureBootPolicyResult struct {
UsedAuthorities []*x509.Certificate // CA's used to authenticate boot components.
UsedAuthorities []*X509CertificateID // CA's used to authenticate boot components.
Flags secureBootPolicyResultFlags
}

Expand Down Expand Up @@ -582,7 +582,7 @@ NextEvent:
if err != nil {
return nil, fmt.Errorf("cannot decode X.509 certificate associated with EV_EFI_VARIABLE_AUTHORITY event in pre-OS phase: %w", err)
}
result.UsedAuthorities = append(result.UsedAuthorities, cert)
result.UsedAuthorities = append(result.UsedAuthorities, newX509CertificateID(cert))
} else {
// Hopefully there shouldn't be any components being authenticated by a digest. We don't support this for
// OS components but this could be allowed for pre-OS, but it would make PCR7 incredibly fragile.
Expand Down Expand Up @@ -691,7 +691,7 @@ NextEvent:
if err != nil {
return nil, fmt.Errorf("cannot decode X.509 certificate associated with EV_EFI_VARIABLE_AUTHORITY event in OS-present phase: %w", err)
}
result.UsedAuthorities = append(result.UsedAuthorities, cert)
result.UsedAuthorities = append(result.UsedAuthorities, newX509CertificateID(cert))
case tcglog.EventTypeSeparator:
// ok
default:
Expand Down
37 changes: 18 additions & 19 deletions efi/preinstall/check_pcr7_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ package preinstall_test
import (
"context"
"crypto"
"crypto/x509"
"errors"
"io"

Expand Down Expand Up @@ -58,7 +57,7 @@ type testCheckSecureBootPolicyMeasurementsAndObtainAuthoritiesParams struct {
iblImage secboot_efi.Image

expectedFlags SecureBootPolicyResultFlags
expectedUsedAuthorities []*x509.Certificate
expectedUsedAuthorities []*X509CertificateID
}

func (s *pcr7Suite) testCheckSecureBootPolicyMeasurementsAndObtainAuthorities(c *C, params *testCheckSecureBootPolicyMeasurementsAndObtainAuthoritiesParams) error {
Expand Down Expand Up @@ -93,7 +92,7 @@ func (s *pcr7Suite) testCheckSecureBootPolicyMeasurementsAndObtainAuthorities(c
c.Check(result.Flags, Equals, params.expectedFlags)
c.Assert(result.UsedAuthorities, HasLen, len(params.expectedUsedAuthorities))
for i, authority := range result.UsedAuthorities {
c.Check(authority.Equal(params.expectedUsedAuthorities[i]), testutil.IsTrue)
c.Check(authority, DeepEquals, params.expectedUsedAuthorities[i])
}
return nil
}
Expand All @@ -118,8 +117,8 @@ func (s *pcr7Suite) TestCheckSecureBootPolicyMeasurementsAndObtainAuthoritiesGoo
},
},
expectedFlags: SecureBootPolicyResultFlags(0),
expectedUsedAuthorities: []*x509.Certificate{
testutil.ParseCertificate(c, msUefiCACert),
expectedUsedAuthorities: []*X509CertificateID{
NewX509CertificateID(testutil.ParseCertificate(c, msUefiCACert)),
},
})
c.Check(err, IsNil)
Expand All @@ -145,8 +144,8 @@ func (s *pcr7Suite) TestCheckSecureBootPolicyMeasurementsAndObtainAuthoritiesGoo
},
},
expectedFlags: SecureBootPolicyResultFlags(0),
expectedUsedAuthorities: []*x509.Certificate{
testutil.ParseCertificate(c, msUefiCACert),
expectedUsedAuthorities: []*X509CertificateID{
NewX509CertificateID(testutil.ParseCertificate(c, msUefiCACert)),
},
})
c.Check(err, IsNil)
Expand Down Expand Up @@ -175,8 +174,8 @@ func (s *pcr7Suite) TestCheckSecureBootPolicyMeasurementsAndObtainAuthoritiesGoo
},
},
expectedFlags: SecureBootPolicyResultFlags(0),
expectedUsedAuthorities: []*x509.Certificate{
testutil.ParseCertificate(c, msUefiCACert),
expectedUsedAuthorities: []*X509CertificateID{
NewX509CertificateID(testutil.ParseCertificate(c, msUefiCACert)),
},
})
c.Check(err, IsNil)
Expand Down Expand Up @@ -206,8 +205,8 @@ func (s *pcr7Suite) TestCheckSecureBootPolicyMeasurementsAndObtainAuthoritiesGoo
},
},
expectedFlags: SecureBootPreOSVerificationIncludesDigest,
expectedUsedAuthorities: []*x509.Certificate{
testutil.ParseCertificate(c, msUefiCACert),
expectedUsedAuthorities: []*X509CertificateID{
NewX509CertificateID(testutil.ParseCertificate(c, msUefiCACert)),
},
})
c.Check(err, IsNil)
Expand Down Expand Up @@ -237,8 +236,8 @@ func (s *pcr7Suite) TestCheckSecureBootPolicyMeasurementsAndObtainAuthoritiesGoo
},
},
expectedFlags: SecureBootIncludesWeakAlg | SecureBootPreOSVerificationIncludesDigest,
expectedUsedAuthorities: []*x509.Certificate{
testutil.ParseCertificate(c, msUefiCACert),
expectedUsedAuthorities: []*X509CertificateID{
NewX509CertificateID(testutil.ParseCertificate(c, msUefiCACert)),
},
})
c.Check(err, IsNil)
Expand Down Expand Up @@ -267,8 +266,8 @@ func (s *pcr7Suite) TestCheckSecureBootPolicyMeasurementsAndObtainAuthoritiesGoo
},
},
expectedFlags: SecureBootPolicyResultFlags(0),
expectedUsedAuthorities: []*x509.Certificate{
testutil.ParseCertificate(c, msUefiCACert),
expectedUsedAuthorities: []*X509CertificateID{
NewX509CertificateID(testutil.ParseCertificate(c, msUefiCACert)),
},
})
c.Check(err, IsNil)
Expand Down Expand Up @@ -297,8 +296,8 @@ func (s *pcr7Suite) TestCheckSecureBootPolicyMeasurementsAndObtainAuthoritiesGoo
},
},
expectedFlags: SecureBootPolicyResultFlags(0),
expectedUsedAuthorities: []*x509.Certificate{
testutil.ParseCertificate(c, msUefiCACert),
expectedUsedAuthorities: []*X509CertificateID{
NewX509CertificateID(testutil.ParseCertificate(c, msUefiCACert)),
},
})
c.Check(err, IsNil)
Expand All @@ -322,8 +321,8 @@ func (s *pcr7Suite) TestCheckSecureBootPolicyMeasurementsAndObtainAuthoritiesGoo
},
},
expectedFlags: SecureBootPolicyResultFlags(0),
expectedUsedAuthorities: []*x509.Certificate{
testutil.ParseCertificate(c, msUefiCACert),
expectedUsedAuthorities: []*X509CertificateID{
NewX509CertificateID(testutil.ParseCertificate(c, msUefiCACert)),
},
})
c.Check(err, IsNil)
Expand Down
13 changes: 9 additions & 4 deletions efi/preinstall/check_tcglog.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down
34 changes: 19 additions & 15 deletions efi/preinstall/check_tcglog_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,7 @@ func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankOldFirmware(c *C) {
expectedAlg: tpm2.HashAlgorithmSHA256,
})
}

func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankUnexpectedStartupLocality(c *C) {
// Test with a StartupLocality event in PCR1
s.allocatePCRBanks(c, tpm2.HashAlgorithmSHA256)
Expand Down Expand Up @@ -395,22 +396,25 @@ func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankUnexpectedStartupLocal
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_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\).
`)
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.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) {
Expand Down Expand Up @@ -471,8 +475,8 @@ func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankOutOfPlaceStartupLocal
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_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
Expand Down Expand Up @@ -514,8 +518,8 @@ func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankInvalidStartupLocality
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_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
Expand All @@ -540,8 +544,8 @@ func (s *tcglogSuite) TestCheckFirmwareLogAndChoosePCRBankPCRMismatchMandatory(c
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_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
Expand Down
Loading

0 comments on commit 42dfed0

Please sign in to comment.