Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
9c58095
docs: add CBnT 2.1 relevant mentions in README's
micgor32 Apr 7, 2026
408e8ab
feat: cmd/core/bg-prov: use unified packages for BPM and KM
micgor32 Apr 7, 2026
f48ee51
feat: bootflow/conditions/biosconds/: use unified packages for BPM an…
micgor32 Apr 7, 2026
447b7ac
chore: bootflow/systemartifacts: update imports
micgor32 Apr 7, 2026
6e1ff2d
feat: add TXTBootStatus representation
micgor32 Apr 7, 2026
3890065
feat: add runtime BG/CBnT version detection
micgor32 Apr 7, 2026
2c3cc1b
feat: pkg/test/fit.go: use actual fw image size in getFITDataSize
micgor32 Apr 7, 2026
2130920
feat: pkg/test/test.go: add SupportedVersion field
micgor32 Apr 7, 2026
128e3b5
feat: pkg/provisioning/bootguard/structures.go: use unified packages …
micgor32 Apr 7, 2026
5b63580
feat: add CBnT 2.1 specific tests for bg-suite
micgor32 Apr 8, 2026
32610d5
feat: pkg/bootflow/datasources/inteldata/ibb.go: adjust to unified CBnT
micgor32 Apr 8, 2026
05f614b
feat: cmd/core/bg-suite: runtime CBnT test selection and test descrip…
micgor32 Apr 8, 2026
cecd500
feat: pkg/provisioning/bootguard/bootguard.go: adapt for CBnT 2.1
micgor32 Apr 8, 2026
62d7375
feat: pkg/bootflow/steps/intelsteps/measure_pcr0_data.go: adapt to un…
micgor32 Apr 8, 2026
bc7cb5e
feat: add function to get ME version from sysfs
micgor32 Apr 9, 2026
1268509
feat: add ME 18/21 structures for HFSTS
micgor32 Apr 9, 2026
6d6d298
test: adjust tests for the changes in Test struct
micgor32 Apr 9, 2026
acf1084
fix: refactor the logic for NewVData()
micgor32 Apr 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
396 changes: 254 additions & 142 deletions cmd/core/bg-prov/cmd.go

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions cmd/core/bg-suite/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
66 changes: 56 additions & 10 deletions cmd/core/bg-suite/TESTPLAN.md
Original file line number Diff line number Diff line change
@@ -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.
45 changes: 39 additions & 6 deletions cmd/core/bg-suite/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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")
Expand All @@ -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)
Expand Down Expand Up @@ -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
Expand All @@ -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 {
Expand All @@ -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
}
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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)
}
}
Expand Down
12 changes: 7 additions & 5 deletions cmd/core/bg-suite/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
44 changes: 35 additions & 9 deletions pkg/bootflow/conditions/biosconds/intelconds/valid_bpm.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)

Expand All @@ -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.KeySignature.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
Expand Down
18 changes: 13 additions & 5 deletions pkg/bootflow/conditions/biosconds/intelconds/valid_ibb.go
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand All @@ -25,20 +25,28 @@ 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()
if err != nil {
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
Expand Down
25 changes: 20 additions & 5 deletions pkg/bootflow/conditions/biosconds/intelconds/valid_km.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)

Expand All @@ -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
}
Loading
Loading