Merge branch 'master' into meparser
This commit is contained in:
commit
91f35e7dd3
|
@ -13,7 +13,7 @@ jobs:
|
|||
- checkout
|
||||
- run: sudo apt install -y golint
|
||||
# specify any bash command here prefixed with `run: `
|
||||
- run: GO111MODULE=off go get github.com/tjfoc/gmsm/sm2 github.com/dustin/go-humanize && go run ./pkg/intel/metadata/manifest/common/manifestcodegen/cmd/manifestcodegen -check ./pkg/intel/metadata/manifest ./pkg/intel/metadata/manifest/bootpolicy ./pkg/intel/metadata/manifest/key
|
||||
- run: GO111MODULE=off go get github.com/tjfoc/gmsm/sm2 github.com/dustin/go-humanize github.com/linuxboot/fiano/pkg/uefi && go run ./pkg/intel/metadata/manifest/common/manifestcodegen/cmd/manifestcodegen -check ./pkg/intel/metadata/manifest ./pkg/intel/metadata/manifest/bootpolicy ./pkg/intel/metadata/manifest/key
|
||||
- run: if [ "$(gofmt -l .)" != "" ]; then exit 1; fi
|
||||
- run: golint -set_exit_status ./pkg/test
|
||||
- run: golint -set_exit_status ./pkg/tools
|
||||
|
|
|
@ -82,6 +82,7 @@ func (cmd Command) Execute(args []string) {
|
|||
}
|
||||
imagePath := args[0]
|
||||
|
||||
fianoUEFI.DisableDecompression = false
|
||||
firmware, err := uefi.ParseUEFIFirmwareFile(imagePath)
|
||||
assertNoError(err)
|
||||
|
||||
|
|
|
@ -3,7 +3,12 @@
|
|||
package bootpolicy
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
"github.com/9elements/converged-security-suite/v2/pkg/intel/metadata/manifest"
|
||||
"github.com/9elements/converged-security-suite/v2/pkg/uefi/consts"
|
||||
"github.com/linuxboot/fiano/pkg/uefi"
|
||||
)
|
||||
|
||||
// StructInfo is the common header of any element.
|
||||
|
@ -27,3 +32,28 @@ type Manifest struct {
|
|||
func (bpm Manifest) StructInfo() StructInfo {
|
||||
return bpm.BPMH.StructInfo
|
||||
}
|
||||
|
||||
func (bpm *Manifest) ValidateIBBs(firmware uefi.Firmware) error {
|
||||
if len(bpm.SE[0].DigestList.List) == 0 {
|
||||
return fmt.Errorf("no IBB hashes")
|
||||
}
|
||||
|
||||
for _, digest := range bpm.SE[0].DigestList.List {
|
||||
h, err := digest.HashAlg.Hash()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid hash function: %v", digest.HashAlg)
|
||||
}
|
||||
|
||||
for _, seg := range bpm.SE[0].IBBSegments {
|
||||
startIdx := consts.CalculateOffsetFromPhysAddr(uint64(seg.Base), uint64(len(firmware.Buf())))
|
||||
h.Write(firmware.Buf()[startIdx : startIdx+uint64(seg.Size)])
|
||||
}
|
||||
hashValue := h.Sum(nil)
|
||||
|
||||
if bytes.Compare(hashValue, digest.HashBuffer) != 0 {
|
||||
return fmt.Errorf("IBB %s hash mismatch: %X != %X", digest.HashAlg, hashValue, digest.HashBuffer)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -4,14 +4,13 @@ package manifest
|
|||
|
||||
import (
|
||||
"crypto"
|
||||
"fmt"
|
||||
"hash"
|
||||
"strings"
|
||||
|
||||
// Required for hash.Hash return in hashInfo struct
|
||||
_ "crypto/sha1"
|
||||
_ "crypto/sha256"
|
||||
_ "crypto/sha512"
|
||||
"fmt"
|
||||
"hash"
|
||||
"strings"
|
||||
|
||||
"github.com/tjfoc/gmsm/sm3"
|
||||
)
|
||||
|
@ -41,14 +40,14 @@ const (
|
|||
)
|
||||
|
||||
var hashInfo = []struct {
|
||||
alg Algorithm
|
||||
hash hash.Hash
|
||||
alg Algorithm
|
||||
hashFactory func() hash.Hash
|
||||
}{
|
||||
{AlgSHA1, crypto.SHA1.New()},
|
||||
{AlgSHA256, crypto.SHA256.New()},
|
||||
{AlgSHA384, crypto.SHA384.New()},
|
||||
{AlgSHA512, crypto.SHA512.New()},
|
||||
{AlgSM3_256, sm3.New()},
|
||||
{AlgSHA1, crypto.SHA1.New},
|
||||
{AlgSHA256, crypto.SHA256.New},
|
||||
{AlgSHA384, crypto.SHA384.New},
|
||||
{AlgSHA512, crypto.SHA512.New},
|
||||
{AlgSM3_256, sm3.New},
|
||||
}
|
||||
|
||||
// IsNull returns true if a is AlgNull or zero (unset).
|
||||
|
@ -61,10 +60,10 @@ func (a Algorithm) IsNull() bool {
|
|||
func (a Algorithm) Hash() (hash.Hash, error) {
|
||||
for _, info := range hashInfo {
|
||||
if info.alg == a {
|
||||
if info.hash == nil {
|
||||
if info.hashFactory == nil {
|
||||
return nil, fmt.Errorf("go hash algorithm #%snot available", info.alg.String())
|
||||
}
|
||||
return info.hash, nil
|
||||
return info.hashFactory(), nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("hash algorithm not supported: %s", a.String())
|
||||
|
|
|
@ -202,6 +202,11 @@ func (k *Key) PrintKMPubKey(kmAlg Algorithm) error {
|
|||
}
|
||||
hash.Write(buf.Bytes())
|
||||
fmt.Printf(" Key Manifest Pubkey Hash: 0x%x\n", hash.Sum(nil))
|
||||
// On SKL and KBL the exponent is not included in the KM hash
|
||||
buf.Truncate(len(k.Data[4:]))
|
||||
hash.Reset()
|
||||
hash.Write(buf.Bytes())
|
||||
fmt.Printf(" Key Manifest Pubkey Hash (Skylake and Kabylake only): 0x%x\n", hash.Sum(nil))
|
||||
} else {
|
||||
fmt.Printf(" Key Manifest Pubkey Hash: Unsupported Algorithm\n")
|
||||
}
|
||||
|
|
|
@ -79,3 +79,11 @@ type ErrUnexpectedEventType struct {
|
|||
func (err ErrUnexpectedEventType) Error() string {
|
||||
return fmt.Sprintf("unexpected event type, reason: '%s'; event: '%#+v'", err.Reason, err.Event)
|
||||
}
|
||||
|
||||
// ErrNoSACM means no S-ACM was found.
|
||||
type ErrNoSACM struct{}
|
||||
|
||||
// Error implements interface `error`.
|
||||
func (err ErrNoSACM) Error() string {
|
||||
return fmt.Sprintf("S-ACM not found")
|
||||
}
|
||||
|
|
|
@ -91,14 +91,15 @@ func (f Flow) MeasurementIDs() MeasurementIDs {
|
|||
13 0 4 4 9069CA78E7450A285173431B3E52C5C25299E473 00000000 <- Separator
|
||||
*/
|
||||
return MeasurementIDs{
|
||||
MeasurementIDInit, // is fake measurement
|
||||
MeasurementIDInit, // is a fake measurement
|
||||
MeasurementIDACM, // is a fake measurement
|
||||
MeasurementIDPCR0_DATA,
|
||||
MeasurementIDPCDFirmwareVendorVersionData,
|
||||
MeasurementIDPCDFirmwareVendorVersionCode, // is fake measurement
|
||||
MeasurementIDPCDFirmwareVendorVersionCode, // is a fake measurement
|
||||
MeasurementIDDXE,
|
||||
MeasurementIDSeparator,
|
||||
MeasurementIDFITPointer, // is fake measurement
|
||||
MeasurementIDFITHeaders, // is fake measurement
|
||||
MeasurementIDFITPointer, // is a fake measurement
|
||||
MeasurementIDFITHeaders, // is a fake measurement
|
||||
}
|
||||
case FlowIntelLegacyTXTEnabled:
|
||||
// See also:
|
||||
|
@ -108,40 +109,42 @@ func (f Flow) MeasurementIDs() MeasurementIDs {
|
|||
// * https://www.trustedcomputinggroup.org/wp-content/uploads/PC-ClientSpecific_Platform_Profile_for_TPM_2p0_Systems_v21.pdf (Section 9.3.1)
|
||||
// * doc/log/ymm03.txt
|
||||
return MeasurementIDs{
|
||||
MeasurementIDInit, // is fake measurement
|
||||
MeasurementIDInit, // is a fake measurement
|
||||
MeasurementIDACM, // is a fake measurement
|
||||
MeasurementIDACMDate,
|
||||
MeasurementIDBIOSStartupModule,
|
||||
MeasurementIDSCRTMSeparator,
|
||||
MeasurementIDPCDFirmwareVendorVersionData,
|
||||
MeasurementIDPCDFirmwareVendorVersionCode, // is fake measurement
|
||||
MeasurementIDPCDFirmwareVendorVersionCode, // is a fake measurement
|
||||
MeasurementIDDXE,
|
||||
MeasurementIDSeparator,
|
||||
MeasurementIDFITPointer, // is fake measurement
|
||||
MeasurementIDFITHeaders, // is fake measurement
|
||||
MeasurementIDFITPointer, // is a fake measurement
|
||||
MeasurementIDFITHeaders, // is a fake measurement
|
||||
}
|
||||
case FlowIntelLegacyTXTEnabledTPM12:
|
||||
return MeasurementIDs{
|
||||
MeasurementIDInit, // is fake measurement
|
||||
MeasurementIDInit, // is a fake measurement
|
||||
MeasurementIDACM, // is a fake measurement
|
||||
MeasurementIDACMDateInPlace,
|
||||
MeasurementIDBIOSStartupModule,
|
||||
MeasurementIDPCDFirmwareVendorVersionData,
|
||||
MeasurementIDPCDFirmwareVendorVersionCode, // is fake measurement
|
||||
MeasurementIDPCDFirmwareVendorVersionCode, // is a fake measurement
|
||||
MeasurementIDDXE,
|
||||
MeasurementIDSeparator,
|
||||
MeasurementIDFITPointer, // is fake measurement
|
||||
MeasurementIDFITHeaders, // is fake measurement
|
||||
MeasurementIDFITPointer, // is a fake measurement
|
||||
MeasurementIDFITHeaders, // is a fake measurement
|
||||
}
|
||||
case FlowIntelLegacyTXTDisabled:
|
||||
return MeasurementIDs{
|
||||
MeasurementIDPCDFirmwareVendorVersionData,
|
||||
MeasurementIDPCDFirmwareVendorVersionCode, // is fake measurement
|
||||
MeasurementIDPCDFirmwareVendorVersionCode, // is a fake measurement
|
||||
MeasurementIDDXE,
|
||||
MeasurementIDSeparator,
|
||||
|
||||
// Also we include as fake measurements the byte ranges which a known
|
||||
// to be necessary to correctly parse the firmware.
|
||||
MeasurementIDFITPointer, // is fake measurement
|
||||
MeasurementIDFITHeaders, // is fake measurement
|
||||
MeasurementIDFITPointer, // is a fake measurement
|
||||
MeasurementIDFITHeaders, // is a fake measurement
|
||||
}
|
||||
}
|
||||
panic(fmt.Sprintf("should not happen: %v", f))
|
||||
|
|
|
@ -15,15 +15,39 @@ func MeasureInit() *Measurement {
|
|||
return NewStaticDataMeasurement(MeasurementIDInit, nil)
|
||||
}
|
||||
|
||||
func MeasureACM(fitEntries []fit.Entry) (*Measurement, error) {
|
||||
m := Measurement{
|
||||
ID: MeasurementIDACM,
|
||||
}
|
||||
|
||||
mErr := &errors.MultiError{}
|
||||
|
||||
for _, fitEntry := range fitEntries {
|
||||
switch fitEntry := fitEntry.(type) {
|
||||
case *fit.EntrySACM: // startup AC module entry
|
||||
mErr.Add(fitEntry.HeadersErrors...)
|
||||
m.Data = append(m.Data, *NewRangeDataChunk(0, fitEntry.GetDataOffset(), uint64(len(fitEntry.GetDataBytes()))))
|
||||
}
|
||||
}
|
||||
|
||||
if len(m.Data) == 0 {
|
||||
return nil, ErrNoSACM{}
|
||||
}
|
||||
|
||||
return &m, mErr.ReturnValue()
|
||||
}
|
||||
|
||||
func MeasureACMDate(fitEntries []fit.Entry) (*Measurement, error) {
|
||||
m := Measurement{
|
||||
ID: MeasurementIDACMDate,
|
||||
}
|
||||
|
||||
mErr := &errors.MultiError{}
|
||||
found := false
|
||||
for _, fitEntry := range fitEntries {
|
||||
switch fitEntry := fitEntry.(type) {
|
||||
case *fit.EntrySACM: // startup AC module entry
|
||||
found = true
|
||||
|
||||
mErr.Add(fitEntry.HeadersErrors...)
|
||||
data, err := fitEntry.ParseData()
|
||||
|
@ -41,6 +65,13 @@ func MeasureACMDate(fitEntries []fit.Entry) (*Measurement, error) {
|
|||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
mErr.Add(ErrNoSACM{})
|
||||
}
|
||||
|
||||
if len(m.Data) == 0 {
|
||||
return nil, mErr.ReturnValue()
|
||||
}
|
||||
return &m, mErr.ReturnValue()
|
||||
}
|
||||
|
||||
|
@ -60,9 +91,11 @@ func MeasureACMDateInPlace(hashAlg manifest.Algorithm, fitEntries []fit.Entry) (
|
|||
}
|
||||
|
||||
mErr := &errors.MultiError{}
|
||||
found := false
|
||||
for _, fitEntry := range fitEntries {
|
||||
switch fitEntry := fitEntry.(type) {
|
||||
case *fit.EntrySACM: // startup AC module entry
|
||||
found = true
|
||||
|
||||
mErr.Add(fitEntry.HeadersErrors...)
|
||||
data, err := fitEntry.ParseData()
|
||||
|
@ -81,6 +114,14 @@ func MeasureACMDateInPlace(hashAlg manifest.Algorithm, fitEntries []fit.Entry) (
|
|||
m.Data = append(m.Data, *NewStaticDataChunk(DataChunkIDUndefined, padding))
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
mErr.Add(ErrNoSACM{})
|
||||
}
|
||||
|
||||
if len(m.Data) == 0 {
|
||||
return nil, mErr.ReturnValue()
|
||||
}
|
||||
return &m, mErr.ReturnValue()
|
||||
}
|
||||
|
||||
|
|
|
@ -48,6 +48,19 @@ func (chunk DataChunk) String() string {
|
|||
return string(b)
|
||||
}
|
||||
|
||||
// Find returns the chunk with the specified DataChunkID.
|
||||
// Or returns nil if such data chunk was not found.
|
||||
func (s DataChunks) Find(id DataChunkID) *DataChunk {
|
||||
for idx := range s {
|
||||
d := &s[idx]
|
||||
if d.ID == id {
|
||||
return d
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Copy performs a deep copy.
|
||||
func (chunk DataChunk) Copy() *DataChunk {
|
||||
if chunk.ForceData != nil {
|
||||
|
@ -250,6 +263,18 @@ func (s Measurements) AddOffset(offset int64) {
|
|||
}
|
||||
}
|
||||
|
||||
// Find returns the first measurement with the specified MeasurementID.
|
||||
// Or returns nil, if such measurement was not found.
|
||||
func (s Measurements) Find(id MeasurementID) *Measurement {
|
||||
for _, measurement := range s {
|
||||
if measurement.ID == id {
|
||||
return measurement
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Copy performs a deep copy.
|
||||
func (s Measurements) Copy() Measurements {
|
||||
if s == nil {
|
||||
|
|
|
@ -34,6 +34,7 @@ const (
|
|||
MeasurementIDUndefined = MeasurementID(iota)
|
||||
MeasurementIDInit
|
||||
MeasurementIDPCR0_DATA
|
||||
MeasurementIDACM
|
||||
MeasurementIDACMDate
|
||||
MeasurementIDBIOSStartupModule
|
||||
MeasurementIDSCRTMSeparator
|
||||
|
@ -55,6 +56,8 @@ func (id MeasurementID) IsFake() bool {
|
|||
return true
|
||||
case MeasurementIDInit:
|
||||
return true
|
||||
case MeasurementIDACM:
|
||||
return true
|
||||
case MeasurementIDPCDFirmwareVendorVersionCode:
|
||||
return true
|
||||
case MeasurementIDFITPointer:
|
||||
|
@ -84,6 +87,8 @@ func (id MeasurementID) String() string {
|
|||
return "undefined"
|
||||
case MeasurementIDInit:
|
||||
return "init"
|
||||
case MeasurementIDACM:
|
||||
return "ACM"
|
||||
case MeasurementIDPCR0_DATA:
|
||||
return "PCR0_DATA"
|
||||
case MeasurementIDACMDate:
|
||||
|
@ -118,6 +123,8 @@ func (id MeasurementID) PCRIDs() []ID {
|
|||
return []ID{0}
|
||||
case MeasurementIDPCR0_DATA:
|
||||
return []ID{0}
|
||||
case MeasurementIDACM:
|
||||
return []ID{0}
|
||||
case MeasurementIDACMDate:
|
||||
return []ID{0}
|
||||
case MeasurementIDACMDateInPlace:
|
||||
|
@ -224,6 +231,10 @@ func (id MeasurementID) MeasureFunc() MeasureFunc {
|
|||
return func(config MeasurementConfig, provider DataProvider) (*Measurement, error) {
|
||||
return MeasurePCR0Data(config, provider.FITEntries())
|
||||
}
|
||||
case MeasurementIDACM:
|
||||
return func(config MeasurementConfig, provider DataProvider) (*Measurement, error) {
|
||||
return MeasureACM(provider.FITEntries())
|
||||
}
|
||||
case MeasurementIDACMDate:
|
||||
return func(config MeasurementConfig, provider DataProvider) (*Measurement, error) {
|
||||
return MeasureACMDate(provider.FITEntries())
|
||||
|
|
|
@ -39,5 +39,9 @@ func (v ValidateManifests) Validate(firmware Firmware) error {
|
|||
return fmt.Errorf("key chain is invalid: %w", err)
|
||||
}
|
||||
|
||||
if err := bpm.ValidateIBBs(firmware); err != nil {
|
||||
return fmt.Errorf("IBB signature in BPM is not valid: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -109,7 +109,7 @@ func TestTXTErrorStatus(t *testing.T) {
|
|||
if txtErrorStatus.BitSize() != 8 {
|
||||
t.Errorf("Incorrect BitSize, expected: 64. actual: %v", txtErrorStatus.BitSize())
|
||||
}
|
||||
if txtErrorStatus.Address() != registers.TxtPublicSpace+registers.TXTStatusRegisterOffset {
|
||||
if txtErrorStatus.Address() != registers.TxtPublicSpace+registers.TXTErrorStatusRegisterOffset {
|
||||
t.Errorf("Incorrect Address, expected: %d. actual: %d",
|
||||
registers.TxtPublicSpace+registers.TXTStatusRegisterOffset,
|
||||
txtErrorStatus.Address(),
|
||||
|
|
Binary file not shown.
Loading…
Reference in New Issue