diff --git a/README.md b/README.md index 8453dd9f..ca250ee6 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ The Converged Security Suite implements all necessary tools for Intel platform s | Intel Trusted Execution Technology CBnT Extension | Missing | Supported | | Intel Boot Guard 1.0 | Supported | Supported | | Intel Boot Guard 2.0 | Supported | Supported | +| Intel Boot Guard 2.1 | Supported | Supported | | Intel Platform Firmware Resilience | N/A | Partly Supported | Documentation diff --git a/cmd/core/bg-prov/cmd.go b/cmd/core/bg-prov/cmd.go index 3f490b7b..6349e249 100644 --- a/cmd/core/bg-prov/cmd.go +++ b/cmd/core/bg-prov/cmd.go @@ -7,13 +7,9 @@ import ( "fmt" "os" - "github.com/linuxboot/fiano/pkg/intel/metadata/bg" - "github.com/linuxboot/fiano/pkg/intel/metadata/bg/bgbootpolicy" - "github.com/linuxboot/fiano/pkg/intel/metadata/bg/bgkey" "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt" - "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt/cbntbootpolicy" - "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt/cbntkey" - "github.com/linuxboot/fiano/pkg/intel/metadata/common/bgheader" + bootpolicy "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt/bootpolicy" + keymanifest "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt/keymanifest" "github.com/linuxboot/fiano/pkg/intel/metadata/fit" log "github.com/sirupsen/logrus" @@ -32,46 +28,46 @@ type versionCmd struct{} type templateCmdv1 struct { Path string `arg:"" required:"" name:"path" help:"Path to the newly generated JSON configuration file." type:"path"` // CBnT Manifest Header args - SVN bg.SVN `flag optional name:"svn" help:"Boot Policy Manifest Security Version Number"` - ACMSVN bg.SVN `flag optional name:"acmsvn" help:"Authorized ACM Security Version Number"` - NEMS bgbootpolicy.Size4K `flag optional name:"nems" help:"Size of data region need by IBB expressed in 4K pages. E.g., value of 1 = 4096 bytes; 2 = 8092 bytes, etc. Must not be zero"` + SVN cbnt.SVN `flag optional name:"svn" help:"Boot Policy Manifest Security Version Number"` + ACMSVN cbnt.SVN `flag optional name:"acmsvn" help:"Authorized ACM Security Version Number"` + NEMS bootpolicy.Size4K `flag optional name:"nems" help:"Size of data region need by IBB expressed in 4K pages. E.g., value of 1 = 4096 bytes; 2 = 8092 bytes, etc. Must not be zero"` // IBB args - PBET bgbootpolicy.PBETValue `flag:"" optional:"" name:"pbet" help:"Protect BIOS Environment Timer (PBET) value."` - IBBSegFlags bgbootpolicy.SEFlags `flag:"" optional:"" name:"ibbflags" help:"IBB Control flags"` - MCHBAR uint64 `flag:"" optional:"" name:"mchbar" help:"MCHBAR address"` - VDTBAR uint64 `flag:"" optional:"" name:"vdtbar" help:"VTDPVC0BAR address"` - PMRLBase uint32 `flag:"" optional:"" name:"dmabase0" help:"Low DMA protected range base"` - PMRLLimit uint32 `flag:"" optional:"" name:"dmasize0" help:"Low DMA protected range limit"` - EntryPoint uint32 `flag:"" optional:"" name:"entrypoint" help:"IBB (Startup BIOS) entry point"` - IbbHash string `flag:"" optional:"" name:"ibbhash" help:"IBB Hash Algorithm. E.g.: SHA256, SHA384, SM3"` + PBET bootpolicy.PBETValue `flag:"" optional:"" name:"pbet" help:"Protect BIOS Environment Timer (PBET) value."` + IBBSegFlags bootpolicy.SEFlags `flag:"" optional:"" name:"ibbflags" help:"IBB Control flags"` + MCHBAR uint64 `flag:"" optional:"" name:"mchbar" help:"MCHBAR address"` + VDTBAR uint64 `flag:"" optional:"" name:"vdtbar" help:"VTDPVC0BAR address"` + PMRLBase uint32 `flag:"" optional:"" name:"dmabase0" help:"Low DMA protected range base"` + PMRLLimit uint32 `flag:"" optional:"" name:"dmasize0" help:"Low DMA protected range limit"` + EntryPoint uint32 `flag:"" optional:"" name:"entrypoint" help:"IBB (Startup BIOS) entry point"` + IbbHash string `flag:"" optional:"" name:"ibbhash" help:"IBB Hash Algorithm. E.g.: SHA256, SHA384, SM3"` } type templateCmdv2 struct { Path string `arg:"" required:"" name:"path" help:"Path to the newly generated JSON configuration file." type:"path"` // CBnT Manifest Header args - Revision uint8 `flag:"" optional:"" name:"revision" help:"Platform Manufacturer’s BPM revision number."` - SVN cbnt.SVN `flag:"" optional:"" name:"svn" help:"Boot Policy Manifest Security Version Number"` - ACMSVN cbnt.SVN `flag:"" optional:"" name:"acmsvn" help:"Authorized ACM Security Version Number"` - NEMS cbntbootpolicy.Size4K `flag:"" optional:"" name:"nems" help:"Size of data region need by IBB expressed in 4K pages. E.g., value of 1 = 4096 bytes; 2 = 8092 bytes, etc. Must not be zero"` + Revision uint8 `flag:"" optional:"" name:"revision" help:"Platform Manufacturer’s BPM revision number."` + SVN cbnt.SVN `flag:"" optional:"" name:"svn" help:"Boot Policy Manifest Security Version Number"` + ACMSVN cbnt.SVN `flag:"" optional:"" name:"acmsvn" help:"Authorized ACM Security Version Number"` + NEMS bootpolicy.Size4K `flag:"" optional:"" name:"nems" help:"Size of data region need by IBB expressed in 4K pages. E.g., value of 1 = 4096 bytes; 2 = 8092 bytes, etc. Must not be zero"` // IBB args - PBET cbntbootpolicy.PBETValue `flag:"" optional:"" name:"pbet" help:"Protect BIOS Environment Timer (PBET) value."` - IBBSegFlags cbntbootpolicy.SEFlags `flag:"" optional:"" name:"ibbflags" help:"IBB Control flags"` - MCHBAR uint64 `flag:"" optional:"" name:"mchbar" help:"MCHBAR address"` - VDTBAR uint64 `flag:"" optional:"" name:"vdtbar" help:"VTDPVC0BAR address"` - DMABase0 uint32 `flag:"" optional:"" name:"dmabase0" help:"Low DMA protected range base"` - DMASize0 uint32 `flag:"" optional:"" name:"dmasize0" help:"Low DMA protected range limit"` - DMABase1 uint64 `flag:"" optional:"" name:"dmabase1" help:"High DMA protected range base."` - DMASize1 uint64 `flag:"" optional:"" name:"dmasize1" help:"High DMA protected range limit."` - EntryPoint uint32 `flag:"" optional:"" name:"entrypoint" help:"IBB (Startup BIOS) entry point"` - IbbHash []string `flag:"" optional:"" name:"ibbhash" help:"IBB Hash Algorithms. E.g.: SHA256, SHA384, SM3"` + PBET bootpolicy.PBETValue `flag:"" optional:"" name:"pbet" help:"Protect BIOS Environment Timer (PBET) value."` + IBBSegFlags bootpolicy.SEFlags `flag:"" optional:"" name:"ibbflags" help:"IBB Control flags"` + MCHBAR uint64 `flag:"" optional:"" name:"mchbar" help:"MCHBAR address"` + VDTBAR uint64 `flag:"" optional:"" name:"vdtbar" help:"VTDPVC0BAR address"` + DMABase0 uint32 `flag:"" optional:"" name:"dmabase0" help:"Low DMA protected range base"` + DMASize0 uint32 `flag:"" optional:"" name:"dmasize0" help:"Low DMA protected range limit"` + DMABase1 uint64 `flag:"" optional:"" name:"dmabase1" help:"High DMA protected range base."` + DMASize1 uint64 `flag:"" optional:"" name:"dmasize1" help:"High DMA protected range limit."` + EntryPoint uint32 `flag:"" optional:"" name:"entrypoint" help:"IBB (Startup BIOS) entry point"` + IbbHash []string `flag:"" optional:"" name:"ibbhash" help:"IBB Hash Algorithms. E.g.: SHA256, SHA384, SM3"` // TXT args - SintMin uint8 `flag:"" optional:"" name:"sintmin" help:"OEM authorized SinitMinSvn value"` - TXTFlags cbntbootpolicy.TXTControlFlags `flag:"" optional:"" name:"txtflags" help:"TXT Element control flags"` - PowerDownInterval cbntbootpolicy.Duration16In5Sec `flag:"" optional:"" name:"powerdowninterval" help:"Duration of Power Down in 5 sec increments"` - ACPIBaseOffset uint16 `flag:"" optional:"" name:"acpibaseoffset" help:"ACPI IO offset."` - PowermBaseOffset uint32 `flag:"" optional:"" name:"powermbaseoffset" help:"ACPI MMIO offset."` - CMOSOff0 uint8 `flag:"" optional:"" name:"cmosoff0" help:"CMOS byte in bank 0 to store platform wakeup time"` - CMOSOff1 uint8 `flag:"" optional:"" name:"cmosoff1" help:"Second CMOS byte in bank 0 to store platform wakeup time"` + SintMin uint8 `flag:"" optional:"" name:"sintmin" help:"OEM authorized SinitMinSvn value"` + TXTFlags bootpolicy.TXTControlFlags `flag:"" optional:"" name:"txtflags" help:"TXT Element control flags"` + PowerDownInterval bootpolicy.Duration16In5Sec `flag:"" optional:"" name:"powerdowninterval" help:"Duration of Power Down in 5 sec increments"` + ACPIBaseOffset uint16 `flag:"" optional:"" name:"acpibaseoffset" help:"ACPI IO offset."` + PowermBaseOffset uint32 `flag:"" optional:"" name:"powermbaseoffset" help:"ACPI MMIO offset."` + CMOSOff0 uint8 `flag:"" optional:"" name:"cmosoff0" help:"CMOS byte in bank 0 to store platform wakeup time"` + CMOSOff1 uint8 `flag:"" optional:"" name:"cmosoff1" help:"Second CMOS byte in bank 0 to store platform wakeup time"` } type kmPrintCmd struct { @@ -154,34 +150,34 @@ type generateACMCmdv0 struct { } type generateKMCmdv1 struct { - KM string `arg:"" required:"" name:"km" help:"Path to the newly generated Key Manifest binary file." type:"path"` - Key string `arg:"" required:"" name:"key" help:"Public signing key"` - Config string `flag:"" optional:"" name:"config" help:"Path to the JSON config file." type:"path"` - SVN bg.SVN `flag:"" optional:"" name:"svn" help:"Boot Policy Manifest Security Version Number"` - ID uint8 `flag:"" optional:"" name:"id" help:"The key Manifest Identifier"` - PKHashAlg string `flag:"" optional:"" name:"pkhashalg" help:"Hash algorithm of OEM public key digest. E.g.: SHA256, SHA384, SM3"` + KM string `arg:"" required:"" name:"km" help:"Path to the newly generated Key Manifest binary file." type:"path"` + Key string `arg:"" required:"" name:"key" help:"Public signing key"` + Config string `flag:"" optional:"" name:"config" help:"Path to the JSON config file." type:"path"` + SVN cbnt.SVN `flag:"" optional:"" name:"svn" help:"Boot Policy Manifest Security Version Number"` + ID uint8 `flag:"" optional:"" name:"id" help:"The key Manifest Identifier"` + PKHashAlg string `flag:"" optional:"" name:"pkhashalg" help:"Hash algorithm of OEM public key digest. E.g.: SHA256, SHA384, SM3"` // KMHash bg.HashStructure `flag optional:"" name:"kmhash" help:"Key hash for BPM, ACM, uCode etc"` BpmPubkey string `flag:"" optional:"" name:"bpmpubkey" help:"Path to bpm public signing key"` - BpmHashAlg string `flag:"" optional:"" name:"bpmhashalgo" help:"Hash algorithm for bpm public signing cbntkey.. E.g.: SHA256, SHA384, SM3"` + BpmHashAlg string `flag:"" optional:"" name:"bpmhashalgo" help:"Hash algorithm for bpm public signing keymanifest.. E.g.: SHA256, SHA384, SM3"` Out string `flag:"" optional:"" name:"out" help:"Path to write applied config to"` Cut bool `flag:"" optional:"" name:"cut" help:"Cuts the signature before writing to binary."` PrintME bool `flag:"" optional:"" name:"printme" help:"Prints the hash of KM public signing key"` } type generateKMCmdv2 struct { - KM string `arg:"" required:"" name:"km" help:"Path to the newly generated Key Manifest binary file." type:"path"` - Key string `arg:"" required:"" name:"key" help:"Public signing key"` - Config string `flag:"" optional:"" name:"config" help:"Path to the JSON config file." type:"path"` - Revision uint8 `flag:"" optional:"" name:"revision" help:"Platform Manufacturer’s BPM revision number."` - SVN cbnt.SVN `flag:"" optional:"" name:"svn" help:"Boot Policy Manifest Security Version Number"` - ID uint8 `flag:"" optional:"" name:"id" help:"The key Manifest Identifier"` - PKHashAlg string `flag:"" optional:"" name:"pkhashalg" help:"Hash algorithm of OEM public key digest. E.g.: SHA256, SHA384, SM3"` - KMHashes []cbntkey.Hash `flag:"" optional:"" name:"kmhashes" help:"Key hashes for BPM, ACM, uCode etc"` - BpmPubkey string `flag:"" optional:"" name:"bpmpubkey" help:"Path to bpm public signing key"` - BpmHashAlg string `flag:"" optional:"" name:"bpmhashalgo" help:"Hash algorithm for bpm public signing cbntkey.. E.g.: SHA256, SHA384, SM3"` - Out string `flag:"" optional:"" name:"out" help:"Path to write applied config to"` - Cut bool `flag:"" optional:"" name:"cut" help:"Cuts the signature before writing to binary."` - PrintME bool `flag:"" optional:"" name:"printme" help:"Prints the hash of KM public signing key"` + KM string `arg:"" required:"" name:"km" help:"Path to the newly generated Key Manifest binary file." type:"path"` + Key string `arg:"" required:"" name:"key" help:"Public signing key"` + Config string `flag:"" optional:"" name:"config" help:"Path to the JSON config file." type:"path"` + Revision uint8 `flag:"" optional:"" name:"revision" help:"Platform Manufacturer’s BPM revision number."` + SVN cbnt.SVN `flag:"" optional:"" name:"svn" help:"Boot Policy Manifest Security Version Number"` + ID uint8 `flag:"" optional:"" name:"id" help:"The key Manifest Identifier"` + PKHashAlg string `flag:"" optional:"" name:"pkhashalg" help:"Hash algorithm of OEM public key digest. E.g.: SHA256, SHA384, SM3"` + KMHashes []keymanifest.Hash `flag:"" optional:"" name:"kmhashes" help:"Key hashes for BPM, ACM, uCode etc"` + BpmPubkey string `flag:"" optional:"" name:"bpmpubkey" help:"Path to bpm public signing key"` + BpmHashAlg string `flag:"" optional:"" name:"bpmhashalgo" help:"Hash algorithm for bpm public signing keymanifest.. E.g.: SHA256, SHA384, SM3"` + Out string `flag:"" optional:"" name:"out" help:"Path to write applied config to"` + Cut bool `flag:"" optional:"" name:"cut" help:"Cuts the signature before writing to binary."` + PrintME bool `flag:"" optional:"" name:"printme" help:"Prints the hash of KM public signing key"` } type generateBPMCmdv1 struct { @@ -189,20 +185,20 @@ type generateBPMCmdv1 struct { BIOS string `arg:"" required:"" name:"bios" help:"Path to the full BIOS binary file." type:"path"` Config string `flag:"" optional:"" name:"config" help:"Path to the JSON config file." type:"path"` // CBnT Manifest Header args - Revision uint8 `flag:"" optional:"" name:"revision" help:"Platform Manufacturer’s BPM revision number."` - SVN bg.SVN `flag:"" optional:"" name:"svn" help:"Boot Policy Manifest Security Version Number"` - ACMSVN bg.SVN `flag:"" optional:"" name:"acmsvn" help:"Authorized ACM Security Version Number"` - NEMS bgbootpolicy.Size4K `flag:"" optional:"" name:"nems" help:"Size of data region need by IBB expressed in 4K pages. E.g., value of 1 = 4096 bytes; 2 = 8092 bytes, etc. Must not be zero"` + Revision uint8 `flag:"" optional:"" name:"revision" help:"Platform Manufacturer’s BPM revision number."` + SVN cbnt.SVN `flag:"" optional:"" name:"svn" help:"Boot Policy Manifest Security Version Number"` + ACMSVN cbnt.SVN `flag:"" optional:"" name:"acmsvn" help:"Authorized ACM Security Version Number"` + NEMS bootpolicy.Size4K `flag:"" optional:"" name:"nems" help:"Size of data region need by IBB expressed in 4K pages. E.g., value of 1 = 4096 bytes; 2 = 8092 bytes, etc. Must not be zero"` // IBB args - PBET bgbootpolicy.PBETValue `flag:"" optional:"" name:"pbet" help:"Protect BIOS Environment Timer (PBET) value."` - IBBSegFlags bgbootpolicy.SEFlags `flag:"" optional:"" name:"ibbflags" help:"IBB Control flags"` - MCHBAR uint64 `flag:"" optional:"" name:"mchbar" help:"MCHBAR address"` - VDTBAR uint64 `flag:"" optional:"" name:"vdtbar" help:"VTDPVC0BAR address"` - PMRLBase uint32 `flag:"" optional:"" name:"dmabase0" help:"Low DMA protected range base"` - PMRLLimit uint32 `flag:"" optional:"" name:"dmasize0" help:"Low DMA protected range limit"` - EntryPoint uint32 `flag:"" optional:"" name:"entrypoint" help:"IBB (Startup BIOS) entry point"` - IbbHash string `flag:"" optional:"" name:"ibbhash" help:"IBB Hash Algorithm. Valid options: SHA256, SHA384, SM3"` - IbbSegFlag uint16 `flag:"" optional:"" name:"ibbsegflag" help:"Reducted"` + PBET bootpolicy.PBETValue `flag:"" optional:"" name:"pbet" help:"Protect BIOS Environment Timer (PBET) value."` + IBBSegFlags bootpolicy.SEFlags `flag:"" optional:"" name:"ibbflags" help:"IBB Control flags"` + MCHBAR uint64 `flag:"" optional:"" name:"mchbar" help:"MCHBAR address"` + VDTBAR uint64 `flag:"" optional:"" name:"vdtbar" help:"VTDPVC0BAR address"` + PMRLBase uint32 `flag:"" optional:"" name:"dmabase0" help:"Low DMA protected range base"` + PMRLLimit uint32 `flag:"" optional:"" name:"dmasize0" help:"Low DMA protected range limit"` + EntryPoint uint32 `flag:"" optional:"" name:"entrypoint" help:"IBB (Startup BIOS) entry point"` + IbbHash string `flag:"" optional:"" name:"ibbhash" help:"IBB Hash Algorithm. Valid options: SHA256, SHA384, SM3"` + IbbSegFlag uint16 `flag:"" optional:"" name:"ibbsegflag" help:"Reducted"` Out string `flag:"" optional:"" name:"out" help:"Path to write applied config to"` Cut bool `flag:"" optional:"" name:"cut" help:"Cuts the signature before writing to binary."` @@ -213,30 +209,30 @@ type generateBPMCmdv2 struct { BIOS string `arg:"" required:"" name:"bios" help:"Path to the full BIOS binary file." type:"path"` Config string `flag:"" optional:"" name:"config" help:"Path to the JSON config file." type:"path"` // CBnT Manifest Header args - Revision uint8 `flag:"" optional:"" name:"revision" help:"Platform Manufacturer’s BPM revision number."` - SVN cbnt.SVN `flag:"" optional:"" name:"svn" help:"Boot Policy Manifest Security Version Number"` - ACMSVN cbnt.SVN `flag:"" optional:"" name:"acmsvn" help:"Authorized ACM Security Version Number"` - NEMS cbntbootpolicy.Size4K `flag:"" optional:"" name:"nems" help:"Size of data region need by IBB expressed in 4K pages. E.g., value of 1 = 4096 bytes; 2 = 8092 bytes, etc. Must not be zero"` + Revision uint8 `flag:"" optional:"" name:"revision" help:"Platform Manufacturer’s BPM revision number."` + SVN cbnt.SVN `flag:"" optional:"" name:"svn" help:"Boot Policy Manifest Security Version Number"` + ACMSVN cbnt.SVN `flag:"" optional:"" name:"acmsvn" help:"Authorized ACM Security Version Number"` + NEMS bootpolicy.Size4K `flag:"" optional:"" name:"nems" help:"Size of data region need by IBB expressed in 4K pages. E.g., value of 1 = 4096 bytes; 2 = 8092 bytes, etc. Must not be zero"` // IBB args - PBET cbntbootpolicy.PBETValue `flag:"" optional:"" name:"pbet" help:"Protect BIOS Environment Timer (PBET) value."` - IBBSegFlags cbntbootpolicy.SEFlags `flag:"" optional:"" name:"ibbflags" help:"IBB Control flags"` - MCHBAR uint64 `flag:"" optional:"" name:"mchbar" help:"MCHBAR address"` - VDTBAR uint64 `flag:"" optional:"" name:"vdtbar" help:"VTDPVC0BAR address"` - DMABase0 uint32 `flag:"" optional:"" name:"dmabase0" help:"Low DMA protected range base"` - DMASize0 uint32 `flag:"" optional:"" name:"dmasize0" help:"Low DMA protected range limit"` - DMABase1 uint64 `flag:"" optional:"" name:"dmabase1" help:"High DMA protected range base."` - DMASize1 uint64 `flag:"" optional:"" name:"dmasize1" help:"High DMA protected range limit."` - EntryPoint uint32 `flag:"" optional:"" name:"entrypoint" help:"IBB (Startup BIOS) entry point"` - IbbHash []string `flag:"" optional:"" name:"ibbhash" help:"IBB Hash Algorithm. Valid options: SHA256, SHA384, SM3"` - IbbSegFlag uint16 `flag:"" optional:"" name:"ibbsegflag" help:"Reducted"` + PBET bootpolicy.PBETValue `flag:"" optional:"" name:"pbet" help:"Protect BIOS Environment Timer (PBET) value."` + IBBSegFlags bootpolicy.SEFlags `flag:"" optional:"" name:"ibbflags" help:"IBB Control flags"` + MCHBAR uint64 `flag:"" optional:"" name:"mchbar" help:"MCHBAR address"` + VDTBAR uint64 `flag:"" optional:"" name:"vdtbar" help:"VTDPVC0BAR address"` + DMABase0 uint32 `flag:"" optional:"" name:"dmabase0" help:"Low DMA protected range base"` + DMASize0 uint32 `flag:"" optional:"" name:"dmasize0" help:"Low DMA protected range limit"` + DMABase1 uint64 `flag:"" optional:"" name:"dmabase1" help:"High DMA protected range base."` + DMASize1 uint64 `flag:"" optional:"" name:"dmasize1" help:"High DMA protected range limit."` + EntryPoint uint32 `flag:"" optional:"" name:"entrypoint" help:"IBB (Startup BIOS) entry point"` + IbbHash []string `flag:"" optional:"" name:"ibbhash" help:"IBB Hash Algorithm. Valid options: SHA256, SHA384, SM3"` + IbbSegFlag uint16 `flag:"" optional:"" name:"ibbsegflag" help:"Reducted"` // TXT args - SinitMin uint8 `flag:"" optional:"" name:"sinitmin" help:"OEM authorized SinitMinSvn value"` - TXTFlags cbntbootpolicy.TXTControlFlags `flag:"" optional:"" name:"txtflags" help:"TXT Element control flags"` - PowerDownInterval cbntbootpolicy.Duration16In5Sec `flag:"" optional:"" name:"powerdowninterval" help:"Duration of Power Down in 5 sec increments"` - ACPIBaseOffset uint16 `flag:"" optional:"" name:"acpibaseoffset" help:"ACPI IO offset."` - PowermBaseOffset uint32 `flag:"" optional:"" name:"powermbaseoffset" help:"ACPI MMIO offset."` - CMOSOff0 uint8 `flag:"" optional:"" name:"cmosoff0" help:"CMOS byte in bank 0 to store platform wakeup time"` - CMOSOff1 uint8 `flag:"" optional:"" name:"cmosoff1" help:"Second CMOS byte in bank 0 to store platform wakeup time"` + SinitMin uint8 `flag:"" optional:"" name:"sinitmin" help:"OEM authorized SinitMinSvn value"` + TXTFlags bootpolicy.TXTControlFlags `flag:"" optional:"" name:"txtflags" help:"TXT Element control flags"` + PowerDownInterval bootpolicy.Duration16In5Sec `flag:"" optional:"" name:"powerdowninterval" help:"Duration of Power Down in 5 sec increments"` + ACPIBaseOffset uint16 `flag:"" optional:"" name:"acpibaseoffset" help:"ACPI IO offset."` + PowermBaseOffset uint32 `flag:"" optional:"" name:"powermbaseoffset" help:"ACPI MMIO offset."` + CMOSOff0 uint8 `flag:"" optional:"" name:"cmosoff0" help:"CMOS byte in bank 0 to store platform wakeup time"` + CMOSOff1 uint8 `flag:"" optional:"" name:"cmosoff1" help:"Second CMOS byte in bank 0 to store platform wakeup time"` Out string `flag:"" optional:"" name:"out" help:"Path to write applied config to"` Cut bool `flag:"" optional:"" name:"cut" help:"Cuts the signature before writing to binary."` @@ -429,20 +425,26 @@ func (bpme *bpmExportCmd) Run(ctx *context) error { func (g *generateKMCmdv1) Run(ctx *context) error { var b bootguard.BootGuard - b.Version = bgheader.Version10 + b.Version = cbnt.Version10 if g.Config != "" { err := b.ReadJSON(g.Config) if err != nil { return fmt.Errorf("unable to read JSON config file: %w", err) } } else { - var err error - b.VData.BGkm = bgkey.NewManifest() - b.VData.BGkm.KMSVN = g.SVN - b.VData.BGkm.KMID = g.ID + bgkm, err := keymanifest.NewManifest(cbnt.Version10) if err != nil { return err } + km, ok := bgkm.(*keymanifest.BGManifest) + if !ok { + return fmt.Errorf("could not assert the type for KM") + } + b.VData.BGkm = km + + b.VData.BGkm.KMSVN = g.SVN + b.VData.BGkm.KMID = g.ID + // b.VData.BGkm.BPKey = g.KMHash // Create KM_Hash for BPM pub signing key if g.BpmPubkey != "" { @@ -455,7 +457,7 @@ func (g *generateKMCmdv1) Run(ctx *context) error { return err } } else { - return fmt.Errorf("add --bpmpubkey= as argument") + return fmt.Errorf("add --bpmpubkey= as argument") } } key, err := bootguard.ReadPubKey(g.Key) @@ -466,7 +468,11 @@ func (g *generateKMCmdv1) Run(ctx *context) error { return err } if g.PrintME { - if b.VData.BGkm.KeyAndSignature.Signature.DataTotalSize() > 1 { + sigDataSize, err := b.VData.BGkm.KeyAndSignature.Signature.SizeOf(4) + if err != nil { + return err + } + if sigDataSize > 1 { if err := b.VData.BGkm.KeyAndSignature.Key.PrintKMPubKey(b.VData.BGkm.BPKey.HashAlg); err != nil { return err } @@ -487,7 +493,11 @@ func (g *generateKMCmdv1) Run(ctx *context) error { } if g.Cut { // Cut signature from binary - bKM = bKM[:int(b.VData.BGkm.KeyAndSignatureOffset())] + off, err := b.VData.BGkm.OffsetOf(5) + if err != nil { + return err + } + bKM = bKM[:int(off)] } if err = os.WriteFile(g.KM, bKM, 0o600); err != nil { return fmt.Errorf("unable to write KM to file: %w", err) @@ -497,15 +507,22 @@ func (g *generateKMCmdv1) Run(ctx *context) error { func (g *generateKMCmdv2) Run(ctx *context) error { var b bootguard.BootGuard - b.Version = bgheader.Version20 + b.Version = cbnt.Version20 if g.Config != "" { err := b.ReadJSON(g.Config) if err != nil { return err } } else { - var err error - b.VData.CBNTkm = cbntkey.NewManifest() + cbntkm, err := keymanifest.NewManifest(cbnt.Version20) + if err != nil { + return err + } + km, ok := cbntkm.(*keymanifest.CBnTManifest) + if !ok { + return fmt.Errorf("could not assert KM type") + } + b.VData.CBNTkm = km b.VData.CBNTkm.Revision = g.Revision b.VData.CBNTkm.KMSVN = g.SVN b.VData.CBNTkm.KMID = g.ID @@ -536,7 +553,12 @@ func (g *generateKMCmdv2) Run(ctx *context) error { return err } if g.PrintME { - if b.VData.CBNTkm.KeyAndSignature.Signature.DataTotalSize() > 1 { + sigDataSize, err := b.VData.CBNTkm.KeyAndSignature.Signature.SizeOf(4) + if err != nil { + return err + } + + if sigDataSize > 1 { if err := b.VData.CBNTkm.KeyAndSignature.Key.PrintKMPubKey(b.VData.CBNTkm.PubKeyHashAlg); err != nil { return err } @@ -567,20 +589,35 @@ func (g *generateKMCmdv2) Run(ctx *context) error { func (g *generateBPMCmdv1) Run(ctx *context) error { var b bootguard.BootGuard - b.Version = bgheader.Version10 + b.Version = cbnt.Version10 if g.Config != "" { err := b.ReadJSON(g.Config) if err != nil { return err } } else { - b.VData.BGbpm = bgbootpolicy.NewManifest() - b.VData.BGbpm.BPMH = *bgbootpolicy.NewBPMH() - b.VData.BGbpm.BPMH.BPMSVN = g.SVN - b.VData.BGbpm.BPMH.ACMSVNAuth = g.ACMSVN - b.VData.BGbpm.BPMH.NEMDataStack = g.NEMS + bgbpm, err := bootpolicy.NewManifest(cbnt.Version10) + if err != nil { + return err + } + bpmh, err := bootpolicy.NewBPMH(cbnt.Version10) + bp, ok := bpmh.(*bootpolicy.BPMHBG) + if !ok { + return fmt.Errorf("could not assert BPMH type") + } + + bpm, ok := bgbpm.(*bootpolicy.ManifestBG) + if !ok { + return fmt.Errorf("could not assert BPM type") + } - b.VData.BGbpm.SE = make([]bgbootpolicy.SE, 1) + b.VData.BGbpm = bpm + b.VData.BGbpm.BPMHBG = *bp + b.VData.BGbpm.BPMHBG.BPMSVN = g.SVN + b.VData.BGbpm.BPMHBG.ACMSVNAuth = g.ACMSVN + b.VData.BGbpm.BPMHBG.NEMDataStack = g.NEMS + + b.VData.BGbpm.SE = make([]bootpolicy.SEBG, 1) b.VData.BGbpm.SE[0].PBETValue = g.PBET b.VData.BGbpm.SE[0].Flags = g.IBBSegFlags b.VData.BGbpm.SE[0].IBBMCHBAR = g.MCHBAR @@ -588,7 +625,7 @@ func (g *generateBPMCmdv1) Run(ctx *context) error { b.VData.BGbpm.SE[0].PMRLBase = g.PMRLBase b.VData.BGbpm.SE[0].PMRLLimit = g.PMRLLimit b.VData.BGbpm.SE[0].IBBEntryPoint = g.EntryPoint - hashAlgo, err := bg.GetAlgFromString(g.IbbHash) + hashAlgo, err := cbnt.GetAlgFromString(g.IbbHash) if err != nil { return err } @@ -616,7 +653,11 @@ func (g *generateBPMCmdv1) Run(ctx *context) error { return err } if g.Cut { - bBPM = bBPM[:b.VData.BGbpm.PMSE.KeySignatureOffset()] + off, err := b.VData.BGbpm.PMSE.OffsetOf(1) + if err != nil { + return err + } + bBPM = bBPM[:int(off)] } if err = os.WriteFile(g.BPM, bBPM, 0o600); err != nil { return fmt.Errorf("unable to write BPM to file: %w", err) @@ -626,21 +667,36 @@ func (g *generateBPMCmdv1) Run(ctx *context) error { func (g *generateBPMCmdv2) Run(ctx *context) error { var b bootguard.BootGuard - b.Version = bgheader.Version20 + b.Version = cbnt.Version20 if g.Config != "" { err := b.ReadJSON(g.Config) if err != nil { return err } } else { - b.VData.CBNTbpm = cbntbootpolicy.NewManifest() - b.VData.CBNTbpm.BPMH = *cbntbootpolicy.NewBPMH() - b.VData.CBNTbpm.BPMH.BPMRevision = g.Revision - b.VData.CBNTbpm.BPMH.BPMSVN = g.SVN - b.VData.CBNTbpm.BPMH.ACMSVNAuth = g.ACMSVN - b.VData.CBNTbpm.BPMH.NEMDataStack = g.NEMS - - b.VData.CBNTbpm.SE = make([]cbntbootpolicy.SE, 1) + cbntbpm, err := bootpolicy.NewManifest(cbnt.Version20) + if err != nil { + return err + } + bpmh, err := bootpolicy.NewBPMH(cbnt.Version20) + bp, ok := bpmh.(*bootpolicy.BPMHCBnT) + if !ok { + return fmt.Errorf("could not assert BPMH type") + } + + bpm, ok := cbntbpm.(*bootpolicy.ManifestCBnT) + if !ok { + return fmt.Errorf("could not assert BPM type") + } + + b.VData.CBNTbpm = bpm + b.VData.CBNTbpm.BPMHCBnT = *bp + b.VData.CBNTbpm.BPMHCBnT.BPMRevision = g.Revision + b.VData.CBNTbpm.BPMHCBnT.BPMSVN = g.SVN + b.VData.CBNTbpm.BPMHCBnT.ACMSVNAuth = g.ACMSVN + b.VData.CBNTbpm.BPMHCBnT.NEMDataStack = g.NEMS + + b.VData.CBNTbpm.SE = make([]bootpolicy.SECBnT, 1) b.VData.CBNTbpm.SE[0].PBETValue = g.PBET b.VData.CBNTbpm.SE[0].Flags = g.IBBSegFlags b.VData.CBNTbpm.SE[0].IBBMCHBAR = g.MCHBAR @@ -663,11 +719,11 @@ func (g *generateBPMCmdv2) Run(ctx *context) error { for iterator := range b.VData.CBNTbpm.SE[0].DigestList.List { b.VData.CBNTbpm.SE[0].DigestList.List[iterator].HashAlg = ibbhashalgs[iterator] } - err := b.CreateIBBSegments(0, g.IbbSegFlag, g.BIOS) + err = b.CreateIBBSegments(0, g.IbbSegFlag, g.BIOS) if err != nil { return err } - txt := cbntbootpolicy.NewTXT() + txt := bootpolicy.NewTXT() txt.SInitMinSVNAuth = g.SinitMin txt.ControlFlags = g.TXTFlags txt.PwrDownInterval = g.PowerDownInterval @@ -695,7 +751,11 @@ func (g *generateBPMCmdv2) Run(ctx *context) error { return err } if g.Cut { - bBPM = bBPM[:b.VData.CBNTbpm.KeySignatureOffset] + off, err := b.VData.CBNTbpm.PMSE.OffsetOf(1) + if err != nil { + return err + } + bBPM = bBPM[:int(off)] } if err = os.WriteFile(g.BPM, bBPM, 0o600); err != nil { return fmt.Errorf("unable to write BPM to file: %w", err) @@ -919,15 +979,41 @@ func (s *signBPMCmd) Run(ctx *context) error { func (t *templateCmdv2) Run(ctx *context) error { var vdata bootguard.VersionedData - vdata.CBNTbpm = cbntbootpolicy.NewManifest() - vdata.CBNTkm = cbntkey.NewManifest() - vdata.CBNTbpm.BPMH.BPMRevision = t.Revision - vdata.CBNTbpm.BPMH.BPMSVN = t.SVN - vdata.CBNTbpm.BPMH.ACMSVNAuth = t.ACMSVN - vdata.CBNTbpm.BPMH.NEMDataStack = t.NEMS + cbntbpm, err := bootpolicy.NewManifest(cbnt.Version20) + if err != nil { + return err + } + bpm, ok := cbntbpm.(*bootpolicy.ManifestCBnT) + if !ok { + return fmt.Errorf("could not assert BPM type") + } + vdata.CBNTbpm = bpm + + cbntkm, err := keymanifest.NewManifest(cbnt.Version20) + if err != nil { + return err + } + km, ok := cbntkm.(*keymanifest.CBnTManifest) + if !ok { + return fmt.Errorf("could not assert KM type") + } + vdata.CBNTkm = km + + vdata.CBNTbpm.BPMHCBnT.BPMRevision = t.Revision + vdata.CBNTbpm.BPMHCBnT.BPMSVN = t.SVN + vdata.CBNTbpm.BPMHCBnT.ACMSVNAuth = t.ACMSVN + vdata.CBNTbpm.BPMHCBnT.NEMDataStack = t.NEMS + + seCommon, err := bootpolicy.NewSE(cbnt.Version20) + if err != nil { + return err + } - se := cbntbootpolicy.NewSE() + se, ok := seCommon.(*bootpolicy.SECBnT) + if !ok { + return err + } se.PBETValue = t.PBET se.Flags = t.IBBSegFlags se.IBBMCHBAR = t.MCHBAR @@ -954,7 +1040,7 @@ func (t *templateCmdv2) Run(ctx *context) error { vdata.CBNTbpm.SE = append(vdata.CBNTbpm.SE, *se) - txt := cbntbootpolicy.NewTXT() + txt := bootpolicy.NewTXT() txt.SInitMinSVNAuth = t.SintMin txt.ControlFlags = t.TXTFlags txt.PwrDownInterval = t.PowerDownInterval @@ -987,16 +1073,42 @@ func (t *templateCmdv2) Run(ctx *context) error { func (t *templateCmdv1) Run(ctx *context) error { var vdata bootguard.VersionedData - var err error + var ok bool - vdata.BGbpm = bgbootpolicy.NewManifest() - vdata.BGkm = bgkey.NewManifest() + bgbpm, err := bootpolicy.NewManifest(cbnt.Version10) + if err != nil { + return err + } + bpm, ok := bgbpm.(*bootpolicy.ManifestBG) + if !ok { + return fmt.Errorf("could not assert BPM type") + } + vdata.BGbpm = bpm - vdata.BGbpm.BPMH.BPMSVN = t.SVN - vdata.BGbpm.BPMH.ACMSVNAuth = t.ACMSVN - vdata.BGbpm.BPMH.NEMDataStack = t.NEMS + bgkm, err := keymanifest.NewManifest(cbnt.Version10) + if err != nil { + return err + } + km, ok := bgkm.(*keymanifest.BGManifest) + if !ok { + return fmt.Errorf("could not assert KM type") + } + vdata.BGkm = km + + vdata.BGbpm.BPMHBG.BPMSVN = t.SVN + vdata.BGbpm.BPMHBG.ACMSVNAuth = t.ACMSVN + vdata.BGbpm.BPMHBG.NEMDataStack = t.NEMS + + seCommon, err := bootpolicy.NewSE(cbnt.Version10) + if err != nil { + return err + } + + se, ok := seCommon.(*bootpolicy.SEBG) + if !ok { + return err + } - se := bgbootpolicy.NewSE() se.PBETValue = t.PBET se.Flags = t.IBBSegFlags se.IBBMCHBAR = t.MCHBAR @@ -1004,7 +1116,7 @@ func (t *templateCmdv1) Run(ctx *context) error { se.PMRLBase = t.PMRLBase se.PMRLLimit = t.PMRLLimit se.IBBEntryPoint = t.EntryPoint - se.Digest.HashAlg, err = bg.GetAlgFromString(t.IbbHash) + se.Digest.HashAlg, err = cbnt.GetAlgFromString(t.IbbHash) if err != nil { return err } diff --git a/cmd/core/bg-suite/README.md b/cmd/core/bg-suite/README.md index 9454fa83..fd905557 100644 --- a/cmd/core/bg-suite/README.md +++ b/cmd/core/bg-suite/README.md @@ -11,6 +11,11 @@ Prerequisites for Usage ----------------------- Supported OS: Any Linux distribution +It is recommended to run this utility on the Intel platform for both, static +and runtime tests. Otherwise, please ignore `BgVersion` field in the output `test_log.json` file. +Additionally, runtime tests are only giving reliable results when executed on the platform running the +firmware provided for the static tests. + **1. Load the MSR kernel module.** Load the *msr* kernel module: diff --git a/cmd/core/bg-suite/TESTPLAN.md b/cmd/core/bg-suite/TESTPLAN.md index 4f7baaf1..42639888 100644 --- a/cmd/core/bg-suite/TESTPLAN.md +++ b/cmd/core/bg-suite/TESTPLAN.md @@ -1,10 +1,56 @@ -Id | Test | Implemented | Document | Chapter -------------|------------|------------|------------|------------ -00 | FIT meets BootGuard requirements | :white_check_mark: | Document 599500 Revision 1.2 | -01 | SACM meets sane BootGuard requirements | :white_check_mark: | Document 315168-017 | Chapter A. Authenticated Code Modules -02 | Key Manifest meets sane BootGuard requirements | :white_check_mark: | Document 557867 / 575623 | -03 | Boot Policy Manifest meets sane BootGuard requirements | :white_check_mark: | Document 557867 / 575623 | -04 | Verifies BPM and IBBs match firmware image | :white_check_mark: | Document 557867 / 575623 | -05 | [RUNTIME] Validates Intel ME specific configuration against KM/BPM in firmware image | :white_check_mark: | Document 557867 / 575623 | -06 | [RUNTIME] Verifies Intel ME Boot Guard configuration is sane and safe | :white_check_mark: | Document 557867 / 575623 | -07 | [RUNTIME] BtG/TXT registers are sane | :white_check_mark: | Document 315168-017 | +Id | Test | Implemented | Document | Chapter | Supported BG/CBnt Version +------------|------------|------------|------------|------------|----------- +00 | FIT meets BootGuard requirements | :white_check_mark: | Document 599500 Revision 1.2 | | 1.0 / 2.0 / 2.1 +01 | SACM meets sane BootGuard requirements | :white_check_mark: | Document 315168-017 | Chapter A. Authenticated Code Module | 1.0 / 2.0 / 2.1 +02 | Key Manifest meets sane BootGuard requirements | :white_check_mark: | Document 557867 / 575623 | | 1.0 / 2.0 / 2.1 +03 | Boot Policy Manifest meets sane BootGuard requirements | :white_check_mark: | Document 557867 / 575623 | | 1.0 / 2.0 / 2.1 +04 | Verifies BPM and IBBs match firmware image | :white_check_mark: | Document 557867 / 575623 | | 1.0 / 2.0 / 2.1 +05 | [RUNTIME] Validates Intel ME specific configuration against KM/BPM in firmware image | :white_check_mark: | Document 557867 / 575623 | | 1.0 / 2.0 +06 | [RUNTIME] Verifies Intel ME Boot Guard status | :white_check_mark: | Document 729124 / 829718 | | 2.1 +07 | [RUNTIME] Verifies Intel ME Boot Guard configuration is sane and safe | :white_check_mark: | Document 557867 / 575623 / 829718 / 729124 | 1.0 / 2.0 / 2.1 +08 | [RUNTIME] Verifies post-boot ACM status | :white_check_mark: | Document 315168-017 / 575623 rev 1.5 | | 1.0 / 2.0 +09 | [RUNTIME] Verifies post-boot BtG/TXT registers | :white_check_mark: | Document 315168-017 / 575623 rev 1.9 | | 1.0 / 2.0 / 2.1 + +## Differences in Test Logic Between BG/CBnT 2.0 and CBnT 2.1 + +Platforms starting from MTL follow CBnT 2.1 specification. This brings additional logic changes in the tests +given above: + - Test 03: As per Document 575623 rev. 1.9, section 5.3.3.5, PCDE and its sub-structures (PDRS and CBNS) are mandatory +in CBnT 2.1. Therefore on "Validate BPM structure" step, they are also included. Additionally, extending PCR7 to the operating system was deprecated +with MTL, therefore with CBnT 2.1, this check is skipped. +> [!NOTE] +> While this extending PCR7 authority is recommended for older platforms, it breaks the BitLocker on Windows >=10. Thus, it is often not set by the OEM, +> and should be treated as information rather than hard error. + + - Test 05: Platforms that conform to CBnT 2.1 use different specification of Intel ME (18 or above). These do not expose neither +SVN for KM and BPM, nor KMID (see Documents 729124/829718). Therefore, Test 05 for CBnT 2.1 is skipped. Instead, Test 6 is available. +It checks BootGuard status exposed by Intel ME, which is equivalent to runtime validation of BootGuard startup process. + + - Test 07: Similarly as with Test 05, some information are not exposed in Intel ME 18 and above, see below: + - Bypass Boot Policy + - Boot Policy validity + - Error Enforcement Policy + - Protected BIOS environment status + - BootGuard disabled bit + Instead, the following is checked with Intel ME 18 and above: + - FPF lock + - Debug Mode status + - Validity of the bits that follow + - Whether RCS origin is ACM + - CPU Debug status + - ME working state correctness + - ME operating mode correctness + + - Test 08: The check for ACM status by reading `txtSpace >> 0x328` only gives a meaningful + results if TXT is disabled in BIOS by the user. Otherwise, the same address will be + used as `TXT.ERRORCODE` register, and filled with the TXT status. Now given that TXT started + successfully, bit 31 will change the meaning, i.e. if set, there is some error that we could + further evaluate, otherwise we shall ignore the rest. Therefore, Test 07 is limited to BG 1.0 + and CBnT 2.0. + +- Test 09: Available for all specifications, same as Test 08, but without the ACM status check if TXT is enabled, and +with the additional checks of BootStatus register, namely: + - Boot Guard startup status + - whether BIOS is considered trusted + - whether CPU error occurred + - SACM startup status. diff --git a/cmd/core/bg-suite/cmd.go b/cmd/core/bg-suite/cmd.go index fb25d37c..58b2495d 100644 --- a/cmd/core/bg-suite/cmd.go +++ b/cmd/core/bg-suite/cmd.go @@ -5,10 +5,12 @@ import ( "fmt" "os" "regexp" + "slices" "sort" "strconv" "strings" + "github.com/9elements/converged-security-suite/v2/pkg/intel" "github.com/9elements/converged-security-suite/v2/pkg/test" "github.com/9elements/converged-security-suite/v2/pkg/tools" log "github.com/sirupsen/logrus" @@ -48,6 +50,12 @@ var cli struct { func (e *execTestsCmd) Run(ctx *context) error { ret := false + bgver := intel.RuntimeBGVersion() + log.Infof("Runtime BG/CBnT version: %s", bgver) + if bgver == intel.Unknown { + log.Warn("Unable to map CPU model to Boot Guard/CBnT generation") + } + data, err := os.ReadFile(e.Firmware) if err != nil { return fmt.Errorf("can't read firmware file") @@ -59,7 +67,7 @@ func (e *execTestsCmd) Run(ctx *context) error { } switch e.Set { case "all": - log.Info("For more information about the documents and chapters, run: bg-suite -m") + log.Info("For more information about the documents and chapters, run: bg-suite markdown") ret = run("All", getTests(), &preset, e.Interactive) case "static": ret = run("Static", getStaticTest(), &preset, e.Interactive) @@ -97,6 +105,10 @@ func (e *execTestsCmd) Run(ctx *context) error { func (l *listCmd) Run(ctx *context) error { tests := getTests() for i := range tests { + if tests[i].Description != "" { + log.Infof("Test No: %v, %v - %v", i, tests[i].Name, tests[i].Description) + continue + } log.Infof("Test No: %v, %v", i, tests[i].Name) } return nil @@ -106,8 +118,8 @@ func (m *markdownCmd) Run(ctx *context) error { var teststate string tests := getTests() - log.Info("Id | Test | Implemented | Document | Chapter") - log.Info("------------|------------|------------|------------|------------") + log.Info("Id | Test | Description | Implemented | Document | Chapter") + log.Info("------------|------------|------------|------------|------------|------------") for i := range tests { if tests[i].Status == test.Implemented { @@ -121,7 +133,7 @@ func (m *markdownCmd) Run(ctx *context) error { if docID != "" { docID = "Document " + docID } - log.Infof("%02d | %-48s | %-22s | %-28s | %-56s", i, tests[i].Name, teststate, docID, tests[i].SpecificationChapter) + log.Infof("%02d | %-48s | %-52s | %-22s | %-28s | %-56s", i, tests[i].Name, tests[i].Description, teststate, docID, tests[i].SpecificationChapter) } return nil } @@ -133,7 +145,15 @@ func (v *versionCmd) Run(ctx *context) error { func getTests() []*test.Test { var tests []*test.Test + bgver := intel.RuntimeBGVersion() + for i := range test.TestsBootGuard { + if strings.HasPrefix(test.TestsBootGuard[i].Name, "[RUNTIME]") { + if slices.Contains(test.TestsBootGuard[i].SupportedVersion, bgver) { + tests = append(tests, test.TestsBootGuard[i]) + } + continue + } tests = append(tests, test.TestsBootGuard[i]) } return tests @@ -151,9 +171,13 @@ func getStaticTest() []*test.Test { func getRuntimeTest() []*test.Test { var tests []*test.Test + bgver := intel.RuntimeBGVersion() + for i := range test.TestsBootGuard { if strings.HasPrefix(test.TestsBootGuard[i].Name, "[RUNTIME]") { - tests = append(tests, test.TestsBootGuard[i]) + if slices.Contains(test.TestsBootGuard[i].SupportedVersion, bgver) { + tests = append(tests, test.TestsBootGuard[i]) + } } } return tests @@ -188,9 +212,18 @@ func run(testGroup string, tests []*test.Test, preset *test.PreSet, interactive if !interactive { var t []temptest + bgVersion := string(intel.RuntimeBGVersion()) for index := range tests { if tests[index].Status != test.NotImplemented { - ttemp := temptest{index, tests[index].Name, tests[index].Result.String(), tests[index].ErrorText, tests[index].Status.String()} + ttemp := temptest{ + Testnumber: index, + Testname: tests[index].Name, + Description: tests[index].Description, + BgVersion: bgVersion, + Result: tests[index].Result.String(), + Error: tests[index].ErrorText, + Status: tests[index].Status.String(), + } t = append(t, ttemp) } } diff --git a/cmd/core/bg-suite/main.go b/cmd/core/bg-suite/main.go index 482be1fd..45aed547 100644 --- a/cmd/core/bg-suite/main.go +++ b/cmd/core/bg-suite/main.go @@ -23,11 +23,13 @@ var ( ) type temptest struct { - Testnumber int - Testname string - Result string - Error string - Status string + Testnumber int + Testname string + Description string + BgVersion string + Result string + Error string + Status string } func main() { diff --git a/go.mod b/go.mod index c150a628..0bed6011 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/9elements/converged-security-suite/v2 -go 1.24.12 +go 1.25.0 require ( github.com/9elements/go-linux-lowlevel-hw v1.0.5-0.20260217195309-8b54f7428e51 @@ -18,13 +18,15 @@ require ( github.com/google/go-tpm v0.9.3 github.com/google/uuid v1.3.0 github.com/hashicorp/go-multierror v1.1.1 - github.com/linuxboot/fiano v1.2.1-0.20250121191917-5620ca1697c5 + github.com/linuxboot/fiano v1.2.1-0.20260430092818-8f28c11fe9e8 github.com/logrusorgru/aurora v2.0.3+incompatible github.com/marcoguerri/go-tpm-tcti v0.0.0-20210425104733-8e8c8fe68e60 + github.com/prometheus/procfs v0.11.0 github.com/sirupsen/logrus v1.9.3 github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3 github.com/stretchr/testify v1.8.4 github.com/tidwall/pretty v1.2.1 + github.com/u-root/cpuid v0.0.0 github.com/ulikunitz/xz v0.5.14 github.com/xaionaro-facebook/go-dmidecode v0.0.0-20220413144237-c42d5bef2498 github.com/xaionaro-go/bytesextra v0.0.0-20220103144954-846e454ddea9 @@ -45,7 +47,6 @@ require ( github.com/google/certificate-transparency-go v1.1.2 // indirect github.com/google/go-tspi v0.3.0 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect - github.com/intel-go/cpuid v0.0.0-20220614022739-219e067757cb // indirect github.com/jedib0t/go-pretty/v6 v6.4.6 // indirect github.com/mattn/go-runewidth v0.0.13 // indirect github.com/micgor32/go-msr v0.0.0-20260216140510-4af4a85b8dc7 // indirect @@ -53,14 +54,14 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rivo/uniseg v0.2.0 // indirect github.com/tjfoc/gmsm v1.4.1 // indirect - github.com/u-root/cpuid v0.0.0 // indirect golang.org/x/crypto v0.45.0 // indirect - golang.org/x/sync v0.18.0 // indirect - golang.org/x/sys v0.38.0 // indirect + golang.org/x/sync v0.20.0 // indirect + golang.org/x/sys v0.42.0 // indirect golang.org/x/text v0.31.0 // indirect ) replace ( github.com/intel-go/cpuid => github.com/u-root/cpuid v0.0.0-20250320140348-cc5fe81d966c github.com/lyft/protoc-gen-validate => github.com/envoyproxy/protoc-gen-validate v1.3.0 + github.com/prometheus/procfs => github.com/micgor32/procfs v0.0.0-20260427172801-e86068ec7955 ) diff --git a/go.sum b/go.sum index 2d8f5817..e72d100b 100644 --- a/go.sum +++ b/go.sum @@ -63,8 +63,6 @@ contrib.go.opencensus.io/exporter/stackdriver v0.13.8/go.mod h1:huNtlWx75MwO7qMs contrib.go.opencensus.io/integrations/ocsql v0.1.4/go.mod h1:8DsSdjz3F+APR+0z0WkU1aRorQCFfRxvqjUUPMbF3fE= contrib.go.opencensus.io/resource v0.1.1/go.mod h1:F361eGI91LCmW1I/Saf+rX0+OFcigGlFvXwEGEnkRLA= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/9elements/go-linux-lowlevel-hw v0.0.0-20240812193855-7e0a5df7e2d0 h1:QkhlY4jC50SFbqc9YGNdPmcekSR3hIspGTIGr9nr2aI= -github.com/9elements/go-linux-lowlevel-hw v0.0.0-20240812193855-7e0a5df7e2d0/go.mod h1:4aGFVjnPLsC83PKysZc3u8kUu5kPrV8wbrE5mL72kLw= github.com/9elements/go-linux-lowlevel-hw v1.0.5-0.20260217195309-8b54f7428e51 h1:Jnz/J8hHJazFkNoQznVt5Uy5yAXg50Hp0t0Pc5eHAR0= github.com/9elements/go-linux-lowlevel-hw v1.0.5-0.20260217195309-8b54f7428e51/go.mod h1:EI2O4DG2V9XYO2JFSiMAVKaDgDjyHMr55g5YrmppPFY= github.com/Azure/azure-amqp-common-go/v2 v2.1.0/go.mod h1:R8rea+gJRuJR6QxTir/XuEd+YuKoUiazDC/N96FiDEU= @@ -87,6 +85,8 @@ github.com/Masterminds/semver/v3 v3.0.3/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0 github.com/Masterminds/semver/v3 v3.1.0/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/Masterminds/sprig v2.15.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= +github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s= +github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= @@ -186,6 +186,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsr github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0= +github.com/creack/pty v1.1.21/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -197,7 +199,6 @@ github.com/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e h1:vUmf0yez github.com/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e/go.mod h1:YTIHhz/QFSYnu/EhlF2SpU2Uk+32abacUYA5ZPljz1A= github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= @@ -341,8 +342,9 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-github/v28 v28.1.1/go.mod h1:bsqJWQX05omyWVmc00nEUql9mhQyv38lDZ8kPZcQVoM= github.com/google/go-licenses v0.0.0-20210329231322-ce1d9163b77d/go.mod h1:+TYOmkVoJOpwnS0wfdsJCV9CoD5nJYsHoFk/0CrTK4M= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= @@ -453,6 +455,10 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo= github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= +github.com/hugelgupf/go-shlex v0.0.0-20200702092117-c80c9d0918fa h1:s3KPo0nThtvjEamF/aElD4k5jSsBHew3/sgNTnth+2M= +github.com/hugelgupf/go-shlex v0.0.0-20200702092117-c80c9d0918fa/go.mod h1:I1uW6ymzwsy5TlQgD1bFAghdMgBYqH1qtCeHoZgHMqs= +github.com/hugelgupf/vmtest v0.0.0-20240307030256-5d9f3d34a58d h1:nP8SfQJqruIVSWYJTuYc37jLHEY1Z0fF+zKSrs3K/C8= +github.com/hugelgupf/vmtest v0.0.0-20240307030256-5d9f3d34a58d/go.mod h1:B63hDJMhTupLWCHwopAyEo7wRFowx9kOc8m8j1sfOqE= github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= @@ -515,8 +521,8 @@ github.com/letsencrypt/pkcs11key/v4 v4.0.0/go.mod h1:EFUvBDay26dErnNb70Nd0/VW3tJ github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= -github.com/linuxboot/fiano v1.2.1-0.20250121191917-5620ca1697c5 h1:J/nKXBQztbBv/RBRzdfTGRyJEN2nd7JyQZHisobpaPE= -github.com/linuxboot/fiano v1.2.1-0.20250121191917-5620ca1697c5/go.mod h1:aB4kacPpV1iKDXueYEpSh4dQ5uRenDrUNnPBIaf2hvU= +github.com/linuxboot/fiano v1.2.1-0.20260430092818-8f28c11fe9e8 h1:WUNicAQPAOxBzBw3HZw6xLbsOHJoIbeC0Zu0UuHaTIM= +github.com/linuxboot/fiano v1.2.1-0.20260430092818-8f28c11fe9e8/go.mod h1:aB4kacPpV1iKDXueYEpSh4dQ5uRenDrUNnPBIaf2hvU= github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/lyft/protoc-gen-star/v2 v2.0.4-0.20230330145011-496ad1ac90a4/go.mod h1:amey7yeodaJhXSbf/TlLvWiqQfLOSpEk//mLlc+axEk= @@ -546,6 +552,8 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5 github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/micgor32/go-msr v0.0.0-20260216140510-4af4a85b8dc7 h1:iZ04F08zvQa5KScTsMnyUavVYrFzvYCMcfVD7rx0Nos= github.com/micgor32/go-msr v0.0.0-20260216140510-4af4a85b8dc7/go.mod h1:kk7JILzEiQxmOhhFi5BYrsL5Ih+t7QDaIq4SAjqaIp4= +github.com/micgor32/procfs v0.0.0-20260427172801-e86068ec7955 h1:uh7Ba5ZaOM/vcWlImqGRPKafWq9m/nPMu5ha8X5QjrI= +github.com/micgor32/procfs v0.0.0-20260427172801-e86068ec7955/go.mod h1:UOx4nf4IO0zAKdb6PSRQu4RtIKHJr7R7lrhTakKuHqs= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/pkcs11 v1.0.2/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= @@ -613,6 +621,8 @@ github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0 github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pierrec/lz4/v4 v4.1.14 h1:+fL8AQEZtz/ijeNnpduH0bROTu0O3NZAlPjQxGn8LwE= +github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -648,14 +658,6 @@ github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8b github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.18.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= -github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/pseudomuto/protoc-gen-doc v1.4.1/go.mod h1:exDTOVwqpp30eV/EDPFLZy3Pwr2sn6hBC1WIYH/UbIg= github.com/pseudomuto/protoc-gen-doc v1.5.0/go.mod h1:exDTOVwqpp30eV/EDPFLZy3Pwr2sn6hBC1WIYH/UbIg= @@ -746,10 +748,14 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1 github.com/tmc/grpc-websocket-proxy v0.0.0-20200427203606-3cfed13b9966/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce/go.mod h1:o8v6yHRoik09Xen7gje4m9ERNah1d1PPsVq1VEx9vE4= -github.com/u-root/cpuid v0.0.0-20250320140348-cc5fe81d966c h1:0ghii+ZNd3GwoEMuzESLxXSGBk9jlRfWOOmkoBClopc= -github.com/u-root/cpuid v0.0.0-20250320140348-cc5fe81d966c/go.mod h1:LnxcvBqTx9ehtEbNgAP+rtKYohCaeJ2Lzmo/FSchi30= github.com/u-root/cpuid v0.0.0 h1:A9eFi+//FIyc5+7iRSnsz+vkYVRH/NqiQIxyUjUa5uo= github.com/u-root/cpuid v0.0.0/go.mod h1:4cKsFal/qG5riWG/6IGedb2y53cl1xdcbSszYjM6IrY= +github.com/u-root/gobusybox/src v0.0.0-20240226024758-7e6217d0eb49 h1:Ajo25H4yhdgtbflwzhbhUu8TgMvsnTrMwdJa4KMukmo= +github.com/u-root/gobusybox/src v0.0.0-20240226024758-7e6217d0eb49/go.mod h1:PW3wGFCHjdHxAhra5FKvcARbCGqGfentYuPKmuhv8DY= +github.com/u-root/mkuimage v0.0.0-20250905073043-9a40452f5d3b h1:ja/A01alYDScunNPtpH4aIN3cYTvFgeFtCk8nwEloEg= +github.com/u-root/mkuimage v0.0.0-20250905073043-9a40452f5d3b/go.mod h1:qzJqwYSsU0kBkl1bX/s93hfd64WbL+CP7AobQdvJb9A= +github.com/u-root/uio v0.0.0-20240209044354-b3d14b93376a h1:BH1SOPEvehD2kVrndDnGJiUF0TrBpNs+iyYocu6h0og= +github.com/u-root/uio v0.0.0-20240209044354-b3d14b93376a/go.mod h1:P3a5rG4X7tI17Nn3aOIAYr5HbIMukwXG0urG0WuL8OA= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= @@ -880,8 +886,6 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= -golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df h1:UA2aFVmmsIlefxMk29Dp2juaUSth8Pyn3Tq5Y5mJGME= -golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ= golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= @@ -914,6 +918,8 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA= +golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1012,8 +1018,8 @@ golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= -golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= +golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1043,7 +1049,6 @@ golang.org/x/sys v0.0.0-20191119060738-e882bf8e40c2/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1100,8 +1105,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= +golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -1211,6 +1216,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= +golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1412,6 +1419,8 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +mvdan.cc/sh/v3 v3.7.0 h1:lSTjdP/1xsddtaKfGg7Myu7DnlHItd3/M2tomOcNNBg= +mvdan.cc/sh/v3 v3.7.0/go.mod h1:K2gwkaesF/D7av7Kxl0HbF5kGOd2ArupNTX3X44+8l8= pack.ag/amqp v0.11.2/go.mod h1:4/cbmt4EJXSKlG6LCfWHoqmN0uFdy5i/+YFz+fTfhV4= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= diff --git a/pkg/bootflow/conditions/biosconds/intelconds/valid_bpm.go b/pkg/bootflow/conditions/biosconds/intelconds/valid_bpm.go index 90632a4c..b4d5a6b1 100644 --- a/pkg/bootflow/conditions/biosconds/intelconds/valid_bpm.go +++ b/pkg/bootflow/conditions/biosconds/intelconds/valid_bpm.go @@ -6,8 +6,8 @@ import ( "github.com/9elements/converged-security-suite/v2/pkg/bootflow/systemartifacts/biosimage/accessor/intelbiosimage" "github.com/9elements/converged-security-suite/v2/pkg/bootflow/types" - bootpolicy "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt/cbntbootpolicy" - key "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt/cbntkey" + bootpolicy "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt/bootpolicy" + key "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt/keymanifest" "github.com/linuxboot/fiano/pkg/intel/metadata/fit" ) @@ -31,25 +31,51 @@ func (ValidBPM) Check(ctx context.Context, s *types.State) bool { return false } - return validateBPM(km, bpm, bpmFIT) == nil + return validateBPM(*km, *bpm, bpmFIT) == nil } // TODO: move this to linuxboot/fiano func validateBPM( - km *key.Manifest, - bpm *bootpolicy.Manifest, + km key.Manifest, + bpm bootpolicy.Manifest, bpmFIT *fit.EntryBootPolicyManifestRecord, ) error { if err := bpm.Validate(); err != nil { return nil } - if err := bpm.PMSE.Verify(bpmFIT.DataSegmentBytes[:bpm.KeySignatureOffset]); err != nil { - return fmt.Errorf("unable to confirm KM signature: %w", err) + if bpmBg, ok := bpm.(*bootpolicy.ManifestBG); ok { + off, err := bpmBg.PMSE.OffsetOf(1) + if err != nil { + return err + } + + if err := bpmBg.PMSE.Verify(bpmFIT.DataSegmentBytes[:off]); err != nil { + return fmt.Errorf("unable to confirm KM signature: %w", err) + } + + // It is safe to assume that in the normal conditions there won't be + // mixed revisions of BPM and KM, otherwise we have bigger problems + // than non-matching BPM key in KM... + if err := km.(*key.BGManifest).ValidateBPMKey(bpmBg.PMSE.KeySignature); err != nil { + return fmt.Errorf("key chain is invalid: %w", err) + } } - if err := km.ValidateBPMKey(bpm.PMSE.KeySignature); err != nil { - return fmt.Errorf("key chain is invalid: %w", err) + if bpmCBnt, ok := bpm.(*bootpolicy.ManifestCBnT); ok { + off, err := bpmCBnt.PMSE.OffsetOf(1) + if err != nil { + return err + } + + if err := bpmCBnt.PMSE.Verify(bpmFIT.DataSegmentBytes[:off]); err != nil { + return fmt.Errorf("unable to confirm KM signature: %w", err) + } + + // Same assumption as above. + if err := km.(*key.BGManifest).ValidateBPMKey(bpmCBnt.PMSE.KeySignature); err != nil { + return fmt.Errorf("key chain is invalid: %w", err) + } } return nil diff --git a/pkg/bootflow/conditions/biosconds/intelconds/valid_ibb.go b/pkg/bootflow/conditions/biosconds/intelconds/valid_ibb.go index 5ee5b87d..1029b7d2 100644 --- a/pkg/bootflow/conditions/biosconds/intelconds/valid_ibb.go +++ b/pkg/bootflow/conditions/biosconds/intelconds/valid_ibb.go @@ -7,7 +7,7 @@ import ( "github.com/9elements/converged-security-suite/v2/pkg/bootflow/systemartifacts/biosimage" "github.com/9elements/converged-security-suite/v2/pkg/bootflow/systemartifacts/biosimage/accessor/intelbiosimage" "github.com/9elements/converged-security-suite/v2/pkg/bootflow/types" - bootpolicy "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt/cbntbootpolicy" + bootpolicy "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt/bootpolicy" ) // ValidIBB checks if the Initial Boot Block is valid (including its signatures). @@ -25,11 +25,11 @@ func (ValidIBB) Check(ctx context.Context, s *types.State) bool { return false } - return validateIBB(bpm, intelFW.SystemArtifact()) == nil + return validateIBB(*bpm, intelFW.SystemArtifact()) == nil } func validateIBB( - bpm *bootpolicy.Manifest, + bpm bootpolicy.Manifest, img *biosimage.BIOSImage, ) error { uefi, err := img.Parse() @@ -37,8 +37,16 @@ func validateIBB( return fmt.Errorf("unable to parse the UEFI layout: %w", err) } - if err := bpm.ValidateIBB(uefi); err != nil { - return fmt.Errorf("IBB signature in BPM is not valid: %w", err) + if bpmBg, ok := bpm.(*bootpolicy.ManifestBG); ok { + if err := bpmBg.ValidateIBB(uefi); err != nil { + return fmt.Errorf("IBB signature in BPM is not valid: %w", err) + } + } + + if bpmCBnt, ok := bpm.(*bootpolicy.ManifestCBnT); ok { + if err := bpmCBnt.ValidateIBB(uefi); err != nil { + return fmt.Errorf("IBB signature in BPM is not valid: %w", err) + } } return nil diff --git a/pkg/bootflow/conditions/biosconds/intelconds/valid_km.go b/pkg/bootflow/conditions/biosconds/intelconds/valid_km.go index 60eb6f1e..aa69aef7 100644 --- a/pkg/bootflow/conditions/biosconds/intelconds/valid_km.go +++ b/pkg/bootflow/conditions/biosconds/intelconds/valid_km.go @@ -6,7 +6,7 @@ import ( "github.com/9elements/converged-security-suite/v2/pkg/bootflow/systemartifacts/biosimage/accessor/intelbiosimage" "github.com/9elements/converged-security-suite/v2/pkg/bootflow/types" - key "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt/cbntkey" + key "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt/keymanifest" "github.com/linuxboot/fiano/pkg/intel/metadata/fit" ) @@ -25,17 +25,32 @@ func (ValidKM) Check(ctx context.Context, s *types.State) bool { return false } - return validateKM(km, kmFIT) == nil + return validateKM(*km, kmFIT) == nil } // TODO: move this to linuxboot/fiano func validateKM( - km *key.Manifest, + km key.Manifest, kmFIT *fit.EntryKeyManifestRecord, ) error { - if err := km.KeyAndSignature.Verify(kmFIT.DataSegmentBytes[:km.KeyManifestSignatureOffset]); err != nil { - return fmt.Errorf("unable to confirm KM signature: %w", err) + if kmBg, ok := km.(*key.BGManifest); ok { + off, err := kmBg.OffsetOf(5) + if err != nil { + return err + } + if err := kmBg.KeyAndSignature.Verify(kmFIT.DataSegmentBytes[:off]); err != nil { + return fmt.Errorf("unable to confirm KM signature: %w", err) + } } + if kmCBnT, ok := km.(*key.CBnTManifest); ok { + off, err := kmCBnT.OffsetOf(8) + if err != nil { + return err + } + if err := kmCBnT.KeyAndSignature.Verify(kmFIT.DataSegmentBytes[:off]); err != nil { + return fmt.Errorf("unable to confirm KM signature: %w", err) + } + } return nil } diff --git a/pkg/bootflow/datasources/inteldata/ibb.go b/pkg/bootflow/datasources/inteldata/ibb.go index 2eeaefe3..3747218b 100644 --- a/pkg/bootflow/datasources/inteldata/ibb.go +++ b/pkg/bootflow/datasources/inteldata/ibb.go @@ -7,6 +7,8 @@ import ( "github.com/9elements/converged-security-suite/v2/pkg/bootflow/systemartifacts/biosimage" "github.com/9elements/converged-security-suite/v2/pkg/bootflow/systemartifacts/biosimage/accessor/intelbiosimage" "github.com/9elements/converged-security-suite/v2/pkg/bootflow/types" + pkgbytes "github.com/linuxboot/fiano/pkg/bytes" + bootpolicy "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt/bootpolicy" ) // IBB implements types.DataSource by referencing to @@ -27,7 +29,17 @@ func (IBB) Data(ctx context.Context, s *types.State) (*types.Data, error) { return nil, fmt.Errorf("unable to get BPM: %w", err) } - ranges := bpm.IBBDataRanges(intelFW.SystemArtifact().Size()) + var ranges pkgbytes.Ranges + bpmP := *bpm + + if bpmBg, ok := bpmP.(*bootpolicy.ManifestBG); ok { + ranges = bpmBg.IBBDataRanges(intelFW.SystemArtifact().Size()) + } + + if bpmCBnt, ok := bpmP.(*bootpolicy.ManifestCBnT); ok { + ranges = bpmCBnt.IBBDataRanges(intelFW.SystemArtifact().Size()) + } + addrMapper := biosimage.PhysMemMapper{} ranges = addrMapper.UnresolveFullImageOffset(intelFW.SystemArtifact(), ranges...) diff --git a/pkg/bootflow/steps/intelsteps/measure_pcr0_data.go b/pkg/bootflow/steps/intelsteps/measure_pcr0_data.go index 969e2785..7ee8dd1c 100644 --- a/pkg/bootflow/steps/intelsteps/measure_pcr0_data.go +++ b/pkg/bootflow/steps/intelsteps/measure_pcr0_data.go @@ -19,6 +19,8 @@ import ( "github.com/google/go-tpm/legacy/tpm2" pkgbytes "github.com/linuxboot/fiano/pkg/bytes" manifest "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt" + bootpolicy "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt/bootpolicy" + key "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt/keymanifest" ) // MeasurePCR0DATA is a types.Step to measure the PCR0_DATA structure. @@ -92,15 +94,55 @@ func (MeasurePCR0DATA) Actions(ctx context.Context, s *types.State) types.Action } } kmAddr := keyManifestFITEntry.Headers.Address.Pointer() - pcr0DATA.kmSignature = types.Reference{ - Artifact: intelFW.SystemArtifact(), - MappedRanges: types.MappedRanges{ - AddressMapper: biosimage.PhysMemMapper{}, - Ranges: []pkgbytes.Range{{ - Offset: kmAddr + keyManifest.KeyAndSignatureOffset() + keyManifest.KeyAndSignature.SignatureOffset() + keyManifest.KeyAndSignature.Signature.DataOffset(), - Length: uint64(len(keyManifest.KeyAndSignature.Signature.Data)), - }}, - }, + switch km := (*keyManifest).(type) { + case *key.BGManifest: + keyAndSignatureOffset, err := km.OffsetOf(5) + if err != nil { + return types.Actions{commonactions.Panic(fmt.Errorf("unable to get BG key manifest key-and-signature offset: %w", err))} + } + signatureOffset, err := km.KeyAndSignature.OffsetOf(2) + if err != nil { + return types.Actions{commonactions.Panic(fmt.Errorf("unable to get BG key manifest signature offset: %w", err))} + } + signatureDataOffset, err := km.KeyAndSignature.Signature.OffsetOf(4) + if err != nil { + return types.Actions{commonactions.Panic(fmt.Errorf("unable to get BG key manifest signature data offset: %w", err))} + } + pcr0DATA.kmSignature = types.Reference{ + Artifact: intelFW.SystemArtifact(), + MappedRanges: types.MappedRanges{ + AddressMapper: biosimage.PhysMemMapper{}, + Ranges: []pkgbytes.Range{{ + Offset: kmAddr + keyAndSignatureOffset + signatureOffset + signatureDataOffset, + Length: uint64(len(km.KeyAndSignature.Signature.Data)), + }}, + }, + } + case *key.CBnTManifest: + keyAndSignatureOffset, err := km.OffsetOf(8) + if err != nil { + return types.Actions{commonactions.Panic(fmt.Errorf("unable to get CBnT key manifest key-and-signature offset: %w", err))} + } + signatureOffset, err := km.KeyAndSignature.OffsetOf(2) + if err != nil { + return types.Actions{commonactions.Panic(fmt.Errorf("unable to get CBnT key manifest signature offset: %w", err))} + } + signatureDataOffset, err := km.KeyAndSignature.Signature.OffsetOf(4) + if err != nil { + return types.Actions{commonactions.Panic(fmt.Errorf("unable to get CBnT key manifest signature data offset: %w", err))} + } + pcr0DATA.kmSignature = types.Reference{ + Artifact: intelFW.SystemArtifact(), + MappedRanges: types.MappedRanges{ + AddressMapper: biosimage.PhysMemMapper{}, + Ranges: []pkgbytes.Range{{ + Offset: kmAddr + keyAndSignatureOffset + signatureOffset + signatureDataOffset, + Length: uint64(len(km.KeyAndSignature.Signature.Data)), + }}, + }, + } + default: + return types.Actions{commonactions.Panic(fmt.Errorf("unsupported key manifest type: %T", km))} } bpManifest, bpManifestFITEntry, err := intelFW.BootPolicyManifest() @@ -110,52 +152,134 @@ func (MeasurePCR0DATA) Actions(ctx context.Context, s *types.State) types.Action } } bpmAddr := bpManifestFITEntry.Headers.Address.Pointer() + var ( + ibbdigests []manifest.HashStructure + firstDigestOffset uint64 + bpmSignatureOffset uint64 + bpmSignatureLength uint64 + ) + switch bpm := (*bpManifest).(type) { + case *bootpolicy.ManifestBG: + pmseOffset, err := bpm.OffsetOf(3) + if err != nil { + return types.Actions{commonactions.Panic(fmt.Errorf("unable to get BG boot policy manifest PMSE offset: %w", err))} + } + keySignatureOffset, err := bpm.PMSE.OffsetOf(1) + if err != nil { + return types.Actions{commonactions.Panic(fmt.Errorf("unable to get BG boot policy manifest key signature offset: %w", err))} + } + signatureOffset, err := bpm.PMSE.KeySignature.OffsetOf(2) + if err != nil { + return types.Actions{commonactions.Panic(fmt.Errorf("unable to get BG boot policy manifest signature offset: %w", err))} + } + signatureDataOffset, err := bpm.PMSE.Signature.OffsetOf(4) + if err != nil { + return types.Actions{commonactions.Panic(fmt.Errorf("unable to get BG boot policy manifest signature data offset: %w", err))} + } + bpmSignatureOffset = pmseOffset + keySignatureOffset + signatureOffset + signatureDataOffset + bpmSignatureLength = uint64(len(bpm.PMSE.Signature.Data)) + + if len(bpm.SE) == 0 { + return types.Actions{commonactions.Panic(fmt.Errorf("IBBDigest list is empty"))} + } + seOffset, err := bpm.OffsetOf(1) + if err != nil { + return types.Actions{commonactions.Panic(fmt.Errorf("unable to get BG boot policy manifest SE offset: %w", err))} + } + digestOffset, err := bpm.SE[0].OffsetOf(13) + if err != nil { + return types.Actions{commonactions.Panic(fmt.Errorf("unable to get BG boot policy manifest digest offset: %w", err))} + } + ibbdigests = []manifest.HashStructure{bpm.SE[0].Digest} + firstDigestOffset = seOffset + digestOffset + case *bootpolicy.ManifestCBnT: + pmseOffset, err := bpm.OffsetOf(6) + if err != nil { + return types.Actions{commonactions.Panic(fmt.Errorf("unable to get CBnT boot policy manifest PMSE offset: %w", err))} + } + keySignatureOffset, err := bpm.PMSE.OffsetOf(1) + if err != nil { + return types.Actions{commonactions.Panic(fmt.Errorf("unable to get CBnT boot policy manifest key signature offset: %w", err))} + } + signatureOffset, err := bpm.PMSE.KeySignature.OffsetOf(2) + if err != nil { + return types.Actions{commonactions.Panic(fmt.Errorf("unable to get CBnT boot policy manifest signature offset: %w", err))} + } + signatureDataOffset, err := bpm.PMSE.Signature.OffsetOf(4) + if err != nil { + return types.Actions{commonactions.Panic(fmt.Errorf("unable to get CBnT boot policy manifest signature data offset: %w", err))} + } + bpmSignatureOffset = pmseOffset + keySignatureOffset + signatureOffset + signatureDataOffset + bpmSignatureLength = uint64(len(bpm.PMSE.Signature.Data)) + + if len(bpm.SE) == 0 { + return types.Actions{commonactions.Panic(fmt.Errorf("IBBDigest list is empty"))} + } + seOffset, err := bpm.OffsetOf(1) + if err != nil { + return types.Actions{commonactions.Panic(fmt.Errorf("unable to get CBnT boot policy manifest SE offset: %w", err))} + } + digestListOffset, err := bpm.SE[0].OffsetOf(14) + if err != nil { + return types.Actions{commonactions.Panic(fmt.Errorf("unable to get CBnT boot policy manifest digest-list offset: %w", err))} + } + digestArrayOffset, err := bpm.SE[0].DigestList.OffsetOf(1) + if err != nil { + return types.Actions{commonactions.Panic(fmt.Errorf("unable to get CBnT boot policy manifest digest-list array offset: %w", err))} + } + ibbdigests = bpm.SE[0].DigestList.List + // +2 skips the digest-list element count prefix (uint16) to point to the first digest. + firstDigestOffset = seOffset + digestListOffset + digestArrayOffset + 2 + default: + return types.Actions{commonactions.Panic(fmt.Errorf("unsupported boot policy manifest type: %T", bpm))} + } pcr0DATA.bpmSignature = types.Reference{ Artifact: intelFW.SystemArtifact(), MappedRanges: types.MappedRanges{ AddressMapper: biosimage.PhysMemMapper{}, Ranges: []pkgbytes.Range{{ - Offset: bpmAddr + uint64(bpManifest.KeySignatureOffset) + bpManifest.PMSE.SignatureOffset() + bpManifest.PMSE.Signature.DataOffset(), - Length: uint64(len(bpManifest.PMSE.Signature.Data)), + Offset: bpmAddr + bpmSignatureOffset, + Length: bpmSignatureLength, }}, }, } - - digests := bpManifest.SE[0].DigestList.List - if len(digests) == 0 { + if len(ibbdigests) == 0 { return types.Actions{ commonactions.Panic(fmt.Errorf("IBBDigest list is empty")), } } var actions types.Actions - offsetToTheFirstDigest := bpmAddr + bpManifest.SEOffset() + - bpManifest.SE[0].DigestListOffset() + (bpManifest.SE[0].DigestList.ListOffset() + 2) for _, hashAlgo := range []manifest.Algorithm{ manifest.AlgSHA1, manifest.AlgSHA256, } { pcr0DATA.hashAlgo = hashAlgo - // Note: +2 - skip array size field to get the first element // find ibbDigest with the required algorithm - offsetToCurrentDigest := offsetToTheFirstDigest + offsetToCurrentDigest := firstDigestOffset var found bool - for idx := range digests { - if digests[idx].HashAlg == hashAlgo { + for idx := range ibbdigests { + if ibbdigests[idx].HashAlg == hashAlgo { + hashBufferOffset, err := ibbdigests[idx].OffsetOf(1) + if err != nil { + actions = append(actions, commonactions.Panic(fmt.Errorf("unable to get IBB digest hash buffer offset: %w", err))) + break + } pcr0DATA.ibbDigest = types.Reference{ Artifact: intelFW.SystemArtifact(), MappedRanges: types.MappedRanges{ AddressMapper: biosimage.PhysMemMapper{}, Ranges: []pkgbytes.Range{{ - Offset: offsetToCurrentDigest + (digests[idx].HashBufferOffset() + 2), - Length: uint64(len(digests[idx].HashBuffer)), + // +2 skips the HashBuffer size prefix (uint16). + Offset: bpmAddr + offsetToCurrentDigest + hashBufferOffset + 2, + Length: uint64(len(ibbdigests[idx].HashBuffer)), }}, }, } found = true break } - offsetToCurrentDigest += digests[idx].TotalSize() + offsetToCurrentDigest += ibbdigests[idx].TotalSize() } if found { diff --git a/pkg/bootflow/systemartifacts/biosimage/accessor/intelbiosimage/bpm.go b/pkg/bootflow/systemartifacts/biosimage/accessor/intelbiosimage/bpm.go index 2e4608f2..acd61f75 100644 --- a/pkg/bootflow/systemartifacts/biosimage/accessor/intelbiosimage/bpm.go +++ b/pkg/bootflow/systemartifacts/biosimage/accessor/intelbiosimage/bpm.go @@ -4,7 +4,7 @@ import ( "fmt" "github.com/9elements/converged-security-suite/v2/pkg/bootflow/systemartifacts/biosimage/accessor" - bootpolicy "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt/cbntbootpolicy" + bootpolicy "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt/bootpolicy" "github.com/linuxboot/fiano/pkg/intel/metadata/fit" ) diff --git a/pkg/bootflow/systemartifacts/biosimage/accessor/intelbiosimage/km.go b/pkg/bootflow/systemartifacts/biosimage/accessor/intelbiosimage/km.go index 324c1fb7..c3f25413 100644 --- a/pkg/bootflow/systemartifacts/biosimage/accessor/intelbiosimage/km.go +++ b/pkg/bootflow/systemartifacts/biosimage/accessor/intelbiosimage/km.go @@ -4,7 +4,7 @@ import ( "fmt" "github.com/9elements/converged-security-suite/v2/pkg/bootflow/systemartifacts/biosimage/accessor" - key "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt/cbntkey" + key "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt/keymanifest" "github.com/linuxboot/fiano/pkg/intel/metadata/fit" ) diff --git a/pkg/bootflow/types/state.go b/pkg/bootflow/types/state.go index 319d969c..4fedbc80 100644 --- a/pkg/bootflow/types/state.go +++ b/pkg/bootflow/types/state.go @@ -22,7 +22,7 @@ type State struct { func typeMapKey(i interface{}) reflect.Type { k := reflect.TypeOf(i) - for k.Kind() == reflect.Ptr { + for k.Kind() == reflect.Pointer { k = k.Elem() } return k @@ -97,7 +97,7 @@ func WithSubSystem[SS SubSystem]( // IncludeSubSystem adds and enables a SubSystem, but each SubSystem type could // be added only once. func (state *State) IncludeSubSystem(subSystem SubSystem) { - if reflect.TypeOf(subSystem).Kind() != reflect.Ptr { + if reflect.TypeOf(subSystem).Kind() != reflect.Pointer { panic(fmt.Sprintf("%T is not a modifiable type", subSystem)) } @@ -143,7 +143,7 @@ func WithSystemArtifact[SA SystemArtifact]( // IncludeSystemArtifact adds and enables a SystemArtifact, but each SystemArtifact type could // be added only once. func (state *State) IncludeSystemArtifact(systemArtifact SystemArtifact) { - if reflect.TypeOf(systemArtifact).Kind() != reflect.Ptr { + if reflect.TypeOf(systemArtifact).Kind() != reflect.Pointer { panic(fmt.Sprintf("%T is not a modifiable type", systemArtifact)) } diff --git a/pkg/intel/soc.go b/pkg/intel/soc.go new file mode 100644 index 00000000..2e2e7039 --- /dev/null +++ b/pkg/intel/soc.go @@ -0,0 +1,188 @@ +package intel + +import ( + cpuid "github.com/u-root/cpuid" +) + +// Based on arch/x86/include/asm/intel-family.h +// from the kernel codebase +const ( + INTEL_PENTIUM_PRO = 0x01 + INTEL_PENTIUM_II_KLAMATH = 0x03 + INTEL_PENTIUM_III_DESCHUTES = 0x05 + INTEL_PENTIUM_III_TUALATIN = 0x0B + INTEL_PENTIUM_M_DOTHAN = 0x0D + + INTEL_CORE_YONAH = 0x0E + + INTEL_CORE2_MEROM = 0x0F + INTEL_CORE2_MEROM_L = 0x16 + INTEL_CORE2_PENRYN = 0x17 + INTEL_CORE2_DUNNINGTON = 0x1D + + INTEL_NEHALEM = 0x1E + INTEL_NEHALEM_G = 0x1F + INTEL_NEHALEM_EP = 0x1A + INTEL_NEHALEM_EX = 0x2E + + INTEL_WESTMERE = 0x25 + INTEL_WESTMERE_EP = 0x2C + INTEL_WESTMERE_EX = 0x2F + + INTEL_SANDYBRIDGE = 0x2A + INTEL_SANDYBRIDGE_X = 0x2D + INTEL_IVYBRIDGE = 0x3A + INTEL_IVYBRIDGE_X = 0x3E + + INTEL_HASWELL = 0x3C + INTEL_HASWELL_X = 0x3F + INTEL_HASWELL_L = 0x45 + INTEL_HASWELL_G = 0x46 + + INTEL_BROADWELL = 0x3D + INTEL_BROADWELL_G = 0x47 + INTEL_BROADWELL_X = 0x4F + INTEL_BROADWELL_D = 0x56 + + INTEL_SKYLAKE_L = 0x4E + INTEL_SKYLAKE = 0x5E + INTEL_SKYLAKE_X = 0x55 + + INTEL_KABYLAKE_L = 0x8E + INTEL_KABYLAKE = 0x9E + + INTEL_COMETLAKE = 0xA5 + INTEL_COMETLAKE_L = 0xA6 + + INTEL_CANNONLAKE_L = 0x66 + + INTEL_ICELAKE_X = 0x6A + INTEL_ICELAKE_D = 0x6C + INTEL_ICELAKE = 0x7D + INTEL_ICELAKE_L = 0x7E + INTEL_ICELAKE_NNPI = 0x9D + + INTEL_ROCKETLAKE = 0xA7 + + INTEL_TIGERLAKE_L = 0x8C + INTEL_TIGERLAKE = 0x8D + + INTEL_SAPPHIRERAPIDS_X = 0x8F + + INTEL_EMERALDRAPIDS_X = 0xCF + + INTEL_GRANITERAPIDS_X = 0xAD + INTEL_GRANITERAPIDS_D = 0xAE + + INTEL_BARTLETTLAKE = 0xD7 + + // Hybrid processors + + INTEL_LAKEFIELD = 0x8A + + INTEL_ALDERLAKE = 0x97 + INTEL_ALDERLAKE_L = 0x9A + + INTEL_RAPTORLAKE = 0xB7 + INTEL_RAPTORLAKE_P = 0xBA + INTEL_RAPTORLAKE_S = 0xBF + + INTEL_METEORLAKE = 0xAC + INTEL_METEORLAKE_L = 0xAA + + INTEL_ARROWLAKE_H = 0xC5 + INTEL_ARROWLAKE = 0xC6 + INTEL_ARROWLAKE_U = 0xB5 + + INTEL_LUNARLAKE_M = 0xBD + + INTEL_PANTHERLAKE_L = 0xCC +) + +type BgVersion string + +const ( + Unknown BgVersion = "Unknown" + Legacy BgVersion = "Legacy (pre-Boot Guard)" + BootGuard BgVersion = "Boot Guard (1.0)" + CBnT20 BgVersion = "CBnT (2.0)" + CBnT21 BgVersion = "CBnT (2.1)" +) + +func bgVersion(model uint32) BgVersion { + switch model { + case INTEL_PENTIUM_PRO, + INTEL_PENTIUM_II_KLAMATH, + INTEL_PENTIUM_III_DESCHUTES, + INTEL_PENTIUM_III_TUALATIN, + INTEL_PENTIUM_M_DOTHAN, + INTEL_CORE_YONAH, + INTEL_CORE2_MEROM, + INTEL_CORE2_MEROM_L, + INTEL_CORE2_PENRYN, + INTEL_CORE2_DUNNINGTON, + INTEL_NEHALEM, + INTEL_NEHALEM_G, + INTEL_NEHALEM_EP, + INTEL_NEHALEM_EX, + INTEL_WESTMERE, + INTEL_WESTMERE_EP, + INTEL_WESTMERE_EX, + INTEL_SANDYBRIDGE, + INTEL_SANDYBRIDGE_X, + INTEL_IVYBRIDGE, + INTEL_IVYBRIDGE_X: + return Legacy + case INTEL_HASWELL, + INTEL_HASWELL_X, + INTEL_HASWELL_L, + INTEL_HASWELL_G, + INTEL_BROADWELL, + INTEL_BROADWELL_G, + INTEL_BROADWELL_X, + INTEL_BROADWELL_D, + INTEL_SKYLAKE_L, + INTEL_SKYLAKE, + INTEL_SKYLAKE_X, + INTEL_KABYLAKE_L, + INTEL_KABYLAKE, + INTEL_COMETLAKE_L, + INTEL_CANNONLAKE_L, + INTEL_ICELAKE_X, + INTEL_ICELAKE_D, + INTEL_ICELAKE, + INTEL_ICELAKE_L, + INTEL_ICELAKE_NNPI, + INTEL_LAKEFIELD: + return BootGuard + case INTEL_TIGERLAKE_L, + INTEL_COMETLAKE, + INTEL_ROCKETLAKE, + INTEL_TIGERLAKE, + INTEL_SAPPHIRERAPIDS_X, + INTEL_EMERALDRAPIDS_X, + INTEL_GRANITERAPIDS_X, + INTEL_GRANITERAPIDS_D, + INTEL_BARTLETTLAKE, + INTEL_ALDERLAKE, + INTEL_ALDERLAKE_L, + INTEL_RAPTORLAKE, + INTEL_RAPTORLAKE_P, + INTEL_RAPTORLAKE_S: + return CBnT20 + case INTEL_METEORLAKE, + INTEL_METEORLAKE_L, + INTEL_ARROWLAKE_H, + INTEL_ARROWLAKE, + INTEL_ARROWLAKE_U, + INTEL_LUNARLAKE_M, + INTEL_PANTHERLAKE_L: + return CBnT21 + default: + return Unknown + } +} + +func RuntimeBGVersion() BgVersion { + return bgVersion(cpuid.DisplayModel) +} diff --git a/pkg/provisioning/bootguard/bootguard.go b/pkg/provisioning/bootguard/bootguard.go index fdbd4845..fbe566ba 100644 --- a/pkg/provisioning/bootguard/bootguard.go +++ b/pkg/provisioning/bootguard/bootguard.go @@ -12,13 +12,10 @@ import ( "github.com/9elements/converged-security-suite/v2/pkg/tools" "github.com/9elements/converged-security-suite/v2/pkg/uefi/consts" "github.com/linuxboot/fiano/pkg/cbfs" - "github.com/linuxboot/fiano/pkg/intel/metadata/bg" - "github.com/linuxboot/fiano/pkg/intel/metadata/bg/bgbootpolicy" - "github.com/linuxboot/fiano/pkg/intel/metadata/bg/bgkey" + "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt" - "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt/cbntbootpolicy" - "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt/cbntkey" - "github.com/linuxboot/fiano/pkg/intel/metadata/common/bgheader" + bootpolicy "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt/bootpolicy" + keymanifest "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt/keymanifest" "github.com/linuxboot/fiano/pkg/intel/metadata/fit" "github.com/linuxboot/fiano/pkg/uefi" "github.com/tidwall/pretty" @@ -29,31 +26,7 @@ import ( // Everything more secure than SHA-1 const minHashTypeSize = 32 -func bgBPMReader(bpm *bgbootpolicy.Manifest) (*bytes.Reader, error) { - if bpm == nil { - return nil, fmt.Errorf("manifest is nil") - } - buf := new(bytes.Buffer) - _, err := bpm.WriteTo(buf) - if err != nil { - return nil, err - } - return bytes.NewReader(buf.Bytes()), nil -} - -func bgKMReader(km *bgkey.Manifest) (*bytes.Reader, error) { - if km == nil { - return nil, fmt.Errorf("manifest is nil") - } - buf := new(bytes.Buffer) - _, err := km.WriteTo(buf) - if err != nil { - return nil, err - } - return bytes.NewReader(buf.Bytes()), nil -} - -func cbntBPMReader(bpm *cbntbootpolicy.Manifest) (*bytes.Reader, error) { +func bpmReader(bpm bootpolicy.Manifest) (*bytes.Reader, error) { if bpm == nil { return nil, fmt.Errorf("manifest is nil") } @@ -65,7 +38,7 @@ func cbntBPMReader(bpm *cbntbootpolicy.Manifest) (*bytes.Reader, error) { return bytes.NewReader(buf.Bytes()), nil } -func cbntKMReader(km *cbntkey.Manifest) (*bytes.Reader, error) { +func kmReader(km keymanifest.Manifest) (*bytes.Reader, error) { if km == nil { return nil, fmt.Errorf("manifest is nil") } @@ -79,22 +52,33 @@ func cbntKMReader(km *cbntkey.Manifest) (*bytes.Reader, error) { func NewVData(vdata VersionedData) (*BootGuard, error) { var b BootGuard - var err error - manifest, err := bgBPMReader(vdata.BGbpm) - if err == nil { - b.Version, _ = bgheader.DetectBGV(manifest) - } - manifest, err = bgKMReader(vdata.BGkm) - if err == nil { - b.Version, _ = bgheader.DetectBGV(manifest) - } - manifest, err = cbntBPMReader(vdata.CBNTbpm) - if err == nil { - b.Version, _ = bgheader.DetectBGV(manifest) + + if vdata.BGbpm != nil && vdata.BGkm != nil { + // For BG 1.0 KM and BPM versions have to be the same. + // So we don't have to call DetectBGV twice. + manifest, err := bpmReader(vdata.BGbpm) + if err == nil { + b.Version, _ = cbnt.DetectBGV(manifest) + } + + _, err = kmReader(vdata.BGkm) + if err != nil { + return nil, fmt.Errorf("NewVData: %v", err) + } } - manifest, err = cbntKMReader(vdata.CBNTkm) - if err == nil { - b.Version, _ = bgheader.DetectBGV(manifest) + + if vdata.CBNTbpm != nil && vdata.CBNTkm != nil { + // for CBnT 2.0 KM and BPM will be the same, and for 2.1 + // we only care about version as reported by BPM. + manifest, err := bpmReader(vdata.CBNTbpm) + if err == nil { + b.Version, _ = cbnt.DetectBGV(manifest) + } + + _, err = kmReader(vdata.CBNTkm) + if err != nil { + return nil, fmt.Errorf("NewVData: %v", err) + } } if b.Version == 0 { return nil, fmt.Errorf("NewVData: can't identify bootguard header") @@ -109,19 +93,37 @@ func NewBPM(bpm io.ReadSeeker) (*BootGuard, error) { return nil, fmt.Errorf("manifest is nil") } var err error - b.Version, err = bgheader.DetectBGV(bpm) + b.Version, err = cbnt.DetectBGV(bpm) if err != nil { return nil, err } switch b.Version { - case bgheader.Version10: - b.VData.BGbpm = bgbootpolicy.NewManifest() + case cbnt.Version10: + bgbpm, err := bootpolicy.NewManifest(cbnt.Version10) + if err != nil { + return nil, err + } + ast, ok := bgbpm.(*bootpolicy.ManifestBG) + if !ok { + return nil, fmt.Errorf("could not assert BPM type") + } + b.VData.BGbpm = ast + _, err = b.VData.BGbpm.ReadFrom(bpm) if err != nil && !errors.Is(err, io.EOF) { return nil, err } - case bgheader.Version20: - b.VData.CBNTbpm = cbntbootpolicy.NewManifest() + case cbnt.Version20, cbnt.Version21: + cbntbpm, err := bootpolicy.NewManifest(cbnt.Version20) + if err != nil { + return nil, err + } + ast, ok := cbntbpm.(*bootpolicy.ManifestCBnT) + if !ok { + return nil, fmt.Errorf("could not assert BPM type") + } + b.VData.CBNTbpm = ast + _, err = b.VData.CBNTbpm.ReadFrom(bpm) if err != nil && !errors.Is(err, io.EOF) { return nil, err @@ -138,19 +140,37 @@ func NewKM(km io.ReadSeeker) (*BootGuard, error) { return nil, fmt.Errorf("manifest is nil") } var err error - b.Version, err = bgheader.DetectBGV(km) + b.Version, err = cbnt.DetectBGV(km) if err != nil { return nil, err } switch b.Version { - case bgheader.Version10: - b.VData.BGkm = bgkey.NewManifest() + case cbnt.Version10: + bgkm, err := keymanifest.NewManifest(cbnt.Version10) + if err != nil { + return nil, err + } + ast, ok := bgkm.(*keymanifest.BGManifest) + if !ok { + return nil, fmt.Errorf("could not assert KM type") + } + b.VData.BGkm = ast + _, err = b.VData.BGkm.ReadFrom(km) if err != nil && !errors.Is(err, io.EOF) { return nil, err } - case bgheader.Version20: - b.VData.CBNTkm = cbntkey.NewManifest() + case cbnt.Version20, cbnt.Version21: + cbntkm, err := keymanifest.NewManifest(b.Version) + if err != nil { + return nil, err + } + ast, ok := cbntkm.(*keymanifest.CBnTManifest) + if !ok { + return nil, fmt.Errorf("could not assert KM type") + } + b.VData.CBNTkm = ast + _, err = b.VData.CBNTkm.ReadFrom(km) if err != nil && !errors.Is(err, io.EOF) { return nil, err @@ -166,24 +186,44 @@ func NewBPMAndKM(bpm io.ReadSeeker, km io.ReadSeeker) (*BootGuard, error) { if bpm == nil || km == nil { return nil, fmt.Errorf("either both or one manifest is nil") } - var err error - bpmV, err := bgheader.DetectBGV(bpm) + bpmV, err := cbnt.DetectBGV(bpm) if err != nil { return nil, err } - kmV, err := bgheader.DetectBGV(km) + kmV, err := cbnt.DetectBGV(km) if err != nil { return nil, err } - if bpmV != kmV { + // This check is not valid for CBnT 2.1 since KM headers were + // not bumped at all. So the case where km header is 0x21 and + // bpm is 0x25 is fine. + if bpmV != kmV && bpmV <= cbnt.Version20 { return nil, fmt.Errorf("km and bpm version number differ") } b.Version = bpmV switch b.Version { - case bgheader.Version10: - b.VData.BGbpm = bgbootpolicy.NewManifest() - b.VData.BGkm = bgkey.NewManifest() - _, err := b.VData.BGbpm.ReadFrom(bpm) + case cbnt.Version10: + bgbpm, err := bootpolicy.NewManifest(cbnt.Version10) + if err != nil { + return nil, err + } + astbpm, ok := bgbpm.(*bootpolicy.ManifestBG) + if !ok { + return nil, fmt.Errorf("could not assert BPM type") + } + b.VData.BGbpm = astbpm + + bgkm, err := keymanifest.NewManifest(cbnt.Version10) + if err != nil { + return nil, err + } + astkm, ok := bgkm.(*keymanifest.BGManifest) + if !ok { + return nil, fmt.Errorf("could not assert KM type") + } + b.VData.BGkm = astkm + + _, err = b.VData.BGbpm.ReadFrom(bpm) if err != nil && !errors.Is(err, io.EOF) { return nil, err } @@ -191,10 +231,28 @@ func NewBPMAndKM(bpm io.ReadSeeker, km io.ReadSeeker) (*BootGuard, error) { if err != nil && !errors.Is(err, io.EOF) { return nil, err } - case bgheader.Version20: - b.VData.CBNTbpm = cbntbootpolicy.NewManifest() - b.VData.CBNTkm = cbntkey.NewManifest() - _, err := b.VData.CBNTbpm.ReadFrom(bpm) + case cbnt.Version20, cbnt.Version21: + cbntbpm, err := bootpolicy.NewManifest(b.Version) + if err != nil { + return nil, err + } + astbpm, ok := cbntbpm.(*bootpolicy.ManifestCBnT) + if !ok { + return nil, fmt.Errorf("could not assert BPM type") + } + b.VData.CBNTbpm = astbpm + + cbntkm, err := keymanifest.NewManifest(cbnt.Version20) + if err != nil { + return nil, err + } + astkm, ok := cbntkm.(*keymanifest.CBnTManifest) + if !ok { + return nil, fmt.Errorf("could not assert KM type") + } + b.VData.CBNTkm = astkm + + _, err = b.VData.CBNTbpm.ReadFrom(bpm) if err != nil && !errors.Is(err, io.EOF) { return nil, err } @@ -218,15 +276,33 @@ func NewBPMAndKMFromBIOS(biosFilepath string, jsonFilepath *os.File) (*BootGuard return nil, err } var b BootGuard - b.Version, err = bgheader.DetectBGV(bpmEntry.Reader()) + b.Version, err = cbnt.DetectBGV(bpmEntry.Reader()) if err != nil { return nil, err } switch b.Version { - case bgheader.Version10: - b.VData.BGbpm = bgbootpolicy.NewManifest() - b.VData.BGkm = bgkey.NewManifest() - _, err := b.VData.BGbpm.ReadFrom(bpmEntry.Reader()) + case cbnt.Version10: + bgbpm, err := bootpolicy.NewManifest(cbnt.Version10) + if err != nil { + return nil, err + } + bpm, ok := bgbpm.(*bootpolicy.ManifestBG) + if !ok { + return nil, fmt.Errorf("could not assert BPM type") + } + b.VData.BGbpm = bpm + + bgkm, err := keymanifest.NewManifest(cbnt.Version10) + if err != nil { + return nil, err + } + km, ok := bgkm.(*keymanifest.BGManifest) + if !ok { + return nil, fmt.Errorf("could not assert KM type") + } + b.VData.BGkm = km + + _, err = b.VData.BGbpm.ReadFrom(bpmEntry.Reader()) if err != nil && !errors.Is(err, io.EOF) { return nil, err } @@ -234,10 +310,28 @@ func NewBPMAndKMFromBIOS(biosFilepath string, jsonFilepath *os.File) (*BootGuard if err != nil && !errors.Is(err, io.EOF) { return nil, err } - case bgheader.Version20: - b.VData.CBNTbpm = cbntbootpolicy.NewManifest() - b.VData.CBNTkm = cbntkey.NewManifest() - _, err := b.VData.CBNTbpm.ReadFrom(bpmEntry.Reader()) + case cbnt.Version20, cbnt.Version21: + cbntbpm, err := bootpolicy.NewManifest(b.Version) + if err != nil { + return nil, err + } + bpm, ok := cbntbpm.(*bootpolicy.ManifestCBnT) + if !ok { + return nil, fmt.Errorf("could not assert BPM type") + } + b.VData.CBNTbpm = bpm + + cbntkm, err := keymanifest.NewManifest(b.Version) + if err != nil { + return nil, err + } + km, ok := cbntkm.(*keymanifest.CBnTManifest) + if !ok { + return nil, fmt.Errorf("could not assert KM type") + } + b.VData.CBNTkm = km + + _, err = b.VData.CBNTbpm.ReadFrom(bpmEntry.Reader()) if err != nil && !errors.Is(err, io.EOF) { return nil, err } @@ -263,9 +357,9 @@ func NewBPMAndKMFromBIOS(biosFilepath string, jsonFilepath *os.File) (*BootGuard // and validates the structure func (b *BootGuard) ValidateBPM() error { switch b.Version { - case bgheader.Version10: + case cbnt.Version10: return b.VData.BGbpm.Validate() - case bgheader.Version20: + case cbnt.Version20, cbnt.Version21: return b.VData.CBNTbpm.Validate() default: return fmt.Errorf("ValidateBPM: can't identify bootguard header") @@ -276,9 +370,9 @@ func (b *BootGuard) ValidateBPM() error { // and validates the structure func (b *BootGuard) ValidateKM() error { switch b.Version { - case bgheader.Version10: + case cbnt.Version10: return b.VData.BGkm.Validate() - case bgheader.Version20: + case cbnt.Version20, cbnt.Version21: return b.VData.CBNTkm.Validate() default: return fmt.Errorf("ValidateKM: can't identify bootguard header") @@ -288,9 +382,9 @@ func (b *BootGuard) ValidateKM() error { // PrintBPM prints the boot policy manifest in human readable func (b *BootGuard) PrintBPM() { switch b.Version { - case bgheader.Version10: + case cbnt.Version10: b.VData.BGbpm.Print() - case bgheader.Version20: + case cbnt.Version20, cbnt.Version21: b.VData.CBNTbpm.Print() default: log.Error("PrintBPM: can't identify bootguard header") @@ -300,9 +394,9 @@ func (b *BootGuard) PrintBPM() { // PrintKM prints the key manifest in human readable func (b *BootGuard) PrintKM() { switch b.Version { - case bgheader.Version10: + case cbnt.Version10: b.VData.BGkm.Print() - case bgheader.Version20: + case cbnt.Version20, cbnt.Version21: b.VData.CBNTkm.Print() default: log.Error("PrintKM: can't identify bootguard header") @@ -314,9 +408,9 @@ func (b *BootGuard) WriteKM() ([]byte, error) { var err error buf := new(bytes.Buffer) switch b.Version { - case bgheader.Version10: + case cbnt.Version10: _, err = b.VData.BGkm.WriteTo(buf) - case bgheader.Version20: + case cbnt.Version20, cbnt.Version21: _, err = b.VData.CBNTkm.WriteTo(buf) default: log.Error("WriteKM: can't identify bootguard header") @@ -329,9 +423,9 @@ func (b *BootGuard) WriteBPM() ([]byte, error) { var err error buf := new(bytes.Buffer) switch b.Version { - case bgheader.Version10: + case cbnt.Version10: _, err = b.VData.BGbpm.WriteTo(buf) - case bgheader.Version20: + case cbnt.Version20, cbnt.Version21: _, err = b.VData.CBNTbpm.WriteTo(buf) default: log.Error("WriteBPM: can't identify bootguard header") @@ -367,15 +461,14 @@ func (b *BootGuard) ReadJSON(filepath string) error { // StitchKM returns a key manifest manifest as byte slice func (b *BootGuard) StitchKM(pubKey crypto.PublicKey, signature []byte) ([]byte, error) { switch b.Version { - case bgheader.Version10: + case cbnt.Version10: if err := b.VData.BGkm.KeyAndSignature.FillSignature(0, pubKey, signature, b.VData.BGkm.BPKey.HashAlg); err != nil { return nil, err } - b.VData.BGkm.RehashRecursive() if err := b.VData.BGkm.Validate(); err != nil { return nil, err } - case bgheader.Version20: + case cbnt.Version20, cbnt.Version21: if err := b.VData.CBNTkm.KeyAndSignature.FillSignature(0, pubKey, signature, b.VData.CBNTkm.PubKeyHashAlg); err != nil { return nil, err } @@ -392,9 +485,14 @@ func (b *BootGuard) StitchKM(pubKey crypto.PublicKey, signature []byte) ([]byte, // StitchBPM returns a boot policy manifest as byte slice func (b *BootGuard) StitchBPM(pubKey crypto.PublicKey, signature []byte) ([]byte, error) { switch b.Version { - case bgheader.Version10: - b.VData.BGbpm.PMSE = *bgbootpolicy.NewSignature() - if err := b.VData.BGbpm.PMSE.FillSignature(0, pubKey, signature, bg.AlgNull); err != nil { + case cbnt.Version10: + sig, err := bootpolicy.NewSignature(cbnt.Version10) + if err != nil { + return nil, err + } + b.VData.BGbpm.PMSE = *sig + + if err := b.VData.BGbpm.PMSE.FillSignature(0, pubKey, signature, cbnt.AlgNull); err != nil { return nil, err } @@ -402,8 +500,12 @@ func (b *BootGuard) StitchBPM(pubKey crypto.PublicKey, signature []byte) ([]byte if err := b.VData.BGbpm.Validate(); err != nil { return nil, err } - case bgheader.Version20: - b.VData.CBNTbpm.PMSE = *cbntbootpolicy.NewSignature() + case cbnt.Version20, cbnt.Version21: + sig, err := bootpolicy.NewSignature(cbnt.Version20) + if err != nil { + return nil, err + } + b.VData.CBNTbpm.PMSE = *sig if err := b.VData.CBNTbpm.PMSE.FillSignature(0, pubKey, signature, cbnt.AlgNull); err != nil { return nil, err } @@ -422,21 +524,25 @@ func (b *BootGuard) StitchBPM(pubKey crypto.PublicKey, signature []byte) ([]byte func (b *BootGuard) SignKM(signAlgo string, signer crypto.Signer) ([]byte, error) { buf := new(bytes.Buffer) switch b.Version { - case bgheader.Version10: - signAlgo, err := bg.GetAlgFromString(signAlgo) + case cbnt.Version10: + signAlgo, err := cbnt.GetAlgFromString(signAlgo) if err != nil { return nil, err } - b.VData.BGkm.RehashRecursive() _, err = b.VData.BGkm.WriteTo(buf) if err != nil { return nil, err } - unsignedKM := buf.Bytes()[:b.VData.BGkm.KeyAndSignatureOffset()] - if err := b.VData.BGkm.SetSignature(signAlgo, signer, unsignedKM); err != nil { + off, err := b.VData.BGkm.OffsetOf(5) + if err != nil { + return nil, err + } + unsignedKM := buf.Bytes()[:off] + // FIXME: second algo here is not needed in BG + if err := b.VData.BGkm.SetSignature(signAlgo, signAlgo, signer, unsignedKM); err != nil { return nil, err } - case bgheader.Version20: + case cbnt.Version20, cbnt.Version21: signAlgo, err := cbnt.GetAlgFromString(signAlgo) if err != nil { return nil, err @@ -446,7 +552,11 @@ func (b *BootGuard) SignKM(signAlgo string, signer crypto.Signer) ([]byte, error if err != nil { return nil, err } - unsignedKM := buf.Bytes()[:b.VData.CBNTkm.KeyAndSignatureOffset()] + v, err := b.VData.CBNTkm.OffsetOf(8) + if err != nil { + return nil, err + } + unsignedKM := buf.Bytes()[:v] if err = b.VData.CBNTkm.SetSignature(signAlgo, b.VData.CBNTkm.PubKeyHashAlg, signer, unsignedKM); err != nil { return nil, err } @@ -460,22 +570,30 @@ func (b *BootGuard) SignKM(signAlgo string, signer crypto.Signer) ([]byte, error func (b *BootGuard) SignBPM(signAlgo, hashAlgo string, privkey crypto.PrivateKey) ([]byte, error) { buf := new(bytes.Buffer) switch b.Version { - case bgheader.Version10: - signAlgo, err := bg.GetAlgFromString(signAlgo) + case cbnt.Version10: + signAlgo, err := cbnt.GetAlgFromString(signAlgo) + if err != nil { + return nil, err + } + sig, err := bootpolicy.NewSignature(cbnt.Version10) if err != nil { return nil, err } - b.VData.BGbpm.PMSE = *bgbootpolicy.NewSignature() + b.VData.BGbpm.PMSE = *sig b.VData.BGbpm.RehashRecursive() _, err = b.VData.BGbpm.WriteTo(buf) if err != nil { return nil, err } - unsignedBPM := buf.Bytes()[:b.VData.BGbpm.PMSE.KeySignatureOffset()] - if err := b.VData.BGbpm.PMSE.SetSignature(signAlgo, privkey.(crypto.Signer), unsignedBPM); err != nil { + off, err := b.VData.BGbpm.PMSE.OffsetOf(1) + if err != nil { + return nil, err + } + unsignedBPM := buf.Bytes()[:off] + if err := b.VData.BGbpm.PMSE.SetSignature(signAlgo, signAlgo, privkey.(crypto.Signer), unsignedBPM); err != nil { return nil, err } - case bgheader.Version20: + case cbnt.Version20, cbnt.Version21: signAlgo, err := cbnt.GetAlgFromString(signAlgo) if err != nil { return nil, err @@ -484,7 +602,11 @@ func (b *BootGuard) SignBPM(signAlgo, hashAlgo string, privkey crypto.PrivateKey if err != nil { return nil, err } - b.VData.CBNTbpm.PMSE = *cbntbootpolicy.NewSignature() + sig, err := bootpolicy.NewSignature(cbnt.Version20) + if err != nil { + return nil, err + } + b.VData.CBNTbpm.PMSE = *sig b.VData.CBNTbpm.RehashRecursive() _, err = b.VData.CBNTbpm.WriteTo(buf) if err != nil { @@ -504,20 +626,27 @@ func (b *BootGuard) SignBPM(signAlgo, hashAlgo string, privkey crypto.PrivateKey func (b *BootGuard) VerifyKM() error { buf := new(bytes.Buffer) switch b.Version { - case bgheader.Version10: + case cbnt.Version10: _, err := b.VData.BGkm.WriteTo(buf) if err != nil { return err } - if err := b.VData.BGkm.KeyAndSignature.Verify(buf.Bytes()[:b.VData.BGkm.KeyAndSignatureOffset()]); err != nil { + km := b.VData.BGkm + off, err := km.OffsetOf(5) + if err != nil { + return err + } + if err := km.KeyAndSignature.Verify(buf.Bytes()[:off]); err != nil { return err } - case bgheader.Version20: + case cbnt.Version20, cbnt.Version21: _, err := b.VData.CBNTkm.WriteTo(buf) if err != nil { return err } - if err := b.VData.CBNTkm.KeyAndSignature.Verify(buf.Bytes()[:b.VData.CBNTkm.KeyAndSignatureOffset()]); err != nil { + + v, _ := b.VData.CBNTkm.OffsetOf(8) + if err := b.VData.CBNTkm.KeyAndSignature.Verify(buf.Bytes()[:v]); err != nil { return err } default: @@ -530,20 +659,25 @@ func (b *BootGuard) VerifyKM() error { func (b *BootGuard) VerifyBPM() error { buf := new(bytes.Buffer) switch b.Version { - case bgheader.Version10: + case cbnt.Version10: _, err := b.VData.BGbpm.WriteTo(buf) if err != nil { return err } - if err := b.VData.BGbpm.PMSE.Verify(buf.Bytes()[:b.VData.BGbpm.PMSEOffset()]); err != nil { + off, err := b.VData.BGbpm.OffsetOf(3) + if err != nil { return err } - case bgheader.Version20: + if err := b.VData.BGbpm.PMSE.Verify(buf.Bytes()[:off]); err != nil { + return err + } + case cbnt.Version20, cbnt.Version21: _, err := b.VData.CBNTbpm.WriteTo(buf) if err != nil { return err } - if err := b.VData.CBNTbpm.PMSE.Verify(buf.Bytes()[:b.VData.CBNTbpm.KeySignatureOffset]); err != nil { + off := uint64(b.VData.CBNTbpm.KeySignatureOffset) + if err := b.VData.CBNTbpm.PMSE.Verify(buf.Bytes()[:off]); err != nil { return err } default: @@ -577,8 +711,8 @@ func (b *BootGuard) CalculateNEMSize(image []byte, acm *tools.ACM) (uint16, erro totalSize += uint32(acm.Header.GetSize().Size()) totalSize += defaultStackAndDataSize switch b.Version { - case bgheader.Version10: - totalSize += uint32((&bgbootpolicy.BPMH{}).TotalSize()) + case cbnt.Version10: + totalSize += uint32((&bootpolicy.BPMHBG{}).TotalSize()) totalSize += uint32(b.VData.BGbpm.SE[0].TotalSize()) for _, ibb := range b.VData.BGbpm.SE[0].IBBSegments { totalSize += ibb.Size @@ -594,10 +728,10 @@ func (b *BootGuard) CalculateNEMSize(image []byte, acm *tools.ACM) (uint16, erro if (totalSize % 4096) != 0 { totalSize += 4096 - (totalSize % 4096) } - return uint16(bgbootpolicy.NewSize4K(totalSize)), nil - case bgheader.Version20: + return uint16(bootpolicy.NewSize4K(totalSize)), nil + case cbnt.Version20, cbnt.Version21: totalSize += uint32(b.VData.CBNTkm.KeyManifestSignatureOffset) - totalSize += uint32((&cbntbootpolicy.BPMH{}).TotalSize()) + totalSize += uint32((&bootpolicy.BPMHCBnT{}).TotalSize()) for _, se := range b.VData.CBNTbpm.SE { totalSize += uint32(se.ElementSize) for _, ibb := range se.IBBSegments { @@ -621,7 +755,7 @@ func (b *BootGuard) CalculateNEMSize(image []byte, acm *tools.ACM) (uint16, erro if (totalSize % 4096) != 0 { totalSize += 4096 - (totalSize % 4096) } - return uint16(cbntbootpolicy.NewSize4K(totalSize)), nil + return uint16(bootpolicy.NewSize4K(totalSize)), nil default: return 0, fmt.Errorf("CalculateNEMSize: can't identify bootguard header") } @@ -636,8 +770,8 @@ func (b *BootGuard) GetBPMPubHash(pubkey crypto.PublicKey, hashAlgo string) erro return err } switch b.Version { - case bgheader.Version10: - hashAlg, err := bg.GetAlgFromString(hashAlgo) + case cbnt.Version10: + hashAlg, err := cbnt.GetAlgFromString(hashAlgo) if err != nil { return err } @@ -650,12 +784,12 @@ func (b *BootGuard) GetBPMPubHash(pubkey crypto.PublicKey, hashAlgo string) erro return err } data = hash.Sum(nil) - hStruc := bg.HashStructure{ - HashAlg: bg.Algorithm(hashAlg), + hStruc := cbnt.HashStructure{ + HashAlg: cbnt.Algorithm(hashAlg), } hStruc.HashBuffer = data b.VData.BGkm.BPKey = hStruc - case bgheader.Version20: + case cbnt.Version20, cbnt.Version21: hashAlg, err := cbnt.GetAlgFromString(hashAlgo) if err != nil { return err @@ -669,14 +803,14 @@ func (b *BootGuard) GetBPMPubHash(pubkey crypto.PublicKey, hashAlgo string) erro return err } data = hash.Sum(nil) - var keyHashes []cbntkey.Hash + var keyHashes []keymanifest.Hash hStruc := &cbnt.HashStructure{ HashAlg: cbnt.Algorithm(hashAlg), } hStruc.HashBuffer = data - kH := cbntkey.Hash{ - Usage: cbntkey.UsageBPMSigningPKD, + kH := keymanifest.Hash{ + Usage: keymanifest.UsageBPMSigningPKD, Digest: *hStruc, } b.VData.CBNTkm.Hash = append(keyHashes, kH) @@ -688,8 +822,8 @@ func (b *BootGuard) GetBPMPubHash(pubkey crypto.PublicKey, hashAlgo string) erro func (b *BootGuard) GetIBBsDigest(image []byte, hashAlgo string) (digest []byte, err error) { switch b.Version { - case bgheader.Version10: - hashAlg, err := bg.GetAlgFromString(hashAlgo) + case cbnt.Version10: + hashAlg, err := cbnt.GetAlgFromString(hashAlgo) if err != nil { return nil, err } @@ -726,7 +860,7 @@ func (b *BootGuard) GetIBBsDigest(image []byte, hashAlgo string) (digest []byte, } } digest = hash.Sum(nil) - case bgheader.Version20: + case cbnt.Version20, cbnt.Version21: hashAlg, err := cbnt.GetAlgFromString(hashAlgo) if err != nil { return nil, err @@ -777,7 +911,7 @@ func (b *BootGuard) CreateIBBDigest(biosFilepath string) error { return fmt.Errorf("unable to read file '%s': %w", biosFilepath, err) } switch b.Version { - case bgheader.Version10: + case cbnt.Version10: hashAlgo := b.VData.BGbpm.SE[0].Digest.HashAlg.String() d, err := b.GetIBBsDigest(data, hashAlgo) if err != nil { @@ -785,7 +919,7 @@ func (b *BootGuard) CreateIBBDigest(biosFilepath string) error { } b.VData.BGbpm.SE[0].Digest.HashBuffer = make([]byte, len(d)) copy(b.VData.BGbpm.SE[0].Digest.HashBuffer, d) - case bgheader.Version20: + case cbnt.Version20, cbnt.Version21: for iterator, item := range b.VData.CBNTbpm.SE[0].DigestList.List { d, err := b.GetIBBsDigest(data, item.HashAlg.String()) if err != nil { @@ -803,16 +937,16 @@ func (b *BootGuard) CreateIBBDigest(biosFilepath string) error { // BPMCryptoSecure verifies that BPM uses sane crypto algorithms func (b *BootGuard) BPMCryptoSecure() (bool, error) { switch b.Version { - case bgheader.Version10: + case cbnt.Version10: hash := b.VData.BGbpm.SE[0].Digest.HashAlg - if hash == bg.AlgSHA1 || hash.IsNull() { + if hash == cbnt.AlgSHA1 || hash.IsNull() { return false, fmt.Errorf("signed IBB hash in BPM uses insecure hash algorithm SHA1/Null") } hash = b.VData.BGbpm.PMSE.Signature.HashAlg - if hash == bg.AlgSHA1 || hash.IsNull() { + if hash == cbnt.AlgSHA1 || hash.IsNull() { return false, fmt.Errorf("BPM signature uses insecure hash algorithm SHA1/Null") } - case bgheader.Version20: + case cbnt.Version20, cbnt.Version21: for _, hash := range b.VData.CBNTbpm.SE[0].DigestList.List { if hash.HashAlg == cbnt.AlgSHA1 || hash.HashAlg.IsNull() { if b.VData.CBNTbpm.SE[0].DigestList.Size < 2 { @@ -831,16 +965,16 @@ func (b *BootGuard) BPMCryptoSecure() (bool, error) { // KMCryptoSecure verifies that KM uses sane crypto algorithms func (b *BootGuard) KMCryptoSecure() (bool, error) { switch b.Version { - case bgheader.Version10: + case cbnt.Version10: hash := b.VData.BGkm.KeyAndSignature.Signature.HashAlg - if hash == bg.AlgSHA1 || hash.IsNull() { + if hash == cbnt.AlgSHA1 || hash.IsNull() { return false, fmt.Errorf("KM signature uses insecure hash algorithm SHA1/Null") } hash = b.VData.BGkm.BPKey.HashAlg - if hash == bg.AlgSHA1 || hash.IsNull() { + if hash == cbnt.AlgSHA1 || hash.IsNull() { return false, fmt.Errorf("signed BPM hash in KM uses insecure hash algorithm SHA1/Null") } - case bgheader.Version20: + case cbnt.Version20, cbnt.Version21: hash := b.VData.CBNTkm.PubKeyHashAlg if hash == cbnt.AlgSHA1 || hash.IsNull() { return false, fmt.Errorf("KM signature uses insecure hash algorithm SHA1/Null") @@ -858,13 +992,17 @@ func (b *BootGuard) KMCryptoSecure() (bool, error) { func (b *BootGuard) KMHasBPMHash() (bool, error) { var bpmHashFound bool switch b.Version { - case bgheader.Version10: - if b.VData.BGkm.BPKey.HashBufferTotalSize() > minHashTypeSize { + case cbnt.Version10: + size, err := b.VData.BGkm.BPKey.SizeOf(1) + if err != nil { + return false, err + } + if size > minHashTypeSize { bpmHashFound = true } - case bgheader.Version20: + case cbnt.Version20, cbnt.Version21: for _, hash := range b.VData.CBNTkm.Hash { - if hash.Usage == cbntkey.UsageBPMSigningPKD { + if hash.Usage == keymanifest.UsageBPMSigningPKD { bpmHashFound = true } } @@ -878,15 +1016,19 @@ func (b *BootGuard) KMHasBPMHash() (bool, error) { // BPMKeyMatchKMHash verifies that BPM pubkey hash matches KM hash of Boot Policy func (b *BootGuard) BPMKeyMatchKMHash() (bool, error) { switch b.Version { - case bgheader.Version10: - if b.VData.BGkm.BPKey.HashBufferTotalSize() > minHashTypeSize { + case cbnt.Version10: + size, err := b.VData.BGkm.BPKey.SizeOf(1) + if err != nil { + return false, err + } + if size > minHashTypeSize { if err := b.VData.BGkm.ValidateBPMKey(b.VData.BGbpm.PMSE.KeySignature); err != nil { return false, fmt.Errorf("couldn't verify bpm hash in km") } } - case bgheader.Version20: + case cbnt.Version20, cbnt.Version21: for _, hash := range b.VData.CBNTkm.Hash { - if hash.Usage == cbntkey.UsageBPMSigningPKD { + if hash.Usage == keymanifest.UsageBPMSigningPKD { if err := b.VData.CBNTkm.ValidateBPMKey(b.VData.CBNTbpm.PMSE.KeySignature); err != nil { return false, fmt.Errorf("couldn't verify bpm hash in km") } @@ -897,37 +1039,38 @@ func (b *BootGuard) BPMKeyMatchKMHash() (bool, error) { } // StrictSaneBPMSecurityProps verifies that BPM contains security properties more strictly -func (b *BootGuard) StrictSaneBPMSecurityProps() (bool, error) { +func (b *BootGuard) StrictSaneBPMSecurityProps() (bool, []string, error) { + var warn []string switch b.Version { - case bgheader.Version10: + case cbnt.Version10: flags := b.VData.BGbpm.SE[0].Flags if !flags.AuthorityMeasure() { - return false, fmt.Errorf("pcr-7 data should extended for OS security") + return false, nil, fmt.Errorf("pcr-7 data should extended for OS security") } if !flags.TPMFailureLeavesHierarchiesEnabled() { - return false, fmt.Errorf("tpm failure should lead to default measurements from PCR0 to PCR7") + warn = append(warn, "tpm failure should lead to default measurements from PCR0 to PCR7") } - case bgheader.Version20: + case cbnt.Version20, cbnt.Version21: bgFlags := b.VData.CBNTbpm.SE[0].Flags - if !bgFlags.AuthorityMeasure() { - return false, fmt.Errorf("pcr-7 data should extended for OS security") + if !bgFlags.AuthorityMeasure() && b.Version != cbnt.Version21 { + return false, nil, fmt.Errorf("pcr-7 data should extended for OS security") } if !bgFlags.TPMFailureLeavesHierarchiesEnabled() { - return false, fmt.Errorf("tpm failure should lead to default measurements from PCR0 to PCR7") + warn = append(warn, "tpm failure should lead to default measurements from PCR0 to PCR7") } txtFlags := b.VData.CBNTbpm.TXTE.ControlFlags - if txtFlags.MemoryScrubbingPolicy() != cbntbootpolicy.MemoryScrubbingPolicySACM { - return false, fmt.Errorf("S-ACM memory scrubbing should be used over the BIOS") + if txtFlags.MemoryScrubbingPolicy() != bootpolicy.MemoryScrubbingPolicySACM { + warn = append(warn, "S-ACM memory scrubbing should be used over the BIOS") } } - - return b.SaneBPMSecurityProps() + ret, err := b.SaneBPMSecurityProps() + return ret, warn, err } // SaneBPMSecurityProps verifies that BPM contains security properties set accordingly to spec func (b *BootGuard) SaneBPMSecurityProps() (bool, error) { switch b.Version { - case bgheader.Version10: + case cbnt.Version10: flags := b.VData.BGbpm.SE[0].Flags if !flags.DMAProtection() { return false, fmt.Errorf("dma protection should be enabled for bootguard") @@ -941,14 +1084,15 @@ func (b *BootGuard) SaneBPMSecurityProps() (bool, error) { if len(b.VData.BGbpm.SE[0].IBBSegments) < 1 { return false, fmt.Errorf("no ibb segments measured") } - case bgheader.Version20: + case cbnt.Version20, cbnt.Version21: bgFlags := b.VData.CBNTbpm.SE[0].Flags if !bgFlags.DMAProtection() { if b.VData.CBNTbpm.SE[0].DMAProtBase0 == 0 && b.VData.CBNTbpm.SE[0].VTdBAR == 0 { return false, fmt.Errorf("dma protection should be enabled for bootguard") } } - if !bgFlags.AuthorityMeasure() { + // PCR7 is not available since MTL + if b.VData.CBNTbpm.Version < 0x25 && !bgFlags.AuthorityMeasure() { return false, fmt.Errorf("pcr-7 data should extended for OS security") } if b.VData.CBNTbpm.SE[0].PBETValue.PBETValue() == 0 { @@ -972,39 +1116,39 @@ func (b *BootGuard) IBBsMatchBPMDigest(image []byte) (bool, error) { return false, fmt.Errorf("can't parse firmware image") } switch b.Version { - case bgheader.Version10: + case cbnt.Version10: if err := b.VData.BGbpm.ValidateIBB(firmware); err != nil { - return false, fmt.Errorf("bpm final ibb hash doesn't match selected measurements in image") + return false, fmt.Errorf("bpm final ibb hash doesn't match selected measurements in image: %w", err) } - case bgheader.Version20: + case cbnt.Version20, cbnt.Version21: if err := b.VData.CBNTbpm.ValidateIBB(firmware); err != nil { - return false, fmt.Errorf("bpm final ibb hash doesn't match selected measurements in image") + return false, fmt.Errorf("bpm final ibb hash doesn't match selected measurements in image: %w", err) } } return true, nil } // ValidateMEAgainstManifests validates during runtime ME configuation with BootGuard KM & BPM manifests -func (b *BootGuard) ValidateMEAgainstManifests(fws *FirmwareStatus6) (bool, error) { +func (b *BootGuard) ValidateMEAgainstManifests(fws *FirmwareStatus) (bool, error) { switch b.Version { - case bgheader.Version10: - if fws.BPMSVN != uint32(b.VData.BGbpm.BPMSVN) { + case cbnt.Version10: + if fws.Status6.BPMSVN != uint32(b.VData.BGbpm.BPMSVN) { return false, fmt.Errorf("bpm svn doesn't match me configuration") } - if fws.KMSVN != uint32(b.VData.BGkm.KMSVN) { + if fws.Status6.KMSVN != uint32(b.VData.BGkm.KMSVN) { return false, fmt.Errorf("km svn doesn't match me configuration") } - if fws.KMID != uint32(b.VData.BGkm.KMID) { + if fws.Status6.KMID != uint32(b.VData.BGkm.KMID) { return false, fmt.Errorf("km KMID doesn't match me configuration") } - case bgheader.Version20: - if fws.BPMSVN > uint32(b.VData.CBNTbpm.BPMSVN) { + case cbnt.Version20: + if fws.Status6.BPMSVN > uint32(b.VData.CBNTbpm.BPMSVN) { return false, fmt.Errorf("bpm svn doesn't match me configuration") } - if fws.KMSVN != uint32(b.VData.CBNTkm.KMSVN) { + if fws.Status6.KMSVN != uint32(b.VData.CBNTkm.KMSVN) { return false, fmt.Errorf("km svn doesn't match me configuration") } - if fws.KMID != uint32(b.VData.CBNTkm.KMID) { + if fws.Status6.KMID != uint32(b.VData.CBNTkm.KMID) { return false, fmt.Errorf("km KMID doesn't match me configuration") } } @@ -1092,15 +1236,15 @@ func (b *BootGuard) CreateIBBSegments(seElement uint8, flags uint16, imagepath s } } switch b.Version { - case bgheader.Version10: - b.VData.BGbpm.SE[seElement].IBBSegments = make([]bgbootpolicy.IBBSegment, len(ibbElements)) + case cbnt.Version10: + b.VData.BGbpm.SE[seElement].IBBSegments = make([]bootpolicy.IBBSegment, len(ibbElements)) for idx, ibb := range ibbElements { b.VData.BGbpm.SE[seElement].IBBSegments[idx].Base = ibb.Base b.VData.BGbpm.SE[seElement].IBBSegments[idx].Size = ibb.Size b.VData.BGbpm.SE[seElement].IBBSegments[idx].Flags = ibb.Flags } - case bgheader.Version20: - b.VData.CBNTbpm.SE[seElement].IBBSegments = make([]cbntbootpolicy.IBBSegment, len(ibbElements)) + case cbnt.Version20, cbnt.Version21: + b.VData.CBNTbpm.SE[seElement].IBBSegments = make([]bootpolicy.IBBSegment, len(ibbElements)) for idx, ibb := range ibbElements { b.VData.CBNTbpm.SE[seElement].IBBSegments[idx].Base = ibb.Base b.VData.CBNTbpm.SE[seElement].IBBSegments[idx].Size = ibb.Size diff --git a/pkg/provisioning/bootguard/hfsts.go b/pkg/provisioning/bootguard/hfsts.go index 3c2f0a13..544c55cd 100644 --- a/pkg/provisioning/bootguard/hfsts.go +++ b/pkg/provisioning/bootguard/hfsts.go @@ -10,6 +10,40 @@ import ( // Const Array with HFSTS Offsets var hfstsOffset = []int{0x40, 0x48, 0x60, 0x64, 0x68, 0x6c} +type FirmwareStatus struct { + // ME 16 + Status1 *FirmwareStatus1 + Status6 *FirmwareStatus6 + // ME 18/21 + Status5 *FirmwareStatus5 +} + +func NewFirmwareStatus(hw hwapi.LowLevelHardwareInterfaces) (*FirmwareStatus, error) { + // ME 16 + hwsts1, err := getHFSTS1(hw) + if err != nil { + return nil, err + } + + hwsts6, err := getHFSTS6(hw) + if err != nil { + return nil, err + } + + hwsts5, err := getHFSTS5(hw) + if err != nil { + return nil, err + } + + return &FirmwareStatus{ + // ME 16 + Status1: hwsts1, + Status6: hwsts6, + // ME 18/21 + Status5: hwsts5, + }, nil +} + type FirmwareStatus1 struct { WorkingState uint32 MfgMode bool @@ -49,7 +83,7 @@ type FirmwareStatus6 struct { TXTSupported bool } -func GetHFSTS1(hw hwapi.LowLevelHardwareInterfaces) (*FirmwareStatus1, error) { +func getHFSTS1(hw hwapi.LowLevelHardwareInterfaces) (*FirmwareStatus1, error) { hfsts1, err := readHFSTSFromPCIConfigSpace(hw, 1) if err != nil { return nil, fmt.Errorf("couldn't read HFSTS6 from PCI config space: %v", err) @@ -77,7 +111,7 @@ func GetHFSTS1(hw hwapi.LowLevelHardwareInterfaces) (*FirmwareStatus1, error) { return &firmwareStatus, nil } -func GetHFSTS6(hw hwapi.LowLevelHardwareInterfaces) (*FirmwareStatus6, error) { +func getHFSTS6(hw hwapi.LowLevelHardwareInterfaces) (*FirmwareStatus6, error) { hfsts6, err := readHFSTSFromPCIConfigSpace(hw, 6) if err != nil { return nil, fmt.Errorf("couldn't read HFSTS6 from PCI config space: %v", err) @@ -109,6 +143,41 @@ func GetHFSTS6(hw hwapi.LowLevelHardwareInterfaces) (*FirmwareStatus6, error) { return &firmwareStatus, nil } +type FirmwareStatus5 struct { + BgACMStatus bool + VLD bool + RCS bool + ErrorCode uint32 + TXTSupported bool + CPUDebugDisabled bool + BSPInitDisabled bool + BPMExecStatus bool + BgStatus uint32 +} + +// ME 18/21 +func getHFSTS5(hw hwapi.LowLevelHardwareInterfaces) (*FirmwareStatus5, error) { + hfsts5, err := readHFSTSFromPCIConfigSpace(hw, 5) + if err != nil { + return nil, fmt.Errorf("couldn't read HFSTS5 from PCI config space: %v", err) + } + + firmwareStatus := FirmwareStatus5{} + + configSpace := binary.LittleEndian.Uint32(hfsts5) + firmwareStatus.BgACMStatus = (configSpace>>0)&1 != 0 + firmwareStatus.VLD = (configSpace>>1)&1 != 0 + firmwareStatus.RCS = (configSpace>>2)&1 != 0 + firmwareStatus.ErrorCode = (configSpace >> 3) & 31 + firmwareStatus.TXTSupported = (configSpace>>17)&1 != 0 + firmwareStatus.CPUDebugDisabled = (configSpace>>21)&1 != 0 + firmwareStatus.BSPInitDisabled = (configSpace>>22)&1 != 0 + firmwareStatus.BPMExecStatus = (configSpace>>23)&1 != 0 + firmwareStatus.BgStatus = (configSpace >> 25) & 15 + + return &firmwareStatus, nil +} + func readHFSTSFromPCIConfigSpace(hw hwapi.LowLevelHardwareInterfaces, offset int) ([]byte, error) { if offset < 1 || offset > 6 { return nil, fmt.Errorf("invalid HFSTS offset") diff --git a/pkg/provisioning/bootguard/me.go b/pkg/provisioning/bootguard/me.go index d2cc25d7..d9deaf2c 100644 --- a/pkg/provisioning/bootguard/me.go +++ b/pkg/provisioning/bootguard/me.go @@ -5,7 +5,7 @@ import ( "github.com/9elements/converged-security-suite/v2/pkg/tools" "github.com/9elements/go-linux-lowlevel-hw/pkg/hwapi" - "github.com/linuxboot/fiano/pkg/intel/metadata/common/bgheader" + "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt" ) const ( @@ -55,8 +55,8 @@ func GetBGInfo(hw hwapi.LowLevelHardwareInterfaces) (*BGInfo, error) { return &bgi, nil } -func StrictSaneBootGuardProvisioning(v bgheader.BootGuardVersion, fws *FirmwareStatus6, bgi *BGInfo) (bool, error) { - if fws.ErrorEnforcementPolicy != EnforcementPolicyShutdownImmediately { +func StrictSaneBootGuardProvisioning(v cbnt.BootGuardVersion, fws *FirmwareStatus, bgi *BGInfo) (bool, error) { + if fws.Status6.ErrorEnforcementPolicy != EnforcementPolicyShutdownImmediately { return false, fmt.Errorf("enforcement policy isn't set to immediate shutdown") } @@ -64,42 +64,90 @@ func StrictSaneBootGuardProvisioning(v bgheader.BootGuardVersion, fws *FirmwareS } // SaneMEBootGuardProvisioning validates during runtime ME bootguard provisioning -func SaneMEBootGuardProvisioning(v bgheader.BootGuardVersion, fws *FirmwareStatus6, bgi *BGInfo) (bool, error) { - if fws.BypassBootPolicy { - return false, fmt.Errorf("bypass boot policy is active") - } - if fws.BootPolicyInvalid { - return false, fmt.Errorf("boot policy is invalid") - } - if !fws.FPFLock { - return false, fmt.Errorf("FPF isn't locked") - } - if fws.ErrorEnforcementPolicy == EnforcementPolicyDoNothing || - fws.ErrorEnforcementPolicy == EnforcementPolicyShutdownSomehow { - return false, fmt.Errorf("enforcement policy is lazy and doesn't stop boot process") - } - if !fws.ProtectBIOSEnvironment { - return false, fmt.Errorf("protected bios enviroment is disabled") - } - if v == bgheader.Version20 && !bgi.ForceAnchorBoot { - return false, fmt.Errorf("force anchor boot is disabled") - } - if !bgi.Verified { - return false, fmt.Errorf("verified boot is disabled, measured boot only may be possible but isn't supported by Intel officially") - } - if bgi.ModuleRevoked { - return false, fmt.Errorf("one of the the ACM, BPM and KM may be revoked") - } - if fws.BootGuardDisable { - return false, fmt.Errorf("boot guard is disabled") +func SaneMEBootGuardProvisioning(v cbnt.BootGuardVersion, fws *FirmwareStatus, bgi *BGInfo) (bool, error) { + ver, err := tools.GetMEVersion() + if err != nil { + return false, err } if !bgi.BootGuardCapability { return false, fmt.Errorf("missing boot guard microcode updates in FIT") } + + switch ver { + case tools.Version16: + if fws.Status6.BypassBootPolicy { + return false, fmt.Errorf("bypass boot policy is active") + } + if fws.Status6.BootPolicyInvalid { + return false, fmt.Errorf("boot policy is invalid") + } + if !fws.Status6.FPFLock { + return false, fmt.Errorf("FPF isn't locked") + } + if fws.Status6.ErrorEnforcementPolicy == EnforcementPolicyDoNothing || + fws.Status6.ErrorEnforcementPolicy == EnforcementPolicyShutdownSomehow { + return false, fmt.Errorf("enforcement policy is lazy and doesn't stop boot process") + } + if !fws.Status6.ProtectBIOSEnvironment { + return false, fmt.Errorf("protected bios enviroment is disabled") + } + if v == cbnt.Version20 && !bgi.ForceAnchorBoot { + return false, fmt.Errorf("force anchor boot is disabled") + } + if !bgi.Verified { + return false, fmt.Errorf("verified boot is disabled, measured boot only may be possible but isn't supported by Intel officially") + } + if bgi.ModuleRevoked { + return false, fmt.Errorf("one of the the ACM, BPM and KM may be revoked") + } + if fws.Status6.BootGuardDisable { + return false, fmt.Errorf("boot guard is disabled") + } + if !bgi.BootGuardCapability { + return false, fmt.Errorf("missing boot guard microcode updates in FIT") + } + case tools.Version18, tools.Version21: + if !fws.Status6.FPFLock { + return false, fmt.Errorf("FPF is not locked") + } + if fws.Status1.MfgMode { + return false, fmt.Errorf("debug mode is enabled") + } + if !fws.Status5.VLD { + return false, fmt.Errorf("bits that follow are invalid") + } + if fws.Status5.RCS { + return false, fmt.Errorf("RCS does not come from ACM") + } + if !fws.Status5.CPUDebugDisabled { + return false, fmt.Errorf("cpu debug is enabled") + } + if fws.Status1.WorkingState != 0x05 { + return false, fmt.Errorf("invalid working state") + } + if fws.Status1.OperatingMode != 0 { + return false, fmt.Errorf("invalid operating mode") + } + if (v == cbnt.Version20 || v == cbnt.Version21) && !bgi.ForceAnchorBoot { + return false, fmt.Errorf("force anchor boot is disabled") + } + if !bgi.Verified { + return false, fmt.Errorf("verified boot is disabled, measured boot only may be possible but isn't supported by Intel officially") + } + if bgi.ModuleRevoked { + return false, fmt.Errorf("one of the the ACM, BPM and KM may be revoked") + } + if fws.Status6.BootGuardDisable { + return false, fmt.Errorf("boot guard is disabled") + } + if !bgi.BootGuardCapability { + return false, fmt.Errorf("missing boot guard microcode updates in FIT") + } + } return true, nil } -func ValidTXTRegister(hw hwapi.LowLevelHardwareInterfaces) (bool, error) { +func ValidACMStatus(hw hwapi.LowLevelHardwareInterfaces) (bool, error) { txtSpace, err := tools.FetchTXTRegs(hw) if err != nil { return false, fmt.Errorf("couldn't fetch TXT regs: %v", err) @@ -132,9 +180,88 @@ func ValidTXTRegister(hw hwapi.LowLevelHardwareInterfaces) (bool, error) { return false, fmt.Errorf("couldn't read bootstatus: %v", err) } - if ((Bootstatus >> 31) & 0x1) != 1 { + if !Bootstatus.BgSuccess { + return false, fmt.Errorf("BootGuard did not startup successfully") + } + + return true, nil +} + +func ValidTXTRegisters(hw hwapi.LowLevelHardwareInterfaces) (bool, error) { + txtSpace, err := tools.FetchTXTRegs(hw) + if err != nil { + return false, fmt.Errorf("couldn't fetch TXT regs: %v", err) + } + + // The check for ACM status by reading txtSpace >> 0x328 only gives a meaningful + // results if TXT is disabled in BIOS by the user. Otherwise the same address will be + // used as TXT.ERRORCODE register, and filled with the TXT status. Now given that TXT started + // successfully, bit 31 will change the meaning, i.e. if set, there is some error that we could + // further evaluate, otherwise we shall ignore the rest. Thus, let's keep the 'old' logic iff TXT + // is disabled. The check can be done by reading 15th bit of IA32_FEATURE_CONTROL MSR. + txtEnabled := hw.ReadMSR(0x3a) + + Bootstatus, err := tools.ReadBootStatusRaw(txtSpace) + if err != nil { + return false, fmt.Errorf("couldn't read bootstatus: %v", err) + } + + if (txtEnabled >> 15) == 0 { + ACMStatus, err := tools.ReadACMStatus(txtSpace) + if err != nil { + return false, fmt.Errorf("couldn't read ACM status: %v", err) + } + + if !ACMStatus.Valid { + return false, fmt.Errorf("ACM status is invalid") + } + + if !ACMStatus.ACMStarted { + return false, fmt.Errorf("ACM isn't started") + } + + } else { + if !Bootstatus.TxtSuccess { + return false, fmt.Errorf("TXT did not startup successfully") + } + } + + ACMStatusPolicy, err := tools.ReadACMPolicyStatusRaw(txtSpace) + if err != nil { + return false, fmt.Errorf("couldn't read ACM policy status: %v", err) + } + + if ((ACMStatusPolicy >> 6) & 0x1) != 0 { + return false, fmt.Errorf("HAP Bit is set") + } + + if ((ACMStatusPolicy >> 4) & 0x1) != 1 { + return false, fmt.Errorf("measured boot is disabled") + } + + if ((ACMStatusPolicy >> 5) & 0x1) != 1 { + return false, fmt.Errorf("verified boot is disabled") + } + + if ((ACMStatusPolicy >> 15) & 0x1) != 1 { + return false, fmt.Errorf("TPM failed") + } + + if !Bootstatus.BgSuccess { return false, fmt.Errorf("BootGuard did not startup successfully") } + if !Bootstatus.BIOSTrusted { + return false, fmt.Errorf("bios is not trusted") + } + + if !Bootstatus.SACMSuccess { + return false, fmt.Errorf("SACM status invalid") + } + + if Bootstatus.CPUError { + return false, fmt.Errorf("CPU error") + } + return true, nil } diff --git a/pkg/provisioning/bootguard/structures.go b/pkg/provisioning/bootguard/structures.go index 4c1d1b60..58b90b0e 100644 --- a/pkg/provisioning/bootguard/structures.go +++ b/pkg/provisioning/bootguard/structures.go @@ -1,12 +1,9 @@ package bootguard import ( - "github.com/linuxboot/fiano/pkg/intel/metadata/bg/bgbootpolicy" - "github.com/linuxboot/fiano/pkg/intel/metadata/bg/bgkey" "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt" - "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt/cbntbootpolicy" - "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt/cbntkey" - "github.com/linuxboot/fiano/pkg/intel/metadata/common/bgheader" + bootpolicy "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt/bootpolicy" + keymanifest "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt/keymanifest" ) // CMOSIoAddress holds information about the location of on-demand power down requests in CMOS. @@ -75,14 +72,14 @@ type KeyHash struct { // Options contains all version bootguard options type VersionedData struct { - BGbpm *bgbootpolicy.Manifest `json:"v1-bootpolicy,omitempty"` - BGkm *bgkey.Manifest `json:"v1-keymanifest,omitempty"` - CBNTbpm *cbntbootpolicy.Manifest `json:"v2-bootpolicy,omitempty"` - CBNTkm *cbntkey.Manifest `json:"v2-keymanifest,omitempty"` + BGbpm *bootpolicy.ManifestBG `json:"v1-bootpolicy,omitempty"` + BGkm *keymanifest.BGManifest `json:"v1-keymanifest,omitempty"` + CBNTbpm *bootpolicy.ManifestCBnT `json:"v2-bootpolicy,omitempty"` + CBNTkm *keymanifest.CBnTManifest `json:"v2-keymanifest,omitempty"` } // BootGuard unification structure, operates on manifests and reader type BootGuard struct { VData VersionedData `json:"bootguard"` - Version bgheader.BootGuardVersion + Version cbnt.BootGuardVersion } diff --git a/pkg/test/bootguard_tests.go b/pkg/test/bootguard_tests.go index d57411e2..10efae8c 100644 --- a/pkg/test/bootguard_tests.go +++ b/pkg/test/bootguard_tests.go @@ -4,10 +4,13 @@ import ( "bytes" "fmt" + "github.com/9elements/converged-security-suite/v2/pkg/intel" "github.com/9elements/converged-security-suite/v2/pkg/provisioning/bootguard" "github.com/9elements/converged-security-suite/v2/pkg/tools" "github.com/9elements/go-linux-lowlevel-hw/pkg/hwapi" "github.com/linuxboot/fiano/pkg/intel/metadata/fit" + + log "github.com/sirupsen/logrus" ) const ( @@ -16,8 +19,13 @@ const ( ) var ( + legacy = []intel.BgVersion{intel.BootGuard, intel.CBnT20} + cbnt21 = []intel.BgVersion{intel.CBnT21} + all = []intel.BgVersion{intel.BootGuard, intel.CBnT20, intel.CBnT21} + testbootguardfit = Test{ Name: "FIT meets BootGuard requirements", + Description: "Checks FIT has all required Boot Guard records (ACM, BPM, and KM).", Required: true, function: BootGuardFIT, Status: Implemented, @@ -27,6 +35,7 @@ var ( } testbootguardacm = Test{ Name: "SACM meets sane BootGuard requirements", + Description: "Parses SACM and validates production mode, ACM type, and optional chipset match.", Required: true, function: BootGuardACM, dependencies: []*Test{&testbootguardfit}, @@ -37,6 +46,7 @@ var ( } testbootguardkm = Test{ Name: "Key Manifest meets sane BootGuard requirements", + Description: "Parses Key Manifest and validates signature, crypto safety, and BPM hash presence.", Required: true, function: BootGuardKM, dependencies: []*Test{&testbootguardfit}, @@ -47,6 +57,7 @@ var ( } testbootguardbpm = Test{ Name: "Boot Policy Manifest meets sane BootGuard requirements", + Description: "Parses BPM/KM and validates BPM structure, signature, security properties, and KM binding.", Required: true, function: BootGuardBPM, dependencies: []*Test{&testbootguardfit}, @@ -57,6 +68,7 @@ var ( } testbootguardibb = Test{ Name: "Verifies BPM and IBBs match firmware image", + Description: "Verifies measured IBBs from firmware match the BPM final IBB digest.", Required: true, function: BootGuardIBB, dependencies: []*Test{&testbootguardfit}, @@ -67,6 +79,7 @@ var ( } testbootguardvalidateme = Test{ Name: "[RUNTIME] Validates Intel ME specific configuration against KM/BPM in firmware image", + Description: "Compares runtime ME Boot Guard status against KM/BPM policy requirements.", Required: true, function: BootGuardValidateME, dependencies: []*Test{&testbootguardfit}, @@ -74,26 +87,53 @@ var ( SpecificationChapter: "", SpecificiationTitle: IntelBootGuardSpecificationTitle, SpecificationDocumentID: IntelBootGuardSpecificationDocumentID, + SupportedVersion: legacy, + } + testbootguardmebootguardsts = Test{ + Name: "[RUNTIME] Verifies Intel ME Boot Guard status", + Description: "Reads Boot Guard related information from ME and checks if they are sane (requires ME 18/21)", + Required: true, + function: BootGuardMESts, + dependencies: []*Test{&testbootguardfit}, + Status: Implemented, + SpecificationChapter: "", + SpecificiationTitle: "Intel Converged Security and Management Engine 18.x/19.x BIOS Specification / Intel Converged Security and Management Engine 21.0", + SpecificationDocumentID: "729124 / 829718", + SupportedVersion: cbnt21, } testbootguardsanemeconfig = Test{ Name: "[RUNTIME] Verifies Intel ME Boot Guard configuration is sane and safe", + Description: "Checks runtime ME Boot Guard provisioning state is sane (strict or relaxed profile).", Required: true, function: BootGuardSaneMEConfig, Status: Implemented, SpecificationChapter: "", SpecificiationTitle: IntelBootGuardSpecificationTitle, SpecificationDocumentID: IntelBootGuardSpecificationDocumentID, + SupportedVersion: all, } - testbootguardtxt = Test{ - Name: "[RUNTIME] BtG/TXT registers are sane", + testbootguardbgacmsts = Test{ + Name: "[RUNTIME] Verifies post-boot ACM status", + Description: "Validates runtime TXT registers for a secure post-boot ACM status.", Required: true, - function: BootGuardTXT, + function: BootGuardTXTACMSts, Status: Implemented, SpecificationChapter: "", SpecificiationTitle: IntelTXTSpecificationTitle, SpecificationDocumentID: IntelTXTSpecificationDocumentID, + SupportedVersion: legacy, + } + testbootguardtxtsts = Test{ + Name: "[RUNTIME] Verifies post-boot BtG/TXT registers", + Description: "Validates runtime TXT/Boot Guard registers for a secure post boot status.", + Required: true, + function: BootGuardTXTRegisters, + Status: Implemented, + SpecificationChapter: "", + SpecificiationTitle: IntelTXTSpecificationTitle, + SpecificationDocumentID: IntelTXTSpecificationDocumentID, + SupportedVersion: all, } - // TestsMemory exposes the slice for memory related txt tests TestsBootGuard = [...]*Test{ &testbootguardfit, @@ -102,8 +142,10 @@ var ( &testbootguardbpm, &testbootguardibb, &testbootguardvalidateme, + &testbootguardmebootguardsts, &testbootguardsanemeconfig, - &testbootguardtxt, + &testbootguardbgacmsts, + &testbootguardtxtsts, } ) @@ -239,8 +281,15 @@ func BootGuardBPM(hw hwapi.LowLevelHardwareInterfaces, p *PreSet) (bool, error, if !secure || err != nil { return false, fmt.Errorf("bpm crypto parameters are insecure"), err } + var warn []string if p.Strict { - secure, err = b.StrictSaneBPMSecurityProps() + secure, warn, err= b.StrictSaneBPMSecurityProps() + if warn != nil { + log.Warn("Strict BPM security properties:") + for _, w := range warn { + log.Warnf("%s", w) + } + } } else { secure, err = b.SaneBPMSecurityProps() } @@ -299,17 +348,38 @@ func BootGuardValidateME(hw hwapi.LowLevelHardwareInterfaces, p *PreSet) (bool, if b == nil || err != nil { return false, fmt.Errorf("couldn't parse KM and BPM"), err } - hfsts6, err := bootguard.GetHFSTS6(hw) + hfsts, err := bootguard.NewFirmwareStatus(hw) if err != nil { - return false, err, nil + return false, fmt.Errorf("couldn't read Intel ME firmware status"), err } - valid, err := b.ValidateMEAgainstManifests(hfsts6) + valid, err := b.ValidateMEAgainstManifests(hfsts) if !valid || err != nil { return false, fmt.Errorf("bootguard km/bpm doesn't match ME BootGuard configuration"), err } return true, nil, nil } +// BootGuardMESts +func BootGuardMESts(hw hwapi.LowLevelHardwareInterfaces, p *PreSet) (bool, error, error) { + hfsts, err := bootguard.NewFirmwareStatus(hw) + if err != nil { + return false, fmt.Errorf("couldn't read Intel ME firmware status"), err + } + if !hfsts.Status5.BgACMStatus { + return false, fmt.Errorf("acm is not active"), err + } + if hfsts.Status5.ErrorCode != 0 { + return false, fmt.Errorf("bg startup failed"), err + } + if !hfsts.Status5.BPMExecStatus { + return false, fmt.Errorf("bpm not executed"), err + } + if hfsts.Status5.BgStatus != 0x01 { + return false, fmt.Errorf("bg status is invalid"), err + } + return true, nil, nil +} + // BootGuardSaneMEConfig func BootGuardSaneMEConfig(hw hwapi.LowLevelHardwareInterfaces, p *PreSet) (bool, error, error) { entries, err := fit.GetEntries(p.Firmware) @@ -328,23 +398,23 @@ func BootGuardSaneMEConfig(hw hwapi.LowLevelHardwareInterfaces, p *PreSet) (bool return false, fmt.Errorf("couldn't parse KM"), err } - hfsts6, err := bootguard.GetHFSTS6(hw) + hfsts, err := bootguard.NewFirmwareStatus(hw) if err != nil { - return false, fmt.Errorf("couldn't read HFSTS6: %v", err), nil + return false, fmt.Errorf("couldn't read HFSTS6"), err } bgi, err := bootguard.GetBGInfo(hw) if err != nil { - return false, err, nil + return false, fmt.Errorf("couldn't read Boot Guard runtime info"), err } if p.Strict { - valid, err := bootguard.StrictSaneBootGuardProvisioning(b.Version, hfsts6, bgi) + valid, err := bootguard.StrictSaneBootGuardProvisioning(b.Version, hfsts, bgi) if !valid || err != nil { return false, fmt.Errorf("provisiong boot guard configuraton in me isn't safe"), err } } else { - valid, err := bootguard.SaneMEBootGuardProvisioning(b.Version, hfsts6, bgi) + valid, err := bootguard.SaneMEBootGuardProvisioning(b.Version, hfsts, bgi) if !valid || err != nil { return false, fmt.Errorf("provisiong boot guard configuraton in me isn't safe"), err } @@ -352,9 +422,19 @@ func BootGuardSaneMEConfig(hw hwapi.LowLevelHardwareInterfaces, p *PreSet) (bool return true, nil, nil } -// BootGuardTXT checks TXT requirements for safe BootGuard configuration -func BootGuardTXT(hw hwapi.LowLevelHardwareInterfaces, p *PreSet) (bool, error, error) { - valid, err := bootguard.ValidTXTRegister(hw) +// BootGuardTXTACMSts checks TXT requirements for safe BootGuard configuration +func BootGuardTXTACMSts(hw hwapi.LowLevelHardwareInterfaces, p *PreSet) (bool, error, error) { + valid, err := bootguard.ValidACMStatus(hw) + if !valid || err != nil { + return false, fmt.Errorf("txt regs aren't valid"), err + } + + return true, nil, nil +} + +// BootGuardTXTRegisters checks TXT requirements for safe BootGuard configuration +func BootGuardTXTRegisters(hw hwapi.LowLevelHardwareInterfaces, p *PreSet) (bool, error, error) { + valid, err := bootguard.ValidTXTRegisters(hw) if !valid || err != nil { return false, fmt.Errorf("txt regs aren't valid"), err } diff --git a/pkg/test/fit.go b/pkg/test/fit.go index fc1afc4f..5dfcc5a1 100644 --- a/pkg/test/fit.go +++ b/pkg/test/fit.go @@ -371,7 +371,11 @@ func HasBIOSPolicy(txtAPI hwapi.LowLevelHardwareInterfaces, p *PreSet) (bool, er func getFITDataSize(hdr fit.EntryHeaders, txtAPI hwapi.LowLevelHardwareInterfaces) uint64 { firmware := newTXTAPIFirmwareReadSeeker(txtAPI) - result, err := fit.EntryDataSegmentSize(fit.NewEntry(&hdr, firmware), firmware) + fwSize, err := fit.FirmwareSizeUsedFromSeeker(firmware) + if err != nil { + panic(err) + } + result, err := fit.EntryDataSegmentSize(fit.NewEntry(&hdr, firmware, fwSize), firmware, fwSize) if err != nil { panic(err) } diff --git a/pkg/test/test.go b/pkg/test/test.go index 0cf54ff9..cd8f438b 100644 --- a/pkg/test/test.go +++ b/pkg/test/test.go @@ -3,6 +3,7 @@ package test import ( "fmt" + "github.com/9elements/converged-security-suite/v2/pkg/intel" "github.com/9elements/go-linux-lowlevel-hw/pkg/hwapi" ) @@ -50,8 +51,9 @@ func (t Status) String() string { // Test exposes the structure in which information about TXT tests are held type Test struct { - Name string - Required bool + Name string + Required bool + Description string //testerror: If test fails and returns an testerror -> test failure //internalerror: If test fails and returns an internalerror //-> mostly api errors, but not directly testrelated problem. @@ -68,6 +70,8 @@ type Test struct { // The specification used in this test SpecificiationTitle string SpecificationDocumentID string + // Only relevant for the runtime tests + SupportedVersion []intel.BgVersion } // Run implements the genereal test function and exposes it. diff --git a/pkg/test/test_test.go b/pkg/test/test_test.go index faea8af7..e9c3c1da 100644 --- a/pkg/test/test_test.go +++ b/pkg/test/test_test.go @@ -4,6 +4,7 @@ import ( "fmt" "testing" + "github.com/9elements/converged-security-suite/v2/pkg/intel" "github.com/9elements/converged-security-suite/v2/pkg/tools" "github.com/9elements/go-linux-lowlevel-hw/pkg/hwapi" "github.com/google/go-tpm/legacy/tpm2" @@ -13,16 +14,19 @@ func TestTest_Run(t *testing.T) { type fields struct { Name string Required bool + Description string function func(hwapi.LowLevelHardwareInterfaces, *PreSet) (bool, error, error) Result Result dependencies []*Test ErrorText string Status Status + SuppVersion []intel.BgVersion } BNotImplemented := Test{ "Test B", true, + "This is Test B", func(a hwapi.LowLevelHardwareInterfaces, p *PreSet) (bool, error, error) { return true, nil, nil }, @@ -34,11 +38,13 @@ func TestTest_Run(t *testing.T) { "", "", "", + []intel.BgVersion{intel.BootGuard}, } BFailed := Test{ "Test B", true, + "This is Test B", func(a hwapi.LowLevelHardwareInterfaces, p *PreSet) (bool, error, error) { return true, nil, nil }, @@ -50,10 +56,12 @@ func TestTest_Run(t *testing.T) { "", "", "", + []intel.BgVersion{intel.BootGuard}, } BNotRun := Test{ "Test B", true, + "This is Test B", func(a hwapi.LowLevelHardwareInterfaces, p *PreSet) (bool, error, error) { return true, nil, nil }, @@ -65,6 +73,7 @@ func TestTest_Run(t *testing.T) { "", "", "", + []intel.BgVersion{intel.CBnT20}, } tests := []struct { @@ -78,6 +87,7 @@ func TestTest_Run(t *testing.T) { fields{ "Test A, ignores unimplemented Test B", true, + "This is Test A", func(a hwapi.LowLevelHardwareInterfaces, p *PreSet) (bool, error, error) { return true, nil, nil }, @@ -85,6 +95,7 @@ func TestTest_Run(t *testing.T) { []*Test{&BNotImplemented}, "", Implemented, + []intel.BgVersion{intel.BootGuard}, }, true, ResultPass, @@ -94,6 +105,7 @@ func TestTest_Run(t *testing.T) { fields{ "Test A, fails on failed dependency Test B", true, + "This is Test A", func(a hwapi.LowLevelHardwareInterfaces, p *PreSet) (bool, error, error) { return true, nil, nil }, @@ -101,6 +113,7 @@ func TestTest_Run(t *testing.T) { []*Test{&BFailed}, "", Implemented, + []intel.BgVersion{intel.BootGuard}, }, false, ResultDependencyFailed, @@ -110,6 +123,7 @@ func TestTest_Run(t *testing.T) { fields{ "Test A, runs dependency Test B", true, + "This is Test A", func(a hwapi.LowLevelHardwareInterfaces, p *PreSet) (bool, error, error) { return BNotRun.Result == ResultPass, nil, nil }, @@ -117,6 +131,7 @@ func TestTest_Run(t *testing.T) { []*Test{&BNotRun}, "", Implemented, + []intel.BgVersion{intel.BootGuard}, }, true, ResultPass, @@ -126,6 +141,7 @@ func TestTest_Run(t *testing.T) { fields{ "Test A, multiple dependencies", true, + "This is Test A", func(a hwapi.LowLevelHardwareInterfaces, p *PreSet) (bool, error, error) { return BNotRun.Result == ResultPass, nil, nil }, @@ -133,6 +149,7 @@ func TestTest_Run(t *testing.T) { []*Test{&BNotRun, &BNotImplemented}, "", Implemented, + []intel.BgVersion{intel.BootGuard}, }, true, ResultPass, @@ -142,6 +159,7 @@ func TestTest_Run(t *testing.T) { fields{ "Test A, returns internal error", true, + "This is Test A", func(a hwapi.LowLevelHardwareInterfaces, p *PreSet) (bool, error, error) { return true, nil, fmt.Errorf("Internal error 24") }, @@ -149,6 +167,7 @@ func TestTest_Run(t *testing.T) { []*Test{}, "", Implemented, + []intel.BgVersion{intel.BootGuard}, }, false, ResultInternalError, @@ -158,6 +177,7 @@ func TestTest_Run(t *testing.T) { fields{ "Test A, returns error", true, + "This is Test A", func(a hwapi.LowLevelHardwareInterfaces, p *PreSet) (bool, error, error) { return true, fmt.Errorf("error 1"), nil }, @@ -165,6 +185,7 @@ func TestTest_Run(t *testing.T) { []*Test{}, "", Implemented, + []intel.BgVersion{intel.BootGuard}, }, false, ResultFail, @@ -174,6 +195,7 @@ func TestTest_Run(t *testing.T) { fields{ "Test A, returns error, but is critical", true, + "This is Test A", func(a hwapi.LowLevelHardwareInterfaces, p *PreSet) (bool, error, error) { return false, fmt.Errorf("error 1"), nil }, @@ -181,6 +203,7 @@ func TestTest_Run(t *testing.T) { []*Test{}, "", Implemented, + []intel.BgVersion{intel.BootGuard}, }, false, ResultFail, diff --git a/pkg/tools/me.go b/pkg/tools/me.go new file mode 100644 index 00000000..9e771c8d --- /dev/null +++ b/pkg/tools/me.go @@ -0,0 +1,60 @@ +package tools + +import ( + "fmt" + "strconv" + "strings" + + "github.com/prometheus/procfs/sysfs" +) + +type MEVersion uint8 + +const ( + Version16 MEVersion = 16 + Version18 MEVersion = 18 + Version21 MEVersion = 21 +) + +func GetMEVersion() (MEVersion, error) { + fs, err := sysfs.NewFS("/sys") + if err != nil { + return 0, err + } + + mei, err := fs.MEIClass() + if err != nil { + return 0, err + } + + // There can be (theoretically) more than one MEI devices. + // We onlly need the version of one of it. + var fwVersion string + for _, dev := range *mei { + fwVersion = *dev.FWVersion + break + } + + // There are always 4 lines in fw_version (no clue why) exposed in sysfs. + // So lets take the first line and then look for what is interesting for us, + // i.e. 0:N where N is one of the defined MEVersion's + fline := strings.Split(fwVersion, "\n") + felem := strings.Split(fline[0], ".") + pref := strings.Split(felem[0], ":") + + ver, err := strconv.Atoi(pref[1]) + if err != nil { + return 0, err + } + + switch ver { + case 16: + return Version16, nil + case 18: + return Version18, nil + case 21: + return Version21, nil + } + + return 0, fmt.Errorf("unknown ME version") +} diff --git a/pkg/tools/txt.go b/pkg/tools/txt.go index 0fa6957c..27286613 100644 --- a/pkg/tools/txt.go +++ b/pkg/tools/txt.go @@ -126,6 +126,18 @@ type TXTBiosMLEFlags struct { IsClientState bool } +// TXTBootStatus holds the results of SACM read from TXT config space +type TXTBootStatus struct { + TxtSuccess bool + BgSuccess bool + Bboot bool + PFRSuccess bool + BgFail bool + BIOSTrusted bool + CPUError bool + SACMSuccess bool +} + // FetchTXTRegs returns a raw copy of the TXT config space func FetchTXTRegs(txtAPI hwapi.LowLevelHardwareInterfaces) ([]byte, error) { data := make([]byte, 0x1000) @@ -448,16 +460,27 @@ func ReadACMPolicyStatusRaw(data []byte) (uint64, error) { } // ReadBootStatusRaw decodes the raw boot status register bits -func ReadBootStatusRaw(data []byte) (uint64, error) { +func ReadBootStatusRaw(data []byte) (TXTBootStatus, error) { + var ret TXTBootStatus var u64 uint64 buf := bytes.NewReader(data) _, err := buf.Seek(txtBootStatus, io.SeekStart) if err != nil { - return 0, err + return ret, err } err = binary.Read(buf, binary.LittleEndian, &u64) if err != nil { - return 0, err + return ret, err } - return u64, nil + + ret.TxtSuccess = (u64>>30)&1 != 0 + ret.BgSuccess = (u64>>31)&1 != 0 + ret.Bboot = (u64>>32)&1 != 0 + ret.PFRSuccess = (u64>>33)&1 != 0 + ret.BgFail = (u64>>48)&1 != 0 + ret.BIOSTrusted = (u64>>59)&1 != 0 + ret.CPUError = (u64>>62)&1 != 0 + ret.SACMSuccess = (u64>>63)&1 != 0 + + return ret, nil }